SDOCM00115373 NameServer local get methods are missing on Linux
[ipc/ipcdev.git] / linux / src / utils / LAD_client.c
1 /*
2  * Copyright (c) 2012-2014, 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>
51 /* traces in this file are controlled via _LAD_Client_verbose */
52 Bool _LAD_Client_verbose = FALSE;
53 #define verbose _LAD_Client_verbose
55 typedef struct _LAD_ClientInfo {
56     Bool connectedToLAD;               /* connection status */
57     UInt PID;                                     /* client's process ID */
58     Char responseFIFOName[LAD_MAXLENGTHFIFONAME]; /* response FIFO name */
59     FILE *responseFIFOFilePtr;                    /* FIFO file pointer */
60 } _LAD_ClientInfo;
62 static Bool initialized = FALSE;
63 static String commandFIFOFileName = LAD_COMMANDFIFO;
64 static FILE *commandFIFOFilePtr = NULL;
65 static _LAD_ClientInfo clientInfo[LAD_MAXNUMCLIENTS];
67 static LAD_Status initWrappers(Void);
68 static Bool openCommandFIFO(Void);
70 #if defined(IPC_BUILDOS_ANDROID)
71 static pthread_mutex_t modGate  = PTHREAD_RECURSIVE_MUTEX_INITIALIZER;
72 #else
73 // only _NP (non-portable) type available in CG tools which we're using
74 static pthread_mutex_t modGate  = PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP;
75 #endif
78 /*
79  * LAD_findHandle() - finds the LAD_ClientHandle for the calling pid (process ID).
80  *
81  * Assumes that there is only one client per process, which has to be the
82  * case since the pid is used to construct the responseFIFOFileName.
83  *
84  * Multiple threads within a process can all connect since each thread gets
85  * its own pid (which might be an OS-specific thing, some OSes (even some
86  * Linux implementations) use the same process pid for every thread within
87  * a process).
88  *
89  * Returns either the found "handle", or LAD_MAXNUMCLIENTS if the handle
90  * can't be found.
91  */
92 LAD_ClientHandle LAD_findHandle(Void)
93 {
94     Int i;
95     Int pid;
97     pid = getpid();
99     for (i = 0; i < LAD_MAXNUMCLIENTS; i++) {
100         if (clientInfo[i].PID == pid &&
101             clientInfo[i].connectedToLAD == TRUE) {
102             break;
103         }
104     }
106     return i;
109 /*
110  *  ======== LAD_connect ========
111  */
112 LAD_Status LAD_connect(LAD_ClientHandle * handle)
114     Char responseFIFOName[LAD_MAXLENGTHFIFONAME];
115     LAD_Status status = LAD_SUCCESS;
116     time_t currentTime;
117     time_t startTime;
118     struct stat statBuf;
119     double delta;
120     Int assignedId;
121     FILE * filePtr;
122     Int n;
123     Int pid;
124     struct LAD_CommandObj cmd;
125     union LAD_ResponseObj rsp;
127     /* sanity check arg */
128     if (handle == NULL) {
129         return(LAD_INVALIDARG);
130     }
132     /* check and initialize on first connect request */
133     if (initialized == FALSE) {
135         /* TODO:M does this need to be atomized? */
136         status = initWrappers();
137         if (status != LAD_SUCCESS) {
138             return(status);
139         }
140         initialized = TRUE;
141     }
143     /* get caller's process ID */
144     pid = getpid();
146     /* form name for dedicated response FIFO */
147     sprintf(responseFIFOName, "%s%d", LAD_RESPONSEFIFOPATH, pid);
149     PRINTVERBOSE2("\nLAD_connect: PID = %d, fifoName = %s\n", pid,
150         responseFIFOName)
152     /* check if FIFO already exists; if yes, reject the request */
153     if (stat(responseFIFOName, &statBuf) == 0) {
154         PRINTVERBOSE0("\nLAD_connect: already connected; request denied!\n")
155         return(LAD_ACCESSDENIED);
156     }
158     cmd.cmd = LAD_CONNECT;
159     strcpy(cmd.args.connect.name, responseFIFOName);
160     strcpy(cmd.args.connect.protocol, LAD_PROTOCOLVERSION);
161     cmd.args.connect.pid = pid;
163     if ((status = LAD_putCommand(&cmd)) != LAD_SUCCESS) {
164         return(status);
165     }
167     /* now open the dedicated response FIFO for this client */
168     startTime = time ((time_t *) 0);
169     while ((filePtr = fopen(responseFIFOName, "r")) == NULL) {
170         /* insert wait to yield, so LAD can process connect command sooner */
171         usleep(100);
172         currentTime = time ((time_t *) 0);
173         delta = difftime(currentTime, startTime);
174         if (delta > LAD_CONNECTTIMEOUT) {
175             pthread_mutex_unlock(&modGate);
177             return(LAD_IOFAILURE);
178         }
179     }
181     /* now get LAD's response to the connection request */
182     n = fread(&rsp, LAD_RESPONSELENGTH, 1, filePtr);
184     /* need to unlock mutex obtained by LAD_putCommand() */
185     pthread_mutex_unlock(&modGate);
187     if (n) {
188         PRINTVERBOSE0("\nLAD_connect: got response\n")
190         /* extract LAD's response code and the client ID */
191         status = rsp.connect.status;
193         /* if a successful connect ... */
194         if (status == LAD_SUCCESS) {
195             assignedId = rsp.connect.assignedId;
196             *handle = assignedId;
198             /* setup client info */
199             clientInfo[assignedId].PID = pid;
200             clientInfo[assignedId].responseFIFOFilePtr = filePtr;
201             strcpy(clientInfo[assignedId].responseFIFOName, responseFIFOName);
202             clientInfo[assignedId].connectedToLAD = TRUE;
204             PRINTVERBOSE1("    status == LAD_SUCCESS, assignedId=%d\n",
205                           assignedId);
206         }
207         else {
208             PRINTVERBOSE1("    status != LAD_SUCCESS (status=%d)\n", status);
209         }
210     }
211     else {
212         PRINTVERBOSE0(
213           "\nLAD_connect: 0 bytes read when getting LAD response!\n")
214         status = LAD_IOFAILURE;
215     }
217     /* if connect failed, close client side of FIFO (LAD closes its side) */
218     if (status != LAD_SUCCESS) {
219         PRINTVERBOSE0("\nLAD_connect failed: closing client-side of FIFO...\n")
220         fclose(filePtr);
221     }
223     return(status);
227 /*
228  *  ======== LAD_disconnect ========
229  */
230 LAD_Status LAD_disconnect(LAD_ClientHandle handle)
232     LAD_Status status = LAD_SUCCESS;
233     Bool waiting = TRUE;
234     struct stat statBuf;
235     time_t currentTime;
236     time_t startTime;
237     double delta;
238     struct LAD_CommandObj cmd;
240     /* sanity check args */
241     if (handle >= LAD_MAXNUMCLIENTS) {
242         return (LAD_INVALIDARG);
243     }
245     /* check for initialization and connection */
246     if ((initialized == FALSE) ||
247         (clientInfo[handle].connectedToLAD == FALSE)) {
248         return (LAD_NOTCONNECTED);
249     }
251     cmd.cmd = LAD_DISCONNECT;
252     cmd.clientId = handle;
254     if ((status = LAD_putCommand(&cmd)) != LAD_SUCCESS) {
255         return(status);
256     }
258     /* on success, close the dedicated response FIFO */
259     fclose(clientInfo[handle].responseFIFOFilePtr);
261     /* need to unlock mutex obtained by LAD_putCommand() */
262     pthread_mutex_unlock(&modGate);
264     /* now wait for LAD to close the connection ... */
265     startTime = time ((time_t *) 0);
266     while (waiting == TRUE) {
268         /* do a minimal wait, to yield, so LAD can disconnect */
269         usleep(1);
270         currentTime = time ((time_t *) 0);
272         /* check to see if LAD has shutdown FIFO yet... */
273         if (stat(clientInfo[handle].responseFIFOName, &statBuf) != 0) {
274             waiting = FALSE;            /* yes, so done */
275         }
276         /* if not, check for timeout */
277         else {
278             delta = difftime(currentTime, startTime);
279             if (delta > LAD_DISCONNECTTIMEOUT) {
280                 PRINTVERBOSE0("\nLAD_disconnect: timeout waiting for LAD!\n")
281                 return(LAD_IOFAILURE);
282             }
283         }
284     }
286     /* reset connection status flag */
287     clientInfo[handle].connectedToLAD = FALSE;
289     return(status);
292 /*
293  *  ======== LAD_getResponse ========
294  */
295 LAD_Status LAD_getResponse(LAD_ClientHandle handle, union LAD_ResponseObj *rsp)
297     LAD_Status status = LAD_SUCCESS;
298     Int n;
300     PRINTVERBOSE1("LAD_getResponse: client = %d\n", handle)
302     n = fread(rsp, LAD_RESPONSELENGTH, 1,
303              clientInfo[handle].responseFIFOFilePtr);
305     pthread_mutex_unlock(&modGate);
307     if (n == 0) {
308         PRINTVERBOSE0("LAD_getResponse: n = 0!\n")
309         status = LAD_IOFAILURE;
310     }
311     else {
312         PRINTVERBOSE0("LAD_getResponse: got response\n")
313     }
315     return(status);
318 /*
319  *  ======== LAD_putCommand ========
320  */
321 LAD_Status LAD_putCommand(struct LAD_CommandObj *cmd)
323     LAD_Status status = LAD_SUCCESS;
324     Int stat;
325     Int n;
327     PRINTVERBOSE1("\nLAD_putCommand: cmd = %d\n", cmd->cmd);
329     pthread_mutex_lock(&modGate);
331     n = fwrite(cmd, LAD_COMMANDLENGTH, 1, commandFIFOFilePtr);
333     if (n == 0) {
334         PRINTVERBOSE0("\nLAD_putCommand: fwrite returned 0!\n")
335         status = LAD_IOFAILURE;
336     }
337     else {
338         stat = fflush(commandFIFOFilePtr);
340         if (stat == (Int) EOF) {
341             PRINTVERBOSE0("\nLAD_putCommand: stat for fflush = EOF!\n")
342             status = LAD_IOFAILURE;
343         }
344     }
346     if (status != LAD_SUCCESS) {
347         pthread_mutex_unlock(&modGate);
348     }
350     PRINTVERBOSE1("LAD_putCommand: status = %d\n", status)
352     return(status);
356 /*
357  *  ======== initWrappers ========
358  */
359 static LAD_Status initWrappers(Void)
361     Int i;
363     /* initialize the client info structures */
364     for (i = 0; i < LAD_MAXNUMCLIENTS; i++) {
365         clientInfo[i].connectedToLAD = FALSE;
366         clientInfo[i].responseFIFOFilePtr = NULL;
367     }
369     /* now open LAD's command FIFO */
370     if (openCommandFIFO() == FALSE) {
371         return(LAD_IOFAILURE);
372     }
373     else {
374         return(LAD_SUCCESS);
375     }
378 /*
379  *  ======== openCommandFIFO ========
380  */
381 static Bool openCommandFIFO(Void)
383     /* open a file for writing to FIFO */
384     commandFIFOFilePtr = fopen(commandFIFOFileName, "w");
386     if (commandFIFOFilePtr == NULL) {
387         PRINTVERBOSE2("\nERROR: failed to open %s, errno = %x\n",
388             commandFIFOFileName, errno)
389         return(FALSE);
390     }
392     return(TRUE);