1 /*
2 * Copyright (c) 2012-2013, Texas Instruments Incorporated
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * * Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 *
12 * * Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 *
16 * * Neither the name of Texas Instruments Incorporated nor the names of
17 * its contributors may be used to endorse or promote products derived
18 * from this software without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
22 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
24 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
25 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
26 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
27 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
28 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
29 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
30 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 */
32 /*!
33 * @file NameServer.c
34 *
35 * @brief NameServer Manager
36 */
38 /* Standard IPC headers */
39 #include <ti/ipc/Std.h>
41 /* POSIX thread support */
42 #include <pthread.h>
44 /* Socket Headers */
45 #include <sys/queue.h>
46 #include <sys/select.h>
47 #include <sys/time.h>
48 #include <sys/types.h>
49 #include <sys/param.h>
50 #include <sys/eventfd.h>
51 #include <sys/socket.h>
52 #include <errno.h>
53 #include <stdio.h>
54 #include <string.h>
55 #include <stdlib.h>
56 #include <unistd.h>
57 #include <assert.h>
59 /* Socket Protocol Family */
60 #include <net/rpmsg.h>
62 /* Module level headers */
63 #include <ti/ipc/NameServer.h>
64 #include <ti/ipc/MultiProc.h>
65 #include <_MultiProc.h>
67 /* Internal stuff: */
68 #include <_NameServer.h>
69 #include <_NameServerRemoteRpmsg.h>
71 /* Socket utils: */
72 #include <SocketFxns.h>
74 #include <_lad.h>
76 #define MESSAGEQ_RPMSG_PORT 61
77 #define NAME_SERVER_RPMSG_ADDR 0
79 #define INVALIDSOCKET (-1)
81 #if defined (__cplusplus)
82 extern "C" {
83 #endif
86 /* =============================================================================
87 * Structures & Enums
88 * =============================================================================
89 */
91 /* Structure of entry in Name/Value table */
92 typedef struct NameServer_TableEntry_tag {
93 CIRCLEQ_ENTRY(NameServer_TableEntry_tag) elem;
94 /* List element */
95 UInt32 hash;
96 /* Hash value */
97 String name;
98 /* Name portion of the name/value pair. */
99 UInt len;
100 /* Length of the value field. */
101 Ptr value;
102 /* Value portion of the name/value entry. */
103 Bool collide;
104 /* Does the hash collide? */
105 struct NameServer_TableEntry_tag * next;
106 /* Pointer to the next entry, used incase of collision only */
107 } NameServer_TableEntry;
109 /* Structure defining object for the NameServer */
110 struct NameServer_Object {
111 CIRCLEQ_ENTRY(NameServer_Object) elem;
112 CIRCLEQ_HEAD(dummy2, NameServer_TableEntry_tag) nameList;
113 String name; /* name of the instance */
114 NameServer_Params params; /* the parameter structure */
115 UInt32 count; /* count of entries */
116 UInt32 refCount; /* reference count to this object */
117 pthread_mutex_t gate; /* crit sect gate */
118 } NameServer_Object;
120 /* structure for NameServer module state */
121 typedef struct NameServer_ModuleObject {
122 CIRCLEQ_HEAD(dummy1, NameServer_Object) objList;
123 Int32 refCount;
124 int sendSock[MultiProc_MAXPROCESSORS];
125 /* Sockets for sending to remote proc nameserver ports: */
126 int recvSock[MultiProc_MAXPROCESSORS];
127 /* Sockets for recving from remote proc nameserver ports: */
128 pthread_t listener;
129 /* Listener thread for NameServer replies and requests. */
130 int unblockFd;
131 /* Event to post to exit listener. */
132 int waitFd;
133 /* Event to post to NameServer_get. */
134 NameServerMsg nsMsg;
135 /* NameServer Message cache. */
136 NameServer_Params defInstParams;
137 /* Default instance paramters */
138 pthread_mutex_t modGate;
139 } NameServer_ModuleObject;
141 #define CIRCLEQ_destruct(head) { \
142 (head)->cqh_first = NULL; \
143 (head)->cqh_last = NULL; \
144 }
146 #define CIRCLEQ_elemClear(elem) { \
147 (elem)->cqe_next = (elem)->cqe_prev = (Void *)(elem); \
148 }
150 #define CIRCLEQ_traverse(x, y, tag) \
151 for (x = (y)->cqh_first; x != (struct tag *)(y); x = x->elem.cqe_next)
153 /* =============================================================================
154 * Globals
155 * =============================================================================
156 */
157 /*
158 * NameServer_state
159 *
160 * Make the module gate "recursive" since NameServer_getHandle() needs to
161 * use it and NameServer_create() needs to hold it around its call to
162 * NameServer_getHandle(). Also, use the static initializer instead of a
163 * run-time init call, so we can use this gate immediately in _setup().
164 */
165 static NameServer_ModuleObject NameServer_state = {
166 .defInstParams.maxRuntimeEntries = 0u,
167 .defInstParams.tableHeap = NULL,
168 .defInstParams.checkExisting = TRUE,
169 .defInstParams.maxValueLen = 0u,
170 .defInstParams.maxNameLen = 16u,
171 #if defined(IPC_BUILDOS_ANDROID)
172 .modGate = PTHREAD_RECURSIVE_MUTEX_INITIALIZER,
173 #else
174 // only _NP (non-portable) type available in CG tools which we're using
175 .modGate = PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP,
176 #endif
177 .refCount = 0
178 };
180 static NameServer_ModuleObject * NameServer_module = &NameServer_state;
182 static const UInt32 stringCrcTab[256u] = {
183 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f,
184 0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
185 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2,
186 0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
187 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9,
188 0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172,
189 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c,
190 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
191 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423,
192 0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
193 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, 0x01db7106,
194 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
195 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d,
196 0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e,
197 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950,
198 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
199 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7,
200 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0,
201 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa,
202 0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
203 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81,
204 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a,
205 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84,
206 0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
207 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb,
208 0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc,
209 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e,
210 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
211 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55,
212 0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
213 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28,
214 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
215 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f,
216 0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38,
217 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242,
218 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
219 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69,
220 0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2,
221 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc,
222 0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
223 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693,
224 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
225 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d,
226 };
228 static UInt32 stringHash(String s)
229 {
230 UInt32 hash = strlen(s);
231 UInt32 i;
233 for (i = 0; i < strlen(s); i++) {
234 hash = (hash >> 8u) ^ stringCrcTab[(hash & 0xff)] ^ s[i];
235 }
237 return (hash);
238 }
240 static void NameServerRemote_processMessage(NameServerMsg * msg, UInt16 procId)
241 {
242 NameServer_Handle handle;
243 Int status = NameServer_E_FAIL;
244 int err;
245 uint64_t buf = 1;
246 int numBytes;
247 int waitFd = NameServer_module->waitFd;
249 if (msg->request == NAMESERVER_REQUEST) {
250 LOG2("NameServer Request: instanceName: %s, name: %s\n",
251 (String)msg->instanceName, (String)msg->name)
253 /*
254 * Message is a request. Lookup name in NameServer table.
255 * Send a response message back to source processor.
256 */
257 handle = NameServer_getHandle((String)msg->instanceName);
259 if (handle != NULL) {
260 /* Search for the NameServer entry */
261 LOG0("Calling NameServer_getLocalUInt32...\n")
262 status = NameServer_getLocalUInt32(handle,
263 (String)msg->name, &msg->value);
264 }
266 LOG2("NameServer Response: instanceName: %s, name: %s,",
267 (String)msg->instanceName, (String)msg->name)
268 /* set the request status */
269 if (status < 0) {
270 LOG1(" Value not found, status: %d\n", status)
271 msg->requestStatus = 0;
272 }
273 else {
274 msg->requestStatus = 1;
275 LOG1(" Value: 0x%x\n", msg->value)
276 }
278 /* specify message as a response */
279 msg->request = NAMESERVER_RESPONSE;
280 msg->reserved = NAMESERVER_MSG_TOKEN;
282 /* send response message to remote processor */
283 err = send(NameServer_module->sendSock[procId], msg,
284 sizeof(NameServerMsg), 0);
285 if (err < 0) {
286 LOG2("NameServer: send failed: %d, %s\n", errno, strerror(errno))
287 }
288 }
289 else {
290 LOG2("NameServer Reply: instanceName: %s, name: %s",
291 (String)msg->instanceName, (String)msg->name)
292 LOG1(", value: 0x%x\n", msg->value)
294 /* Save the response message. */
295 memcpy(&NameServer_module->nsMsg, msg, sizeof(NameServerMsg));
297 /* Post the eventfd upon which NameServer_get() is waiting */
298 numBytes = write(waitFd, &buf, sizeof(uint64_t));
299 }
300 }
303 static void *listener_cb(void *arg)
304 {
305 fd_set rfds;
306 int ret = 0, maxfd;
307 UInt16 procId;
308 struct sockaddr_rpmsg fromAddr;
309 unsigned int len;
310 NameServerMsg msg;
311 int byteCount;
312 UInt16 numProcs = MultiProc_getNumProcessors();
313 int sock;
315 LOG0("listener_cb: Entered Listener thread.\n")
317 do {
318 /* Wait for NameServer messages or unblockFd notification */
319 FD_ZERO(&rfds);
320 FD_SET(NameServer_module->unblockFd, &rfds);
321 maxfd = NameServer_module->unblockFd;
322 for (procId = 0; procId < numProcs; procId++) {
323 if (procId == MultiProc_self() ||
324 NameServer_module->recvSock[procId] == INVALIDSOCKET) {
325 continue;
326 }
327 sock = NameServer_module->recvSock[procId];
328 FD_SET(sock, &rfds);
329 maxfd = MAX(sock, maxfd);
330 }
332 maxfd = maxfd + 1;
333 LOG2("NameServer: waiting for unblockFd: %d, and socks: maxfd: %d\n",
334 NameServer_module->unblockFd, maxfd)
335 ret = select(maxfd, &rfds, NULL, NULL, NULL);
336 if (ret == -1) {
337 LOG0("listener_cb: select failed.")
338 break;
339 }
340 LOG0("NameServer: back from select()\n")
342 for (procId = 0; procId < numProcs; procId++) {
343 if (procId == MultiProc_self() ||
344 NameServer_module->recvSock[procId] == INVALIDSOCKET) {
345 continue;
346 }
347 sock = NameServer_module->recvSock[procId];
348 if (FD_ISSET(sock, &rfds)) {
349 LOG1("NameServer: Listener got NameServer message "
350 "from sock: %d!\n", sock);
351 /* Get NameServer message and process: */
352 memset(&fromAddr, 0, sizeof(fromAddr));
353 len = sizeof(fromAddr);
355 byteCount = recvfrom(sock, &msg, sizeof(NameServerMsg), 0,
356 (struct sockaddr *)&fromAddr, &len);
357 if (len != sizeof(fromAddr)) {
358 LOG1("recvfrom: got bad addr len (%d)\n", len)
359 break;
360 }
361 if (byteCount < 0) {
362 LOG2("recvfrom failed: %s (%d)\n", strerror(errno), errno)
363 break;
364 }
365 else {
366 LOG1("listener_cb: recvfrom socket: fd: %d\n", sock)
367 LOG2("\tReceived ns msg: byteCount: %d, from addr: %d, ",
368 byteCount, fromAddr.addr)
369 LOG1("from vproc: %d\n", fromAddr.vproc_id)
370 NameServerRemote_processMessage(&msg, procId);
371 }
372 }
373 }
374 if (FD_ISSET(NameServer_module->unblockFd, &rfds)) {
375 /* We are told to unblock and exit: */
376 LOG0("NameServer: Listener thread exiting\n")
377 break;
378 }
379 } while (1);
381 return ((void *)ret);
382 }
384 /* =============================================================================
385 * APIS
386 * =============================================================================
387 */
389 /* Function to setup the nameserver module. */
390 Int NameServer_setup(Void)
391 {
392 Int status = NameServer_S_SUCCESS;
393 int err;
394 int sock;
395 int ret;
396 UInt16 procId;
397 UInt16 numProcs;
399 pthread_mutex_lock(&NameServer_module->modGate);
401 LOG1("NameServer_setup: entered, refCount=%d\n", NameServer_module->refCount)
403 NameServer_module->refCount++;
405 if (NameServer_module->refCount > 1) {
406 LOG0("NameServer_setup: already setup\n")
407 status = NameServer_S_ALREADYSETUP;
408 goto exit;
409 }
411 numProcs = MultiProc_getNumProcessors();
413 NameServer_module->unblockFd = eventfd(0, 0);
414 if (NameServer_module->unblockFd < 0) {
415 status = NameServer_E_FAIL;
416 LOG0("NameServer_setup: failed to create unblockFd.\n")
417 goto exit;
418 }
420 NameServer_module->waitFd = eventfd(0, 0);
421 if (NameServer_module->waitFd < 0) {
422 status = NameServer_E_FAIL;
423 LOG0("NameServer_setup: failed to create waitFd.\n")
424 goto exit;
425 }
427 for (procId = 0; procId < numProcs; procId++) {
428 NameServer_module->sendSock[procId] = INVALIDSOCKET;
429 NameServer_module->recvSock[procId] = INVALIDSOCKET;
431 /* Only support NameServer to remote procs: */
432 if (procId == MultiProc_self()) {
433 continue;
434 }
436 /* Create the socket for sending messages to each remote proc: */
437 sock = socket(AF_RPMSG, SOCK_SEQPACKET, 0);
438 if (sock < 0) {
439 status = NameServer_E_FAIL;
440 LOG2("NameServer_setup: socket failed: %d, %s\n",
441 errno, strerror(errno))
442 }
443 else {
444 LOG1("NameServer_setup: created send socket: %d\n", sock)
445 err = ConnectSocket(sock, procId, MESSAGEQ_RPMSG_PORT);
446 if (err < 0) {
447 status = NameServer_E_FAIL;
448 LOG2("NameServer_setup: connect failed: %d, %s\n",
449 errno, strerror(errno))
451 LOG1(" closing send socket: %d\n", sock)
452 close(sock);
453 }
454 else {
455 NameServer_module->sendSock[procId] = sock;
456 }
457 }
459 /* Create the socket for recving messages from each remote proc: */
460 sock = socket(AF_RPMSG, SOCK_SEQPACKET, 0);
461 if (sock < 0) {
462 status = NameServer_E_FAIL;
463 LOG2("NameServer_setup: socket failed: %d, %s\n",
464 errno, strerror(errno))
465 }
466 else {
467 LOG1("NameServer_setup: created recv socket: %d\n", sock)
469 err = SocketBindAddr(sock, procId, NAME_SERVER_RPMSG_ADDR);
470 if (err < 0) {
471 status = NameServer_E_FAIL;
472 LOG2("NameServer_setup: bind failed: %d, %s\n",
473 errno, strerror(errno))
475 LOG1(" closing recv socket: %d\n", sock)
476 close(sock);
477 }
478 else {
479 NameServer_module->recvSock[procId] = sock;
480 }
481 }
482 }
484 /* Construct the list object */
485 CIRCLEQ_INIT(&NameServer_module->objList);
487 /* Create the listener thread: */
488 LOG0("NameServer_setup: creating listener thread\n")
489 ret = pthread_create(&NameServer_module->listener, NULL, listener_cb, NULL);
490 if (ret) {
491 LOG1("NameServer_setup: can't spawn thread: %s\n", strerror(ret))
492 LOG0("NameServer_setup: eventfd failed");
494 status = NameServer_E_FAIL;
495 }
496 else {
497 /* look for at least one good send/recv pair to indicate success */
498 for (procId = 0; procId < numProcs; procId++) {
499 if (NameServer_module->sendSock[procId] != INVALIDSOCKET &&
500 NameServer_module->recvSock[procId] != INVALIDSOCKET) {
501 status = NameServer_S_SUCCESS;
503 break;
504 }
505 }
506 }
508 exit:
509 LOG1("NameServer_setup: exiting, refCount=%d\n", NameServer_module->refCount)
511 pthread_mutex_unlock(&NameServer_module->modGate);
513 return (status);
514 }
516 /*! Function to destroy the nameserver module. */
517 Int NameServer_destroy(void)
518 {
519 Int status = NameServer_S_SUCCESS;
520 UInt16 numProcs = MultiProc_getNumProcessors();
521 UInt16 procId;
522 int sock;
523 uint64_t buf = 1;
524 int numBytes;
526 pthread_mutex_lock(&NameServer_module->modGate);
528 LOG1("NameServer_destroy: entered, refCount=%d\n", NameServer_module->refCount)
530 NameServer_module->refCount--;
532 if (NameServer_module->refCount > 0) {
533 LOG1("NameServer_destroy(): refCount(%d) > 0, exiting\n", NameServer_module->refCount)
534 status = NameServer_S_SUCCESS;
536 goto exit;
537 }
539 for (procId = 0; procId < numProcs; procId++) {
540 /* Only support NameServer to remote procs: */
541 if (procId == MultiProc_self()) {
542 continue;
543 }
545 /* Close the socket: */
546 sock = NameServer_module->sendSock[procId];
547 if (sock != INVALIDSOCKET) {
548 LOG1("NameServer_destroy: closing socket: %d\n", sock)
549 close(sock);
550 NameServer_module->sendSock[procId] = INVALIDSOCKET;
551 }
552 /* Close the socket: */
553 sock = NameServer_module->recvSock[procId];
554 if (sock != INVALIDSOCKET) {
555 LOG1("NameServer_destroy: closing socket: %d\n", sock)
556 close(sock);
557 NameServer_module->recvSock[procId] = INVALIDSOCKET;
558 }
559 }
561 CIRCLEQ_destruct(&NameServer_module->objList);
563 /* Unblock the NameServer listener thread: */
564 LOG0("NameServer_destroy: unblocking listener...\n")
565 numBytes = write(NameServer_module->unblockFd, &buf, sizeof(uint64_t));
567 /* Join: */
568 LOG0("NameServer_destroy: joining listener thread...\n")
569 pthread_join(NameServer_module->listener, NULL);
571 close(NameServer_module->unblockFd);
572 close(NameServer_module->waitFd);
574 exit:
575 LOG1("NameServer_destroy: exiting, refCount=%d\n", NameServer_module->refCount)
577 pthread_mutex_unlock(&NameServer_module->modGate);
579 return (status);
580 }
582 /* Function to retrieve a NameServer handle from name. */
583 NameServer_Handle NameServer_getHandle(String name)
584 {
585 NameServer_Handle handle = NULL;
586 Bool found = FALSE;
587 struct NameServer_Object * elem;
589 assert(name != NULL);
590 assert(NameServer_module->refCount != 0);
592 pthread_mutex_lock(&NameServer_module->modGate);
594 /* Lookup handle from name: */
595 CIRCLEQ_traverse(elem, &NameServer_module->objList, NameServer_Object) {
596 handle = (NameServer_Handle) elem;
597 if (strcmp(handle->name, name) == 0) {
598 found = TRUE;
599 break;
600 }
601 }
603 if (found == FALSE) {
604 handle = NULL;
605 }
607 pthread_mutex_unlock(&NameServer_module->modGate);
609 return (handle);
610 }
613 /* Function to create a name server. */
614 NameServer_Handle NameServer_create(String name,
615 const NameServer_Params * params)
616 {
617 NameServer_Handle handle = NULL;
618 pthread_mutexattr_t mutex_attr;
620 assert(params != NULL);
621 assert(name != NULL);
622 assert(NameServer_module->refCount != 0);
624 LOG1("NameServer_create(): '%s'\n", name)
626 pthread_mutex_lock(&NameServer_module->modGate);
628 if (params->maxValueLen > sizeof(UInt32)) {
629 LOG1("NameServer_create: params->maxValueLen (%d) too big for now\n", params->maxValueLen)
630 /* Can't handle more than UInt32 at this time: */
631 goto leave;
632 }
634 /* check if the name is already created or not */
635 handle = NameServer_getHandle(name);
636 if (handle != NULL) {
637 if (memcmp((Ptr)&handle->params, (Ptr)params,
638 sizeof(NameServer_Params)) == 0) {
639 handle->refCount++;
640 }
641 else {
642 LOG0("NameServer_create: NameServer params mismatch\n")
643 handle = NULL;
644 }
645 goto leave;
646 }
647 else {
648 handle = (NameServer_Handle)calloc(1, sizeof(NameServer_Object));
649 }
651 if (!handle) {
652 LOG0("NameServer_create: NameServer_Handle alloc failed\n")
653 goto leave;
654 }
656 handle->refCount = 1;
657 handle->name = (String)malloc(strlen(name) + 1u);
658 if (!handle->name) {
659 LOG0("NameServer_create: instance name alloc failed\n")
660 goto cleanup;
661 }
662 strncpy(handle->name, name, strlen (name) + 1u);
663 memcpy((Ptr) &handle->params, (Ptr) params, sizeof(NameServer_Params));
665 if (params->maxValueLen < sizeof(UInt32)) {
666 handle->params.maxValueLen = sizeof(UInt32);
667 }
668 else {
669 handle->params.maxValueLen = params->maxValueLen;
670 }
672 CIRCLEQ_INIT(&handle->nameList);
673 handle->count = 0u;
675 /* Put in the local list */
676 CIRCLEQ_elemClear(&handle->elem);
677 CIRCLEQ_INSERT_HEAD(&NameServer_module->objList, handle, elem);
679 /*
680 * NameServer_removeEntry() enters gate and is called by
681 * NameServer_remove() while holding the gate.
682 */
683 pthread_mutexattr_settype(&mutex_attr, PTHREAD_MUTEX_RECURSIVE);
684 pthread_mutex_init(&handle->gate, &mutex_attr);
686 goto leave;
688 cleanup:
689 free(handle);
690 handle = NULL;
692 leave:
693 pthread_mutex_unlock(&NameServer_module->modGate);
695 return (handle);
696 }
699 /* Function to delete a name server. */
700 Int NameServer_delete(NameServer_Handle * handle)
701 {
702 Int status = NameServer_S_SUCCESS;
704 assert(handle != NULL);
705 assert(*handle != NULL);
706 assert((*handle)->count == 0);
707 assert(NameServer_module->refCount != 0);
709 pthread_mutex_lock(&NameServer_module->modGate);
711 (*handle)->refCount--;
712 if ((*handle)->refCount != 0) {
713 goto leave;
714 }
716 if ((*handle)->count == 0) {
717 CIRCLEQ_REMOVE(&NameServer_module->objList, *handle, elem);
719 if ((*handle)->name != NULL) {
720 free((*handle)->name);
721 (*handle)->name = NULL;
722 }
724 CIRCLEQ_destruct(&(*handle)->nameList);
726 free((*handle));
727 (*handle) = NULL;
728 }
730 leave:
731 pthread_mutex_unlock(&NameServer_module->modGate);
733 return (status);
734 }
736 /* Adds a variable length value into the local NameServer table */
737 Ptr NameServer_add(NameServer_Handle handle, String name, Ptr buf, UInt len)
738 {
739 Int status = NameServer_S_SUCCESS;
740 NameServer_TableEntry * node = NULL;
741 NameServer_TableEntry * new_node = NULL;
742 Bool found = FALSE;
743 UInt32 hash;
745 assert(handle != NULL);
746 assert(name != NULL);
747 assert(buf != NULL);
748 assert(len != 0);
749 assert(NameServer_module->refCount != 0);
751 /* Calculate the hash */
752 hash = stringHash(name);
754 pthread_mutex_lock(&handle->gate);
756 /* Traverse the list to find duplicate check */
757 CIRCLEQ_traverse(node, &handle->nameList, NameServer_TableEntry_tag) {
758 /* Hash matches */
759 if (node->hash == hash) {
760 /* If the name matches, incase hash is duplicate */
761 if (strcmp(node->name, name) == 0) {
762 if (handle->params.checkExisting == TRUE) {
763 status = NameServer_E_INVALIDARG;
764 LOG1("NameServer_add: '%s' - duplicate entry found!\n", name)
765 break;
766 }
767 }
768 else {
769 found = TRUE;
770 break;
771 } /* name does not match */
772 } /* hash does not match */
773 } /* CIRCLEQ_traverse */
775 if (status != NameServer_S_SUCCESS) {
776 new_node = NULL;
777 goto exit;
778 }
780 /* Now add the new entry. */
781 new_node = (NameServer_TableEntry *)malloc(sizeof(NameServer_TableEntry));
782 if (new_node == NULL) {
783 status = NameServer_E_MEMORY;
784 LOG1("NameServer_add: %d - malloc new_node failed!\n", status)
786 goto exit;
787 }
789 new_node->hash = hash;
790 new_node->collide = found; /* Indicate if there is a collision*/
791 new_node->len = len;
792 new_node->next = NULL;
793 new_node->name = (String)malloc(strlen(name) + 1u);
794 new_node->value = (Ptr)malloc(len);
795 strncpy(new_node->name, name, strlen(name) + 1u);
796 memcpy((Ptr)new_node->value, (Ptr)buf, len);
798 if (found == TRUE) {
799 /* If hash is found, need to stitch the list to link the
800 * new node to the existing node with the same hash.
801 */
802 new_node->next = node->next;
803 node->next = new_node;
804 }
805 else {
806 /* put the new node into the list */
807 CIRCLEQ_INSERT_HEAD(&handle->nameList, new_node, elem);
808 }
810 handle->count++;
812 LOG2("NameServer_add: Entered key: '%s', data: 0x%x\n",
813 name, *(UInt32 *)buf)
815 exit:
816 pthread_mutex_unlock(&handle->gate);
818 return (new_node);
819 }
822 /* Function to add a UInt32 value into a name server. */
823 Ptr NameServer_addUInt32(NameServer_Handle handle, String name, UInt32 value)
824 {
825 Ptr entry = NULL;
827 assert(handle != NULL);
828 assert(name != NULL);
829 assert(NameServer_module->refCount != 0);
831 entry = NameServer_add(handle, name, &value, sizeof(UInt32));
833 return (entry);
834 }
836 /* Function to remove a name/value pair from a name server. */
837 Int NameServer_remove(NameServer_Handle handle, String name)
838 {
839 Int status = NameServer_S_SUCCESS;
840 NameServer_TableEntry *prev = NULL;
841 NameServer_TableEntry *temp = NULL;
842 NameServer_TableEntry *node = NULL;
843 Bool done = FALSE;
844 UInt32 hash;
846 assert(handle != NULL);
847 assert(name != NULL);
848 assert(NameServer_module->refCount != 0);
850 /* Calculate the hash */
851 hash = stringHash(name);
853 pthread_mutex_lock(&handle->gate);
855 /* Traverse the list to find duplicate check */
856 CIRCLEQ_traverse(node, &handle->nameList, NameServer_TableEntry_tag) {
857 /* Hash matchs */
858 if (node->hash == hash) {
859 if (node->collide == TRUE) {
860 if (strcmp(node->name, name) == 0){
861 free(node->value);
862 free(node->name);
863 memcpy((Ptr)node, (Ptr) node->next,
864 sizeof(NameServer_TableEntry));
865 node->next = node->next->next;
866 free(node->next);
867 handle->count--;
868 done = TRUE;
869 break;
870 }
871 else {
872 prev = node;
873 temp = node->next;
874 while (temp) {
875 if (strcmp(temp->name, name) == 0){
876 free(temp->value);
877 free(temp->name);
878 prev->next = temp->next;
879 free(temp);
880 handle->count--;
881 done = TRUE;
882 break;
883 }
884 temp = temp->next;
885 }
886 break;
887 }
888 }
889 else {
890 NameServer_removeEntry(handle, (Ptr)node);
892 done = TRUE;
893 break;
894 }
895 }
896 }
898 if (done == FALSE) {
899 status = NameServer_E_INVALIDARG;
900 LOG1("NameServer_remove %d Entry not found!\n", status)
901 }
903 pthread_mutex_unlock(&handle->gate);
905 return (status);
906 }
908 /* Function to remove a name/value pair from a name server. */
909 Int NameServer_removeEntry(NameServer_Handle handle, Ptr entry)
910 {
911 Int status = NameServer_S_SUCCESS;
912 NameServer_TableEntry * node;
914 assert(handle != NULL);
915 assert(entry != NULL);
916 assert(NameServer_module->refCount != 0);
918 pthread_mutex_lock(&handle->gate);
920 node = (NameServer_TableEntry *)entry;
922 free(node->value);
923 free(node->name);
924 CIRCLEQ_REMOVE(&handle->nameList, node, elem);
925 free(node);
926 handle->count--;
928 pthread_mutex_unlock(&handle->gate);
930 return (status);
931 }
934 /* Initialize this config-params structure with supplier-specified
935 * defaults before instance creation.
936 */
937 Void NameServer_Params_init(NameServer_Params * params)
938 {
939 assert(params != NULL);
941 memcpy(params, &(NameServer_module->defInstParams),
942 sizeof (NameServer_Params));
943 }
946 Int NameServer_getRemote(NameServer_Handle handle,
947 String name,
948 Ptr value,
949 UInt32 * len,
950 UInt16 procId)
951 {
952 Int status = NameServer_S_SUCCESS;
953 struct NameServer_Object *obj = (struct NameServer_Object *)(handle);
954 NameServerMsg nsMsg;
955 NameServerMsg *replyMsg;
956 fd_set rfds;
957 int ret = 0, sock, maxfd, waitFd;
958 struct timeval tv;
959 uint64_t buf = 1;
960 int numBytes;
961 int err;
963 /* Set Timeout to wait: */
964 tv.tv_sec = 0;
965 tv.tv_usec = NAMESERVER_GET_TIMEOUT;
967 /* Create request message and send to remote: */
968 sock = NameServer_module->sendSock[procId];
969 if (sock == INVALIDSOCKET) {
970 LOG1("NameServer_getRemote: no socket connection to processor %d\n",
971 procId);
972 status = NameServer_E_RESOURCE;
973 goto exit;
974 }
976 LOG1("NameServer_getRemote: Sending request via sock: %d\n", sock)
978 /* Create request message and send to remote processor: */
979 nsMsg.reserved = NAMESERVER_MSG_TOKEN;
980 nsMsg.request = NAMESERVER_REQUEST;
981 nsMsg.requestStatus = 0;
982 nsMsg.valueLen = *len;
984 strncpy((char *)nsMsg.instanceName, obj->name, strlen(obj->name) + 1);
985 strncpy((char *)nsMsg.name, name, strlen(name) + 1);
987 LOG2("NameServer_getRemote: Requesting from procId %d, %s:",
988 procId, (String)nsMsg.instanceName)
989 LOG1("%s...\n", (String)nsMsg.name)
991 err = send(sock, &nsMsg, sizeof(NameServerMsg), 0);
992 if (err < 0) {
993 LOG2("NameServer_getRemote: send failed: %d, %s\n",
994 errno, strerror(errno))
995 status = NameServer_E_FAIL;
996 goto exit;
997 }
999 /* Block on waitFd for signal from listener thread: */
1000 waitFd = NameServer_module->waitFd;
1001 FD_ZERO(&rfds);
1002 FD_SET(waitFd, &rfds);
1003 maxfd = waitFd + 1;
1004 LOG1("NameServer_getRemote: pending on waitFd: %d\n", waitFd)
1005 ret = select(maxfd, &rfds, NULL, NULL, &tv);
1006 if (ret == -1) {
1007 LOG0("NameServer_getRemote: select failed.")
1008 status = NameServer_E_FAIL;
1009 goto exit;
1010 }
1011 else if (!ret) {
1012 LOG0("NameServer_getRemote: select timed out.\n")
1013 status = NameServer_E_TIMEOUT;
1014 goto exit;
1015 }
1017 if (FD_ISSET(waitFd, &rfds)) {
1018 /* Read, just to balance the write: */
1019 numBytes = read(waitFd, &buf, sizeof(uint64_t));
1021 /* Process response: */
1022 replyMsg = &NameServer_module->nsMsg;
1024 if (replyMsg->requestStatus) {
1025 /* name is found */
1026 /* set the contents of value */
1027 *(UInt32 *)value = (UInt32)replyMsg->value;
1029 LOG2("NameServer_getRemote: Reply from: %d, %s:",
1030 procId, (String)replyMsg->instanceName)
1031 LOG2("%s, value: 0x%x...\n",
1032 (String)replyMsg->name, *(UInt32 *)value)
1033 goto exit;
1034 }
1035 else {
1036 /* name is not found */
1037 LOG2("NameServer_getRemote: value for %s:%s not found.\n",
1038 (String)replyMsg->instanceName, (String)replyMsg->name)
1040 /* set status to not found */
1041 status = NameServer_E_NOTFOUND;
1042 }
1043 }
1045 exit:
1046 return (status);
1047 }
1049 /* Function to retrieve the value portion of a name/value pair from
1050 * local table.
1051 */
1052 Int NameServer_get(NameServer_Handle handle,
1053 String name,
1054 Ptr value,
1055 UInt32 * len,
1056 UInt16 procId[])
1057 {
1058 Int status = NameServer_S_SUCCESS;
1059 UInt16 numProcs = MultiProc_getNumProcessors();
1060 UInt32 i;
1062 /*
1063 * BIOS side uses a gate (mutex) to protect NameServer_module->nsMsg, but
1064 * since this goes in a daemon, it will not be necessary.
1065 */
1067 if (procId == NULL) {
1068 status = NameServer_getLocal(handle, name, value, len);
1069 if (status == NameServer_E_NOTFOUND) {
1070 for (i = 0; i < numProcs; i++) {
1071 /* getLocal call already covers "self", keep going */
1072 if (i == MultiProc_self()) {
1073 continue;
1074 }
1076 status = NameServer_getRemote(handle, name, value, len, i);
1078 if ((status >= 0) ||
1079 ((status < 0) && (status != NameServer_E_NOTFOUND) &&
1080 (status != NameServer_E_RESOURCE))) {
1081 break;
1082 }
1083 }
1084 }
1085 }
1086 else {
1087 /*
1088 * Search the query list. It might contain the local proc
1089 * somewhere in the list.
1090 */
1091 i = 0;
1092 while (procId[i] != MultiProc_INVALIDID) {
1093 if (procId[i] == MultiProc_self()) {
1094 status = NameServer_getLocal(handle, name, value, len);
1095 }
1096 else {
1097 status = NameServer_getRemote(handle, name, value, len, i);
1098 }
1100 if ((status >= 0) ||
1101 ((status < 0) && (status != NameServer_E_NOTFOUND) &&
1102 (status != NameServer_E_RESOURCE))) {
1103 break;
1104 }
1106 i++;
1107 }
1108 }
1110 if (status == NameServer_E_RESOURCE) {
1111 status = NameServer_E_NOTFOUND;
1112 }
1114 return (status);
1115 }
1117 /* Gets a 32-bit value by name */
1118 Int NameServer_getUInt32(NameServer_Handle handle,
1119 String name,
1120 Ptr value,
1121 UInt16 procId[])
1122 {
1123 Int status;
1124 UInt32 len = sizeof(UInt32);
1126 assert(handle != NULL);
1127 assert(name != NULL);
1128 assert(value != NULL);
1129 assert(NameServer_module->refCount != 0);
1131 status = NameServer_get(handle, name, value, &len, procId);
1133 return (status);
1134 }
1136 /* Function to Retrieve the value portion of a name/value pair from
1137 * local table.
1138 */
1139 Int NameServer_getLocal(NameServer_Handle handle,
1140 String name,
1141 Ptr value,
1142 UInt32 * len)
1143 {
1144 Int status = NameServer_E_NOTFOUND;
1145 NameServer_TableEntry * node = NULL;
1146 NameServer_TableEntry * temp = NULL;
1147 Bool done = FALSE;
1148 UInt32 length;
1149 UInt32 hash;
1151 assert(handle != NULL);
1152 assert(name != NULL);
1153 assert(value != NULL);
1154 assert(len != NULL);
1155 assert(NameServer_module->refCount != 0);
1157 length = *len;
1159 /* Calculate the hash */
1160 hash = stringHash(name);
1162 pthread_mutex_lock(&handle->gate);
1164 /* Traverse the list to find duplicate check */
1165 CIRCLEQ_traverse(node, &handle->nameList, NameServer_TableEntry_tag) {
1166 if (node->hash == hash) {
1167 if (node->collide == TRUE) {
1168 temp = node;
1169 while (temp) {
1170 if (strcmp(temp->name, name) == 0u){
1171 if (length <= node->len) {
1172 memcpy(value, node->value, length);
1173 *len = length;
1174 }
1175 else {
1176 memcpy(value, node->value, node->len);
1177 *len = node->len;
1178 }
1179 done = TRUE;
1180 break;
1181 }
1182 temp = temp->next;
1183 }
1184 break;
1185 }
1186 else {
1187 if (length <= node->len) {
1188 memcpy(value, node->value, length);
1189 *len = length;
1190 }
1191 else {
1192 memcpy(value, node->value, node->len);
1193 *len = node->len;
1194 }
1195 done = TRUE;
1196 break;
1197 }
1198 }
1199 }
1201 pthread_mutex_unlock(&handle->gate);
1203 if (done == FALSE) {
1204 LOG1("NameServer_getLocal: entry key: '%s' not found!\n", name)
1205 }
1206 else {
1207 LOG2("NameServer_getLocal: Found entry key: '%s', data: 0x%x\n",
1208 node->name, (UInt32)node->value)
1209 status = NameServer_S_SUCCESS;
1210 }
1212 return (status);
1213 }
1215 /*
1216 * Gets a 32-bit value by name from the local table
1217 *
1218 * If the name is found, the 32-bit value is copied into the value
1219 * argument and a success status is returned.
1220 *
1221 * If the name is not found, zero is returned in len and the contents
1222 * of value are not modified. Not finding a name is not considered
1223 * an error.
1224 *
1225 * This function only searches the local name/value table.
1226 *
1227 */
1228 Int NameServer_getLocalUInt32(NameServer_Handle handle, String name, Ptr value)
1229 {
1230 Int status;
1231 UInt32 len = sizeof(UInt32);
1233 assert(handle != NULL);
1234 assert(name != NULL);
1235 assert(value != NULL);
1236 assert(NameServer_module->refCount != 0);
1238 LOG0("NameServer_getLocalUInt32: calling NameServer_getLocal()...\n")
1239 status = NameServer_getLocal(handle, name, value, &len);
1241 return (status);
1242 }
1245 #if defined (__cplusplus)
1246 }
1247 #endif /* defined (__cplusplus) */