/[svn]/liblscp/trunk/examples/server.c
ViewVC logotype

Annotation of /liblscp/trunk/examples/server.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 187 - (hide annotations) (download)
Wed Jul 7 23:41:07 2004 UTC (19 years, 9 months ago) by capela
File MIME type: text/plain
File size: 22986 byte(s)
* lscp_isplit_create() gets wrong zero item if string list is empty: fixed.
* lscp_param_concat() was quitting prematurely when deplist is null: fixed.
* Lil'bit more informative example_client test run; new teststep command.

1 capela 98 // server.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 "server.h"
24    
25 capela 146 #define LSCP_SERVER_SLEEP 30 // Period in seconds for watchdog wakeup (idle loop).
26 capela 98
27    
28     // Local prototypes.
29    
30     static lscp_connect_t *_lscp_connect_create (lscp_server_t *pServer, lscp_socket_t sock, struct sockaddr_in *pAddr, int cAddr);
31     static lscp_status_t _lscp_connect_destroy (lscp_connect_t *pConnect);
32     static lscp_status_t _lscp_connect_recv (lscp_connect_t *pConnect);
33    
34     static void _lscp_connect_list_append (lscp_connect_list_t *pList, lscp_connect_t *pItem);
35     static void _lscp_connect_list_remove (lscp_connect_list_t *pList, lscp_connect_t *pItem);
36     static void _lscp_connect_list_remove_safe (lscp_connect_list_t *pList, lscp_connect_t *pItem);
37     static void _lscp_connect_list_free (lscp_connect_list_t *pList);
38     static lscp_connect_t *_lscp_connect_list_find_sock (lscp_connect_list_t *pList, lscp_socket_t sock);
39    
40     static void _lscp_server_thread_proc (lscp_server_t *pServer);
41     static void _lscp_server_select_proc (lscp_server_t *pServer);
42    
43 capela 146 static void _lscp_server_agent_proc (void *pvServer);
44 capela 98
45    
46     //-------------------------------------------------------------------------
47     // Server-side client connection list methods.
48    
49     static void _lscp_connect_list_init ( lscp_connect_list_t *pList )
50     {
51     // fprintf(stderr, "_lscp_connect_list_init: pList=%p.\n", pList);
52    
53     pList->first = NULL;
54     pList->last = NULL;
55     pList->count = 0;
56    
57     lscp_mutex_init(pList->mutex);
58     }
59    
60    
61     static void _lscp_connect_list_append ( lscp_connect_list_t *pList, lscp_connect_t *pItem )
62     {
63     // fprintf(stderr, "_lscp_connect_list_append: pList=%p pItem=%p.\n", pList, pItem);
64    
65     lscp_mutex_lock(pList->mutex);
66    
67     pItem->prev = pList->last;
68     pItem->next = NULL;
69    
70     if (pList->last)
71     (pList->last)->next = pItem;
72     else
73     pList->first = pItem;
74    
75     pList->last = pItem;
76    
77     pList->count++;
78    
79     lscp_mutex_unlock(pList->mutex);
80     }
81    
82    
83     static void _lscp_connect_list_remove ( lscp_connect_list_t *pList, lscp_connect_t *pItem )
84     {
85     // fprintf(stderr, "_lscp_connect_list_remove: pList=%p pItem=%p.\n", pList, pItem);
86    
87     if (pItem->next)
88     (pItem->next)->prev = pItem->prev;
89     else
90     pList->last = pItem->prev;
91    
92     if (pItem->prev)
93     (pItem->prev)->next = pItem->next;
94     else
95     pList->first = pItem->next;
96    
97     pItem->next = NULL;
98     pItem->prev = NULL;
99    
100     pList->count--;
101     }
102    
103    
104     static void _lscp_connect_list_remove_safe ( lscp_connect_list_t *pList, lscp_connect_t *pItem )
105     {
106     lscp_connect_t *p;
107    
108     // fprintf(stderr, "_lscp_connect_list_remove_safe: pList=%p pItem=%p.\n", pList, pItem);
109    
110     lscp_mutex_lock(pList->mutex);
111    
112     for (p = pList->first; p; p = p->next) {
113     if (p == pItem) {
114     _lscp_connect_list_remove(pList, pItem);
115     break;
116     }
117     }
118    
119     lscp_mutex_unlock(pList->mutex);
120     }
121    
122    
123     static void _lscp_connect_list_free ( lscp_connect_list_t *pList )
124     {
125     lscp_connect_t *p, *pNext;
126    
127     // fprintf(stderr, "_lscp_connect_list_free: pList=%p.\n", pList);
128    
129     lscp_mutex_lock(pList->mutex);
130    
131     for (p = pList->first; p; p = pNext) {
132     pNext = p->next;
133     _lscp_connect_list_remove(pList, p);
134     _lscp_connect_destroy(p);
135     }
136    
137     lscp_mutex_unlock(pList->mutex);
138    
139     lscp_mutex_destroy(pList->mutex);
140     }
141    
142    
143     static lscp_connect_t *_lscp_connect_list_find_sock ( lscp_connect_list_t *pList, lscp_socket_t sock )
144     {
145     lscp_connect_t *p;
146    
147     // fprintf(stderr, "_lscp_connect_list_find_sock: pList=%p sock=%d.\n", pList, sock);
148    
149     for (p = pList->first; p; p = p->next) {
150     if (sock == p->client.sock)
151     return p;
152     }
153    
154     return NULL;
155     }
156    
157     //-------------------------------------------------------------------------
158     // Server-side threaded client connections.
159    
160     static void _lscp_connect_proc ( void *pvConnect )
161     {
162     lscp_connect_t *pConnect = (lscp_connect_t *) pvConnect;
163     lscp_server_t *pServer = pConnect->server;
164    
165 capela 146 while (pServer->agent.iState && pConnect->client.iState) {
166 capela 98 if (_lscp_connect_recv(pConnect) != LSCP_OK)
167     pConnect->client.iState = 0;
168     }
169    
170     (*pServer->pfnCallback)(pConnect, NULL, LSCP_CONNECT_CLOSE, pServer->pvData);
171     _lscp_connect_list_remove_safe(&(pServer->connects), pConnect);
172     closesocket(pConnect->client.sock);
173     }
174    
175     static lscp_connect_t *_lscp_connect_create ( lscp_server_t *pServer, lscp_socket_t sock, struct sockaddr_in *pAddr, int cAddr )
176     {
177     lscp_connect_t *pConnect;
178    
179     if (pServer == NULL || sock == INVALID_SOCKET || pAddr == NULL) {
180     fprintf(stderr, "_lscp_connect_create: Invalid connection arguments.\n");
181     return NULL;
182     }
183    
184     pConnect = (lscp_connect_t *) malloc(sizeof(lscp_connect_t));
185     if (pConnect == NULL) {
186     fprintf(stderr, "_lscp_connect_create: Out of memory.\n");
187     closesocket(sock);
188     return NULL;
189     }
190     memset(pConnect, 0, sizeof(lscp_connect_t));
191    
192     pConnect->server = pServer;
193 capela 146 pConnect->events = LSCP_EVENT_NONE;
194 capela 98
195     #ifdef DEBUG
196     fprintf(stderr, "_lscp_connect_create: pConnect=%p: sock=%d addr=%s port=%d.\n", pConnect, sock, inet_ntoa(pAddr->sin_addr), ntohs(pAddr->sin_port));
197     #endif
198    
199     lscp_socket_agent_init(&(pConnect->client), sock, pAddr, cAddr);
200    
201     if (pServer->mode == LSCP_SERVER_THREAD) {
202     if (lscp_socket_agent_start(&(pConnect->client), _lscp_connect_proc, pConnect, 0) != LSCP_OK) {
203     closesocket(sock);
204     free(pConnect);
205     return NULL;
206     }
207     }
208    
209     return pConnect;
210     }
211    
212    
213     static lscp_status_t _lscp_connect_destroy ( lscp_connect_t *pConnect )
214     {
215     lscp_status_t ret = LSCP_FAILED;
216    
217     if (pConnect == NULL)
218     return ret;
219    
220     #ifdef DEBUG
221     fprintf(stderr, "_lscp_connect_destroy: pConnect=%p.\n", pConnect);
222     #endif
223    
224     lscp_socket_agent_free(&(pConnect->client));
225    
226     free(pConnect);
227    
228     return ret;
229     }
230    
231    
232     lscp_status_t _lscp_connect_recv ( lscp_connect_t *pConnect )
233     {
234     lscp_status_t ret = LSCP_FAILED;
235     lscp_server_t *pServer;
236     char achBuffer[LSCP_BUFSIZ];
237     int cchBuffer;
238    
239     if (pConnect == NULL)
240     return ret;
241    
242     pServer = pConnect->server;
243     if (pServer == NULL)
244     return ret;
245    
246     cchBuffer = recv(pConnect->client.sock, achBuffer, sizeof(achBuffer), 0);
247     if (cchBuffer > 0)
248     ret = (*pServer->pfnCallback)(pConnect, achBuffer, cchBuffer, pServer->pvData);
249     else if (cchBuffer < 0)
250     lscp_socket_perror("_lscp_connect_recv: recv");
251    
252     return ret;
253     }
254    
255    
256     //-------------------------------------------------------------------------
257 capela 132 // Command service (stream oriented).
258 capela 98
259     static void _lscp_server_thread_proc ( lscp_server_t *pServer )
260     {
261     lscp_socket_t sock;
262     struct sockaddr_in addr;
263     int cAddr;
264     lscp_connect_t *pConnect;
265    
266     #ifdef DEBUG
267     fprintf(stderr, "_lscp_server_thread_proc: Server listening for connections.\n");
268     #endif
269    
270 capela 146 while (pServer->agent.iState) {
271 capela 98 cAddr = sizeof(struct sockaddr_in);
272 capela 146 sock = accept(pServer->agent.sock, (struct sockaddr *) &addr, &cAddr);
273 capela 98 if (sock == INVALID_SOCKET) {
274     lscp_socket_perror("_lscp_server_thread_proc: accept");
275 capela 146 pServer->agent.iState = 0;
276 capela 98 } else {
277     pConnect = _lscp_connect_create(pServer, sock, &addr, cAddr);
278     if (pConnect) {
279     _lscp_connect_list_append(&(pServer->connects), pConnect);
280     (*pServer->pfnCallback)(pConnect, NULL, LSCP_CONNECT_OPEN, pServer->pvData);
281     }
282     }
283     }
284    
285     #ifdef DEBUG
286     fprintf(stderr, "_lscp_server_thread_proc: Server closing.\n");
287     #endif
288     }
289    
290    
291     static void _lscp_server_select_proc ( lscp_server_t *pServer )
292     {
293     fd_set master_fds; // Master file descriptor list.
294     fd_set select_fds; // temp file descriptor list for select().
295     int fd, fdmax; // Maximum file descriptor number.
296     struct timeval tv; // For specifying a timeout value.
297     int iSelect; // Holds select return status.
298    
299     lscp_socket_t sock;
300     struct sockaddr_in addr;
301     int cAddr;
302     lscp_connect_t *pConnect;
303    
304     #ifdef DEBUG
305     fprintf(stderr, "_lscp_server_select_proc: Server listening for connections.\n");
306     #endif
307     FD_ZERO(&master_fds);
308     FD_ZERO(&select_fds);
309    
310 capela 146 // Add the listener to the master set
311     FD_SET((unsigned int) pServer->agent.sock, &master_fds);
312 capela 98
313     // Keep track of the biggest file descriptor;
314     // So far, it's ourself, the listener.
315 capela 146 fdmax = (int) pServer->agent.sock;
316 capela 98
317     // Main loop...
318 capela 146 while (pServer->agent.iState) {
319 capela 98
320     // Use a copy of the master.
321     select_fds = master_fds;
322     // Use the timeout feature for watchdoggin.
323 capela 146 tv.tv_sec = LSCP_SERVER_SLEEP;
324 capela 98 tv.tv_usec = 0;
325     // Wait for events...
326     iSelect = select(fdmax + 1, &select_fds, NULL, NULL, &tv);
327    
328     if (iSelect < 0) {
329     lscp_socket_perror("_lscp_server_select_proc: select");
330 capela 146 pServer->agent.iState = 0;
331 capela 98 }
332     else if (iSelect > 0) {
333     // Run through the existing connections looking for data to read...
334     for (fd = 0; fd < fdmax + 1; fd++) {
335     if (FD_ISSET(fd, &select_fds)) { // We got one!!
336 capela 132 // Is it ourselves, the command listener?
337 capela 146 if (fd == (int) pServer->agent.sock) {
338 capela 98 // Accept the connection...
339     cAddr = sizeof(struct sockaddr_in);
340 capela 146 sock = accept(pServer->agent.sock, (struct sockaddr *) &addr, &cAddr);
341 capela 98 if (sock == INVALID_SOCKET) {
342     lscp_socket_perror("_lscp_server_select_proc: accept");
343 capela 146 pServer->agent.iState = 0;
344 capela 98 } else {
345     // Add to master set.
346     FD_SET((unsigned int) sock, &master_fds);
347     // Keep track of the maximum.
348     if ((int) sock > fdmax)
349     fdmax = (int) sock;
350     // And do create the client connection entry.
351     pConnect = _lscp_connect_create(pServer, sock, &addr, cAddr);
352     if (pConnect) {
353     _lscp_connect_list_append(&(pServer->connects), pConnect);
354     (*pServer->pfnCallback)(pConnect, NULL, LSCP_CONNECT_OPEN, pServer->pvData);
355     }
356     }
357     // Done with one new connection.
358     } else {
359     // Otherwise it's trivial transaction...
360     lscp_mutex_lock(pServer->connects.mutex);
361     // Find the connection on our cache...
362     pConnect = _lscp_connect_list_find_sock(&(pServer->connects), (lscp_socket_t) fd);
363     // Handle data from a client.
364     if (_lscp_connect_recv(pConnect) != LSCP_OK) {
365     // Say bye bye!
366     if (pConnect) {
367     (*pServer->pfnCallback)(pConnect, NULL, LSCP_CONNECT_CLOSE, pServer->pvData);
368     _lscp_connect_list_remove(&(pServer->connects), pConnect);
369     _lscp_connect_destroy(pConnect);
370     }
371     // Remove from master set.
372     FD_CLR((unsigned int) fd, &master_fds);
373     }
374     lscp_mutex_unlock(pServer->connects.mutex);
375     }
376     }
377     }
378     // Done (iSelect > 0)
379     }
380     }
381    
382     #ifdef DEBUG
383     fprintf(stderr, "_lscp_server_select_proc: Server closing.\n");
384     #endif
385     }
386    
387    
388 capela 146 static void _lscp_server_agent_proc ( void *pvServer )
389 capela 98 {
390     lscp_server_t *pServer = (lscp_server_t *) pvServer;
391    
392     if (pServer->mode == LSCP_SERVER_THREAD)
393     _lscp_server_thread_proc(pServer);
394     else
395     _lscp_server_select_proc(pServer);
396     }
397    
398    
399     //-------------------------------------------------------------------------
400     // Server versioning teller fuunction.
401    
402     /** Retrieve the current server library version string. */
403     const char* lscp_server_package (void) { return LSCP_PACKAGE; }
404    
405     /** Retrieve the current server library version string. */
406     const char* lscp_server_version (void) { return LSCP_VERSION; }
407    
408     /** Retrieve the current server library build timestamp string. */
409     const char* lscp_server_build (void) { return __DATE__ " " __TIME__; }
410    
411    
412     //-------------------------------------------------------------------------
413     // Server sockets.
414    
415     /**
416     * Create a server instance, listening on the given port for client
417     * connections. A server callback function must be suplied that will
418     * handle every and each client request.
419     *
420     * @param iPort Port number where the server will bind for listening.
421     * @param pfnCallback Callback function to receive and handle client requests.
422     * @param pvData Server context opaque data, that will be passed
423     * to the callback function without change.
424     *
425     * @returns The new server instance pointer @ref lscp_server_t if successfull,
426     * which shall be used on all subsequent server calls, NULL otherwise.
427     */
428     lscp_server_t* lscp_server_create ( int iPort, lscp_server_proc_t pfnCallback, void *pvData )
429     {
430     return lscp_server_create_ex(iPort, pfnCallback, pvData, LSCP_SERVER_SELECT);
431     }
432    
433    
434     /**
435     * Create a server instance, listening on the given port for client
436     * connections. A server callback function must be suplied that will
437     * handle every and each client request. A server threading model
438     * maybe specified either as multi-threaded (one thread per client)
439     * or single thread multiplex mode (one thread serves all clients).
440     *
441     * @param iPort Port number where the server will bind for listening.
442     * @param pfnCallback Callback function to receive and handle client requests.
443     * @param pvData Server context opaque data, that will be passed
444     * to the callback function without change.
445     * @param mode Server mode of operation, regarding the internal
446     * threading model, either @ref LSCP_SERVER_THREAD for
447     * a multi-threaded server, or @ref LSCP_SERVER_SELECT
448     * for a single-threaded multiplexed server.
449     *
450     * @returns The new server instance pointer if successfull, which shall be
451     * used on all subsequent server calls, NULL otherwise.
452     */
453     lscp_server_t* lscp_server_create_ex ( int iPort, lscp_server_proc_t pfnCallback, void *pvData, lscp_server_mode_t mode )
454     {
455     lscp_server_t *pServer;
456     lscp_socket_t sock;
457     struct sockaddr_in addr;
458     int cAddr;
459     int iSockOpt = (-1);
460    
461     if (pfnCallback == NULL) {
462     fprintf(stderr, "lscp_server_create: Invalid server callback function.\n");
463     return NULL;
464     }
465    
466     // Allocate server descriptor...
467    
468     pServer = (lscp_server_t *) malloc(sizeof(lscp_server_t));
469     if (pServer == NULL) {
470     fprintf(stderr, "lscp_server_create: Out of memory.\n");
471     return NULL;
472     }
473     memset(pServer, 0, sizeof(lscp_server_t));
474    
475     _lscp_connect_list_init(&(pServer->connects));
476    
477     pServer->mode = mode;
478     pServer->pfnCallback = pfnCallback;
479     pServer->pvData = pvData;
480    
481     #ifdef DEBUG
482     fprintf(stderr, "lscp_server_create: pServer=%p: iPort=%d.\n", pServer, iPort);
483     #endif
484    
485 capela 132 // Prepare the command stream server socket...
486 capela 98
487     sock = socket(AF_INET, SOCK_STREAM, 0);
488     if (sock == INVALID_SOCKET) {
489 capela 146 lscp_socket_perror("lscp_server_create: socket");
490 capela 98 free(pServer);
491     return NULL;
492     }
493    
494     if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char *) &iSockOpt, sizeof(int)) == SOCKET_ERROR)
495 capela 146 lscp_socket_perror("lscp_server_create: setsockopt(SO_REUSEADDR)");
496 capela 98 #if defined(WIN32)
497     if (setsockopt(sock, SOL_SOCKET, SO_DONTLINGER, (char *) &iSockOpt, sizeof(int)) == SOCKET_ERROR)
498 capela 146 lscp_socket_perror("lscp_server_create: setsockopt(SO_DONTLINGER)");
499 capela 98 #endif
500    
501     #ifdef DEBUG
502 capela 146 lscp_socket_getopts("lscp_server_create", sock);
503 capela 98 #endif
504    
505     cAddr = sizeof(struct sockaddr_in);
506     memset((char *) &addr, 0, cAddr);
507     addr.sin_family = AF_INET;
508     addr.sin_addr.s_addr = htonl(INADDR_ANY);
509     addr.sin_port = htons((short) iPort);
510    
511     if (bind(sock, (const struct sockaddr *) &addr, cAddr) == SOCKET_ERROR) {
512 capela 146 lscp_socket_perror("lscp_server_create: bind");
513 capela 98 closesocket(sock);
514     free(pServer);
515     return NULL;
516     }
517    
518     if (listen(sock, 10) == SOCKET_ERROR) {
519 capela 146 lscp_socket_perror("lscp_server_create: listen");
520 capela 98 closesocket(sock);
521     free(pServer);
522     return NULL;
523     }
524    
525     if (iPort == 0) {
526     if (getsockname(sock, (struct sockaddr *) &addr, &cAddr) == SOCKET_ERROR) {
527 capela 146 lscp_socket_perror("lscp_server_create: getsockname");
528 capela 98 closesocket(sock);
529     free(pServer);
530     }
531     }
532    
533 capela 146 lscp_socket_agent_init(&(pServer->agent), sock, &addr, cAddr);
534 capela 98
535     #ifdef DEBUG
536 capela 146 fprintf(stderr, "lscp_server_create: sock=%d addr=%s port=%d.\n", pServer->agent.sock, inet_ntoa(pServer->agent.addr.sin_addr), ntohs(pServer->agent.addr.sin_port));
537 capela 98 #endif
538    
539     // Now's finally time to startup threads...
540    
541 capela 132 // Command service thread...
542 capela 146 if (lscp_socket_agent_start(&(pServer->agent), _lscp_server_agent_proc, pServer, 0) != LSCP_OK) {
543     lscp_socket_agent_free(&(pServer->agent));
544 capela 98 free(pServer);
545     return NULL;
546     }
547    
548     // Finally we've some success...
549     return pServer;
550     }
551    
552    
553     /**
554     * Wait for a server instance to terminate graciously.
555     *
556     * @param pServer Pointer to server instance structure.
557     */
558     lscp_status_t lscp_server_join ( lscp_server_t *pServer )
559     {
560     if (pServer == NULL)
561     return LSCP_FAILED;
562    
563     #ifdef DEBUG
564     fprintf(stderr, "lscp_server_join: pServer=%p.\n", pServer);
565     #endif
566    
567 capela 146 lscp_socket_agent_join(&(pServer->agent));
568 capela 98
569     return LSCP_OK;
570     }
571    
572    
573     /**
574     * Terminate and destroy a server instance.
575     *
576     * @param pServer Pointer to server instance structure.
577     */
578     lscp_status_t lscp_server_destroy ( lscp_server_t *pServer )
579     {
580     if (pServer == NULL)
581     return LSCP_FAILED;
582    
583     #ifdef DEBUG
584     fprintf(stderr, "lscp_server_destroy: pServer=%p.\n", pServer);
585     #endif
586    
587     _lscp_connect_list_free(&(pServer->connects));
588 capela 146 lscp_socket_agent_free(&(pServer->agent));
589 capela 98
590     free(pServer);
591    
592     return LSCP_OK;
593     }
594    
595    
596     /**
597 capela 146 * Send an event notification message to all subscribed clients.
598 capela 98 *
599 capela 147 * @param pServer Pointer to server instance structure.
600     * @param event Event type flag to send to all subscribed clients.
601     * @param pchData Pointer to event data to be sent to all clients.
602     * @param cchData Length of the event data to be sent in bytes.
603 capela 98 *
604     * @returns LSCP_OK on success, LSCP_FAILED otherwise.
605     */
606 capela 146 lscp_status_t lscp_server_broadcast ( lscp_server_t *pServer, lscp_event_t event, const char *pchData, int cchData )
607 capela 98 {
608     lscp_connect_t *p;
609 capela 146 const char *pszEvent;
610     char achBuffer[LSCP_BUFSIZ];
611     int cchBuffer;
612 capela 98
613     if (pServer == NULL)
614     return LSCP_FAILED;
615 capela 146 if (pchData == NULL || cchData < 1)
616 capela 98 return LSCP_FAILED;
617    
618 capela 146 // Which (single) event?
619     pszEvent = lscp_event_to_text(event);
620     if (pszEvent == NULL)
621     return LSCP_FAILED;
622    
623     // Build the event message string...
624     cchBuffer = sprintf(achBuffer, "NOTIFY:%s:", pszEvent);
625     if (pchData) {
626     if (cchData > LSCP_BUFSIZ - cchBuffer - 2)
627     cchData = LSCP_BUFSIZ - cchBuffer - 2;
628     strncpy(&achBuffer[cchBuffer], pchData, cchData);
629     cchBuffer += cchData;
630     }
631     achBuffer[cchBuffer++] = '\r';
632     achBuffer[cchBuffer++] = '\n';
633    
634     // And do the direct broadcasting...
635    
636 capela 98 lscp_mutex_lock(pServer->connects.mutex);
637    
638     for (p = pServer->connects.first; p; p = p->next) {
639 capela 146 if (p->events & event)
640     send(p->client.sock, achBuffer, cchBuffer, 0);
641 capela 98 }
642    
643     lscp_mutex_unlock(pServer->connects.mutex);
644    
645     return LSCP_OK;
646     }
647    
648    
649     /**
650     * Send response for the current client callback request.
651     *
652     * @param pConnect Pointer to client connection instance structure.
653     * @param pchBuffer Pointer to data to be sent to the client as response.
654     * @param cchBuffer Length of the response data to be sent in bytes.
655     *
656     * @returns LSCP_OK on success, LSCP_FAILED otherwise.
657     */
658     lscp_status_t lscp_server_result ( lscp_connect_t *pConnect, const char *pchBuffer, int cchBuffer )
659     {
660     lscp_status_t ret = LSCP_FAILED;
661    
662     if (pConnect == NULL)
663     return ret;
664     if (pchBuffer == NULL || cchBuffer < 1)
665     return ret;
666    
667     if (send(pConnect->client.sock, pchBuffer, cchBuffer, 0) != cchBuffer)
668     lscp_socket_perror("lscp_server_result");
669     else
670     ret = LSCP_OK;
671    
672     return ret;
673     }
674    
675    
676     /**
677     * Register client as a subscriber of event broadcast messages.
678     *
679 capela 132 * @param pConnect Pointer to client connection instance structure.
680 capela 146 * @param event Event type flag of the requesting client subscription.
681 capela 98 *
682     * @returns LSCP_OK on success, LSCP_FAILED otherwise.
683     */
684 capela 146 lscp_status_t lscp_server_subscribe ( lscp_connect_t *pConnect, lscp_event_t event )
685 capela 98 {
686     if (pConnect == NULL)
687     return LSCP_FAILED;
688 capela 146 if (event == LSCP_EVENT_NONE)
689 capela 98 return LSCP_FAILED;
690    
691 capela 146 pConnect->events |= event;
692 capela 98
693 capela 146 return LSCP_OK;
694 capela 98 }
695    
696    
697     /**
698     * Deregister client as subscriber of event broadcast messages.
699     *
700 capela 146 * @param pConnect Pointer to client connection instance structure.
701     * @param event Event type flag of the requesting client unsubscription.
702 capela 98 *
703     * @returns LSCP_OK on success, LSCP_FAILED otherwise.
704     */
705 capela 146 lscp_status_t lscp_server_unsubscribe ( lscp_connect_t *pConnect, lscp_event_t event )
706 capela 98 {
707     if (pConnect == NULL)
708     return LSCP_FAILED;
709 capela 146 if (event == LSCP_EVENT_NONE)
710 capela 98 return LSCP_FAILED;
711    
712 capela 146 pConnect->events &= ~event;
713 capela 98
714     return LSCP_OK;
715     }
716    
717    
718     // end of server.c

  ViewVC Help
Powered by ViewVC