Merge recent 3.00 changes into 3.10
[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 <ti/ipc/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);
67 #if defined(IPC_BUILDOS_ANDROID)
68 static pthread_mutex_t modGate  = PTHREAD_RECURSIVE_MUTEX_INITIALIZER;
69 #else
70 // only _NP (non-portable) type available in CG tools which we're using
71 static pthread_mutex_t modGate  = PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP;
72 #endif
75 /*
76  * LAD_findHandle() - finds the LAD_ClientHandle for the calling pid (process ID).
77  *
78  * Assumes that there is only one client per process, which has to be the
79  * case since the pid is used to construct the responseFIFOFileName.
80  *
81  * Multiple threads within a process can all connect since each thread gets
82  * its own pid (which might be an OS-specific thing, some OSes (even some
83  * Linux implementations) use the same process pid for every thread within
84  * a process).
85  *
86  * Returns either the found "handle", or LAD_MAXNUMCLIENTS if the handle
87  * can't be found.
88  */
89 LAD_ClientHandle LAD_findHandle(Void)
90 {
91     Int i;
92     Int pid;
94     pid = getpid();
96     for (i = 0; i < LAD_MAXNUMCLIENTS; i++) {
97         if (clientInfo[i].PID == pid &&
98             clientInfo[i].connectedToLAD == TRUE) {
99             break;
100         }
101     }
103     return i;
106 /*
107  *  ======== LAD_connect ========
108  */
109 LAD_Status LAD_connect(LAD_ClientHandle * handle)
111     Char responseFIFOName[LAD_MAXLENGTHFIFONAME];
112     LAD_Status status = LAD_SUCCESS;
113     time_t currentTime;
114     time_t startTime;
115     struct stat statBuf;
116     double delta;
117     Int assignedId;
118     FILE * filePtr;
119     Int n;
120     Int pid;
121     struct LAD_CommandObj cmd;
122     union LAD_ResponseObj rsp;
124     /* sanity check arg */
125     if (handle == NULL) {
126         return(LAD_INVALIDARG);
127     }
129     /* check and initialize on first connect request */
130     if (initialized == FALSE) {
132         /* TODO:M does this need to be atomized? */
133         status = initWrappers();
134         if (status != LAD_SUCCESS) {
135             return(status);
136         }
137         initialized = TRUE;
138     }
140     /* get caller's process ID */
141     pid = getpid();
143     /* form name for dedicated response FIFO */
144     sprintf(responseFIFOName, "%s%d", LAD_RESPONSEFIFOPATH, pid);
146     PRINTVERBOSE2("\nLAD_connect: PID = %d, fifoName = %s\n", pid,
147         responseFIFOName)
149     /* check if FIFO already exists; if yes, reject the request */
150     if (stat(responseFIFOName, &statBuf) == 0) {
151         PRINTVERBOSE0("\nLAD_connect: already connected; request denied!\n")
152         return(LAD_ACCESSDENIED);
153     }
155     cmd.cmd = LAD_CONNECT;
156     strcpy(cmd.args.connect.name, responseFIFOName);
157     strcpy(cmd.args.connect.protocol, LAD_PROTOCOLVERSION);
158     cmd.args.connect.pid = pid;
160     if ((status = LAD_putCommand(&cmd)) != LAD_SUCCESS) {
161         return(status);
162     }
164     /* now open the dedicated response FIFO for this client */
165     startTime = time ((time_t *) 0);
166     while ((filePtr = fopen(responseFIFOName, "r")) == NULL) {
167         /* insert wait to yield, so LAD can process connect command sooner */
168         usleep(100);
169         currentTime = time ((time_t *) 0);
170         delta = difftime(currentTime, startTime);
171         if (delta > LAD_CONNECTTIMEOUT) {
172             pthread_mutex_unlock(&modGate);
174             return(LAD_IOFAILURE);
175         }
176     }
178     /* now get LAD's response to the connection request */
179     n = fread(&rsp, LAD_RESPONSELENGTH, 1, filePtr);
181     /* need to unlock mutex obtained by LAD_putCommand() */
182     pthread_mutex_unlock(&modGate);
184     if (n) {
185         PRINTVERBOSE0("\nLAD_connect: got response\n")
187         /* extract LAD's response code and the client ID */
188         status = rsp.connect.status;
190         /* if a successful connect ... */
191         if (status == LAD_SUCCESS) {
192             assignedId = rsp.connect.assignedId;
193             *handle = assignedId;
195             /* setup client info */
196             clientInfo[assignedId].PID = pid;
197             clientInfo[assignedId].responseFIFOFilePtr = filePtr;
198             strcpy(clientInfo[assignedId].responseFIFOName, responseFIFOName);
199             clientInfo[assignedId].connectedToLAD = TRUE;
201             PRINTVERBOSE1("    status == LAD_SUCCESS, assignedId=%d\n",
202                           assignedId);
203         }
204         else {
205             PRINTVERBOSE1("    status != LAD_SUCCESS (status=%d)\n", status);
206         }
207     }
208     else {
209         PRINTVERBOSE0(
210           "\nLAD_connect: 0 bytes read when getting LAD response!\n")
211         status = LAD_IOFAILURE;
212     }
214     /* if connect failed, close client side of FIFO (LAD closes its side) */
215     if (status != LAD_SUCCESS) {
216         PRINTVERBOSE0("\nLAD_connect failed: closing client-side of FIFO...\n")
217         fclose(filePtr);
218     }
220     return(status);
224 /*
225  *  ======== LAD_disconnect ========
226  */
227 LAD_Status LAD_disconnect(LAD_ClientHandle handle)
229     LAD_Status status = LAD_SUCCESS;
230     Bool waiting = TRUE;
231     struct stat statBuf;
232     time_t currentTime;
233     time_t startTime;
234     double delta;
235     struct LAD_CommandObj cmd;
237     /* sanity check args */
238     if (handle >= LAD_MAXNUMCLIENTS) {
239         return (LAD_INVALIDARG);
240     }
242     /* check for initialization and connection */
243     if ((initialized == FALSE) ||
244         (clientInfo[handle].connectedToLAD == FALSE)) {
245         return (LAD_NOTCONNECTED);
246     }
248     cmd.cmd = LAD_DISCONNECT;
249     cmd.clientId = handle;
251     if ((status = LAD_putCommand(&cmd)) != LAD_SUCCESS) {
252         return(status);
253     }
255     /* on success, close the dedicated response FIFO */
256     fclose(clientInfo[handle].responseFIFOFilePtr);
258     /* need to unlock mutex obtained by LAD_putCommand() */
259     pthread_mutex_unlock(&modGate);
261     /* now wait for LAD to close the connection ... */
262     startTime = time ((time_t *) 0);
263     while (waiting == TRUE) {
265         /* do a minimal wait, to yield, so LAD can disconnect */
266         usleep(1);
267         currentTime = time ((time_t *) 0);
269         /* check to see if LAD has shutdown FIFO yet... */
270         if (stat(clientInfo[handle].responseFIFOName, &statBuf) != 0) {
271             waiting = FALSE;            /* yes, so done */
272         }
273         /* if not, check for timeout */
274         else {
275             delta = difftime(currentTime, startTime);
276             if (delta > LAD_DISCONNECTTIMEOUT) {
277                 PRINTVERBOSE0("\nLAD_disconnect: timeout waiting for LAD!\n")
278                 return(LAD_IOFAILURE);
279             }
280         }
281     }
283     /* reset connection status flag */
284     clientInfo[handle].connectedToLAD = FALSE;
286     return(status);
289 /*
290  *  ======== LAD_getResponse ========
291  */
292 LAD_Status LAD_getResponse(LAD_ClientHandle handle, union LAD_ResponseObj *rsp)
294     LAD_Status status = LAD_SUCCESS;
295     Int n;
297     PRINTVERBOSE1("LAD_getResponse: client = %d\n", handle)
299     n = fread(rsp, LAD_RESPONSELENGTH, 1,
300              clientInfo[handle].responseFIFOFilePtr);
302     pthread_mutex_unlock(&modGate);
304     if (n == 0) {
305         PRINTVERBOSE0("LAD_getResponse: n = 0!\n")
306         status = LAD_IOFAILURE;
307     }
308     else {
309         PRINTVERBOSE0("LAD_getResponse: got response\n")
310     }
312     return(status);
315 /*
316  *  ======== LAD_putCommand ========
317  */
318 LAD_Status LAD_putCommand(struct LAD_CommandObj *cmd)
320     LAD_Status status = LAD_SUCCESS;
321     Int stat;
322     Int n;
324     PRINTVERBOSE1("\nLAD_putCommand: cmd = %d\n", cmd->cmd);
326     pthread_mutex_lock(&modGate);
328     n = fwrite(cmd, LAD_COMMANDLENGTH, 1, commandFIFOFilePtr);
330     if (n == 0) {
331         PRINTVERBOSE0("\nLAD_putCommand: fwrite returned 0!\n")
332         status = LAD_IOFAILURE;
333     }
334     else {
335         stat = fflush(commandFIFOFilePtr);
337         if (stat == (Int) EOF) {
338             PRINTVERBOSE0("\nLAD_putCommand: stat for fflush = EOF!\n")
339             status = LAD_IOFAILURE;
340         }
341     }
343     if (status != LAD_SUCCESS) {
344         pthread_mutex_unlock(&modGate);
345     }
347     PRINTVERBOSE1("LAD_putCommand: status = %d\n", status)
349     return(status);
353 /*
354  *  ======== initWrappers ========
355  */
356 static LAD_Status initWrappers(Void)
358     Int i;
360     /* initialize the client info structures */
361     for (i = 0; i < LAD_MAXNUMCLIENTS; i++) {
362         clientInfo[i].connectedToLAD = FALSE;
363         clientInfo[i].responseFIFOFilePtr = NULL;
364     }
366     /* now open LAD's command FIFO */
367     if (openCommandFIFO() == FALSE) {
368         return(LAD_IOFAILURE);
369     }
370     else {
371         return(LAD_SUCCESS);
372     }
375 /*
376  *  ======== openCommandFIFO ========
377  */
378 static Bool openCommandFIFO(Void)
380     /* open a file for writing to FIFO */
381     commandFIFOFilePtr = fopen(commandFIFOFileName, "w");
383     if (commandFIFOFilePtr == NULL) {
384         PRINTVERBOSE2("\nERROR: failed to open %s, errno = %x\n",
385             commandFIFOFileName, errno)
386         return(FALSE);
387     }
389     return(TRUE);