55c549fa0babb8adfb536af2e50663e5bc6c9083
1 /*
2 * Copyright (c) 2012-2014, 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 * ======== lad.c ========
34 */
36 #include <ti/ipc/Std.h>
38 #include <stdio.h>
39 #include <stdlib.h>
40 #include <string.h>
41 #include <errno.h>
42 #include <fcntl.h>
43 #include <sys/stat.h>
44 #include <sys/types.h>
45 #include <signal.h>
46 #include <unistd.h>
48 #include <ti/ipc/MessageQ.h>
49 #include <_MessageQ.h>
50 #include <ti/ipc/NameServer.h>
51 #include <_NameServer.h>
52 #include <ti/ipc/GateMP.h>
53 #include <_GateMP_daemon.h>
55 #include <GateHWSpinlock.h>
57 #include <ladclient.h>
58 #include <_lad.h>
60 #define DAEMON 1 /* 1 = run as a daemon; 0 = run as app */
62 Bool logFile = FALSE;
63 FILE *logPtr = NULL;
65 static String commandFIFOFile = LAD_COMMANDFIFO;
66 static FILE *commandFIFOFilePtr = NULL;
68 static Bool gatempEnabled = FALSE;
70 /* LAD client info arrays */
71 static Bool clientConnected[LAD_MAXNUMCLIENTS];
72 static UInt clientPID[LAD_MAXNUMCLIENTS];
73 static Char clientFIFOName[LAD_MAXNUMCLIENTS][LAD_MAXLENGTHFIFONAME];
74 static FILE * responseFIFOFilePtr[LAD_MAXNUMCLIENTS];
76 /* local internal routines */
77 static LAD_ClientHandle assignClientId(Void);
78 static Void cleanupDepartedClients(Void);
79 static Int connectToLAD(String clientName, Int pid, String clientProto, Int *clientIdPtr);
80 static Void disconnectFromLAD(Int clientId);
81 static Void doDisconnect(Int clientId);
83 struct LAD_CommandObj cmd;
84 union LAD_ResponseObj rsp;
86 #define LAD_USAGE "\
87 Usage:\n\
88 lad_<platform> [options] \n\
89 \n\
90 Options:\n\
91 h : print this help message\n\
92 g : enable GateMP support \n\
93 l <logfile> : name of logfile for LAD\n\
94 \n\
95 Examples:\n\
96 lad_<platform> -h\n\
97 lad_<platform> -l log.txt\n\
98 lad_<platform> -g -l log.txt\n\
99 \n"
101 /*
102 * ======== main ========
103 */
104 int main(int argc, char * argv[])
105 {
106 MessageQ_Handle handle;
107 UInt16 *procIdPtr;
108 Int statusIO;
109 Int clientId;
110 Int command;
111 Int flags;
112 Int i;
113 Int n;
114 Int c;
115 Int status;
116 String tmpString;
117 #if DAEMON
118 pid_t pid;
119 pid_t sid;
120 #endif
122 /* change to LAD's working directory */
123 if ((chdir(LAD_WORKINGDIR)) < 0) {
125 /* if can't change directory assume it needs to be created, do it */
126 if ((mkdir(LAD_WORKINGDIR, 0666)) < 0) {
127 printf("\nERROR: Failed to create LAD's working directory!\n");
128 exit(EXIT_FAILURE);
129 }
130 /* now change to the new directory */
131 if ((chdir(LAD_WORKINGDIR)) < 0) {
132 printf("\nERROR: Failed to change to LAD's working directory!\n");
133 exit(EXIT_FAILURE);
134 }
135 }
137 /* process command line args */
138 while (1) {
139 c = getopt(argc, argv, "ghl:");
140 if (c == -1) {
141 break;
142 }
144 switch (c) {
145 case 'g':
146 #if defined(GATEMP_SUPPORT)
147 printf("\nGateMP support enabled on host\n");
148 gatempEnabled = TRUE;
149 #else
150 printf("\nGateMP is not supported for this device\n");
151 #endif
152 break;
153 case 'h':
154 printf("%s", LAD_USAGE);
155 exit(0);
156 break;
157 case 'l':
158 logPtr = fopen(optarg, "w");
159 if (logPtr == NULL) {
160 printf("\nERROR: unable to open log file %s\n", optarg);
161 exit(EXIT_FAILURE);
162 }
163 else {
164 logFile = TRUE;
165 printf("\nOpened log file: %s", optarg);
166 /* close log file upon LAD termination */
167 flags = fcntl(fileno(logPtr), F_GETFD);
168 if (flags != -1) {
169 fcntl(fileno(logPtr), F_SETFD, flags | FD_CLOEXEC);
170 }
171 }
172 break;
173 default:
174 fprintf (stderr, "\nUnrecognized argument\n");
175 exit(EXIT_FAILURE);
176 }
177 }
179 #if DAEMON
180 /* fork off a child process */
181 pid = fork();
183 /* if fork of child failed then exit immediately; no child created */
184 if (pid < 0) {
185 printf("\nERROR: Failed to fork child process!");
186 exit(EXIT_FAILURE);
187 }
189 /* if pid > 0 this is the parent; time to die ... */
190 if (pid > 0) {
191 printf("\nSpawned daemon: %s\n\n", argv[0]);
192 exit(EXIT_SUCCESS);
193 }
195 /* child continues from here (pid == 0) ... */
197 /* change file mode mask */
198 umask(0);
200 /* create new session ID for the child */
201 sid = setsid();
203 /* exit with failure code if failed to get session ID... */
204 if (sid < 0) {
205 printf("\nERROR: Failed to acquire new session ID!");
206 exit(EXIT_FAILURE);
207 }
209 /* disassociate from the standard file descriptors */
210 close(STDIN_FILENO);
211 close(STDOUT_FILENO);
212 close(STDERR_FILENO);
214 #endif
216 LOG0("\nInitializing LAD... ")
218 /* TODO:L make sure LAD is not already running? */
220 /* initialize client info arrays */
221 for (i = 0; i < LAD_MAXNUMCLIENTS; i++) {
222 clientConnected[i] = FALSE;
223 responseFIFOFilePtr[i] = NULL;
224 }
226 /* if command FIFO exists from previous LAD session delete it now */
227 unlink(commandFIFOFile);
229 /* create command FIFO */
230 statusIO = mkfifo(commandFIFOFile, 0777);
231 if (statusIO != 0) {
232 LOG2("\nERROR: unable to create %s, errno = %x\n", commandFIFOFile,
233 errno)
234 return(0);
235 }
237 /* set FIFO permissions to read/write */
238 chmod(commandFIFOFile, 0666);
240 /* Setup modules relevant for GateMP if necessary */
241 #if defined(GATEMP_SUPPORT)
242 if (gatempEnabled) {
243 /* Set up NameServer for resource manager process */
244 status = NameServer_setup();
245 if (status < 0) {
246 LOG0("\nERROR: unable to setup NameServer\n")
247 return(0);
248 }
250 status = GateHWSpinlock_start();
251 if (status < 0) {
252 LOG0("\nERROR: unable to start GateHWSpinlock\n");
253 return(0);
254 }
256 /* Set up GateMP */
257 status = GateMP_setup();
258 if (status < 0) {
259 LOG0("\nERROR: unable to setup GateMP\n")
260 NameServer_destroy();
261 return(0);
262 }
263 }
264 #endif
266 opencommandFIFO:
268 /* now open file for FIFO - will block until writer arrives... */
269 LOG1("\n opening FIFO: %s\n", commandFIFOFile)
270 commandFIFOFilePtr = fopen(commandFIFOFile, "r");
271 if (commandFIFOFilePtr == NULL) {
272 LOG0("\nERROR: unable to open command FIFO\n")
273 unlink(commandFIFOFile);
274 #if defined(GATEMP_SUPPORT)
275 if (gatempEnabled) {
276 GateMP_destroy();
277 NameServer_destroy();
278 }
279 #endif
280 return(0);
281 }
283 /* COMMAND PROCESSING LOOP */
284 while (1) {
285 LOG0("Retrieving command...\n")
287 /* read the next command packet */
288 n = fread(&cmd, LAD_COMMANDLENGTH, 1, commandFIFOFilePtr);
290 /*
291 * if last client closes FIFO then it must be closed and reopened ...
292 */
293 if (!n) {
294 LOG1(" EOF detected on FIFO, closing FIFO: %s\n", commandFIFOFile)
295 fclose(commandFIFOFilePtr);
297 goto opencommandFIFO;
298 }
300 /* cleanup for any connected/started clients that have departed */
301 cleanupDepartedClients();
303 command = cmd.cmd;
304 clientId = cmd.clientId;
306 /* process individual commands */
307 switch (command) {
308 /*
309 * Since cmd is a union of rcv and snd structs, don't write
310 * any snd elements before all rcv elements have been referenced
311 * (either saved in separate variables or passed to a function).
312 *
313 * cmd.cmd has already been saved in 'command'
314 * cmd.clientId has already been saved in 'clientId'
315 */
316 case LAD_CONNECT:
317 connectToLAD(cmd.args.connect.name, cmd.args.connect.pid,
318 cmd.args.connect.protocol, NULL);
320 break;
322 case LAD_DISCONNECT:
323 disconnectFromLAD(clientId);
325 break;
327 case LAD_NAMESERVER_SETUP:
328 LOG0("LAD_NAMESERVER_SETUP: calling NameServer_setup()...\n")
330 rsp.status = NameServer_setup();
332 LOG1(" status = %d\n", rsp.status)
333 LOG0("DONE\n")
335 break;
337 case LAD_NAMESERVER_DESTROY:
338 LOG0("LAD_NAMESERVER_DESTROY: calling NameServer_destroy()...\n")
340 rsp.status = NameServer_destroy();
342 LOG1(" status = %d\n", rsp.status)
343 LOG0("DONE\n")
345 break;
347 case LAD_NAMESERVER_PARAMS_INIT:
348 LOG0("LAD_NAMESERVER_PARAMS_INIT: calling NameServer_Params_init()...\n")
350 NameServer_Params_init(&rsp.params);
352 LOG0("DONE\n")
354 break;
356 case LAD_NAMESERVER_CREATE:
357 LOG1("LAD_NAMESERVER_CREATE: calling NameServer_create('%s')...\n", cmd.args.create.name)
359 rsp.handle = NameServer_create(cmd.args.create.name,
360 &cmd.args.create.params);
362 LOG1(" handle = %p\n", rsp.handle)
363 LOG0("DONE\n")
365 break;
367 case LAD_NAMESERVER_DELETE:
368 LOG1("LAD_NAMESERVER_DELETE: calling NameServer_delete(%p)...\n", cmd.args.delete.handle)
370 rsp.delete.handle = cmd.args.delete.handle;
371 rsp.delete.status = NameServer_delete(&rsp.delete.handle);
373 LOG1(" status = %d\n", rsp.status)
374 LOG0("DONE\n")
376 break;
378 case LAD_NAMESERVER_ADD:
379 LOG1("LAD_NAMESERVER_ADD: calling NameServer_add(%p, ", cmd.args.add.handle)
380 LOG2("'%s', %p,", cmd.args.add.name, cmd.args.add.buf)
381 LOG1(" 0x%x)...\n", cmd.args.add.len)
383 rsp.entryPtr = NameServer_add(
384 cmd.args.add.handle,
385 cmd.args.add.name,
386 cmd.args.add.buf,
387 cmd.args.add.len);
389 LOG1(" entryPtr = %p\n", rsp.entryPtr)
390 LOG0("DONE\n")
392 break;
394 case LAD_NAMESERVER_GET:
395 LOG2("LAD_NAMESERVER_GET: calling NameServer_get(%p, '%s'",
396 cmd.args.get.handle, cmd.args.get.name)
397 LOG0(")...\n")
399 if (cmd.args.get.procId[0] == (UInt16)-1) {
400 procIdPtr = NULL;
401 }
402 else {
403 procIdPtr = cmd.args.get.procId;
404 }
405 rsp.status = NameServer_get(
406 cmd.args.get.handle,
407 cmd.args.get.name,
408 rsp.get.buf,
409 &cmd.args.get.len,
410 procIdPtr);
411 rsp.get.len = cmd.args.get.len;
413 LOG1(" value = 0x%x\n", rsp.get.len)
414 LOG1(" status = %d\n", rsp.status)
415 LOG0("DONE\n")
417 break;
419 case LAD_NAMESERVER_ADDUINT32:
420 LOG1("LAD_NAMESERVER_ADDUINT32: calling NameServer_addUInt32(%p, ", cmd.args.addUInt32.handle)
421 LOG2("'%s', 0x%x)...\n", cmd.args.addUInt32.name, cmd.args.addUInt32.val)
423 rsp.entryPtr = NameServer_addUInt32(
424 cmd.args.addUInt32.handle,
425 cmd.args.addUInt32.name,
426 cmd.args.addUInt32.val);
428 LOG1(" entryPtr = %p\n", rsp.entryPtr)
429 LOG0("DONE\n")
431 break;
433 case LAD_NAMESERVER_GETUINT32:
434 LOG2("LAD_NAMESERVER_GETUINT32: calling NameServer_getUInt32(%p, '%s')...\n", cmd.args.getUInt32.handle, cmd.args.getUInt32.name)
436 if (cmd.args.getUInt32.procId[0] == (UInt16)-1) {
437 procIdPtr = NULL;
438 }
439 else {
440 procIdPtr = cmd.args.getUInt32.procId;
441 }
442 rsp.status = NameServer_getUInt32(
443 cmd.args.getUInt32.handle,
444 cmd.args.getUInt32.name,
445 &rsp.getUInt32.val,
446 procIdPtr);
448 LOG1(" value = 0x%x\n", rsp.getUInt32.val)
449 LOG1(" status = %d\n", rsp.status)
450 LOG0("DONE\n")
452 break;
454 case LAD_NAMESERVER_REMOVE:
455 LOG2("LAD_NAMESERVER_REMOVE: calling NameServer_remove(%p, '%s')...\n", cmd.args.remove.handle, cmd.args.remove.name)
457 rsp.status = NameServer_remove(cmd.args.remove.handle,
458 cmd.args.remove.name);
460 LOG1(" status = %d\n", rsp.status)
461 LOG0("DONE\n")
463 break;
465 case LAD_NAMESERVER_REMOVEENTRY:
466 LOG2("LAD_NAMESERVER_REMOVEENTRY: calling NameServer_removeEntry(%p, %p)...\n", cmd.args.removeEntry.handle, cmd.args.removeEntry.entryPtr)
468 rsp.status = NameServer_removeEntry(
469 cmd.args.removeEntry.handle,
470 cmd.args.removeEntry.entryPtr);
472 LOG1(" status = %d\n", rsp.status)
473 LOG0("DONE\n")
475 break;
477 case LAD_MESSAGEQ_GETCONFIG:
478 LOG0("LAD_MESSAGEQ_GETCONFIG: calling MessageQ_getConfig()...\n")
480 MessageQ_getConfig(&rsp.messageQGetConfig.cfg);
481 rsp.messageQGetConfig.status = 0;
483 LOG1(" status = %d\n", rsp.messageQGetConfig.status)
484 LOG0("DONE\n")
486 break;
488 case LAD_MESSAGEQ_SETUP:
489 LOG0("LAD_MESSAGEQ_SETUP: calling MessageQ_setup()...\n")
491 rsp.setup.status = MessageQ_setup(&cmd.args.messageQSetup.cfg);
492 rsp.setup.nameServerHandle = MessageQ_getNameServerHandle();
494 LOG1(" status = %d\n", rsp.setup.status)
495 LOG0("DONE\n")
497 break;
499 case LAD_MESSAGEQ_DESTROY:
500 LOG0("LAD_MESSAGEQ_DESTROY: calling MessageQ_destroy()...\n")
502 rsp.status = MessageQ_destroy();
504 LOG1(" status = %d\n", rsp.status)
505 LOG0("DONE\n")
507 break;
509 case LAD_MESSAGEQ_CREATE:
510 LOG2("LAD_MESSAGEQ_CREATE: calling MessageQ_create(%p, %p)...\n",
511 cmd.args.messageQCreate.name,
512 &cmd.args.messageQCreate.params);
514 tmpString = (cmd.args.messageQCreate.name[0] == '\0') ? NULL :
515 cmd.args.messageQCreate.name;
517 handle = MessageQ_create(tmpString, &cmd.args.messageQCreate.params);
518 rsp.messageQCreate.serverHandle = handle;
520 if (handle) {
521 rsp.messageQCreate.queueId = MessageQ_getQueueId(handle);
522 MessageQ_setQueueOwner(handle, clientPID[clientId]);
523 rsp.messageQCreate.status = 0;
524 }
525 else {
526 rsp.messageQCreate.status = -1;
527 }
529 LOG1(" status = %d\n", rsp.messageQCreate.status)
530 LOG0("DONE\n")
532 break;
534 case LAD_MESSAGEQ_DELETE:
535 LOG1("LAD_MESSAGEQ_DELETE: calling MessageQ_delete(%p)...\n", cmd.args.messageQDelete.serverHandle)
537 rsp.messageQDelete.status =
538 MessageQ_delete((MessageQ_Handle *)&cmd.args.messageQDelete.serverHandle);
540 LOG1(" status = %d\n", rsp.messageQDelete.status)
541 LOG0("DONE\n")
543 break;
545 case LAD_MESSAGEQ_MSGINIT:
546 LOG1("LAD_MESSAGEQ_MSGINIT: calling MessageQ_msgInit(%p)...\n", &rsp.msgInit.msg);
548 MessageQ_msgInit(&rsp.msgInit.msg);
549 rsp.msgInit.status = 0;
551 LOG1(" status = %d\n", rsp.msgInit.status)
552 LOG0("DONE\n")
554 break;
556 case LAD_MULTIPROC_GETCONFIG:
557 LOG0("LAD_MULTIPROC_GETCONFIG: calling MultiProc_getConfig()...\n")
559 MultiProc_getConfig(&rsp.multiprocGetConfig.cfg);
560 rsp.multiprocGetConfig.status = 0;
562 LOG1(" status = %d\n", rsp.multiprocGetConfig.status)
563 LOG0("DONE\n")
565 break;
567 #if defined(GATEMP_SUPPORT)
568 case LAD_GATEMP_START:
569 LOG0("LAD_GATEMP_START: calling GateMP_start()...\n")
571 rsp.gateMPStart.nameServerHandle = GateMP_getNameServer();
572 rsp.gateMPStart.status = GateMP_S_SUCCESS;;
574 LOG1(" status = %d\n", rsp.gateMPStart.status)
575 LOG0("DONE\n")
577 break;
579 case LAD_GATEMP_GETNUMRESOURCES:
580 LOG0("LAD_GATEMP_GETNUMRESOURCES: calling GateMP_getNumResources()...\n")
582 rsp.gateMPGetNumResources.value = GateMP_getNumResources(
583 cmd.args.gateMPGetNumResources.type);
584 rsp.gateMPGetNumResources.status = GateMP_S_SUCCESS;;
586 LOG1(" status = %d\n", rsp.gateMPGetNumResources.status)
587 LOG0("DONE\n")
589 break;
591 case LAD_GATEMP_GETFREERESOURCE:
592 LOG0("LAD_GATEMP_GETFREERESOURCE: calling GateMP_getFreeResource()...\n")
594 rsp.gateMPGetFreeResource.id = GateMP_getFreeResource(
595 cmd.args.gateMPGetFreeResource.type);
596 rsp.gateMPGetFreeResource.status = GateMP_S_SUCCESS;;
598 LOG1(" status = %d\n", rsp.gateMPGetFreeResource.status)
599 LOG0("DONE\n")
601 break;
603 case LAD_GATEMP_RELEASERESOURCE:
604 LOG0("LAD_GATEMP_RELEASERESOURCE: calling GateMP_releaseResource()...\n")
606 rsp.gateMPReleaseResource.status = GateMP_releaseResource(
607 cmd.args.gateMPReleaseResource.id,
608 cmd.args.gateMPReleaseResource.type);
610 LOG1(" status = %d\n", rsp.gateMPReleaseResource.status)
611 LOG0("DONE\n")
613 break;
615 case LAD_GATEMP_ISSETUP:
616 LOG0("LAD_GATEMP_ISSETUP: calling GateMP_isSetup()...\n")
618 rsp.gateMPIsSetup.result = GateMP_isSetup();
619 rsp.gateMPIsSetup.status = GateMP_S_SUCCESS;
621 LOG1(" status = %d\n", rsp.gateMPIsSetup.status)
622 LOG0("DONE\n")
624 break;
626 case LAD_GATEHWSPINLOCK_GETCONFIG:
627 LOG0("LAD_GATEHWSPINLOCK_GETCONFIG: calling GateHWSpinlock_getConfig()...\n")
629 GateHWSpinlock_getConfig(&rsp.gateHWSpinlockGetConfig.cfgParams);
630 rsp.gateHWSpinlockGetConfig.status = 0;
632 LOG1(" status = %d\n", rsp.gateHWSpinlockGetConfig.status)
633 LOG0("DONE\n")
635 break;
636 #endif
638 case LAD_EXIT:
639 goto exitNow;
641 break;
643 default:
644 LOG1("\nUnrecognized command: 0x%x\n", command)
646 break;
647 }
649 switch (command) {
650 case LAD_CONNECT:
651 case LAD_DISCONNECT:
652 break;
654 case LAD_NAMESERVER_SETUP:
655 case LAD_NAMESERVER_DESTROY:
656 case LAD_NAMESERVER_PARAMS_INIT:
657 case LAD_NAMESERVER_CREATE:
658 case LAD_NAMESERVER_DELETE:
659 case LAD_NAMESERVER_ADD:
660 case LAD_NAMESERVER_GET:
661 case LAD_NAMESERVER_ADDUINT32:
662 case LAD_NAMESERVER_GETUINT32:
663 case LAD_NAMESERVER_REMOVE:
664 case LAD_NAMESERVER_REMOVEENTRY:
665 case LAD_MESSAGEQ_GETCONFIG:
666 case LAD_MESSAGEQ_SETUP:
667 case LAD_MESSAGEQ_DESTROY:
668 case LAD_MESSAGEQ_CREATE:
669 case LAD_MESSAGEQ_DELETE:
670 case LAD_MESSAGEQ_MSGINIT:
671 case LAD_MULTIPROC_GETCONFIG:
672 #if defined(GATEMP_SUPPORT)
673 case LAD_GATEMP_START:
674 case LAD_GATEMP_GETNUMRESOURCES:
675 case LAD_GATEMP_GETFREERESOURCE:
676 case LAD_GATEMP_RELEASERESOURCE:
677 case LAD_GATEMP_ISSETUP:
678 case LAD_GATEHWSPINLOCK_GETCONFIG:
679 #endif
681 LOG0("Sending response...\n");
683 fwrite(&rsp, LAD_RESPONSELENGTH, 1, responseFIFOFilePtr[clientId]);
684 fflush(responseFIFOFilePtr[clientId]);
686 break;
688 default:
689 break;
690 }
691 }
693 exitNow:
694 #if defined(GATEMP_SUPPORT)
695 if (gatempEnabled) {
696 GateMP_destroy();
697 NameServer_destroy();
698 }
699 #endif
700 if (logFile) {
701 LOG0("\n\nLAD IS SELF TERMINATING...\n\n")
702 fclose(logPtr);
703 }
704 unlink(commandFIFOFile);
706 return(0);
708 }
711 /*
712 * ======== assignClientId ========
713 */
714 static LAD_ClientHandle assignClientId(Void)
715 {
716 Int clientId = -1;
717 Int i;
719 /* scan connection status flags to acquire a clientId */
720 for (i = 0; i < LAD_MAXNUMCLIENTS; i++) {
721 /* if slot open then provisionally select this clientId */
722 if (clientConnected[i] == FALSE) {
723 clientId = i;
724 break;
725 }
726 }
728 return(clientId);
729 }
732 /*
733 * ======== cleanupDepartedClients ========
734 */
735 static Void cleanupDepartedClients(Void)
736 {
737 Int killStat;
738 Int i;
740 /* scan all connections to verify client processes still exist... */
741 for (i = 0; i < LAD_MAXNUMCLIENTS; i++) {
743 /* if connected... */
744 if (clientConnected[i] == TRUE) {
746 /* check if the client process (PID) still exists */
747 /*
748 * NOTE - calling kill with signal value of 0 will perform
749 * error checking, but not actually send a signal. Will use this
750 * error check to see if PID still exists. An alternative was
751 * to call getpgid. This worked, but is apparently limited to
752 * USE_XOPEN_EXTENDED configurations.
753 */
754 killStat = kill(clientPID[i], 0);
755 if ((killStat == -1) && (errno == ESRCH)) {
757 LOG1("\nDETECTED CONNECTED CLIENT #%d HAS DEPARTED!", i)
759 /* will always need to do the disconnect... */
760 LOG0("\nDoing DISCONNECT on behalf of client...")
761 doDisconnect(i);
763 MessageQ_cleanupOwner(clientPID[i]);
764 // NameServer_cleanupOwner(clientPID[i]);
766 LOG0("DONE\n")
767 }
768 }
769 }
770 }
773 /*
774 * ======== connectToLAD ========
775 */
776 static Int connectToLAD(String clientName, Int pid, String clientProto, Int *clientIdPtr)
777 {
778 Int clientId = -1;
779 Bool connectDenied = FALSE;
780 Int status = LAD_SUCCESS;
781 FILE * filePtr;
782 Int statusIO;
784 /*
785 * TODO:L here, and everywhere parse FIFO strings: should
786 * add full error checking for incomplete or corrupted
787 * strings? Since LAD to ladclient comms are "closed", and
788 * tested, the likelihood of problems seems very low.
789 * But should still consider doing full error checking
790 * and, hopefully, recovery.
791 */
792 LOG0("\nLAD_CONNECT: \n")
793 LOG1(" client FIFO name = %s\n", clientName)
794 LOG1(" client PID = %d\n", pid)
796 /* first check for proper communication protocol */
797 if (strcmp(clientProto, LAD_PROTOCOLVERSION) != 0) {
799 /* if no match then reject the request */
800 LOG0(" ERROR: mismatch in communication protocol!\n")
801 LOG1(" LAD protocol = %s\n", LAD_PROTOCOLVERSION)
802 LOG1(" client protocol = %s\n", clientProto)
803 status = LAD_INVALIDVERSION;
805 /* set flag so know to close FIFO after response */
806 connectDenied = TRUE;
808 /* now jump forward a bit to send response */
809 goto openResponseFIFO;
810 }
812 /* determine this client's ID */
813 clientId = assignClientId();
815 /* if failed to acquire an ID then exit early */
816 if (clientId == -1) {
817 LOG0(" no free handle; too many connections!\n")
818 status = LAD_ACCESSDENIED;
820 /* set flag so know to close FIFO after response */
821 connectDenied = TRUE;
822 }
823 else {
824 LOG1(" assigned client handle = %d\n", clientId)
826 /* save the client's FIFO name for when disconnect */
827 strcpy(clientFIFOName[clientId], clientName);
828 }
830 openResponseFIFO:
832 /* if response FIFO exists from previous LAD session delete it now */
833 unlink(clientName);
835 /* create the dedicated response FIFO to the client */
836 statusIO = mkfifo(clientName, 0777);
837 if (statusIO != 0) {
839 LOG2("\nERROR: unable to mkfifo %s, errno = %x\n", clientName, errno)
841 status = LAD_IOFAILURE;
843 /* send no response; connection request will timeout */
844 goto doneconnect;
845 }
847 LOG1(" FIFO %s created\n", clientName)
849 /* set FIFO permissions to read/write */
850 chmod(clientName, 0666);
852 filePtr = fopen(clientName, "w");
853 if (filePtr == NULL) {
854 LOG1("\nERROR: unable to open response FIFO %s\n", clientName)
856 /* if failed open, still need to delete the FIFO */
857 unlink(clientName);
859 status = LAD_IOFAILURE;
861 /* send no response; connection request will timeout */
862 goto doneconnect;
863 }
865 LOG1(" FIFO %s opened for writing\n", clientName)
867 /*
868 * set "this client is connected" flag; this client ID is now "owned", and
869 * is no longer provisional
870 */
871 if (connectDenied == FALSE) {
872 responseFIFOFilePtr[clientId] = filePtr;
873 clientPID[clientId] = pid;
874 clientConnected[clientId] = TRUE;
875 }
877 rsp.connect.assignedId = clientId;
878 rsp.status = status;
880 /* put response to FIFO */
881 fwrite(&rsp, LAD_RESPONSELENGTH, 1, filePtr);
882 fflush(filePtr);
884 LOG0(" sent response\n")
886 /* if connection was denied, must now close FIFO */
887 if (connectDenied == TRUE) {
888 LOG1(" connect denied; closing FIFO %s\n", clientName)
889 fclose(filePtr);
890 unlink(clientName);
891 }
893 LOG0("DONE\n")
895 doneconnect:
896 if (clientIdPtr != NULL) {
897 *clientIdPtr = clientId;
898 }
900 return(status);
901 }
904 /*
905 * ======== disconnectFromLAD ========
906 */
907 static Void disconnectFromLAD(Int clientId)
908 {
909 LOG0("\nLAD_DISCONNECT: ")
911 LOG1("\n client handle = %x", clientId)
912 doDisconnect(clientId);
914 LOG0("DONE\n")
916 return;
917 }
920 /*
921 * ======== doDisconnect ========
922 */
923 static Void doDisconnect(Int clientId)
924 {
925 /* set "this client is not connected" flag */
926 clientConnected[clientId] = FALSE;
928 /* close and remove the response FIFO */
929 LOG2("\n closing FIFO %s (filePtr=%p)\n",
930 clientFIFOName[clientId], responseFIFOFilePtr[clientId])
931 fclose(responseFIFOFilePtr[clientId]);
933 LOG1(" done, unlinking %s\n", clientFIFOName[clientId]);
934 unlink(clientFIFOName[clientId]);
935 }