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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 3866 - (hide annotations) (download)
Sat Mar 27 12:17:51 2021 UTC (3 years ago) by capela
File MIME type: text/plain
File size: 20944 byte(s)
* Switching to CMake build system as for packaging default.
1 capela 98 // server.c
2     //
3     /****************************************************************************
4     liblscp - LinuxSampler Control Protocol API
5 capela 3866 Copyright (C) 2004-2021, rncbc aka Rui Nuno Capela. All rights reserved.
6 capela 98
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 capela 921 You should have received a copy of the GNU General Public License along
18     with this program; if not, write to the Free Software Foundation, Inc.,
19     51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20 capela 98
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 capela 963 pList->first = NULL;
54     pList->last = NULL;
55     pList->count = 0;
56 capela 98
57 capela 963 lscp_mutex_init(pList->mutex);
58 capela 98 }
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 capela 963 lscp_mutex_lock(pList->mutex);
66 capela 98
67 capela 963 pItem->prev = pList->last;
68     pItem->next = NULL;
69 capela 98
70 capela 963 if (pList->last)
71     (pList->last)->next = pItem;
72     else
73     pList->first = pItem;
74 capela 98
75 capela 963 pList->last = pItem;
76 capela 98
77 capela 963 pList->count++;
78 capela 98
79 capela 963 lscp_mutex_unlock(pList->mutex);
80 capela 98 }
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 capela 963 if (pItem->next)
88     (pItem->next)->prev = pItem->prev;
89     else
90     pList->last = pItem->prev;
91 capela 98
92 capela 963 if (pItem->prev)
93     (pItem->prev)->next = pItem->next;
94     else
95     pList->first = pItem->next;
96 capela 98
97 capela 963 pItem->next = NULL;
98     pItem->prev = NULL;
99 capela 98
100 capela 963 pList->count--;
101 capela 98 }
102    
103    
104     static void _lscp_connect_list_remove_safe ( lscp_connect_list_t *pList, lscp_connect_t *pItem )
105     {
106 capela 963 lscp_connect_t *p;
107 capela 98
108     // fprintf(stderr, "_lscp_connect_list_remove_safe: pList=%p pItem=%p.\n", pList, pItem);
109    
110 capela 963 lscp_mutex_lock(pList->mutex);
111 capela 98
112 capela 963 for (p = pList->first; p; p = p->next) {
113     if (p == pItem) {
114     _lscp_connect_list_remove(pList, pItem);
115     break;
116     }
117     }
118 capela 98
119 capela 963 lscp_mutex_unlock(pList->mutex);
120 capela 98 }
121    
122    
123     static void _lscp_connect_list_free ( lscp_connect_list_t *pList )
124     {
125 capela 963 lscp_connect_t *p, *pNext;
126 capela 98
127     // fprintf(stderr, "_lscp_connect_list_free: pList=%p.\n", pList);
128    
129 capela 963 lscp_mutex_lock(pList->mutex);
130 capela 98
131 capela 963 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 capela 98
137 capela 963 lscp_mutex_unlock(pList->mutex);
138    
139     lscp_mutex_destroy(pList->mutex);
140 capela 98 }
141    
142    
143     static lscp_connect_t *_lscp_connect_list_find_sock ( lscp_connect_list_t *pList, lscp_socket_t sock )
144     {
145 capela 963 lscp_connect_t *p;
146 capela 98
147     // fprintf(stderr, "_lscp_connect_list_find_sock: pList=%p sock=%d.\n", pList, sock);
148    
149 capela 963 for (p = pList->first; p; p = p->next) {
150     if (sock == p->client.sock)
151     return p;
152     }
153 capela 98
154 capela 963 return NULL;
155 capela 98 }
156    
157     //-------------------------------------------------------------------------
158     // Server-side threaded client connections.
159    
160     static void _lscp_connect_proc ( void *pvConnect )
161     {
162 capela 963 lscp_connect_t *pConnect = (lscp_connect_t *) pvConnect;
163     lscp_server_t *pServer = pConnect->server;
164 capela 98
165 capela 963 while (pServer->agent.iState && pConnect->client.iState) {
166     if (_lscp_connect_recv(pConnect) != LSCP_OK)
167     pConnect->client.iState = 0;
168     }
169 capela 98
170 capela 963 (*pServer->pfnCallback)(pConnect, NULL, LSCP_CONNECT_CLOSE, pServer->pvData);
171     _lscp_connect_list_remove_safe(&(pServer->connects), pConnect);
172     closesocket(pConnect->client.sock);
173 capela 98 }
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 capela 963 lscp_connect_t *pConnect;
178 capela 98
179 capela 963 if (pServer == NULL || sock == INVALID_SOCKET || pAddr == NULL) {
180     fprintf(stderr, "_lscp_connect_create: Invalid connection arguments.\n");
181     return NULL;
182     }
183 capela 98
184 capela 963 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 capela 98
192 capela 963 pConnect->server = pServer;
193     pConnect->events = LSCP_EVENT_NONE;
194 capela 98
195 capela 3866 #ifdef CONFIG_DEBUG
196 capela 963 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 capela 98 #endif
198    
199 capela 963 lscp_socket_agent_init(&(pConnect->client), sock, pAddr, cAddr);
200 capela 98
201 capela 963 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 capela 98
209 capela 963 return pConnect;
210 capela 98 }
211    
212    
213     static lscp_status_t _lscp_connect_destroy ( lscp_connect_t *pConnect )
214     {
215 capela 963 lscp_status_t ret = LSCP_FAILED;
216 capela 98
217 capela 963 if (pConnect == NULL)
218     return ret;
219 capela 98
220 capela 3866 #ifdef CONFIG_DEBUG
221 capela 963 fprintf(stderr, "_lscp_connect_destroy: pConnect=%p.\n", pConnect);
222 capela 98 #endif
223    
224 capela 963 lscp_socket_agent_free(&(pConnect->client));
225 capela 98
226 capela 963 free(pConnect);
227 capela 98
228 capela 963 return ret;
229 capela 98 }
230    
231    
232     lscp_status_t _lscp_connect_recv ( lscp_connect_t *pConnect )
233     {
234 capela 963 lscp_status_t ret = LSCP_FAILED;
235     lscp_server_t *pServer;
236     char achBuffer[LSCP_BUFSIZ];
237     int cchBuffer;
238 capela 98
239 capela 963 if (pConnect == NULL)
240     return ret;
241 capela 98
242 capela 963 pServer = pConnect->server;
243     if (pServer == NULL)
244     return ret;
245 capela 98
246 capela 963 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 capela 98
252 capela 963 return ret;
253 capela 98 }
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 capela 963 lscp_socket_t sock;
262     struct sockaddr_in addr;
263     socklen_t cAddr;
264     lscp_connect_t *pConnect;
265 capela 98
266 capela 3866 #ifdef CONFIG_DEBUG
267 capela 963 fprintf(stderr, "_lscp_server_thread_proc: Server listening for connections.\n");
268 capela 98 #endif
269    
270 capela 963 while (pServer->agent.iState) {
271     cAddr = sizeof(struct sockaddr_in);
272     sock = accept(pServer->agent.sock, (struct sockaddr *) &addr, &cAddr);
273     if (sock == INVALID_SOCKET) {
274     lscp_socket_perror("_lscp_server_thread_proc: accept");
275     pServer->agent.iState = 0;
276     } 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 capela 98
285 capela 3866 #ifdef CONFIG_DEBUG
286 capela 963 fprintf(stderr, "_lscp_server_thread_proc: Server closing.\n");
287 capela 98 #endif
288     }
289    
290    
291     static void _lscp_server_select_proc ( lscp_server_t *pServer )
292     {
293 capela 963 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 capela 98
299 capela 963 lscp_socket_t sock;
300     struct sockaddr_in addr;
301     socklen_t cAddr;
302     lscp_connect_t *pConnect;
303 capela 98
304 capela 3866 #ifdef CONFIG_DEBUG
305 capela 963 fprintf(stderr, "_lscp_server_select_proc: Server listening for connections.\n");
306 capela 98 #endif
307 capela 963 FD_ZERO(&master_fds);
308     FD_ZERO(&select_fds);
309 capela 98
310 capela 963 // Add the listener to the master set
311     FD_SET((unsigned int) pServer->agent.sock, &master_fds);
312 capela 98
313 capela 963 // Keep track of the biggest file descriptor;
314     // So far, it's ourself, the listener.
315     fdmax = (int) pServer->agent.sock;
316 capela 98
317 capela 963 // Main loop...
318     while (pServer->agent.iState) {
319 capela 98
320 capela 963 // Use a copy of the master.
321     select_fds = master_fds;
322     // Use the timeout feature for watchdoggin.
323     tv.tv_sec = LSCP_SERVER_SLEEP;
324     tv.tv_usec = 0;
325     // Wait for events...
326     iSelect = select(fdmax + 1, &select_fds, NULL, NULL, &tv);
327 capela 98
328 capela 963 if (iSelect < 0) {
329     lscp_socket_perror("_lscp_server_select_proc: select");
330     pServer->agent.iState = 0;
331     }
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     // Is it ourselves, the command listener?
337     if (fd == (int) pServer->agent.sock) {
338     // Accept the connection...
339     cAddr = sizeof(struct sockaddr_in);
340     sock = accept(pServer->agent.sock, (struct sockaddr *) &addr, &cAddr);
341     if (sock == INVALID_SOCKET) {
342     lscp_socket_perror("_lscp_server_select_proc: accept");
343     pServer->agent.iState = 0;
344     } 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 capela 98
382 capela 3866 #ifdef CONFIG_DEBUG
383 capela 963 fprintf(stderr, "_lscp_server_select_proc: Server closing.\n");
384 capela 98 #endif
385     }
386    
387    
388 capela 146 static void _lscp_server_agent_proc ( void *pvServer )
389 capela 98 {
390 capela 963 lscp_server_t *pServer = (lscp_server_t *) pvServer;
391 capela 98
392 capela 963 if (pServer->mode == LSCP_SERVER_THREAD)
393     _lscp_server_thread_proc(pServer);
394     else
395     _lscp_server_select_proc(pServer);
396 capela 98 }
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 capela 3519 /** Retrieve the current server library build string. */
409     const char* lscp_server_build (void) { return LSCP_BUILD; }
410 capela 98
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 capela 963 return lscp_server_create_ex(iPort, pfnCallback, pvData, LSCP_SERVER_SELECT);
431 capela 98 }
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 capela 963 lscp_server_t *pServer;
456     lscp_socket_t sock;
457     struct sockaddr_in addr;
458     socklen_t cAddr;
459     int iSockOpt = (-1);
460 capela 98
461 capela 963 if (pfnCallback == NULL) {
462     fprintf(stderr, "lscp_server_create: Invalid server callback function.\n");
463     return NULL;
464     }
465 capela 98
466 capela 963 // Allocate server descriptor...
467 capela 98
468 capela 963 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 capela 98
475 capela 963 _lscp_connect_list_init(&(pServer->connects));
476 capela 98
477 capela 963 pServer->mode = mode;
478     pServer->pfnCallback = pfnCallback;
479     pServer->pvData = pvData;
480 capela 98
481 capela 3866 #ifdef CONFIG_DEBUG
482 capela 963 fprintf(stderr, "lscp_server_create: pServer=%p: iPort=%d.\n", pServer, iPort);
483 capela 98 #endif
484    
485 capela 963 // Prepare the command stream server socket...
486 capela 98
487 capela 963 sock = socket(AF_INET, SOCK_STREAM, 0);
488     if (sock == INVALID_SOCKET) {
489     lscp_socket_perror("lscp_server_create: socket");
490     free(pServer);
491     return NULL;
492     }
493 capela 98
494 capela 963 if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char *) &iSockOpt, sizeof(int)) == SOCKET_ERROR)
495     lscp_socket_perror("lscp_server_create: setsockopt(SO_REUSEADDR)");
496 capela 98 #if defined(WIN32)
497 capela 963 if (setsockopt(sock, SOL_SOCKET, SO_DONTLINGER, (char *) &iSockOpt, sizeof(int)) == SOCKET_ERROR)
498     lscp_socket_perror("lscp_server_create: setsockopt(SO_DONTLINGER)");
499 capela 98 #endif
500    
501 capela 3866 #ifdef CONFIG_DEBUG
502 capela 963 lscp_socket_getopts("lscp_server_create", sock);
503 capela 98 #endif
504    
505 capela 963 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 capela 98
511 capela 963 if (bind(sock, (const struct sockaddr *) &addr, cAddr) == SOCKET_ERROR) {
512     lscp_socket_perror("lscp_server_create: bind");
513     closesocket(sock);
514     free(pServer);
515     return NULL;
516     }
517 capela 98
518 capela 963 if (listen(sock, 10) == SOCKET_ERROR) {
519     lscp_socket_perror("lscp_server_create: listen");
520     closesocket(sock);
521     free(pServer);
522     return NULL;
523     }
524 capela 98
525 capela 963 if (iPort == 0) {
526     if (getsockname(sock, (struct sockaddr *) &addr, &cAddr) == SOCKET_ERROR) {
527     lscp_socket_perror("lscp_server_create: getsockname");
528     closesocket(sock);
529     free(pServer);
530     }
531     }
532 capela 98
533 capela 963 lscp_socket_agent_init(&(pServer->agent), sock, &addr, cAddr);
534 capela 98
535 capela 3866 #ifdef CONFIG_DEBUG
536 capela 963 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 capela 963 // Now's finally time to startup threads...
540 capela 98
541 capela 963 // Command service thread...
542     if (lscp_socket_agent_start(&(pServer->agent), _lscp_server_agent_proc, pServer, 0) != LSCP_OK) {
543     lscp_socket_agent_free(&(pServer->agent));
544     free(pServer);
545     return NULL;
546     }
547 capela 98
548 capela 963 // Finally we've some success...
549     return pServer;
550 capela 98 }
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 capela 963 if (pServer == NULL)
561     return LSCP_FAILED;
562 capela 98
563 capela 3866 #ifdef CONFIG_DEBUG
564 capela 963 fprintf(stderr, "lscp_server_join: pServer=%p.\n", pServer);
565 capela 98 #endif
566    
567 capela 963 lscp_socket_agent_join(&(pServer->agent));
568 capela 98
569 capela 963 return LSCP_OK;
570 capela 98 }
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 capela 963 if (pServer == NULL)
581     return LSCP_FAILED;
582 capela 98
583 capela 3866 #ifdef CONFIG_DEBUG
584 capela 963 fprintf(stderr, "lscp_server_destroy: pServer=%p.\n", pServer);
585 capela 98 #endif
586    
587 capela 963 _lscp_connect_list_free(&(pServer->connects));
588     lscp_socket_agent_free(&(pServer->agent));
589 capela 98
590 capela 963 free(pServer);
591 capela 98
592 capela 963 return LSCP_OK;
593 capela 98 }
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 capela 963 lscp_connect_t *p;
609     const char *pszEvent;
610     char achBuffer[LSCP_BUFSIZ];
611     int cchBuffer;
612 capela 98
613 capela 963 if (pServer == NULL)
614     return LSCP_FAILED;
615     if (pchData == NULL || cchData < 1)
616     return LSCP_FAILED;
617 capela 98
618 capela 963 // Which (single) event?
619     pszEvent = lscp_event_to_text(event);
620     if (pszEvent == NULL)
621     return LSCP_FAILED;
622 capela 146
623 capela 963 // 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 capela 146
634 capela 963 // And do the direct broadcasting...
635    
636     lscp_mutex_lock(pServer->connects.mutex);
637 capela 98
638 capela 963 for (p = pServer->connects.first; p; p = p->next) {
639     if (p->events & event)
640     send(p->client.sock, achBuffer, cchBuffer, 0);
641     }
642 capela 98
643 capela 963 lscp_mutex_unlock(pServer->connects.mutex);
644 capela 98
645 capela 963 return LSCP_OK;
646 capela 98 }
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 capela 963 lscp_status_t ret = LSCP_FAILED;
661 capela 98
662 capela 963 if (pConnect == NULL)
663     return ret;
664     if (pchBuffer == NULL || cchBuffer < 1)
665     return ret;
666 capela 98
667 capela 963 if (send(pConnect->client.sock, pchBuffer, cchBuffer, 0) != cchBuffer)
668     lscp_socket_perror("lscp_server_result");
669     else
670     ret = LSCP_OK;
671 capela 98
672 capela 963 return ret;
673 capela 98 }
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 capela 963 if (pConnect == NULL)
687     return LSCP_FAILED;
688     if (event == LSCP_EVENT_NONE)
689     return LSCP_FAILED;
690 capela 98
691 capela 963 pConnect->events |= event;
692 capela 98
693 capela 963 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 capela 963 */
705 capela 146 lscp_status_t lscp_server_unsubscribe ( lscp_connect_t *pConnect, lscp_event_t event )
706 capela 98 {
707 capela 963 if (pConnect == NULL)
708     return LSCP_FAILED;
709     if (event == LSCP_EVENT_NONE)
710     return LSCP_FAILED;
711 capela 98
712 capela 963 pConnect->events &= ~event;
713 capela 98
714 capela 963 return LSCP_OK;
715 capela 98 }
716    
717    
718     // end of server.c

  ViewVC Help
Powered by ViewVC