/[svn]/liblscp/trunk/src/common.c
ViewVC logotype

Annotation of /liblscp/trunk/src/common.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 132 - (hide annotations) (download)
Fri Jun 18 14:19:19 2004 UTC (19 years, 9 months ago) by capela
File MIME type: text/plain
File size: 14684 byte(s)
* Overall mutexing of client command calls;
  preparation of forthcoming v.09 LSCP document draft.

1 capela 103 // client.c
2     //
3     /****************************************************************************
4     liblscp - LinuxSampler Control Protocol API
5     Copyright (C) 2004, rncbc aka Rui Nuno Capela. All rights reserved.
6    
7     This library is free software; you can redistribute it and/or
8     modify it under the terms of the GNU Lesser General Public
9     License as published by the Free Software Foundation; either
10     version 2.1 of the License, or (at your option) any later version.
11    
12     This library is distributed in the hope that it will be useful,
13     but WITHOUT ANY WARRANTY; without even the implied warranty of
14     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15     Lesser General Public License for more details.
16    
17     You should have received a copy of the GNU Lesser General Public
18     License along with this library; if not, write to the Free Software
19     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20    
21     *****************************************************************************/
22    
23     #include "common.h"
24    
25     #include <ctype.h>
26    
27    
28     // Chunk size magic:
29     // LSCP_SPLIT_CHUNK1 = 2 ^ LSCP_SPLIT_CHUNK2
30     #define LSCP_SPLIT_CHUNK1 4
31     #define LSCP_SPLIT_CHUNK2 2
32     // Chunk size legal calculator.
33     #define LSCP_SPLIT_SIZE(n) ((((n) >> LSCP_SPLIT_CHUNK2) + 1) << LSCP_SPLIT_CHUNK2)
34    
35    
36     //-------------------------------------------------------------------------
37 capela 132 // Local client request executive.
38 capela 103
39 capela 132 // Result buffer internal settler.
40     void lscp_client_set_result ( lscp_client_t *pClient, char *pszResult, int iErrno )
41     {
42     if (pClient->pszResult)
43     free(pClient->pszResult);
44     pClient->pszResult = NULL;
45    
46     pClient->iErrno = iErrno;
47    
48     if (pszResult)
49     pClient->pszResult = strdup(lscp_ltrim(pszResult));
50     }
51    
52     // The main client requester call executive.
53     lscp_status_t lscp_client_call ( lscp_client_t *pClient, const char *pszQuery )
54     {
55     fd_set fds; // File descriptor list for select().
56     int fd, fdmax; // Maximum file descriptor number.
57     struct timeval tv; // For specifying a timeout value.
58     int iSelect; // Holds select return status.
59     int iTimeout;
60     int cchQuery;
61     char achResult[LSCP_BUFSIZ];
62     int cchResult;
63     const char *pszSeps = ":[]";
64     char *pszResult;
65     char *pszToken;
66     char *pch;
67     int iErrno;
68    
69     lscp_status_t ret = LSCP_FAILED;
70    
71     if (pClient == NULL)
72     return ret;
73    
74     pszResult = NULL;
75     iErrno = -1;
76    
77     // Check if command socket socket is still valid.
78     if (pClient->cmd.sock == INVALID_SOCKET) {
79     pszResult = "Connection closed or no longer valid";
80     lscp_client_set_result(pClient, pszResult, iErrno);
81     return ret;
82     }
83    
84     // Send data, and then, wait for the result...
85     cchQuery = strlen(pszQuery);
86     if (send(pClient->cmd.sock, pszQuery, cchQuery, 0) < cchQuery) {
87     lscp_socket_perror("_lscp_client_call: send");
88     pszResult = "Failure during send operation";
89     lscp_client_set_result(pClient, pszResult, iErrno);
90     return ret;
91     }
92    
93     // Prepare for waiting on select...
94     fd = (int) pClient->cmd.sock;
95     FD_ZERO(&fds);
96     FD_SET((unsigned int) fd, &fds);
97     fdmax = fd;
98    
99     // Use the timeout select feature...
100     iTimeout = pClient->iTimeout;
101     if (iTimeout > 1000) {
102     tv.tv_sec = iTimeout / 1000;
103     iTimeout -= tv.tv_sec * 1000;
104     }
105     else tv.tv_sec = 0;
106     tv.tv_usec = iTimeout * 1000;
107    
108     // Wait for event...
109     iSelect = select(fdmax + 1, &fds, NULL, NULL, &tv);
110     if (iSelect > 0 && FD_ISSET(fd, &fds)) {
111     // May recv now...
112     cchResult = recv(pClient->cmd.sock, achResult, sizeof(achResult), 0);
113     if (cchResult > 0) {
114     // Assume early success.
115     ret = LSCP_OK;
116     // Always force the result to be null terminated (and trim trailing CRLFs)!
117     while (cchResult > 0 && (achResult[cchResult - 1] == '\n' || achResult[cchResult- 1] == '\r'))
118     cchResult--;
119     achResult[cchResult] = (char) 0;
120     // Check if the response it's an error or warning message.
121     if (strncasecmp(achResult, "WRN:", 4) == 0)
122     ret = LSCP_WARNING;
123     else if (strncasecmp(achResult, "ERR:", 4) == 0)
124     ret = LSCP_ERROR;
125     // So we got a result...
126     if (ret == LSCP_OK) {
127     // Reset errno in case of success.
128     iErrno = 0;
129     // Is it a special successful response?
130     if (strncasecmp(achResult, "OK[", 3) == 0) {
131     // Parse the OK message, get the return string under brackets...
132     pszToken = lscp_strtok(achResult, pszSeps, &(pch));
133     if (pszToken)
134     pszResult = lscp_strtok(NULL, pszSeps, &(pch));
135     }
136     else pszResult = achResult;
137     // The result string is now set to the command response, if any.
138     } else {
139     // Parse the error/warning message, skip first colon...
140     pszToken = lscp_strtok(achResult, pszSeps, &(pch));
141     if (pszToken) {
142     // Get the error number...
143     pszToken = lscp_strtok(NULL, pszSeps, &(pch));
144     if (pszToken) {
145     iErrno = atoi(pszToken);
146     // And make the message text our final result.
147     pszResult = lscp_strtok(NULL, pszSeps, &(pch));
148     }
149     }
150     // The result string is set to the error/warning message text.
151     }
152     }
153     else if (cchResult == 0) {
154     // Damn, server disconnected, we better free everything down here.
155     lscp_socket_agent_free(&(pClient->evt));
156     lscp_socket_agent_free(&(pClient->cmd));
157     // Fake a result message.
158     ret = LSCP_QUIT;
159     pszResult = "Server terminated the connection";
160     iErrno = (int) ret;
161     } else {
162     // What's down?
163     lscp_socket_perror("_lscp_client_call: recv");
164     pszResult = "Failure during receive operation";
165     }
166     } // Check if select has timed out.
167     else if (iSelect == 0) {
168     // Fake a result message.
169     ret = LSCP_TIMEOUT;
170     pszResult = "Timeout during receive operation";
171     iErrno = (int) ret;
172     }
173     else lscp_socket_perror("_lscp_client_call: select");
174    
175     // Make the result official...
176     lscp_client_set_result(pClient, pszResult, iErrno);
177    
178     return ret;
179     }
180    
181    
182     //-------------------------------------------------------------------------
183     // Other general utility functions.
184    
185 capela 103 // Trimming left spaces...
186     char *lscp_ltrim ( char *psz )
187     {
188     while (isspace(*psz))
189     psz++;
190     return psz;
191     }
192    
193     // Unquote an in-split string.
194     char *lscp_unquote ( char **ppsz, int dup )
195     {
196     char chQuote;
197     char *psz = *ppsz;
198    
199     while (isspace(*psz))
200     ++psz;
201     if (*psz == '\"' || *psz == '\'') {
202     chQuote = *psz++;
203     while (isspace(*psz))
204     ++psz;
205     if (dup)
206     psz = strdup(psz);
207     *ppsz = psz;
208     if (*ppsz) {
209     while (**ppsz && **ppsz != chQuote)
210     ++(*ppsz);
211     if (**ppsz) {
212     while (isspace(*(*ppsz - 1)) && *ppsz > psz)
213     --(*ppsz);
214     *(*ppsz)++ = (char) 0;
215     }
216     }
217     }
218     else if (dup) {
219     psz = strdup(psz);
220     *ppsz = psz;
221     }
222    
223     return psz;
224     }
225    
226    
227     // Custom tokenizer.
228     char *lscp_strtok ( char *pchBuffer, const char *pszSeps, char **ppch )
229     {
230     char *pszToken;
231    
232     if (pchBuffer == NULL)
233     pchBuffer = *ppch;
234    
235     pchBuffer += strspn(pchBuffer, pszSeps);
236     if (*pchBuffer == '\0')
237     return NULL;
238    
239     pszToken = pchBuffer;
240     pchBuffer = strpbrk(pszToken, pszSeps);
241     if (pchBuffer == NULL) {
242     *ppch = strchr(pszToken, '\0');
243     } else {
244     *pchBuffer = '\0';
245     *ppch = pchBuffer + 1;
246     while (**ppch && strchr(pszSeps, **ppch))
247     (*ppch)++;
248     }
249    
250     return pszToken;
251     }
252    
253    
254     // Split a comma separated string into a null terminated array of strings.
255     char **lscp_szsplit_create ( const char *pszCsv, const char *pszSeps )
256     {
257     char *pszHead, *pch;
258     int iSize, i, j, cchSeps;
259     char **ppszSplit, **ppszNewSplit;
260    
261     // Initial size is one chunk away.
262     iSize = LSCP_SPLIT_CHUNK1;
263     // Allocate and split...
264     ppszSplit = (char **) malloc(iSize * sizeof(char *));
265     if (ppszSplit == NULL)
266     return NULL;
267    
268     // Make a copy of the original string.
269     i = 0;
270     pszHead = (char *) pszCsv;
271     if ((ppszSplit[i++] = lscp_unquote(&pszHead, 1)) == NULL) {
272     free(ppszSplit);
273     return NULL;
274     }
275    
276     // Go on for it...
277     cchSeps = strlen(pszSeps);
278     while ((pch = strpbrk(pszHead, pszSeps)) != NULL) {
279     // Pre-advance to next item.
280     pszHead = pch + cchSeps;
281     // Trim and null terminate current item.
282     while (isspace(*(pch - 1)) && pch > ppszSplit[0])
283     --pch;
284     *pch = (char) 0;
285     // Make it official.
286     ppszSplit[i++] = lscp_unquote(&pszHead, 0);
287     // Do we need to grow?
288     if (i >= iSize) {
289     // Yes, but only grow in chunks.
290     iSize += LSCP_SPLIT_CHUNK1;
291     // Allocate and copy to new split array.
292     ppszNewSplit = (char **) malloc(iSize * sizeof(char *));
293     if (ppszNewSplit) {
294     for (j = 0; j < i; j++)
295     ppszNewSplit[j] = ppszSplit[j];
296     free(ppszSplit);
297     ppszSplit = ppszNewSplit;
298     }
299     }
300     }
301    
302     // NULL terminate split array.
303     for ( ; i < iSize; i++)
304     ppszSplit[i] = NULL;
305    
306     return ppszSplit;
307     }
308    
309    
310     // Free allocated memory of a legal null terminated array of strings.
311     void lscp_szsplit_destroy ( char **ppszSplit )
312     {
313     // Our split string is always the first item, if any.
314     if (ppszSplit && ppszSplit[0])
315     free(ppszSplit[0]);
316     // Now free the array itself.
317     if (ppszSplit)
318     free(ppszSplit);
319     }
320    
321    
322     #ifdef LSCP_SZSPLIT_COUNT
323    
324     // Return the number of items of a null terminated array of strings.
325     int lscp_szsplit_count ( char **ppszSplit )
326     {
327     int i = 0;
328     while (ppszSplit && ppszSplit[i])
329     i++;
330     return i;
331     }
332    
333     // Return the allocated number of items of a splitted string array.
334     int lscp_szsplit_size ( char **ppszSplit )
335     {
336     return LSCP_SPLIT_SIZE(lscp_szsplit_count(ppszSplit));
337     }
338    
339     #endif // LSCP_SZSPLIT_COUNT
340    
341    
342 capela 125 // Split a comma separated string into a -1 terminated array of positive integers.
343     int *lscp_isplit_create ( const char *pszCsv, const char *pszSeps )
344     {
345     char *pchHead, *pch;
346     int iSize, i, j, cchSeps;
347     int *piSplit, *piNewSplit;
348    
349     // Initial size is one chunk away.
350     iSize = LSCP_SPLIT_CHUNK1;
351     // Allocate and split...
352     piSplit = (int *) malloc(iSize * sizeof(int));
353     if (piSplit == NULL)
354     return NULL;
355    
356     // Make a copy of the original string.
357     i = 0;
358     pchHead = (char *) pszCsv;
359     if ((piSplit[i++] = atoi(pchHead)) < 0) {
360     free(piSplit);
361     return NULL;
362     }
363    
364     // Go on for it...
365     cchSeps = strlen(pszSeps);
366     while ((pch = strpbrk(pchHead, pszSeps)) != NULL) {
367     // Pre-advance to next item.
368     pchHead = pch + cchSeps;
369     // Make it official.
370     piSplit[i++] = atoi(pchHead);
371     // Do we need to grow?
372     if (i >= iSize) {
373     // Yes, but only grow in chunks.
374     iSize += LSCP_SPLIT_CHUNK1;
375     // Allocate and copy to new split array.
376     piNewSplit = (int *) malloc(iSize * sizeof(int));
377     if (piNewSplit) {
378     for (j = 0; j < i; j++)
379     piNewSplit[j] = piSplit[j];
380     free(piSplit);
381     piSplit = piNewSplit;
382     }
383     }
384     }
385    
386     // NULL terminate split array.
387     for ( ; i < iSize; i++)
388     piSplit[i] = -1;
389    
390     return piSplit;
391     }
392    
393    
394     // Destroy a integer splitted array.
395     void lscp_isplit_destroy ( int *piSplit )
396     {
397     if (piSplit)
398     free(piSplit);
399     }
400    
401    
402     #ifdef LSCP_ISPLIT_COUNT
403    
404     // Compute a string list valid item count.
405     int lscp_isplit_count ( int *piSplit )
406     {
407     int i = 0;
408     while (piSplit && piSplit[i] >= 0)
409     i++;
410     return i;
411     }
412    
413     // Compute a string list size.
414     int lscp_isplit_size ( int *piSplit )
415     {
416     return LSCP_SPLIT_SIZE(lscp_isplit_count(piSplit));
417     }
418    
419     #endif // LSCP_ISPLIT_COUNT
420    
421    
422 capela 103 //-------------------------------------------------------------------------
423     // Engine info struct helper functions.
424    
425     void lscp_engine_info_init ( lscp_engine_info_t *pEngineInfo )
426     {
427     pEngineInfo->description = NULL;
428     pEngineInfo->version = NULL;
429     }
430    
431     void lscp_engine_info_reset ( lscp_engine_info_t *pEngineInfo )
432     {
433     if (pEngineInfo->description)
434     free(pEngineInfo->description);
435     if (pEngineInfo->version)
436     free(pEngineInfo->version);
437    
438     lscp_engine_info_init(pEngineInfo);
439     }
440    
441    
442     //-------------------------------------------------------------------------
443     // Channel info struct helper functions.
444    
445     void lscp_channel_info_init ( lscp_channel_info_t *pChannelInfo )
446     {
447 capela 132 pChannelInfo->engine_name = NULL;
448     pChannelInfo->audio_device = 0;
449     pChannelInfo->audio_channels = 0;
450     pChannelInfo->audio_routing = NULL;
451     pChannelInfo->instrument_file = NULL;
452     pChannelInfo->instrument_nr = 0;
453     pChannelInfo->instrument_status = 0;
454     pChannelInfo->midi_device = 0;
455     pChannelInfo->midi_port = 0;
456     pChannelInfo->midi_channel = 0;
457     pChannelInfo->volume = 0.0;
458 capela 103 }
459    
460     void lscp_channel_info_reset ( lscp_channel_info_t *pChannelInfo )
461     {
462     if (pChannelInfo->engine_name)
463     free(pChannelInfo->engine_name);
464     if (pChannelInfo->audio_routing)
465     lscp_szsplit_destroy(pChannelInfo->audio_routing);
466     if (pChannelInfo->instrument_file)
467     free(pChannelInfo->instrument_file);
468    
469     lscp_channel_info_init(pChannelInfo);
470     }
471    
472    
473     //-------------------------------------------------------------------------
474     // Driver info struct functions.
475    
476     void lscp_driver_info_init ( lscp_driver_info_t *pDriverInfo )
477     {
478     pDriverInfo->description = NULL;
479     pDriverInfo->version = NULL;
480     pDriverInfo->parameters = NULL;
481     }
482    
483     void lscp_driver_info_reset ( lscp_driver_info_t *pDriverInfo )
484     {
485     if (pDriverInfo->description)
486     free(pDriverInfo->description);
487     if (pDriverInfo->version)
488     free(pDriverInfo->version);
489     lscp_szsplit_destroy(pDriverInfo->parameters);
490    
491     lscp_driver_info_init(pDriverInfo);
492     }
493    
494    
495     // end of common.c

  ViewVC Help
Powered by ViewVC