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;
104 }
106 /*
107 * ======== LAD_connect ========
108 */
109 LAD_Status LAD_connect(LAD_ClientHandle * handle)
110 {
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);
221 }
224 /*
225 * ======== LAD_disconnect ========
226 */
227 LAD_Status LAD_disconnect(LAD_ClientHandle handle)
228 {
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);
287 }
289 /*
290 * ======== LAD_getResponse ========
291 */
292 LAD_Status LAD_getResponse(LAD_ClientHandle handle, union LAD_ResponseObj *rsp)
293 {
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);
313 }
315 /*
316 * ======== LAD_putCommand ========
317 */
318 LAD_Status LAD_putCommand(struct LAD_CommandObj *cmd)
319 {
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);
350 }
353 /*
354 * ======== initWrappers ========
355 */
356 static LAD_Status initWrappers(Void)
357 {
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 }
373 }
375 /*
376 * ======== openCommandFIFO ========
377 */
378 static Bool openCommandFIFO(Void)
379 {
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);
390 }