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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 146 - (hide annotations) (download)
Fri Jun 25 12:00:25 2004 UTC (19 years, 9 months ago) by capela
File MIME type: text/plain
File size: 23319 byte(s)
* Major changes to server event protocol interface
  on attempt to comply with draft-protocol v.11.

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

  ViewVC Help
Powered by ViewVC