LAD: Dead code removal
[ipc/ipcdev.git] / linux / src / daemon / lad.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  *  ======== 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>
53 #include <ladclient.h>
54 #include <_lad.h>
56 #define DAEMON        1           /* 1 = run as a daemon; 0 = run as app */
58 Bool logFile = FALSE;
59 FILE *logPtr = NULL;
61 static String commandFIFOFile = LAD_COMMANDFIFO;
62 static FILE *commandFIFOFilePtr = NULL;
64 /* LAD client info arrays */
65 static Bool clientConnected[LAD_MAXNUMCLIENTS];
66 static UInt clientPID[LAD_MAXNUMCLIENTS];
67 static Char clientFIFOName[LAD_MAXNUMCLIENTS][LAD_MAXLENGTHFIFONAME];
68 static FILE * responseFIFOFilePtr[LAD_MAXNUMCLIENTS];
70 /* local internal routines */
71 static LAD_ClientHandle assignClientId(Void);
72 static Void cleanupDepartedClients(Void);
73 static Int connectToLAD(String clientName, Int pid, String clientProto, Int *clientIdPtr);
74 static Void disconnectFromLAD(Int clientId);
75 static Void doDisconnect(Int clientId);
77 struct LAD_CommandObj cmd;
78 union LAD_ResponseObj rsp;
82 /*
83  *  ======== main ========
84  */
85 int main(int argc, char * argv[])
86 {
87     MessageQ_Handle handle;
88     UInt16 *procIdPtr;
89     Int statusIO;
90     Int clientId;
91     Int command;
92     Int flags;
93     Int i;
94     Int n;
95     String tmpString;
96 #if DAEMON
97     pid_t pid;
98     pid_t sid;
99 #endif
101     /* if more than two args: turn "ON" launch status printfs */
102     if (argc > 2) {
103         printf("\nLAD starting up...");
104     }
106     /* change to LAD's working directory */
107     if ((chdir(LAD_WORKINGDIR)) < 0) {
109         /* if can't change directory assume it needs to be created, do it */
110         if ((mkdir(LAD_WORKINGDIR, 0666)) < 0) {
111             printf("\nERROR: Failed to create LAD's working directory!\n");
112             exit(EXIT_FAILURE);
113         }
114         /* now change to the new directory */
115         if ((chdir(LAD_WORKINGDIR)) < 0) {
116             printf("\nERROR: Failed to change to LAD's working directory!\n");
117             exit(EXIT_FAILURE);
118         }
119     }
121     /* process command line args */
122     if (argc > 1) {
123         logPtr = fopen(argv[1], "w");
124         if (logPtr == NULL) {
125             printf("\nERROR: unable to open log file %s\n", argv[1]);
126             exit(EXIT_FAILURE);
127         }
128         else {
129             logFile = TRUE;
130             if (argc > 2) {
131                 printf("\nOpened log file: %s", argv[1]);
132             }
133             /* close log file upon LAD termination */
134             flags = fcntl(fileno(logPtr), F_GETFD);
135             if (flags != -1) {
136                 fcntl(fileno(logPtr), F_SETFD, flags | FD_CLOEXEC);
137             }
138         }
139     }
141 #if DAEMON
142     /* fork off a child process */
143     pid = fork();
145     /* if fork of child failed then exit immediately; no child created */
146     if (pid < 0) {
147         printf("\nERROR: Failed to fork child process!");
148         exit(EXIT_FAILURE);
149     }
151     /* if pid > 0 this is the parent; time to die ... */
152     if (pid > 0) {
153         if (argc > 2) {
154             printf("\nSpawned daemon: %s\n\n", argv[0]);
155         }
156         exit(EXIT_SUCCESS);
157     }
159     /* child continues from here (pid == 0) ... */
161     /* change file mode mask */
162     umask(0);
164     /* create new session ID for the child */
165     sid = setsid();
167     /* exit with failure code if failed to get session ID... */
168     if (sid < 0) {
169         printf("\nERROR: Failed to acquire new session ID!");
170         exit(EXIT_FAILURE);
171     }
173     /* disassociate from the standard file descriptors */
174     close(STDIN_FILENO);
175     close(STDOUT_FILENO);
176     close(STDERR_FILENO);
178 #endif
180     LOG0("\nInitializing LAD... ")
182     /* TODO:L make sure LAD is not already running? */
184     /* initialize client info arrays */
185     for (i = 0; i < LAD_MAXNUMCLIENTS; i++) {
186         clientConnected[i] = FALSE;
187         responseFIFOFilePtr[i] = NULL;
188     }
190     /* if command FIFO exists from previous LAD session delete it now */
191     unlink(commandFIFOFile);
193     /* create command FIFO */
194     statusIO = mkfifo(commandFIFOFile, 0777);
195     if (statusIO != 0) {
196         LOG2("\nERROR: unable to create %s, errno = %x\n", commandFIFOFile,
197             errno)
198         return(0);
199     }
201     /* set FIFO permissions to read/write */
202     chmod(commandFIFOFile, 0666);
204 opencommandFIFO:
206     /* now open file for FIFO - will block until writer arrives... */
207     LOG1("\n    opening FIFO: %s\n", commandFIFOFile)
208     commandFIFOFilePtr = fopen(commandFIFOFile, "r");
209     if (commandFIFOFilePtr == NULL) {
210         LOG0("\nERROR: unable to open command FIFO\n")
211         unlink(commandFIFOFile);
212         return(0);
213     }
215     /* COMMAND PROCESSING LOOP */
216     while (1) {
217         LOG0("Retrieving command...\n")
219         /* read the next command packet */
220         n = fread(&cmd, LAD_COMMANDLENGTH, 1, commandFIFOFilePtr);
222         /*
223          * if last client closes FIFO then it must be closed and reopened ...
224          */
225         if (!n) {
226             LOG1("    EOF detected on FIFO, closing FIFO: %s\n", commandFIFOFile)
227             fclose(commandFIFOFilePtr);
229             goto opencommandFIFO;
230         }
232         /* cleanup for any connected/started clients that have departed */
233         cleanupDepartedClients();
235         command = cmd.cmd;
236         clientId = cmd.clientId;
238         /* process individual commands */
239         switch (command) {
240           /*
241            * Since cmd is a union of rcv and snd structs, don't write
242            * any snd elements before all rcv elements have been referenced
243            * (either saved in separate variables or passed to a function).
244            *
245            * cmd.cmd has already been saved in 'command'
246            * cmd.clientId has already been saved in 'clientId'
247            */
248           case LAD_CONNECT:
249             connectToLAD(cmd.args.connect.name, cmd.args.connect.pid,
250                          cmd.args.connect.protocol, NULL);
252             break;
254           case LAD_DISCONNECT:
255             disconnectFromLAD(clientId);
257             break;
259           case LAD_NAMESERVER_SETUP:
260             LOG0("LAD_NAMESERVER_SETUP: calling NameServer_setup()...\n")
262             rsp.status = NameServer_setup();
264             LOG1("    status = %d\n", rsp.status)
265             LOG0("DONE\n")
267             break;
269           case LAD_NAMESERVER_DESTROY:
270             LOG0("LAD_NAMESERVER_DESTROY: calling NameServer_destroy()...\n")
272             rsp.status = NameServer_destroy();
274             LOG1("    status = %d\n", rsp.status)
275             LOG0("DONE\n")
277             break;
279           case LAD_NAMESERVER_PARAMS_INIT:
280             LOG0("LAD_NAMESERVER_PARAMS_INIT: calling NameServer_Params_init()...\n")
282             NameServer_Params_init(&rsp.params);
284             LOG0("DONE\n")
286             break;
288           case LAD_NAMESERVER_CREATE:
289             LOG1("LAD_NAMESERVER_CREATE: calling NameServer_create('%s')...\n", cmd.args.create.name)
291             rsp.handle = NameServer_create(cmd.args.create.name,
292                                                &cmd.args.create.params);
294             LOG1("    handle = %p\n", rsp.handle)
295             LOG0("DONE\n")
297             break;
299           case LAD_NAMESERVER_DELETE:
300             LOG1("LAD_NAMESERVER_DELETE: calling NameServer_delete(%p)...\n", cmd.args.delete.handle)
302             rsp.delete.handle = cmd.args.delete.handle;
303             rsp.delete.status = NameServer_delete(&rsp.delete.handle);
305             LOG1("    status = %d\n", rsp.status)
306             LOG0("DONE\n")
308             break;
310           case LAD_NAMESERVER_ADDUINT32:
311             LOG1("LAD_NAMESERVER_ADDUINT32: calling NameServer_addUInt32(%p, ", cmd.args.addUInt32.handle)
312             LOG2("'%s', 0x%x)...\n", cmd.args.addUInt32.name, cmd.args.addUInt32.val)
314             rsp.entryPtr = NameServer_addUInt32(
315                 cmd.args.addUInt32.handle,
316                 cmd.args.addUInt32.name,
317                 cmd.args.addUInt32.val);
319             LOG1("    entryPtr = %p\n", rsp.entryPtr)
320             LOG0("DONE\n")
322             break;
324           case LAD_NAMESERVER_GETUINT32:
325             LOG2("LAD_NAMESERVER_GETUINT32: calling NameServer_getUInt32(%p, '%s')...\n", cmd.args.getUInt32.handle, cmd.args.getUInt32.name)
327             if (cmd.args.getUInt32.procId[0] == (UInt16)-1) {
328                 procIdPtr = NULL;
329             }
330             else {
331                 procIdPtr = cmd.args.getUInt32.procId;
332             }
333             rsp.status = NameServer_getUInt32(
334                 cmd.args.getUInt32.handle,
335                 cmd.args.getUInt32.name,
336                 &rsp.getUInt32.val,
337                 procIdPtr);
339             LOG1("    value = 0x%x\n", rsp.getUInt32.val)
340             LOG1("    status = %d\n", rsp.status)
341             LOG0("DONE\n")
343             break;
345           case LAD_NAMESERVER_REMOVE:
346             LOG2("LAD_NAMESERVER_REMOVE: calling NameServer_remove(%p, '%s')...\n", cmd.args.remove.handle, cmd.args.remove.name)
348             rsp.status = NameServer_remove(cmd.args.remove.handle,
349                                                cmd.args.remove.name);
351             LOG1("    status = %d\n", rsp.status)
352             LOG0("DONE\n")
354             break;
356           case LAD_NAMESERVER_REMOVEENTRY:
357             LOG2("LAD_NAMESERVER_REMOVEENTRY: calling NameServer_removeEntry(%p, %p)...\n", cmd.args.removeEntry.handle, cmd.args.removeEntry.entryPtr)
359             rsp.status = NameServer_removeEntry(
360                 cmd.args.removeEntry.handle,
361                 cmd.args.removeEntry.entryPtr);
363             LOG1("    status = %d\n", rsp.status)
364             LOG0("DONE\n")
366             break;
368           case LAD_MESSAGEQ_GETCONFIG:
369             LOG0("LAD_MESSAGEQ_GETCONFIG: calling MessageQ_getConfig()...\n")
371             MessageQ_getConfig(&rsp.messageQGetConfig.cfg);
372             rsp.messageQGetConfig.status = 0;
374             LOG1("    status = %d\n", rsp.messageQGetConfig.status)
375             LOG0("DONE\n")
377             break;
379           case LAD_MESSAGEQ_SETUP:
380             LOG0("LAD_MESSAGEQ_SETUP: calling MessageQ_setup()...\n")
382             rsp.setup.status = MessageQ_setup(&cmd.args.messageQSetup.cfg);
383             rsp.setup.nameServerHandle = MessageQ_getNameServerHandle();
385             LOG1("    status = %d\n", rsp.setup.status)
386             LOG0("DONE\n")
388             break;
390           case LAD_MESSAGEQ_DESTROY:
391             LOG0("LAD_MESSAGEQ_DESTROY: calling MessageQ_destroy()...\n")
393             rsp.status = MessageQ_destroy();
395             LOG1("    status = %d\n", rsp.status)
396             LOG0("DONE\n")
398             break;
400           case LAD_MESSAGEQ_CREATE:
401             LOG2("LAD_MESSAGEQ_CREATE: calling MessageQ_create(%p, %p)...\n",
402                     cmd.args.messageQCreate.name,
403                     &cmd.args.messageQCreate.params);
405             tmpString = (cmd.args.messageQCreate.name[0] == '\0') ? NULL :
406                 cmd.args.messageQCreate.name;
408             handle = MessageQ_create(tmpString, &cmd.args.messageQCreate.params);
409             rsp.messageQCreate.serverHandle = handle;
411             if (handle) {
412                 rsp.messageQCreate.queueId = MessageQ_getQueueId(handle);
413                 MessageQ_setQueueOwner(handle, clientPID[clientId]);
414                 rsp.messageQCreate.status = 0;
415             }
416             else {
417                 rsp.messageQCreate.status = -1;
418             }
420             LOG1("    status = %d\n", rsp.messageQCreate.status)
421             LOG0("DONE\n")
423             break;
425           case LAD_MESSAGEQ_DELETE:
426             LOG1("LAD_MESSAGEQ_DELETE: calling MessageQ_delete(%p)...\n", cmd.args.messageQDelete.serverHandle)
428             rsp.messageQDelete.status =
429                 MessageQ_delete((MessageQ_Handle *)&cmd.args.messageQDelete.serverHandle);
431             LOG1("    status = %d\n", rsp.messageQDelete.status)
432             LOG0("DONE\n")
434             break;
436           case LAD_MESSAGEQ_MSGINIT:
437             LOG1("LAD_MESSAGEQ_MSGINIT: calling MessageQ_msgInit(%p)...\n", &rsp.msgInit.msg);
439             MessageQ_msgInit(&rsp.msgInit.msg);
440             rsp.msgInit.status = 0;
442             LOG1("    status = %d\n", rsp.msgInit.status)
443             LOG0("DONE\n")
445             break;
447           case LAD_MULTIPROC_GETCONFIG:
448             LOG0("LAD_MULTIPROC_GETCONFIG: calling MultiProc_getConfig()...\n")
450             MultiProc_getConfig(&rsp.multiprocGetConfig.cfg);
451             rsp.multiprocGetConfig.status = 0;
453             LOG1("    status = %d\n", rsp.multiprocGetConfig.status)
454             LOG0("DONE\n")
456             break;
458           case LAD_EXIT:
459             goto exitNow;
461             break;
463           default:
464             LOG1("\nUnrecognized command: 0x%x\n", command)
466             break;
467         }
469         switch (command) {
470           case LAD_CONNECT:
471           case LAD_DISCONNECT:
472             break;
474           case LAD_NAMESERVER_SETUP:
475           case LAD_NAMESERVER_DESTROY:
476           case LAD_NAMESERVER_PARAMS_INIT:
477           case LAD_NAMESERVER_CREATE:
478           case LAD_NAMESERVER_DELETE:
479           case LAD_NAMESERVER_ADDUINT32:
480           case LAD_NAMESERVER_GETUINT32:
481           case LAD_NAMESERVER_REMOVE:
482           case LAD_NAMESERVER_REMOVEENTRY:
483           case LAD_MESSAGEQ_GETCONFIG:
484           case LAD_MESSAGEQ_SETUP:
485           case LAD_MESSAGEQ_DESTROY:
486           case LAD_MESSAGEQ_CREATE:
487           case LAD_MESSAGEQ_DELETE:
488           case LAD_MESSAGEQ_MSGINIT:
489           case LAD_MULTIPROC_GETCONFIG:
490             LOG0("Sending response...\n");
492             fwrite(&rsp, LAD_RESPONSELENGTH, 1, responseFIFOFilePtr[clientId]);
493             fflush(responseFIFOFilePtr[clientId]);
495             break;
497           default:
498             break;
499         }
500     }
502 exitNow:
503     if (logFile) {
504         LOG0("\n\nLAD IS SELF TERMINATING...\n\n")
505         fclose(logPtr);
506     }
507     unlink(commandFIFOFile);
509     return(0);
514 /*
515  *  ======== assignClientId ========
516  */
517 static LAD_ClientHandle assignClientId(Void)
519     Int clientId = -1;
520     Int i;
522     /* scan connection status flags to acquire a clientId */
523     for (i = 0; i < LAD_MAXNUMCLIENTS; i++) {
524         /* if slot open then provisionally select this clientId */
525         if (clientConnected[i] == FALSE) {
526              clientId = i;
527              break;
528         }
529     }
531     return(clientId);
535 /*
536  *  ======== cleanupDepartedClients ========
537  */
538 static Void cleanupDepartedClients(Void)
540     Int killStat;
541     Int i;
543     /* scan all connections to verify client processes still exist... */
544     for (i = 0; i < LAD_MAXNUMCLIENTS; i++) {
546         /* if connected... */
547         if (clientConnected[i] == TRUE) {
549             /* check if the client process (PID) still exists */
550             /*
551              * NOTE - calling kill with signal value of 0 will perform
552              * error checking, but not actually send a signal.  Will use this
553              * error check to see if PID still exists.  An alternative was
554              * to call getpgid.  This worked, but is apparently limited to
555              * USE_XOPEN_EXTENDED configurations.
556              */
557             killStat = kill(clientPID[i], 0);
558             if ((killStat == -1) && (errno == ESRCH)) {
560                 LOG1("\nDETECTED CONNECTED CLIENT #%d HAS DEPARTED!", i)
562                 /* will always need to do the disconnect... */
563                 LOG0("\nDoing DISCONNECT on behalf of client...")
564                 doDisconnect(i);
566                 MessageQ_cleanupOwner(clientPID[i]);
567 //                NameServer_cleanupOwner(clientPID[i]);
569                 LOG0("DONE\n")
570             }
571         }
572     }
576 /*
577  *  ======== connectToLAD ========
578  */
579 static Int connectToLAD(String clientName, Int pid, String clientProto, Int *clientIdPtr)
581     Int clientId = -1;
582     Bool connectDenied = FALSE;
583     Int status = LAD_SUCCESS;
584     FILE * filePtr;
585     Int statusIO;
587     /*
588      * TODO:L here, and everywhere parse FIFO strings: should
589      * add full error checking for incomplete or corrupted
590      * strings? Since LAD to ladclient comms are "closed", and
591      * tested, the likelihood of problems seems very low.
592      * But should still consider doing full error checking
593      * and, hopefully, recovery.
594      */
595     LOG0("\nLAD_CONNECT: \n")
596     LOG1("    client FIFO name = %s\n", clientName)
597     LOG1("    client PID = %d\n", pid)
599     /* first check for proper communication protocol */
600     if (strcmp(clientProto, LAD_PROTOCOLVERSION) != 0) {
602         /* if no match then reject the request */
603         LOG0("    ERROR: mismatch in communication protocol!\n")
604         LOG1("        LAD protocol = %s\n", LAD_PROTOCOLVERSION)
605         LOG1("        client protocol = %s\n", clientProto)
606         status = LAD_INVALIDVERSION;
608         /* set flag so know to close FIFO after response */
609         connectDenied = TRUE;
611         /* now jump forward a bit to send response */
612         goto openResponseFIFO;
613     }
615     /* determine this client's ID */
616     clientId = assignClientId();
618     /* if failed to acquire an ID then exit early */
619     if (clientId == -1) {
620         LOG0("    no free handle; too many connections!\n")
621         status = LAD_ACCESSDENIED;
623         /* set flag so know to close FIFO after response */
624         connectDenied = TRUE;
625     }
626     else {
627         LOG1("    assigned client handle = %d\n", clientId)
629         /* save the client's FIFO name for when disconnect */
630         strcpy(clientFIFOName[clientId], clientName);
631     }
633 openResponseFIFO:
635     /* create the dedicated response FIFO to the client */
636     statusIO = mkfifo(clientName, 0777);
637     if (statusIO != 0) {
639         LOG2("\nERROR: unable to mkfifo %s, errno = %x\n", clientName, errno)
641         status = LAD_IOFAILURE;
643         /* send no response; connection request will timeout */
644         goto doneconnect;
645     }
647     LOG1("    FIFO %s created\n", clientName)
649     /* set FIFO permissions to read/write */
650     chmod(clientName, 0666);
652     filePtr = fopen(clientName, "w");
653     if (filePtr == NULL) {
654         LOG1("\nERROR: unable to open response FIFO %s\n", clientName)
656         /* if failed open, still need to delete the FIFO */
657         unlink(clientName);
659         status = LAD_IOFAILURE;
661         /* send no response; connection request will timeout */
662         goto doneconnect;
663     }
665     LOG1("    FIFO %s opened for writing\n", clientName)
667     /*
668      * set "this client is connected" flag; this client ID is now "owned", and
669      * is no longer provisional
670      */
671     if (connectDenied == FALSE) {
672         responseFIFOFilePtr[clientId] = filePtr;
673         clientPID[clientId] = pid;
674         clientConnected[clientId] = TRUE;
675     }
677     rsp.connect.assignedId = clientId;
678     rsp.status = status;
680     /* put response to FIFO */
681     fwrite(&rsp, LAD_RESPONSELENGTH, 1, filePtr);
682     fflush(filePtr);
684     LOG0("    sent response\n")
686     /* if connection was denied, must now close FIFO */
687     if (connectDenied == TRUE) {
688         LOG1("    connect denied; closing FIFO %s\n", clientName)
689         fclose(filePtr);
690         unlink(clientName);
691     }
693     LOG0("DONE\n")
695 doneconnect:
696     if (clientIdPtr != NULL) {
697         *clientIdPtr = clientId;
698     }
700     return(status);
704 /*
705  *  ======== disconnectFromLAD ========
706  */
707 static Void disconnectFromLAD(Int clientId)
709     LOG0("\nLAD_DISCONNECT: ")
711     LOG1("\n    client handle = %x", clientId)
712     doDisconnect(clientId);
714     LOG0("DONE\n")
716     return;
720 /*
721  *  ======== doDisconnect ========
722  */
723 static Void doDisconnect(Int clientId)
725     /* set "this client is not connected" flag */
726     clientConnected[clientId] = FALSE;
728     /* close and remove the response FIFO */
729     LOG2("\n    closing FIFO %s (filePtr=%p)\n",
730         clientFIFOName[clientId], responseFIFOFilePtr[clientId])
731     fclose(responseFIFOFilePtr[clientId]);
733     LOG1("    done, unlinking %s\n", clientFIFOName[clientId]);
734     unlink(clientFIFOName[clientId]);