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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 178 - (hide annotations) (download)
Tue Jul 6 15:52:25 2004 UTC (19 years, 9 months ago) by capela
File MIME type: text/plain
File size: 23054 byte(s)
Slight change to thread join termination code.

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 capela 146 #ifdef DEBUG
227     fprintf(stderr, "<%p> Done.\n", pConnect);
228     #endif
229 capela 98
230     free(pConnect);
231    
232     return ret;
233     }
234    
235    
236     lscp_status_t _lscp_connect_recv ( lscp_connect_t *pConnect )
237     {
238     lscp_status_t ret = LSCP_FAILED;
239     lscp_server_t *pServer;
240     char achBuffer[LSCP_BUFSIZ];
241     int cchBuffer;
242    
243     if (pConnect == NULL)
244     return ret;
245    
246     pServer = pConnect->server;
247     if (pServer == NULL)
248     return ret;
249    
250     cchBuffer = recv(pConnect->client.sock, achBuffer, sizeof(achBuffer), 0);
251     if (cchBuffer > 0)
252     ret = (*pServer->pfnCallback)(pConnect, achBuffer, cchBuffer, pServer->pvData);
253     else if (cchBuffer < 0)
254     lscp_socket_perror("_lscp_connect_recv: recv");
255    
256     return ret;
257     }
258    
259    
260     //-------------------------------------------------------------------------
261 capela 132 // Command service (stream oriented).
262 capela 98
263     static void _lscp_server_thread_proc ( lscp_server_t *pServer )
264     {
265     lscp_socket_t sock;
266     struct sockaddr_in addr;
267     int cAddr;
268     lscp_connect_t *pConnect;
269    
270     #ifdef DEBUG
271     fprintf(stderr, "_lscp_server_thread_proc: Server listening for connections.\n");
272     #endif
273    
274 capela 146 while (pServer->agent.iState) {
275 capela 98 cAddr = sizeof(struct sockaddr_in);
276 capela 146 sock = accept(pServer->agent.sock, (struct sockaddr *) &addr, &cAddr);
277 capela 98 if (sock == INVALID_SOCKET) {
278     lscp_socket_perror("_lscp_server_thread_proc: accept");
279 capela 146 pServer->agent.iState = 0;
280 capela 98 } else {
281     pConnect = _lscp_connect_create(pServer, sock, &addr, cAddr);
282     if (pConnect) {
283     _lscp_connect_list_append(&(pServer->connects), pConnect);
284     (*pServer->pfnCallback)(pConnect, NULL, LSCP_CONNECT_OPEN, pServer->pvData);
285     }
286     }
287     }
288    
289     #ifdef DEBUG
290     fprintf(stderr, "_lscp_server_thread_proc: Server closing.\n");
291     #endif
292     }
293    
294    
295     static void _lscp_server_select_proc ( lscp_server_t *pServer )
296     {
297     fd_set master_fds; // Master file descriptor list.
298     fd_set select_fds; // temp file descriptor list for select().
299     int fd, fdmax; // Maximum file descriptor number.
300     struct timeval tv; // For specifying a timeout value.
301     int iSelect; // Holds select return status.
302    
303     lscp_socket_t sock;
304     struct sockaddr_in addr;
305     int cAddr;
306     lscp_connect_t *pConnect;
307    
308     #ifdef DEBUG
309     fprintf(stderr, "_lscp_server_select_proc: Server listening for connections.\n");
310     #endif
311     FD_ZERO(&master_fds);
312     FD_ZERO(&select_fds);
313    
314 capela 146 // Add the listener to the master set
315     FD_SET((unsigned int) pServer->agent.sock, &master_fds);
316 capela 98
317     // Keep track of the biggest file descriptor;
318     // So far, it's ourself, the listener.
319 capela 146 fdmax = (int) pServer->agent.sock;
320 capela 98
321     // Main loop...
322 capela 146 while (pServer->agent.iState) {
323 capela 98
324     // Use a copy of the master.
325     select_fds = master_fds;
326     // Use the timeout feature for watchdoggin.
327 capela 146 tv.tv_sec = LSCP_SERVER_SLEEP;
328 capela 98 tv.tv_usec = 0;
329     // Wait for events...
330     iSelect = select(fdmax + 1, &select_fds, NULL, NULL, &tv);
331    
332     if (iSelect < 0) {
333     lscp_socket_perror("_lscp_server_select_proc: select");
334 capela 146 pServer->agent.iState = 0;
335 capela 98 }
336     else if (iSelect > 0) {
337     // Run through the existing connections looking for data to read...
338     for (fd = 0; fd < fdmax + 1; fd++) {
339     if (FD_ISSET(fd, &select_fds)) { // We got one!!
340 capela 132 // Is it ourselves, the command listener?
341 capela 146 if (fd == (int) pServer->agent.sock) {
342 capela 98 // Accept the connection...
343     cAddr = sizeof(struct sockaddr_in);
344 capela 146 sock = accept(pServer->agent.sock, (struct sockaddr *) &addr, &cAddr);
345 capela 98 if (sock == INVALID_SOCKET) {
346     lscp_socket_perror("_lscp_server_select_proc: accept");
347 capela 146 pServer->agent.iState = 0;
348 capela 98 } else {
349     // Add to master set.
350     FD_SET((unsigned int) sock, &master_fds);
351     // Keep track of the maximum.
352     if ((int) sock > fdmax)
353     fdmax = (int) sock;
354     // And do create the client connection entry.
355     pConnect = _lscp_connect_create(pServer, sock, &addr, cAddr);
356     if (pConnect) {
357     _lscp_connect_list_append(&(pServer->connects), pConnect);
358     (*pServer->pfnCallback)(pConnect, NULL, LSCP_CONNECT_OPEN, pServer->pvData);
359     }
360     }
361     // Done with one new connection.
362     } else {
363     // Otherwise it's trivial transaction...
364     lscp_mutex_lock(pServer->connects.mutex);
365     // Find the connection on our cache...
366     pConnect = _lscp_connect_list_find_sock(&(pServer->connects), (lscp_socket_t) fd);
367     // Handle data from a client.
368     if (_lscp_connect_recv(pConnect) != LSCP_OK) {
369     // Say bye bye!
370     if (pConnect) {
371     (*pServer->pfnCallback)(pConnect, NULL, LSCP_CONNECT_CLOSE, pServer->pvData);
372     _lscp_connect_list_remove(&(pServer->connects), pConnect);
373     _lscp_connect_destroy(pConnect);
374     }
375     // Remove from master set.
376     FD_CLR((unsigned int) fd, &master_fds);
377     }
378     lscp_mutex_unlock(pServer->connects.mutex);
379     }
380     }
381     }
382     // Done (iSelect > 0)
383     }
384     }
385    
386     #ifdef DEBUG
387     fprintf(stderr, "_lscp_server_select_proc: Server closing.\n");
388     #endif
389     }
390    
391    
392 capela 146 static void _lscp_server_agent_proc ( void *pvServer )
393 capela 98 {
394     lscp_server_t *pServer = (lscp_server_t *) pvServer;
395    
396     if (pServer->mode == LSCP_SERVER_THREAD)
397     _lscp_server_thread_proc(pServer);
398     else
399     _lscp_server_select_proc(pServer);
400     }
401    
402    
403     //-------------------------------------------------------------------------
404     // Server versioning teller fuunction.
405    
406     /** Retrieve the current server library version string. */
407     const char* lscp_server_package (void) { return LSCP_PACKAGE; }
408    
409     /** Retrieve the current server library version string. */
410     const char* lscp_server_version (void) { return LSCP_VERSION; }
411    
412     /** Retrieve the current server library build timestamp string. */
413     const char* lscp_server_build (void) { return __DATE__ " " __TIME__; }
414    
415    
416     //-------------------------------------------------------------------------
417     // Server sockets.
418    
419     /**
420     * Create a server instance, listening on the given port for client
421     * connections. A server callback function must be suplied that will
422     * handle every and each client request.
423     *
424     * @param iPort Port number where the server will bind for listening.
425     * @param pfnCallback Callback function to receive and handle client requests.
426     * @param pvData Server context opaque data, that will be passed
427     * to the callback function without change.
428     *
429     * @returns The new server instance pointer @ref lscp_server_t if successfull,
430     * which shall be used on all subsequent server calls, NULL otherwise.
431     */
432     lscp_server_t* lscp_server_create ( int iPort, lscp_server_proc_t pfnCallback, void *pvData )
433     {
434     return lscp_server_create_ex(iPort, pfnCallback, pvData, LSCP_SERVER_SELECT);
435     }
436    
437    
438     /**
439     * Create a server instance, listening on the given port for client
440     * connections. A server callback function must be suplied that will
441     * handle every and each client request. A server threading model
442     * maybe specified either as multi-threaded (one thread per client)
443     * or single thread multiplex mode (one thread serves all clients).
444     *
445     * @param iPort Port number where the server will bind for listening.
446     * @param pfnCallback Callback function to receive and handle client requests.
447     * @param pvData Server context opaque data, that will be passed
448     * to the callback function without change.
449     * @param mode Server mode of operation, regarding the internal
450     * threading model, either @ref LSCP_SERVER_THREAD for
451     * a multi-threaded server, or @ref LSCP_SERVER_SELECT
452     * for a single-threaded multiplexed server.
453     *
454     * @returns The new server instance pointer if successfull, which shall be
455     * used on all subsequent server calls, NULL otherwise.
456     */
457     lscp_server_t* lscp_server_create_ex ( int iPort, lscp_server_proc_t pfnCallback, void *pvData, lscp_server_mode_t mode )
458     {
459     lscp_server_t *pServer;
460     lscp_socket_t sock;
461     struct sockaddr_in addr;
462     int cAddr;
463     int iSockOpt = (-1);
464    
465     if (pfnCallback == NULL) {
466     fprintf(stderr, "lscp_server_create: Invalid server callback function.\n");
467     return NULL;
468     }
469    
470     // Allocate server descriptor...
471    
472     pServer = (lscp_server_t *) malloc(sizeof(lscp_server_t));
473     if (pServer == NULL) {
474     fprintf(stderr, "lscp_server_create: Out of memory.\n");
475     return NULL;
476     }
477     memset(pServer, 0, sizeof(lscp_server_t));
478    
479     _lscp_connect_list_init(&(pServer->connects));
480    
481     pServer->mode = mode;
482     pServer->pfnCallback = pfnCallback;
483     pServer->pvData = pvData;
484    
485     #ifdef DEBUG
486     fprintf(stderr, "lscp_server_create: pServer=%p: iPort=%d.\n", pServer, iPort);
487     #endif
488    
489 capela 132 // Prepare the command stream server socket...
490 capela 98
491     sock = socket(AF_INET, SOCK_STREAM, 0);
492     if (sock == INVALID_SOCKET) {
493 capela 146 lscp_socket_perror("lscp_server_create: socket");
494 capela 98 free(pServer);
495     return NULL;
496     }
497    
498     if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char *) &iSockOpt, sizeof(int)) == SOCKET_ERROR)
499 capela 146 lscp_socket_perror("lscp_server_create: setsockopt(SO_REUSEADDR)");
500 capela 98 #if defined(WIN32)
501     if (setsockopt(sock, SOL_SOCKET, SO_DONTLINGER, (char *) &iSockOpt, sizeof(int)) == SOCKET_ERROR)
502 capela 146 lscp_socket_perror("lscp_server_create: setsockopt(SO_DONTLINGER)");
503 capela 98 #endif
504    
505     #ifdef DEBUG
506 capela 146 lscp_socket_getopts("lscp_server_create", sock);
507 capela 98 #endif
508    
509     cAddr = sizeof(struct sockaddr_in);
510     memset((char *) &addr, 0, cAddr);
511     addr.sin_family = AF_INET;
512     addr.sin_addr.s_addr = htonl(INADDR_ANY);
513     addr.sin_port = htons((short) iPort);
514    
515     if (bind(sock, (const struct sockaddr *) &addr, cAddr) == SOCKET_ERROR) {
516 capela 146 lscp_socket_perror("lscp_server_create: bind");
517 capela 98 closesocket(sock);
518     free(pServer);
519     return NULL;
520     }
521    
522     if (listen(sock, 10) == SOCKET_ERROR) {
523 capela 146 lscp_socket_perror("lscp_server_create: listen");
524 capela 98 closesocket(sock);
525     free(pServer);
526     return NULL;
527     }
528    
529     if (iPort == 0) {
530     if (getsockname(sock, (struct sockaddr *) &addr, &cAddr) == SOCKET_ERROR) {
531 capela 146 lscp_socket_perror("lscp_server_create: getsockname");
532 capela 98 closesocket(sock);
533     free(pServer);
534     }
535     }
536    
537 capela 146 lscp_socket_agent_init(&(pServer->agent), sock, &addr, cAddr);
538 capela 98
539     #ifdef DEBUG
540 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));
541 capela 98 #endif
542    
543     // Now's finally time to startup threads...
544    
545 capela 132 // Command service thread...
546 capela 146 if (lscp_socket_agent_start(&(pServer->agent), _lscp_server_agent_proc, pServer, 0) != LSCP_OK) {
547     lscp_socket_agent_free(&(pServer->agent));
548 capela 98 free(pServer);
549     return NULL;
550     }
551    
552     // Finally we've some success...
553     return pServer;
554     }
555    
556    
557     /**
558     * Wait for a server instance to terminate graciously.
559     *
560     * @param pServer Pointer to server instance structure.
561     */
562     lscp_status_t lscp_server_join ( lscp_server_t *pServer )
563     {
564     if (pServer == NULL)
565     return LSCP_FAILED;
566    
567     #ifdef DEBUG
568     fprintf(stderr, "lscp_server_join: pServer=%p.\n", pServer);
569     #endif
570    
571 capela 146 lscp_socket_agent_join(&(pServer->agent));
572 capela 98
573     return LSCP_OK;
574     }
575    
576    
577     /**
578     * Terminate and destroy a server instance.
579     *
580     * @param pServer Pointer to server instance structure.
581     */
582     lscp_status_t lscp_server_destroy ( lscp_server_t *pServer )
583     {
584     if (pServer == NULL)
585     return LSCP_FAILED;
586    
587     #ifdef DEBUG
588     fprintf(stderr, "lscp_server_destroy: pServer=%p.\n", pServer);
589     #endif
590    
591     _lscp_connect_list_free(&(pServer->connects));
592 capela 146 lscp_socket_agent_free(&(pServer->agent));
593 capela 98
594     free(pServer);
595    
596     return LSCP_OK;
597     }
598    
599    
600     /**
601 capela 146 * Send an event notification message to all subscribed clients.
602 capela 98 *
603 capela 147 * @param pServer Pointer to server instance structure.
604     * @param event Event type flag to send to all subscribed clients.
605     * @param pchData Pointer to event data to be sent to all clients.
606     * @param cchData Length of the event data to be sent in bytes.
607 capela 98 *
608     * @returns LSCP_OK on success, LSCP_FAILED otherwise.
609     */
610 capela 146 lscp_status_t lscp_server_broadcast ( lscp_server_t *pServer, lscp_event_t event, const char *pchData, int cchData )
611 capela 98 {
612     lscp_connect_t *p;
613 capela 146 const char *pszEvent;
614     char achBuffer[LSCP_BUFSIZ];
615     int cchBuffer;
616 capela 98
617     if (pServer == NULL)
618     return LSCP_FAILED;
619 capela 146 if (pchData == NULL || cchData < 1)
620 capela 98 return LSCP_FAILED;
621    
622 capela 146 // Which (single) event?
623     pszEvent = lscp_event_to_text(event);
624     if (pszEvent == NULL)
625     return LSCP_FAILED;
626    
627     // Build the event message string...
628     cchBuffer = sprintf(achBuffer, "NOTIFY:%s:", pszEvent);
629     if (pchData) {
630     if (cchData > LSCP_BUFSIZ - cchBuffer - 2)
631     cchData = LSCP_BUFSIZ - cchBuffer - 2;
632     strncpy(&achBuffer[cchBuffer], pchData, cchData);
633     cchBuffer += cchData;
634     }
635     achBuffer[cchBuffer++] = '\r';
636     achBuffer[cchBuffer++] = '\n';
637    
638     // And do the direct broadcasting...
639    
640 capela 98 lscp_mutex_lock(pServer->connects.mutex);
641    
642     for (p = pServer->connects.first; p; p = p->next) {
643 capela 146 if (p->events & event)
644     send(p->client.sock, achBuffer, cchBuffer, 0);
645 capela 98 }
646    
647     lscp_mutex_unlock(pServer->connects.mutex);
648    
649     return LSCP_OK;
650     }
651    
652    
653     /**
654     * Send response for the current client callback request.
655     *
656     * @param pConnect Pointer to client connection instance structure.
657     * @param pchBuffer Pointer to data to be sent to the client as response.
658     * @param cchBuffer Length of the response data to be sent in bytes.
659     *
660     * @returns LSCP_OK on success, LSCP_FAILED otherwise.
661     */
662     lscp_status_t lscp_server_result ( lscp_connect_t *pConnect, const char *pchBuffer, int cchBuffer )
663     {
664     lscp_status_t ret = LSCP_FAILED;
665    
666     if (pConnect == NULL)
667     return ret;
668     if (pchBuffer == NULL || cchBuffer < 1)
669     return ret;
670    
671     if (send(pConnect->client.sock, pchBuffer, cchBuffer, 0) != cchBuffer)
672     lscp_socket_perror("lscp_server_result");
673     else
674     ret = LSCP_OK;
675    
676     return ret;
677     }
678    
679    
680     /**
681     * Register client as a subscriber of event broadcast messages.
682     *
683 capela 132 * @param pConnect Pointer to client connection instance structure.
684 capela 146 * @param event Event type flag of the requesting client subscription.
685 capela 98 *
686     * @returns LSCP_OK on success, LSCP_FAILED otherwise.
687     */
688 capela 146 lscp_status_t lscp_server_subscribe ( lscp_connect_t *pConnect, lscp_event_t event )
689 capela 98 {
690     if (pConnect == NULL)
691     return LSCP_FAILED;
692 capela 146 if (event == LSCP_EVENT_NONE)
693 capela 98 return LSCP_FAILED;
694    
695 capela 146 pConnect->events |= event;
696 capela 98
697 capela 146 return LSCP_OK;
698 capela 98 }
699    
700    
701     /**
702     * Deregister client as subscriber of event broadcast messages.
703     *
704 capela 146 * @param pConnect Pointer to client connection instance structure.
705     * @param event Event type flag of the requesting client unsubscription.
706 capela 98 *
707     * @returns LSCP_OK on success, LSCP_FAILED otherwise.
708     */
709 capela 146 lscp_status_t lscp_server_unsubscribe ( lscp_connect_t *pConnect, lscp_event_t event )
710 capela 98 {
711     if (pConnect == NULL)
712     return LSCP_FAILED;
713 capela 146 if (event == LSCP_EVENT_NONE)
714 capela 98 return LSCP_FAILED;
715    
716 capela 146 pConnect->events &= ~event;
717 capela 98
718     return LSCP_OK;
719     }
720    
721    
722     // end of server.c

  ViewVC Help
Powered by ViewVC