Disabled automake maintainer mode for Linux-side config to prevent unnecessary regen...
[ipc/ipcdev.git] / linux / src / utils / LAD_client.c
1 /*
2  * Copyright (c) 2012, 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_client.c ========
34  */
35 #include <Std.h>
37 #include <stdio.h>
38 #include <stdlib.h>
39 #include <string.h>
40 #include <errno.h>
41 #include <sys/stat.h>
42 #include <sys/types.h>
43 #include <unistd.h>
44 #include <time.h>
45 #include <pthread.h>
47 #include <ladclient.h>
48 #include <_lad.h>
50 static Bool verbose = FALSE;
52 typedef struct _LAD_ClientInfo {
53     Bool connectedToLAD;               /* connection status */
54     UInt PID;                                     /* client's process ID */
55     Char responseFIFOName[LAD_MAXLENGTHFIFONAME]; /* response FIFO name */
56     FILE *responseFIFOFilePtr;                    /* FIFO file pointer */
57 } _LAD_ClientInfo;
59 static Bool initialized = FALSE;
60 static String commandFIFOFileName = LAD_COMMANDFIFO;
61 static FILE *commandFIFOFilePtr = NULL;
62 static _LAD_ClientInfo clientInfo[LAD_MAXNUMCLIENTS];
64 static LAD_Status initWrappers(Void);
65 static Bool openCommandFIFO(Void);
66 // only _NP (non-portable) type available in CG tools which we're using
67 static pthread_mutex_t modGate  = PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP;
68 // static pthread_mutex_t modGate  = PTHREAD_RECURSIVE_MUTEX_INITIALIZER;
71 /*
72  * LAD_findHandle() - finds the LAD_ClientHandle for the calling pid (process ID).
73  *
74  * Assumes that there is only one client per process, which has to be the
75  * case since the pid is used to construct the responseFIFOFileName.
76  *
77  * Multiple threads within a process can all connect since each thread gets
78  * its own pid (which might be an OS-specific thing, some OSes (even some
79  * Linux implementations) use the same process pid for every thread within
80  * a process).
81  *
82  * Returns either the found "handle", or LAD_MAXNUMCLIENTS if the handle
83  * can't be found.
84  */
85 LAD_ClientHandle LAD_findHandle(Void)
86 {
87     Int i;
88     Int pid;
90     pid = getpid();
92     for (i = 0; i < LAD_MAXNUMCLIENTS; i++) {
93         if (clientInfo[i].PID == pid &&
94             clientInfo[i].connectedToLAD == TRUE) {
95             break;
96         }
97     }
99     return i;
102 /*
103  *  ======== LAD_connect ========
104  */
105 LAD_Status LAD_connect(LAD_ClientHandle * handle)
107     Char responseFIFOName[LAD_MAXLENGTHFIFONAME];
108     LAD_Status status = LAD_SUCCESS;
109     time_t currentTime;
110     time_t startTime;
111     struct stat statBuf;
112     double delta;
113     Int assignedId;
114     FILE * filePtr;
115     Int n;
116     Int pid;
117     struct LAD_CommandObj cmd;
118     union LAD_ResponseObj rsp;
120     /* sanity check arg */
121     if (handle == NULL) {
122         return(LAD_INVALIDARG);
123     }
125     /* check and initialize on first connect request */
126     if (initialized == FALSE) {
128         /* TODO:M does this need to be atomized? */
129         status = initWrappers();
130         if (status != LAD_SUCCESS) {
131             return(status);
132         }
133         initialized = TRUE;
134     }
136     /* get caller's process ID */
137     pid = getpid();
139     /* form name for dedicated response FIFO */
140     sprintf(responseFIFOName, "%s%d", LAD_RESPONSEFIFOPATH, pid);
142     PRINTVERBOSE2("\nLAD_connect: PID = %d, fifoName = %s\n", pid,
143         responseFIFOName)
145     /* check if FIFO already exists; if yes, reject the request */
146     if (stat(responseFIFOName, &statBuf) == 0) {
147         PRINTVERBOSE0("\nLAD_connect: already connected; request denied!\n")
148         return(LAD_ACCESSDENIED);
149     }
151     cmd.cmd = LAD_CONNECT;
152     strcpy(cmd.args.connect.name, responseFIFOName);
153     strcpy(cmd.args.connect.protocol, LAD_PROTOCOLVERSION);
154     cmd.args.connect.pid = pid;
156     if ((status = LAD_putCommand(&cmd)) != LAD_SUCCESS) {
157         return(status);
158     }
160     /* now open the dedicated response FIFO for this client */
161     startTime = time ((time_t *) 0);
162     while ((filePtr = fopen(responseFIFOName, "r")) == NULL) {
163         /* insert wait to yield, so LAD can process connect command sooner */
164         usleep(100);
165         currentTime = time ((time_t *) 0);
166         delta = difftime(currentTime, startTime);
167         if (delta > LAD_CONNECTTIMEOUT) {
168             pthread_mutex_unlock(&modGate);
170             return(LAD_IOFAILURE);
171         }
172     }
174     /* now get LAD's response to the connection request */
175     n = fread(&rsp, LAD_RESPONSELENGTH, 1, filePtr);
177     /* need to unlock mutex obtained by LAD_putCommand() */
178     pthread_mutex_unlock(&modGate);
180     if (n) {
181         PRINTVERBOSE0("\nLAD_connect: got response\n")
183         /* extract LAD's response code and the client ID */
184         status = rsp.connect.status;
186         /* if a successful connect ... */
187         if (status == LAD_SUCCESS) {
188             assignedId = rsp.connect.assignedId;
189             *handle = assignedId;
191             /* setup client info */
192             clientInfo[assignedId].PID = pid;
193             clientInfo[assignedId].responseFIFOFilePtr = filePtr;
194             strcpy(clientInfo[assignedId].responseFIFOName, responseFIFOName);
195             clientInfo[assignedId].connectedToLAD = TRUE;
197             PRINTVERBOSE1("    status == LAD_SUCCESS, assignedId=%d\n",
198                           assignedId);
199         }
200         else {
201             PRINTVERBOSE1("    status != LAD_SUCCESS (status=%d)\n", status);
202         }
203     }
204     else {
205         PRINTVERBOSE0(
206           "\nLAD_connect: 0 bytes read when getting LAD response!\n")
207         status = LAD_IOFAILURE;
208     }
210     /* if connect failed, close client side of FIFO (LAD closes its side) */
211     if (status != LAD_SUCCESS) {
212         PRINTVERBOSE0("\nLAD_connect failed: closing client-side of FIFO...\n")
213         fclose(filePtr);
214     }
216     return(status);
220 /*
221  *  ======== LAD_disconnect ========
222  */
223 LAD_Status LAD_disconnect(LAD_ClientHandle handle)
225     LAD_Status status = LAD_SUCCESS;
226     Bool waiting = TRUE;
227     struct stat statBuf;
228     time_t currentTime;
229     time_t startTime;
230     double delta;
231     struct LAD_CommandObj cmd;
233     /* sanity check args */
234     if (handle >= LAD_MAXNUMCLIENTS) {
235         return (LAD_INVALIDARG);
236     }
238     /* check for initialization and connection */
239     if ((initialized == FALSE) ||
240         (clientInfo[handle].connectedToLAD == FALSE)) {
241         return (LAD_NOTCONNECTED);
242     }
244     cmd.cmd = LAD_DISCONNECT;
245     cmd.clientId = handle;
247     if ((status = LAD_putCommand(&cmd)) != LAD_SUCCESS) {
248         return(status);
249     }
251     /* on success, close the dedicated response FIFO */
252     fclose(clientInfo[handle].responseFIFOFilePtr);
254     /* need to unlock mutex obtained by LAD_putCommand() */
255     pthread_mutex_unlock(&modGate);
257     /* now wait for LAD to close the connection ... */
258     startTime = time ((time_t *) 0);
259     while (waiting == TRUE) {
261         /* do a minimal wait, to yield, so LAD can disconnect */
262         usleep(1);
263         currentTime = time ((time_t *) 0);
265         /* check to see if LAD has shutdown FIFO yet... */
266         if (stat(clientInfo[handle].responseFIFOName, &statBuf) != 0) {
267             waiting = FALSE;            /* yes, so done */
268         }
269         /* if not, check for timeout */
270         else {
271             delta = difftime(currentTime, startTime);
272             if (delta > LAD_DISCONNECTTIMEOUT) {
273                 PRINTVERBOSE0("\nLAD_disconnect: timeout waiting for LAD!\n")
274                 return(LAD_IOFAILURE);
275             }
276         }
277     }
279     /* reset connection status flag */
280     clientInfo[handle].connectedToLAD = FALSE;
282     return(status);
285 /*
286  *  ======== LAD_getResponse ========
287  */
288 LAD_Status LAD_getResponse(LAD_ClientHandle handle, union LAD_ResponseObj *rsp)
290     LAD_Status status = LAD_SUCCESS;
291     Int n;
293     PRINTVERBOSE1("LAD_getResponse: client = %d\n", handle)
295     n = fread(rsp, LAD_RESPONSELENGTH, 1,
296              clientInfo[handle].responseFIFOFilePtr);
298     pthread_mutex_unlock(&modGate);
300     if (n == 0) {
301         PRINTVERBOSE0("LAD_getResponse: n = 0!\n")
302         status = LAD_IOFAILURE;
303     }
304     else {
305         PRINTVERBOSE0("LAD_getResponse: got response\n")
306     }
308     return(status);
311 /*
312  *  ======== LAD_putCommand ========
313  */
314 LAD_Status LAD_putCommand(struct LAD_CommandObj *cmd)
316     LAD_Status status = LAD_SUCCESS;
317     Int stat;
318     Int n;
320     PRINTVERBOSE1("\nLAD_putCommand: cmd = %d\n", cmd->cmd);
322     pthread_mutex_lock(&modGate);
324     n = fwrite(cmd, LAD_COMMANDLENGTH, 1, commandFIFOFilePtr);
326     if (n == 0) {
327         PRINTVERBOSE0("\nLAD_putCommand: fwrite returned 0!\n")
328         status = LAD_IOFAILURE;
329     }
330     else {
331         stat = fflush(commandFIFOFilePtr);
333         if (stat == (Int) EOF) {
334             PRINTVERBOSE0("\nLAD_putCommand: stat for fflush = EOF!\n")
335             status = LAD_IOFAILURE;
336         }
337     }
339     if (status != LAD_SUCCESS) {
340         pthread_mutex_unlock(&modGate);
341     }
343     PRINTVERBOSE1("LAD_putCommand: status = %d\n", status)
345     return(status);
349 /*
350  *  ======== initWrappers ========
351  */
352 static LAD_Status initWrappers(Void)
354     Int i;
356     /* initialize the client info structures */
357     for (i = 0; i < LAD_MAXNUMCLIENTS; i++) {
358         clientInfo[i].connectedToLAD = FALSE;
359         clientInfo[i].responseFIFOFilePtr = NULL;
360     }
362     /* now open LAD's command FIFO */
363     if (openCommandFIFO() == FALSE) {
364         return(LAD_IOFAILURE);
365     }
366     else {
367         return(LAD_SUCCESS);
368     }
371 /*
372  *  ======== openCommandFIFO ========
373  */
374 static Bool openCommandFIFO(Void)
376     /* open a file for writing to FIFO */
377     commandFIFOFilePtr = fopen(commandFIFOFileName, "w");
379     if (commandFIFOFilePtr == NULL) {
380         PRINTVERBOSE2("\nERROR: failed to open %s, errno = %x\n",
381             commandFIFOFileName, errno)
382         return(FALSE);
383     }
385     return(TRUE);