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

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

Parent Directory Parent Directory | Revision Log Revision Log


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

1 // 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 #define LSCP_SERVER_SLEEP 30 // Period in seconds for watchdog wakeup (idle loop).
26
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 static void _lscp_server_agent_proc (void *pvServer);
44
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 while (pServer->agent.iState && pConnect->client.iState) {
166 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 pConnect->events = LSCP_EVENT_NONE;
194
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 #ifdef DEBUG
227 fprintf(stderr, "<%p> Done.\n", pConnect);
228 #endif
229
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 // Command service (stream oriented).
262
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 while (pServer->agent.iState) {
275 cAddr = sizeof(struct sockaddr_in);
276 sock = accept(pServer->agent.sock, (struct sockaddr *) &addr, &cAddr);
277 if (sock == INVALID_SOCKET) {
278 lscp_socket_perror("_lscp_server_thread_proc: accept");
279 pServer->agent.iState = 0;
280 } 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 // Add the listener to the master set
315 FD_SET((unsigned int) pServer->agent.sock, &master_fds);
316
317 // Keep track of the biggest file descriptor;
318 // So far, it's ourself, the listener.
319 fdmax = (int) pServer->agent.sock;
320
321 // Main loop...
322 while (pServer->agent.iState) {
323
324 // Use a copy of the master.
325 select_fds = master_fds;
326 // Use the timeout feature for watchdoggin.
327 tv.tv_sec = LSCP_SERVER_SLEEP;
328 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 pServer->agent.iState = 0;
335 }
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 // Is it ourselves, the command listener?
341 if (fd == (int) pServer->agent.sock) {
342 // Accept the connection...
343 cAddr = sizeof(struct sockaddr_in);
344 sock = accept(pServer->agent.sock, (struct sockaddr *) &addr, &cAddr);
345 if (sock == INVALID_SOCKET) {
346 lscp_socket_perror("_lscp_server_select_proc: accept");
347 pServer->agent.iState = 0;
348 } 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 static void _lscp_server_agent_proc ( void *pvServer )
393 {
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 // Prepare the command stream server socket...
490
491 sock = socket(AF_INET, SOCK_STREAM, 0);
492 if (sock == INVALID_SOCKET) {
493 lscp_socket_perror("lscp_server_create: socket");
494 free(pServer);
495 return NULL;
496 }
497
498 if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char *) &iSockOpt, sizeof(int)) == SOCKET_ERROR)
499 lscp_socket_perror("lscp_server_create: setsockopt(SO_REUSEADDR)");
500 #if defined(WIN32)
501 if (setsockopt(sock, SOL_SOCKET, SO_DONTLINGER, (char *) &iSockOpt, sizeof(int)) == SOCKET_ERROR)
502 lscp_socket_perror("lscp_server_create: setsockopt(SO_DONTLINGER)");
503 #endif
504
505 #ifdef DEBUG
506 lscp_socket_getopts("lscp_server_create", sock);
507 #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 lscp_socket_perror("lscp_server_create: bind");
517 closesocket(sock);
518 free(pServer);
519 return NULL;
520 }
521
522 if (listen(sock, 10) == SOCKET_ERROR) {
523 lscp_socket_perror("lscp_server_create: listen");
524 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 lscp_socket_perror("lscp_server_create: getsockname");
532 closesocket(sock);
533 free(pServer);
534 }
535 }
536
537 lscp_socket_agent_init(&(pServer->agent), sock, &addr, cAddr);
538
539 #ifdef DEBUG
540 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 #endif
542
543 // Now's finally time to startup threads...
544
545 // Command service thread...
546 if (lscp_socket_agent_start(&(pServer->agent), _lscp_server_agent_proc, pServer, 0) != LSCP_OK) {
547 lscp_socket_agent_free(&(pServer->agent));
548 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 lscp_socket_agent_join(&(pServer->agent));
572
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 lscp_socket_agent_free(&(pServer->agent));
593
594 free(pServer);
595
596 return LSCP_OK;
597 }
598
599
600 /**
601 * Send an event notification message to all subscribed clients.
602 *
603 * @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 *
608 * @returns LSCP_OK on success, LSCP_FAILED otherwise.
609 */
610 lscp_status_t lscp_server_broadcast ( lscp_server_t *pServer, lscp_event_t event, const char *pchData, int cchData )
611 {
612 lscp_connect_t *p;
613 const char *pszEvent;
614 char achBuffer[LSCP_BUFSIZ];
615 int cchBuffer;
616
617 if (pServer == NULL)
618 return LSCP_FAILED;
619 if (pchData == NULL || cchData < 1)
620 return LSCP_FAILED;
621
622 // 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 lscp_mutex_lock(pServer->connects.mutex);
641
642 for (p = pServer->connects.first; p; p = p->next) {
643 if (p->events & event)
644 send(p->client.sock, achBuffer, cchBuffer, 0);
645 }
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 * @param pConnect Pointer to client connection instance structure.
684 * @param event Event type flag of the requesting client subscription.
685 *
686 * @returns LSCP_OK on success, LSCP_FAILED otherwise.
687 */
688 lscp_status_t lscp_server_subscribe ( lscp_connect_t *pConnect, lscp_event_t event )
689 {
690 if (pConnect == NULL)
691 return LSCP_FAILED;
692 if (event == LSCP_EVENT_NONE)
693 return LSCP_FAILED;
694
695 pConnect->events |= event;
696
697 return LSCP_OK;
698 }
699
700
701 /**
702 * Deregister client as subscriber of event broadcast messages.
703 *
704 * @param pConnect Pointer to client connection instance structure.
705 * @param event Event type flag of the requesting client unsubscription.
706 *
707 * @returns LSCP_OK on success, LSCP_FAILED otherwise.
708 */
709 lscp_status_t lscp_server_unsubscribe ( lscp_connect_t *pConnect, lscp_event_t event )
710 {
711 if (pConnect == NULL)
712 return LSCP_FAILED;
713 if (event == LSCP_EVENT_NONE)
714 return LSCP_FAILED;
715
716 pConnect->events &= ~event;
717
718 return LSCP_OK;
719 }
720
721
722 // end of server.c

  ViewVC Help
Powered by ViewVC