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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 146 - (show 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 // 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 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 #endif
229
230 lscp_socket_agent_free(&(pConnect->client));
231
232 #ifdef DEBUG
233 fprintf(stderr, "<%p> Done.\n", pConnect);
234 #endif
235
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 // Command service (stream oriented).
268
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 while (pServer->agent.iState) {
281 cAddr = sizeof(struct sockaddr_in);
282 sock = accept(pServer->agent.sock, (struct sockaddr *) &addr, &cAddr);
283 if (sock == INVALID_SOCKET) {
284 lscp_socket_perror("_lscp_server_thread_proc: accept");
285 pServer->agent.iState = 0;
286 } 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 // Add the listener to the master set
321 FD_SET((unsigned int) pServer->agent.sock, &master_fds);
322
323 // Keep track of the biggest file descriptor;
324 // So far, it's ourself, the listener.
325 fdmax = (int) pServer->agent.sock;
326
327 // Main loop...
328 while (pServer->agent.iState) {
329
330 // Use a copy of the master.
331 select_fds = master_fds;
332 // Use the timeout feature for watchdoggin.
333 tv.tv_sec = LSCP_SERVER_SLEEP;
334 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 pServer->agent.iState = 0;
341 }
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 // Is it ourselves, the command listener?
347 if (fd == (int) pServer->agent.sock) {
348 // Accept the connection...
349 cAddr = sizeof(struct sockaddr_in);
350 sock = accept(pServer->agent.sock, (struct sockaddr *) &addr, &cAddr);
351 if (sock == INVALID_SOCKET) {
352 lscp_socket_perror("_lscp_server_select_proc: accept");
353 pServer->agent.iState = 0;
354 } 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 static void _lscp_server_agent_proc ( void *pvServer )
399 {
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 // Prepare the command stream server socket...
496
497 sock = socket(AF_INET, SOCK_STREAM, 0);
498 if (sock == INVALID_SOCKET) {
499 lscp_socket_perror("lscp_server_create: socket");
500 free(pServer);
501 return NULL;
502 }
503
504 if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char *) &iSockOpt, sizeof(int)) == SOCKET_ERROR)
505 lscp_socket_perror("lscp_server_create: setsockopt(SO_REUSEADDR)");
506 #if defined(WIN32)
507 if (setsockopt(sock, SOL_SOCKET, SO_DONTLINGER, (char *) &iSockOpt, sizeof(int)) == SOCKET_ERROR)
508 lscp_socket_perror("lscp_server_create: setsockopt(SO_DONTLINGER)");
509 #endif
510
511 #ifdef DEBUG
512 lscp_socket_getopts("lscp_server_create", sock);
513 #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 lscp_socket_perror("lscp_server_create: bind");
523 closesocket(sock);
524 free(pServer);
525 return NULL;
526 }
527
528 if (listen(sock, 10) == SOCKET_ERROR) {
529 lscp_socket_perror("lscp_server_create: listen");
530 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 lscp_socket_perror("lscp_server_create: getsockname");
538 closesocket(sock);
539 free(pServer);
540 }
541 }
542
543 lscp_socket_agent_init(&(pServer->agent), sock, &addr, cAddr);
544
545 #ifdef DEBUG
546 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 #endif
548
549 // Now's finally time to startup threads...
550
551 // Command service thread...
552 if (lscp_socket_agent_start(&(pServer->agent), _lscp_server_agent_proc, pServer, 0) != LSCP_OK) {
553 lscp_socket_agent_free(&(pServer->agent));
554 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 lscp_socket_agent_join(&(pServer->agent));
578
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 lscp_socket_agent_free(&(pServer->agent));
599
600 free(pServer);
601
602 return LSCP_OK;
603 }
604
605
606 /**
607 * Send an event notification message to all subscribed clients.
608 *
609 * @param pServer Pointer to server instance structure.
610 * @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 *
614 * @returns LSCP_OK on success, LSCP_FAILED otherwise.
615 */
616 lscp_status_t lscp_server_broadcast ( lscp_server_t *pServer, lscp_event_t event, const char *pchData, int cchData )
617 {
618 lscp_connect_t *p;
619 const char *pszEvent;
620 char achBuffer[LSCP_BUFSIZ];
621 int cchBuffer;
622
623 if (pServer == NULL)
624 return LSCP_FAILED;
625 if (pchData == NULL || cchData < 1)
626 return LSCP_FAILED;
627
628 // 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 lscp_mutex_lock(pServer->connects.mutex);
647
648 for (p = pServer->connects.first; p; p = p->next) {
649 if (p->events & event)
650 send(p->client.sock, achBuffer, cchBuffer, 0);
651 }
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 * @param pConnect Pointer to client connection instance structure.
690 * @param event Event type flag of the requesting client subscription.
691 *
692 * @returns LSCP_OK on success, LSCP_FAILED otherwise.
693 */
694 lscp_status_t lscp_server_subscribe ( lscp_connect_t *pConnect, lscp_event_t event )
695 {
696 if (pConnect == NULL)
697 return LSCP_FAILED;
698 if (event == LSCP_EVENT_NONE)
699 return LSCP_FAILED;
700
701 pConnect->events |= event;
702
703 return LSCP_OK;
704 }
705
706
707 /**
708 * Deregister client as subscriber of event broadcast messages.
709 *
710 * @param pConnect Pointer to client connection instance structure.
711 * @param event Event type flag of the requesting client unsubscription.
712 *
713 * @returns LSCP_OK on success, LSCP_FAILED otherwise.
714 */
715 lscp_status_t lscp_server_unsubscribe ( lscp_connect_t *pConnect, lscp_event_t event )
716 {
717 if (pConnect == NULL)
718 return LSCP_FAILED;
719 if (event == LSCP_EVENT_NONE)
720 return LSCP_FAILED;
721
722 pConnect->events &= ~event;
723
724 return LSCP_OK;
725 }
726
727
728 // end of server.c

  ViewVC Help
Powered by ViewVC