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;
100 }
102 /*
103 * ======== LAD_connect ========
104 */
105 LAD_Status LAD_connect(LAD_ClientHandle * handle)
106 {
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);
217 }
220 /*
221 * ======== LAD_disconnect ========
222 */
223 LAD_Status LAD_disconnect(LAD_ClientHandle handle)
224 {
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);
283 }
285 /*
286 * ======== LAD_getResponse ========
287 */
288 LAD_Status LAD_getResponse(LAD_ClientHandle handle, union LAD_ResponseObj *rsp)
289 {
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);
309 }
311 /*
312 * ======== LAD_putCommand ========
313 */
314 LAD_Status LAD_putCommand(struct LAD_CommandObj *cmd)
315 {
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);
346 }
349 /*
350 * ======== initWrappers ========
351 */
352 static LAD_Status initWrappers(Void)
353 {
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 }
369 }
371 /*
372 * ======== openCommandFIFO ========
373 */
374 static Bool openCommandFIFO(Void)
375 {
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);
386 }