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

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

Parent Directory Parent Directory | Revision Log Revision Log


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

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

  ViewVC Help
Powered by ViewVC