067bcd809a0630f3c2c2b432ead99a3b4f58e120
[ipc/ipcdev.git] / linux / src / daemon / NameServer_daemon.c
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     pthread_mutex_t    gate;            /* crit sect gate */
117 } NameServer_Object;
119 /* structure for NameServer module state */
120 typedef struct NameServer_ModuleObject {
121     CIRCLEQ_HEAD(dummy1, NameServer_Object) objList;
122     Int32               refCount;
123     int                 sendSock[MultiProc_MAXPROCESSORS];
124     /* Sockets for sending to remote proc nameserver ports: */
125     int                 recvSock[MultiProc_MAXPROCESSORS];
126     /* Sockets for recving from remote proc nameserver ports: */
127     pthread_t           listener;
128     /* Listener thread for NameServer replies and requests. */
129     int                 unblockFd;
130     /* Event to post to exit listener. */
131     int                 waitFd;
132     /* Event to post to NameServer_get. */
133     NameServerMsg       nsMsg;
134     /* NameServer Message cache. */
135     NameServer_Params   defInstParams;
136     /* Default instance paramters */
137     pthread_mutex_t     modGate;
138 } NameServer_ModuleObject;
140 #define CIRCLEQ_destruct(head) { \
141         (head)->cqh_first = NULL; \
142         (head)->cqh_last = NULL; \
145 #define CIRCLEQ_elemClear(elem) { \
146         (elem)->cqe_next = (elem)->cqe_prev = (Void *)(elem); \
149 #define CIRCLEQ_traverse(x, y, tag) \
150         for (x = (y)->cqh_first; x != (struct tag *)(y); x = x->elem.cqe_next)
152 /* =============================================================================
153  *  Globals
154  * =============================================================================
155  */
156 /*
157  * NameServer_state
158  *
159  * Make the module gate "recursive" since NameServer_getHandle() needs to
160  * use it and NameServer_create() needs to hold it around its call to
161  * NameServer_getHandle().  Also, use the static initializer instead of a
162  * run-time init call, so we can use this gate immediately in _setup().
163  */
164 static NameServer_ModuleObject NameServer_state = {
165     .defInstParams.maxRuntimeEntries = 0u,
166     .defInstParams.tableHeap         = NULL,
167     .defInstParams.checkExisting     = TRUE,
168     .defInstParams.maxValueLen       = 0u,
169     .defInstParams.maxNameLen        = 16u,
170 // only _NP (non-portable) type available in CG tools which we're using
171     .modGate                         = PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP,
172 //    .modGate                         = PTHREAD_RECURSIVE_MUTEX_INITIALIZER,
173     .refCount                        = 0
174 };
176 static NameServer_ModuleObject * NameServer_module = &NameServer_state;
178 static const UInt32 stringCrcTab[256u] = {
179   0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f,
180   0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
181   0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2,
182   0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
183   0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9,
184   0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172,
185   0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c,
186   0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
187   0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423,
188   0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
189   0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, 0x01db7106,
190   0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
191   0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d,
192   0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e,
193   0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950,
194   0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
195   0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7,
196   0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0,
197   0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa,
198   0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
199   0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81,
200   0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a,
201   0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84,
202   0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
203   0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb,
204   0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc,
205   0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e,
206   0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
207   0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55,
208   0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
209   0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28,
210   0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
211   0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f,
212   0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38,
213   0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242,
214   0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
215   0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69,
216   0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2,
217   0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc,
218   0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
219   0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693,
220   0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
221   0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d,
222 };
224 static UInt32 stringHash(String s)
226     UInt32 hash = strlen(s);
227     UInt32 i;
229     for (i = 0; i < strlen(s); i++) {
230         hash = (hash >> 8u) ^ stringCrcTab[(hash & 0xff)] ^ s[i];
231     }
233     return (hash);
236 static void NameServerRemote_processMessage(NameServerMsg * msg, UInt16 procId)
238     NameServer_Handle handle;
239     Int               status = NameServer_E_FAIL;
240     int               err;
241     uint64_t          buf = 1;
242     int               numBytes;
243     int               waitFd = NameServer_module->waitFd;
245     if (msg->request == NAMESERVER_REQUEST) {
246         LOG2("NameServer Request: instanceName: %s, name: %s\n",
247              (String)msg->instanceName, (String)msg->name)
249         /*
250          *  Message is a request. Lookup name in NameServer table.
251          *  Send a response message back to source processor.
252          */
253         handle = NameServer_getHandle((String)msg->instanceName);
255         if (handle != NULL) {
256             /* Search for the NameServer entry */
257             LOG0("Calling NameServer_getLocalUInt32...\n")
258             status = NameServer_getLocalUInt32(handle,
259                      (String)msg->name, &msg->value);
260         }
262         LOG2("NameServer Response: instanceName: %s, name: %s,",
263              (String)msg->instanceName, (String)msg->name)
264         /* set the request status */
265         if (status < 0) {
266             LOG1(" Value not found, status: %d\n", status)
267             msg->requestStatus = 0;
268         }
269         else {
270             msg->requestStatus = 1;
271             LOG1(" Value: 0x%x\n", msg->value)
272         }
274         /* specify message as a response */
275         msg->request = NAMESERVER_RESPONSE;
276         msg->reserved = NAMESERVER_MSG_TOKEN;
278         /* send response message to remote processor */
279         err = send(NameServer_module->sendSock[procId], msg,
280                    sizeof(NameServerMsg), 0);
281         if (err < 0) {
282             LOG2("NameServer: send failed: %d, %s\n", errno, strerror(errno))
283         }
284     }
285     else {
286         LOG2("NameServer Reply: instanceName: %s, name: %s",
287              (String)msg->instanceName, (String)msg->name)
288         LOG1(", value: 0x%x\n", msg->value)
290         /* Save the response message.  */
291         memcpy(&NameServer_module->nsMsg, msg, sizeof(NameServerMsg));
293         /* Post the eventfd upon which NameServer_get() is waiting */
294         numBytes = write(waitFd, &buf, sizeof(uint64_t));
295     }
299 static void *listener_cb(void *arg)
301     fd_set rfds;
302     int ret = 0, maxfd;
303     UInt16 procId;
304     struct  sockaddr_rpmsg  fromAddr;
305     unsigned int len;
306     NameServerMsg msg;
307     int     byteCount;
308     UInt16  numProcs = MultiProc_getNumProcessors();
309     int     sock;
311     LOG0("listener_cb: Entered Listener thread.\n")
313     do {
314         /* Wait for NameServer messages or unblockFd notification */
315         FD_ZERO(&rfds);
316         FD_SET(NameServer_module->unblockFd, &rfds);
317         maxfd = NameServer_module->unblockFd;
318         for (procId = 0; procId < numProcs; procId++) {
319             if (procId == MultiProc_self() ||
320                 NameServer_module->recvSock[procId] == INVALIDSOCKET) {
321                 continue;
322             }
323             sock = NameServer_module->recvSock[procId];
324             FD_SET(sock, &rfds);
325             maxfd = MAX(sock, maxfd);
326         }
328         maxfd = maxfd + 1;
329         LOG2("NameServer: waiting for unblockFd: %d, and socks: maxfd: %d\n",
330              NameServer_module->unblockFd, maxfd)
331         ret = select(maxfd, &rfds, NULL, NULL, NULL);
332         if (ret == -1) {
333             LOG0("listener_cb: select failed.")
334             break;
335         }
336         LOG0("NameServer: back from select()\n")
338         for (procId = 0; procId < numProcs; procId++) {
339             if (procId == MultiProc_self() ||
340                 NameServer_module->recvSock[procId] == INVALIDSOCKET) {
341                 continue;
342             }
343             sock = NameServer_module->recvSock[procId];
344             if (FD_ISSET(sock, &rfds)) {
345                 LOG1("NameServer: Listener got NameServer message "
346                      "from sock: %d!\n", sock);
347                 /* Get NameServer message and process: */
348                 memset(&fromAddr, 0, sizeof(fromAddr));
349                 len = sizeof(fromAddr);
351                 byteCount = recvfrom(sock, &msg, sizeof(NameServerMsg), 0,
352                                 (struct sockaddr *)&fromAddr, &len);
353                 if (len != sizeof(fromAddr)) {
354                     LOG1("recvfrom: got bad addr len (%d)\n", len)
355                     break;
356                 }
357                 if (byteCount < 0) {
358                     LOG2("recvfrom failed: %s (%d)\n", strerror(errno), errno)
359                     break;
360                 }
361                 else {
362                     LOG1("listener_cb: recvfrom socket: fd: %d\n", sock)
363                     LOG2("\tReceived ns msg: byteCount: %d, from addr: %d, ",
364                          byteCount, fromAddr.addr)
365                     LOG1("from vproc: %d\n", fromAddr.vproc_id)
366                     NameServerRemote_processMessage(&msg, procId);
367                 }
368             }
369         }
370         if (FD_ISSET(NameServer_module->unblockFd, &rfds)) {
371             /* We are told to unblock and exit: */
372             LOG0("NameServer: Listener thread exiting\n")
373             break;
374         }
375     } while (1);
377     return ((void *)ret);
380 /* =============================================================================
381  * APIS
382  * =============================================================================
383  */
385 /* Function to setup the nameserver module. */
386 Int NameServer_setup(Void)
388     Int    status = NameServer_S_SUCCESS;
389     int    err;
390     int    sock;
391     int    ret;
392     UInt16 procId;
393     UInt16 numProcs;
395     pthread_mutex_lock(&NameServer_module->modGate);
397     LOG1("NameServer_setup: entered, refCount=%d\n", NameServer_module->refCount)
399     NameServer_module->refCount++;
401     if (NameServer_module->refCount > 1) {
402         LOG0("NameServer_setup: already setup\n")
403         status = NameServer_S_ALREADYSETUP;
404         goto exit;
405     }
407     numProcs = MultiProc_getNumProcessors();
409     NameServer_module->unblockFd = eventfd(0, 0);
410     if (NameServer_module->unblockFd < 0) {
411         status = NameServer_E_FAIL;
412         LOG0("NameServer_setup: failed to create unblockFd.\n")
413         goto exit;
414     }
416     NameServer_module->waitFd = eventfd(0, 0);
417     if (NameServer_module->waitFd < 0) {
418         status = NameServer_E_FAIL;
419         LOG0("NameServer_setup: failed to create waitFd.\n")
420         goto exit;
421     }
423     for (procId = 0; procId < numProcs; procId++) {
424         NameServer_module->sendSock[procId] = INVALIDSOCKET;
425         NameServer_module->recvSock[procId] = INVALIDSOCKET;
427         /* Only support NameServer to remote procs: */
428         if (procId == MultiProc_self()) {
429             continue;
430         }
432         /* Create the socket for sending messages to each remote proc: */
433         sock = socket(AF_RPMSG, SOCK_SEQPACKET, 0);
434         if (sock < 0) {
435             status = NameServer_E_FAIL;
436             LOG2("NameServer_setup: socket failed: %d, %s\n",
437                  errno, strerror(errno))
438         }
439         else  {
440             LOG1("NameServer_setup: created send socket: %d\n", sock)
441             err = ConnectSocket(sock, procId, MESSAGEQ_RPMSG_PORT);
442             if (err < 0) {
443                 status = NameServer_E_FAIL;
444                 LOG2("NameServer_setup: connect failed: %d, %s\n",
445                      errno, strerror(errno))
447                 LOG1("    closing send socket: %d\n", sock)
448                 close(sock);
449             }
450             else {
451                 NameServer_module->sendSock[procId] = sock;
452             }
453         }
455         /* Create the socket for recving messages from each remote proc: */
456         sock = socket(AF_RPMSG, SOCK_SEQPACKET, 0);
457         if (sock < 0) {
458             status = NameServer_E_FAIL;
459             LOG2("NameServer_setup: socket failed: %d, %s\n",
460                  errno, strerror(errno))
461         }
462         else  {
463             LOG1("NameServer_setup: created recv socket: %d\n", sock)
465             err = SocketBindAddr(sock, procId, NAME_SERVER_RPMSG_ADDR);
466             if (err < 0) {
467                status = NameServer_E_FAIL;
468                LOG2("NameServer_setup: bind failed: %d, %s\n",
469                     errno, strerror(errno))
471                 LOG1("    closing recv socket: %d\n", sock)
472                 close(sock);
473             }
474             else {
475                NameServer_module->recvSock[procId] = sock;
476             }
477         }
478     }
480     /* Construct the list object */
481     CIRCLEQ_INIT(&NameServer_module->objList);
483     /* Create the listener thread: */
484     LOG0("NameServer_setup: creating listener thread\n")
485     ret = pthread_create(&NameServer_module->listener, NULL, listener_cb, NULL);
486     if (ret) {
487         LOG1("NameServer_setup: can't spawn thread: %s\n", strerror(ret))
488         LOG0("NameServer_setup: eventfd failed");
490         status = NameServer_E_FAIL;
491     }
493 exit:
494     LOG1("NameServer_setup: exiting, refCount=%d\n", NameServer_module->refCount)
496     pthread_mutex_unlock(&NameServer_module->modGate);
498     return (status);
501 /*! Function to destroy the nameserver module. */
502 Int NameServer_destroy(void)
504     Int      status    = NameServer_S_SUCCESS;
505     UInt16   numProcs = MultiProc_getNumProcessors();
506     UInt16   procId;
507     int      sock;
508     uint64_t buf = 1;
509     int      numBytes;
511     pthread_mutex_lock(&NameServer_module->modGate);
513     LOG1("NameServer_destroy: entered, refCount=%d\n", NameServer_module->refCount)
515     NameServer_module->refCount--;
517     if (NameServer_module->refCount > 0) {
518         LOG1("NameServer_destroy(): refCount(%d) > 0, exiting\n", NameServer_module->refCount)
519         status = NameServer_S_SUCCESS;
521         goto exit;
522     }
524     for (procId = 0; procId < numProcs; procId++) {
525         /* Only support NameServer to remote procs: */
526         if (procId == MultiProc_self()) {
527             continue;
528         }
530         /* Close the socket: */
531         sock = NameServer_module->sendSock[procId];
532         if (sock != INVALIDSOCKET) {
533             LOG1("NameServer_destroy: closing socket: %d\n", sock)
534             close(sock);
535             NameServer_module->sendSock[procId] = INVALIDSOCKET;
536         }
537         /* Close the socket: */
538         sock = NameServer_module->recvSock[procId];
539         if (sock != INVALIDSOCKET) {
540             LOG1("NameServer_destroy: closing socket: %d\n", sock)
541             close(sock);
542             NameServer_module->recvSock[procId] = INVALIDSOCKET;
543         }
544     }
546     CIRCLEQ_destruct(&NameServer_module->objList);
548     /* Unblock the NameServer listener thread: */
549     LOG0("NameServer_destroy: unblocking listener...\n")
550     numBytes = write(NameServer_module->unblockFd, &buf, sizeof(uint64_t));
552     /* Join: */
553     LOG0("NameServer_destroy: joining listener thread...\n")
554     pthread_join(NameServer_module->listener, NULL);
556     close(NameServer_module->unblockFd);
557     close(NameServer_module->waitFd);
559 exit:
560     LOG1("NameServer_destroy: exiting, refCount=%d\n", NameServer_module->refCount)
562     pthread_mutex_unlock(&NameServer_module->modGate);
564     return (status);
567 /* Function to retrieve a NameServer handle from name. */
568 NameServer_Handle NameServer_getHandle(String name)
570     NameServer_Handle handle = NULL;
571     Bool              found = FALSE;
572     struct NameServer_Object * elem;
574     assert(name != NULL);
575     assert(NameServer_module->refCount != 0);
577     pthread_mutex_lock(&NameServer_module->modGate);
579     /* Lookup handle from name: */
580     CIRCLEQ_traverse(elem, &NameServer_module->objList, NameServer_Object) {
581         handle = (NameServer_Handle) elem;
582         if (strcmp(handle->name, name) == 0) {
583             found = TRUE;
584             break;
585         }
586     }
588     if (found == FALSE) {
589         handle = NULL;
590     }
592     pthread_mutex_unlock(&NameServer_module->modGate);
594     return (handle);
598 /* Function to create a name server. */
599 NameServer_Handle NameServer_create(String name,
600                                     const NameServer_Params * params)
602     NameServer_Handle handle = NULL;
603     pthread_mutexattr_t mutex_attr;
605     assert(params != NULL);
606     assert(name != NULL);
607     assert(NameServer_module->refCount != 0);
609     LOG1("NameServer_create(): '%s'\n", name)
611     pthread_mutex_lock(&NameServer_module->modGate);
613     if (params->maxValueLen > sizeof(UInt32)) {
614         LOG1("NameServer_create: params->maxValueLen (%d) too big for now\n", params->maxValueLen)
615        /* Can't handle more than UInt32 at this time: */
616        goto leave;
617     }
619     /* check if the name is already created or not */
620     if (NameServer_getHandle(name)) {
621         LOG0("NameServer_create NameServer_E_INVALIDARG Name is in use!\n")
622         handle = NULL;
623         goto leave;
624     }
625     else {
626         handle = (NameServer_Handle)calloc(1, sizeof(NameServer_Object));
627     }
629     if (!handle) {
630         LOG0("NameServer_create: NameServer_Handle alloc failed\n")
631         goto leave;
632     }
634     handle->name = (String)malloc(strlen(name) + 1u);
635     if (!handle->name) {
636         LOG0("NameServer_create: instance name alloc failed\n")
637         goto cleanup;
638     }
639     strncpy(handle->name, name, strlen (name) + 1u);
640     memcpy((Ptr) &handle->params, (Ptr) params, sizeof(NameServer_Params));
642     if (params->maxValueLen < sizeof(UInt32)) {
643         handle->params.maxValueLen = sizeof(UInt32);
644     }
645     else {
646         handle->params.maxValueLen = params->maxValueLen;
647     }
649     CIRCLEQ_INIT(&handle->nameList);
650     handle->count = 0u;
652     /* Put in the local list */
653     CIRCLEQ_elemClear(&handle->elem);
654     CIRCLEQ_INSERT_HEAD(&NameServer_module->objList, handle, elem);
656     /*
657      * NameServer_removeEntry() enters gate and is called by
658      * NameServer_remove() while holding the gate.
659      */
660     pthread_mutexattr_settype(&mutex_attr, PTHREAD_MUTEX_RECURSIVE);
661     pthread_mutex_init(&handle->gate, &mutex_attr);
663     goto leave;
665 cleanup:
666     free(handle);
667     handle = NULL;
669 leave:
670     pthread_mutex_unlock(&NameServer_module->modGate);
672     return (handle);
676 /* Function to delete a name server. */
677 Int NameServer_delete(NameServer_Handle * handle)
679     Int status = NameServer_S_SUCCESS;
681     assert(handle != NULL);
682     assert(*handle != NULL);
683     assert((*handle)->count == 0);
684     assert(NameServer_module->refCount != 0);
686     pthread_mutex_lock(&NameServer_module->modGate);
688     if ((*handle)->count == 0) {
689         CIRCLEQ_REMOVE(&NameServer_module->objList, *handle, elem);
691         if ((*handle)->name != NULL) {
692             free((*handle)->name);
693             (*handle)->name = NULL;
694         }
696         CIRCLEQ_destruct(&(*handle)->nameList);
698         free((*handle));
699         (*handle) = NULL;
700     }
702     pthread_mutex_unlock(&NameServer_module->modGate);
704     return (status);
707 /* Adds a variable length value into the local NameServer table */
708 Ptr NameServer_add(NameServer_Handle handle, String name, Ptr buf, UInt len)
710     Int                 status = NameServer_S_SUCCESS;
711     NameServer_TableEntry * node = NULL;
712     NameServer_TableEntry * new_node = NULL;
713     Bool                found = FALSE;
714     UInt32              hash;
716     assert(handle != NULL);
717     assert(name     != NULL);
718     assert(buf      != NULL);
719     assert(len      != 0);
720     assert(NameServer_module->refCount != 0);
722     /* Calculate the hash */
723     hash = stringHash(name);
725     pthread_mutex_lock(&handle->gate);
727     /* Traverse the list to find duplicate check */
728     CIRCLEQ_traverse(node, &handle->nameList, NameServer_TableEntry_tag) {
729         /* Hash matches */
730         if (node->hash == hash) {
731             /* If the name matches, incase hash is duplicate */
732             if (strcmp(node->name, name) == 0) {
733                 if (handle->params.checkExisting == TRUE) {
734                     status = NameServer_E_INVALIDARG;
735                     LOG1("NameServer_add: '%s' - duplicate entry found!\n", name)
736                     break;
737                 }
738             }
739             else {
740                 found = TRUE;
741                 break;
742             } /* name does not match */
743         } /* hash does not match */
744     } /* CIRCLEQ_traverse */
746     if (status != NameServer_S_SUCCESS) {
747         new_node = NULL;
748         goto exit;
749     }
751     /* Now add the new entry. */
752     new_node = (NameServer_TableEntry *)malloc(sizeof(NameServer_TableEntry));
753     if (new_node == NULL) {
754         status = NameServer_E_MEMORY;
755         LOG1("NameServer_add: %d - malloc new_node failed!\n", status)
757         goto exit;
758     }
760     new_node->hash    = hash;
761     new_node->collide = found; /* Indicate if there is a collision*/
762     new_node->len     = len;
763     new_node->next    = NULL;
764     new_node->name = (String)malloc(strlen(name) + 1u);
765     new_node->value  = (Ptr)malloc(len);
766     strncpy(new_node->name, name, strlen(name) + 1u);
767     memcpy((Ptr)new_node->value, (Ptr)buf, len);
769     if (found == TRUE) {
770         /* If hash is found, need to stitch the list to link the
771          * new node to the existing node with the same hash.
772          */
773         new_node->next = node->next;
774         node->next = new_node;
775     }
776     else {
777         /* put the new node into the list */
778         CIRCLEQ_INSERT_HEAD(&handle->nameList, new_node, elem);
779     }
781     handle->count++;
783     LOG2("NameServer_add: Entered key: '%s', data: 0x%x\n",
784          name, *(UInt32 *)buf)
786 exit:
787     pthread_mutex_unlock(&handle->gate);
789     return (new_node);
793 /* Function to add a UInt32 value into a name server. */
794 Ptr NameServer_addUInt32(NameServer_Handle handle, String name, UInt32 value)
796     Ptr entry = NULL;
798     assert(handle != NULL);
799     assert(name   != NULL);
800     assert(NameServer_module->refCount != 0);
802     entry = NameServer_add(handle, name, &value, sizeof(UInt32));
804     return (entry);
807 /* Function to remove a name/value pair from a name server. */
808 Int NameServer_remove(NameServer_Handle handle, String name)
810     Int                 status = NameServer_S_SUCCESS;
811     NameServer_TableEntry *prev = NULL;
812     NameServer_TableEntry *temp = NULL;
813     NameServer_TableEntry *node = NULL;
814     Bool                done   = FALSE;
815     UInt32              hash;
817     assert(handle != NULL);
818     assert(name   != NULL);
819     assert(NameServer_module->refCount != 0);
821     /* Calculate the hash */
822     hash = stringHash(name);
824     pthread_mutex_lock(&handle->gate);
826     /* Traverse the list to find duplicate check */
827     CIRCLEQ_traverse(node, &handle->nameList, NameServer_TableEntry_tag) {
828         /* Hash matchs */
829         if (node->hash == hash) {
830             if (node->collide == TRUE) {
831                 if (strcmp(node->name, name) == 0){
832                     free(node->value);
833                     free(node->name);
834                     memcpy((Ptr)node, (Ptr) node->next,
835                            sizeof(NameServer_TableEntry));
836                     node->next = node->next->next;
837                     free(node->next);
838                     handle->count--;
839                     done = TRUE;
840                     break;
841                 }
842                 else {
843                     prev = node;
844                     temp = node->next;
845                     while (temp) {
846                         if (strcmp(temp->name, name) == 0){
847                             free(temp->value);
848                             free(temp->name);
849                             prev->next = temp->next;
850                             free(temp);
851                             handle->count--;
852                             done = TRUE;
853                             break;
854                         }
855                         temp = temp->next;
856                     }
857                     break;
858                 }
859             }
860             else {
861                 NameServer_removeEntry(handle, (Ptr)node);
863                 done = TRUE;
864                 break;
865             }
866         }
867     }
869     if (done == FALSE) {
870         status = NameServer_E_INVALIDARG;
871         LOG1("NameServer_remove %d Entry not found!\n", status)
872     }
874     pthread_mutex_unlock(&handle->gate);
876     return (status);
879 /* Function to remove a name/value pair from a name server. */
880 Int NameServer_removeEntry(NameServer_Handle handle, Ptr entry)
882     Int  status = NameServer_S_SUCCESS;
883     NameServer_TableEntry * node;
885     assert(handle != NULL);
886     assert(entry  != NULL);
887     assert(NameServer_module->refCount != 0);
889     pthread_mutex_lock(&handle->gate);
891     node = (NameServer_TableEntry *)entry;
893     free(node->value);
894     free(node->name);
895     CIRCLEQ_REMOVE(&handle->nameList, node, elem);
896     free(node);
897     handle->count--;
899     pthread_mutex_unlock(&handle->gate);
901     return (status);
905 /* Initialize this config-params structure with supplier-specified
906  * defaults before instance creation.
907  */
908 Void NameServer_Params_init(NameServer_Params * params)
910     assert(params != NULL);
912     memcpy(params, &(NameServer_module->defInstParams),
913            sizeof (NameServer_Params));
917 Int NameServer_getRemote(NameServer_Handle handle,
918                      String            name,
919                      Ptr               value,
920                      UInt32 *          len,
921                      UInt16            procId)
923     Int status = NameServer_S_SUCCESS;
924     struct NameServer_Object *obj = (struct NameServer_Object *)(handle);
925     NameServerMsg nsMsg;
926     NameServerMsg *replyMsg;
927     fd_set rfds;
928     int ret = 0, sock, maxfd, waitFd;
929     struct timeval tv;
930     uint64_t buf = 1;
931     int numBytes;
932     int err;
934     /* Set Timeout to wait: */
935     tv.tv_sec = 0;
936     tv.tv_usec = NAMESERVER_GET_TIMEOUT;
938     /* Create request message and send to remote: */
939     sock = NameServer_module->sendSock[procId];
940     LOG1("NameServer_getRemote: Sending request via sock: %d\n", sock)
942     /* Create request message and send to remote processor: */
943     nsMsg.reserved = NAMESERVER_MSG_TOKEN;
944     nsMsg.request = NAMESERVER_REQUEST;
945     nsMsg.requestStatus = 0;
947     strncpy((char *)nsMsg.instanceName, obj->name, strlen(obj->name) + 1);
948     strncpy((char *)nsMsg.name, name, strlen(name) + 1);
950     LOG2("NameServer_getRemote: Requesting from procId %d, %s:",
951            procId, (String)nsMsg.instanceName)
952     LOG1("%s...\n", (String)nsMsg.name)
954     err = send(sock, &nsMsg, sizeof(NameServerMsg), 0);
955     if (err < 0) {
956         LOG2("NameServer_getRemote: send failed: %d, %s\n",
957              errno, strerror(errno))
958         status = NameServer_E_FAIL;
959         goto exit;
960     }
962     /* Block on waitFd for signal from listener thread: */
963     waitFd = NameServer_module->waitFd;
964     FD_ZERO(&rfds);
965     FD_SET(waitFd, &rfds);
966     maxfd = waitFd + 1;
967     LOG1("NameServer_getRemote: pending on waitFd: %d\n", waitFd)
968     ret = select(maxfd, &rfds, NULL, NULL, &tv);
969     if (ret == -1) {
970         LOG0("NameServer_getRemote: select failed.")
971         status = NameServer_E_FAIL;
972         goto exit;
973     }
974     else if (!ret) {
975         LOG0("NameServer_getRemote: select timed out.\n")
976         status = NameServer_E_TIMEOUT;
977         goto exit;
978     }
980     if (FD_ISSET(waitFd, &rfds)) {
981         /* Read, just to balance the write: */
982         numBytes = read(waitFd, &buf, sizeof(uint64_t));
984         /* Process response: */
985         replyMsg = &NameServer_module->nsMsg;
987         if (replyMsg->requestStatus) {
988             /* name is found */
989             /* set the contents of value */
990             *(UInt32 *)value = (UInt32)replyMsg->value;
992             LOG2("NameServer_getRemote: Reply from: %d, %s:",
993                  procId, (String)replyMsg->instanceName)
994             LOG2("%s, value: 0x%x...\n",
995                  (String)replyMsg->name, *(UInt32 *)value)
996             goto exit;
997         }
998         else {
999             /* name is not found */
1000             LOG2("NameServer_getRemote: value for %s:%s not found.\n",
1001                  (String)replyMsg->instanceName, (String)replyMsg->name)
1003             /* set status to not found */
1004             status = NameServer_E_NOTFOUND;
1005         }
1006     }
1008 exit:
1009     return (status);
1012 /* Function to retrieve the value portion of a name/value pair from
1013  * local table.
1014  */
1015 Int NameServer_get(NameServer_Handle handle,
1016                String            name,
1017                Ptr               value,
1018                UInt32 *          len,
1019                UInt16            procId[])
1021     Int status = NameServer_S_SUCCESS;
1022     UInt16 numProcs = MultiProc_getNumProcessors();
1023     UInt32 i;
1025     /*
1026      * BIOS side uses a gate (mutex) to protect NameServer_module->nsMsg, but
1027      * since this goes in a daemon, it will not be necessary.
1028      */
1030     if (procId == NULL) {
1031         status = NameServer_getLocal(handle, name, value, len);
1032         if (status == NameServer_E_NOTFOUND) {
1033             for (i = 0; i < numProcs; i++) {
1034                 /* getLocal call already covers "self", keep going */
1035                 if (i == MultiProc_self()) {
1036                     continue;
1037                 }
1039                 status = NameServer_getRemote(handle, name, value, len, i);
1041                 if ((status >= 0) ||
1042                     ((status < 0) && (status != NameServer_E_NOTFOUND))) {
1043                     break;
1044                 }
1045             }
1046         }
1047     }
1048     else {
1049         /*
1050          *  Search the query list. It might contain the local proc
1051          *  somewhere in the list.
1052          */
1053         i = 0;
1054         while (procId[i] != MultiProc_INVALIDID) {
1055             if (procId[i] == MultiProc_self()) {
1056                 status = NameServer_getLocal(handle, name, value, len);
1057             }
1058             else {
1059                 status = NameServer_getRemote(handle, name, value, len, i);
1060             }
1062             if ((status >= 0) ||
1063                 ((status < 0) && (status != NameServer_E_NOTFOUND))) {
1064                 break;
1065             }
1067             i++;
1068         }
1069     }
1071     return (status);
1074 /* Gets a 32-bit value by name */
1075 Int NameServer_getUInt32(NameServer_Handle handle,
1076                      String            name,
1077                      Ptr               value,
1078                      UInt16            procId[])
1080     Int  status;
1081     UInt32 len = sizeof(UInt32);
1083     assert(handle != NULL);
1084     assert(name   != NULL);
1085     assert(value  != NULL);
1086     assert(NameServer_module->refCount != 0);
1088     status = NameServer_get(handle, name, value, &len, procId);
1090     return (status);
1093 /* Function to Retrieve the value portion of a name/value pair from
1094  * local table.
1095  */
1096 Int NameServer_getLocal(NameServer_Handle handle,
1097                     String            name,
1098                     Ptr               value,
1099                     UInt32 *          len)
1101     Int status = NameServer_E_NOTFOUND;
1102     NameServer_TableEntry * node = NULL;
1103     NameServer_TableEntry * temp = NULL;
1104     Bool done   = FALSE;
1105     UInt32 length;
1106     UInt32 hash;
1108     assert(handle != NULL);
1109     assert(name   != NULL);
1110     assert(value  != NULL);
1111     assert(len    != NULL);
1112     assert(NameServer_module->refCount != 0);
1114     length = *len;
1116     /* Calculate the hash */
1117     hash = stringHash(name);
1119     pthread_mutex_lock(&handle->gate);
1121     /* Traverse the list to find duplicate check */
1122     CIRCLEQ_traverse(node, &handle->nameList, NameServer_TableEntry_tag) {
1123         if (node->hash == hash) {
1124             if (node->collide == TRUE) {
1125                 temp = node;
1126                 while (temp) {
1127                     if (strcmp(temp->name, name) == 0u){
1128                         if (length <= node->len) {
1129                             memcpy(value, node->value, length);
1130                             *len = length;
1131                         }
1132                         else {
1133                             memcpy(value, node->value, node->len);
1134                             *len = node->len;
1135                         }
1136                         done = TRUE;
1137                         break;
1138                     }
1139                     temp = temp->next;
1140                 }
1141                 break;
1142             }
1143             else {
1144                 if (length <= node->len) {
1145                     memcpy(value, node->value, length);
1146                     *len = length;
1147                 }
1148                 else {
1149                     memcpy(value, node->value, node->len);
1150                     *len = node->len;
1151                 }
1152                 done = TRUE;
1153                 break;
1154             }
1155         }
1156     }
1158     pthread_mutex_unlock(&handle->gate);
1160     if (done == FALSE) {
1161         LOG1("NameServer_getLocal: entry key: '%s' not found!\n", name)
1162     }
1163     else {
1164         LOG2("NameServer_getLocal: Found entry key: '%s', data: 0x%x\n",
1165              node->name, (UInt32)node->value)
1166         status = NameServer_S_SUCCESS;
1167     }
1169     return (status);
1172 /*
1173  *  Gets a 32-bit value by name from the local table
1174  *
1175  *  If the name is found, the 32-bit value is copied into the value
1176  *  argument and a success status is returned.
1177  *
1178  *  If the name is not found, zero is returned in len and the contents
1179  *  of value are not modified. Not finding a name is not considered
1180  *  an error.
1181  *
1182  *  This function only searches the local name/value table.
1183  *
1184  */
1185 Int NameServer_getLocalUInt32(NameServer_Handle handle, String name, Ptr value)
1187     Int                 status;
1188     UInt32              len    = sizeof(UInt32);
1190     assert(handle != NULL);
1191     assert(name   != NULL);
1192     assert(value  != NULL);
1193     assert(NameServer_module->refCount != 0);
1195     LOG0("NameServer_getLocalUInt32: calling NameServer_getLocal()...\n")
1196     status = NameServer_getLocal(handle, name, value, &len);
1198     return (status);
1202 #if defined (__cplusplus)
1204 #endif /* defined (__cplusplus) */