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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 98 - (hide annotations) (download)
Tue Jun 1 11:13:56 2004 UTC (19 years, 10 months ago) by capela
File MIME type: text/plain
File size: 32004 byte(s)
Initial alpha release.

1 capela 98 // server.c
2     //
3     /****************************************************************************
4     liblscp - LinuxSampler Control Protocol API
5     Copyright (C) 2004, rncbc aka Rui Nuno Capela. All rights reserved.
6    
7     This library is free software; you can redistribute it and/or
8     modify it under the terms of the GNU Lesser General Public
9     License as published by the Free Software Foundation; either
10     version 2.1 of the License, or (at your option) any later version.
11    
12     This library is distributed in the hope that it will be useful,
13     but WITHOUT ANY WARRANTY; without even the implied warranty of
14     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15     Lesser General Public License for more details.
16    
17     You should have received a copy of the GNU Lesser General Public
18     License along with this library; if not, write to the Free Software
19     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20    
21     *****************************************************************************/
22    
23     #include "server.h"
24    
25     #define LSCP_SERVER_RETRY 3 // Maximum number of unanswered PING retries.
26     #define LSCP_SERVER_SLEEP 30 // Period in seconds for watchdog wakeup.
27    
28    
29     // Local prototypes.
30    
31     static lscp_connect_t *_lscp_connect_create (lscp_server_t *pServer, lscp_socket_t sock, struct sockaddr_in *pAddr, int cAddr);
32     static lscp_status_t _lscp_connect_destroy (lscp_connect_t *pConnect);
33     static lscp_status_t _lscp_connect_recv (lscp_connect_t *pConnect);
34     static lscp_status_t _lscp_connect_send (lscp_connect_t *pConnect, const char *pchBuffer, int cchBuffer);
35     static lscp_status_t _lscp_connect_ping (lscp_connect_t *pConnect);
36    
37     static void _lscp_connect_list_append (lscp_connect_list_t *pList, lscp_connect_t *pItem);
38     static void _lscp_connect_list_remove (lscp_connect_list_t *pList, lscp_connect_t *pItem);
39     static void _lscp_connect_list_remove_safe (lscp_connect_list_t *pList, lscp_connect_t *pItem);
40     static void _lscp_connect_list_free (lscp_connect_list_t *pList);
41     static lscp_connect_t *_lscp_connect_list_find_addr (lscp_connect_list_t *pList, struct sockaddr_in *pAddr);
42     static lscp_connect_t *_lscp_connect_list_find_sock (lscp_connect_list_t *pList, lscp_socket_t sock);
43    
44     static lscp_status_t _lscp_server_udp_recv (lscp_server_t *pServer);
45    
46     static void _lscp_server_thread_proc (lscp_server_t *pServer);
47     static void _lscp_server_select_proc (lscp_server_t *pServer);
48    
49     static void _lscp_server_tcp_proc (void *pvServer);
50     static void _lscp_server_udp_proc (void *pvServer);
51    
52     static void _lscp_watchdog_scan (lscp_server_t *pServer);
53    
54     static void _lscp_watchdog_proc (void *pvServer);
55    
56     #if defined(WIN32)
57     #include <time.h>
58     #undef gettimeofday
59     #define gettimeofday(p,n) {(p)->tv_sec = (long) (clock() / CLOCKS_PER_SEC); (p)->tv_usec = 0;}
60     #else
61     #include <sys/time.h>
62     #endif
63    
64     //-------------------------------------------------------------------------
65     // Server-side client connection list methods.
66    
67     static void _lscp_connect_list_init ( lscp_connect_list_t *pList )
68     {
69     // fprintf(stderr, "_lscp_connect_list_init: pList=%p.\n", pList);
70    
71     pList->first = NULL;
72     pList->last = NULL;
73     pList->count = 0;
74    
75     lscp_mutex_init(pList->mutex);
76     }
77    
78    
79     static void _lscp_connect_list_append ( lscp_connect_list_t *pList, lscp_connect_t *pItem )
80     {
81     // fprintf(stderr, "_lscp_connect_list_append: pList=%p pItem=%p.\n", pList, pItem);
82    
83     lscp_mutex_lock(pList->mutex);
84    
85     pItem->prev = pList->last;
86     pItem->next = NULL;
87    
88     if (pList->last)
89     (pList->last)->next = pItem;
90     else
91     pList->first = pItem;
92    
93     pList->last = pItem;
94    
95     pList->count++;
96    
97     lscp_mutex_unlock(pList->mutex);
98     }
99    
100    
101     static void _lscp_connect_list_remove ( lscp_connect_list_t *pList, lscp_connect_t *pItem )
102     {
103     // fprintf(stderr, "_lscp_connect_list_remove: pList=%p pItem=%p.\n", pList, pItem);
104    
105     if (pItem->next)
106     (pItem->next)->prev = pItem->prev;
107     else
108     pList->last = pItem->prev;
109    
110     if (pItem->prev)
111     (pItem->prev)->next = pItem->next;
112     else
113     pList->first = pItem->next;
114    
115     pItem->next = NULL;
116     pItem->prev = NULL;
117    
118     pList->count--;
119     }
120    
121    
122     static void _lscp_connect_list_remove_safe ( lscp_connect_list_t *pList, lscp_connect_t *pItem )
123     {
124     lscp_connect_t *p;
125    
126     // fprintf(stderr, "_lscp_connect_list_remove_safe: pList=%p pItem=%p.\n", pList, pItem);
127    
128     lscp_mutex_lock(pList->mutex);
129    
130     for (p = pList->first; p; p = p->next) {
131     if (p == pItem) {
132     _lscp_connect_list_remove(pList, pItem);
133     break;
134     }
135     }
136    
137     lscp_mutex_unlock(pList->mutex);
138     }
139    
140    
141     static void _lscp_connect_list_free ( lscp_connect_list_t *pList )
142     {
143     lscp_connect_t *p, *pNext;
144    
145     // fprintf(stderr, "_lscp_connect_list_free: pList=%p.\n", pList);
146    
147     lscp_mutex_lock(pList->mutex);
148    
149     for (p = pList->first; p; p = pNext) {
150     pNext = p->next;
151     _lscp_connect_list_remove(pList, p);
152     _lscp_connect_destroy(p);
153     }
154    
155     lscp_mutex_unlock(pList->mutex);
156    
157     lscp_mutex_destroy(pList->mutex);
158     }
159    
160    
161     static lscp_connect_t *_lscp_connect_list_find_addr ( lscp_connect_list_t *pList, struct sockaddr_in *pAddr )
162     {
163     int iPort = ntohs(pAddr->sin_port);
164     const char *pszAddr = inet_ntoa(pAddr->sin_addr);
165     lscp_connect_t *p;
166    
167     // fprintf(stderr, "_lscp_connect_list_find_addr: pList=%p addr=%s port=%d.\n", pList, inet_ntoa(pAddr->sin_addr), ntohs(pAddr->sin_port));
168    
169     for (p = pList->first; p; p = p->next) {
170     if (iPort == p->port && strcmp(pszAddr, inet_ntoa(p->client.addr.sin_addr)) == 0)
171     return p;
172     }
173    
174     return NULL;
175     }
176    
177    
178     static lscp_connect_t *_lscp_connect_list_find_sock ( lscp_connect_list_t *pList, lscp_socket_t sock )
179     {
180     lscp_connect_t *p;
181    
182     // fprintf(stderr, "_lscp_connect_list_find_sock: pList=%p sock=%d.\n", pList, sock);
183    
184     for (p = pList->first; p; p = p->next) {
185     if (sock == p->client.sock)
186     return p;
187     }
188    
189     return NULL;
190     }
191    
192     //-------------------------------------------------------------------------
193     // Server-side threaded client connections.
194    
195     static void _lscp_connect_proc ( void *pvConnect )
196     {
197     lscp_connect_t *pConnect = (lscp_connect_t *) pvConnect;
198     lscp_server_t *pServer = pConnect->server;
199    
200     while (pServer->tcp.iState && pConnect->client.iState) {
201     if (_lscp_connect_recv(pConnect) != LSCP_OK)
202     pConnect->client.iState = 0;
203     }
204    
205     (*pServer->pfnCallback)(pConnect, NULL, LSCP_CONNECT_CLOSE, pServer->pvData);
206     _lscp_connect_list_remove_safe(&(pServer->connects), pConnect);
207     closesocket(pConnect->client.sock);
208     }
209    
210     static lscp_connect_t *_lscp_connect_create ( lscp_server_t *pServer, lscp_socket_t sock, struct sockaddr_in *pAddr, int cAddr )
211     {
212     lscp_connect_t *pConnect;
213    
214     if (pServer == NULL || sock == INVALID_SOCKET || pAddr == NULL) {
215     fprintf(stderr, "_lscp_connect_create: Invalid connection arguments.\n");
216     return NULL;
217     }
218    
219     pConnect = (lscp_connect_t *) malloc(sizeof(lscp_connect_t));
220     if (pConnect == NULL) {
221     fprintf(stderr, "_lscp_connect_create: Out of memory.\n");
222     closesocket(sock);
223     return NULL;
224     }
225     memset(pConnect, 0, sizeof(lscp_connect_t));
226    
227     pConnect->server = pServer;
228    
229     #ifdef DEBUG
230     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));
231     #endif
232    
233     lscp_socket_agent_init(&(pConnect->client), sock, pAddr, cAddr);
234    
235     if (pServer->mode == LSCP_SERVER_THREAD) {
236     if (lscp_socket_agent_start(&(pConnect->client), _lscp_connect_proc, pConnect, 0) != LSCP_OK) {
237     closesocket(sock);
238     free(pConnect);
239     return NULL;
240     }
241     }
242    
243     return pConnect;
244     }
245    
246    
247     static lscp_status_t _lscp_connect_destroy ( lscp_connect_t *pConnect )
248     {
249     lscp_status_t ret = LSCP_FAILED;
250    
251     if (pConnect == NULL)
252     return ret;
253    
254     #ifdef DEBUG
255     fprintf(stderr, "_lscp_connect_destroy: pConnect=%p.\n", pConnect);
256     #endif
257    
258     lscp_socket_agent_free(&(pConnect->client));
259    
260     if (pConnect->sessid)
261     free(pConnect->sessid);
262    
263     free(pConnect);
264    
265     return ret;
266     }
267    
268    
269     lscp_status_t _lscp_connect_recv ( lscp_connect_t *pConnect )
270     {
271     lscp_status_t ret = LSCP_FAILED;
272     lscp_server_t *pServer;
273     char achBuffer[LSCP_BUFSIZ];
274     int cchBuffer;
275    
276     if (pConnect == NULL)
277     return ret;
278    
279     pServer = pConnect->server;
280     if (pServer == NULL)
281     return ret;
282    
283     cchBuffer = recv(pConnect->client.sock, achBuffer, sizeof(achBuffer), 0);
284     if (cchBuffer > 0)
285     ret = (*pServer->pfnCallback)(pConnect, achBuffer, cchBuffer, pServer->pvData);
286     else if (cchBuffer < 0)
287     lscp_socket_perror("_lscp_connect_recv: recv");
288    
289     return ret;
290     }
291    
292    
293     static lscp_status_t _lscp_connect_send ( lscp_connect_t *pConnect, const char *pchBuffer, int cchBuffer )
294     {
295     lscp_status_t ret = LSCP_FAILED;
296     struct sockaddr_in addr;
297     int cAddr;
298    
299     if (pConnect == NULL)
300     return ret;
301     if (pchBuffer == NULL || cchBuffer < 1)
302     return ret;
303     if (pConnect->port == 0)
304     return ret;
305    
306     cAddr = sizeof(struct sockaddr_in);
307     memcpy((char *) &addr, (char *) &(pConnect->client.addr), cAddr);
308     addr.sin_port = htons((short) pConnect->port);
309    
310     if (sendto((pConnect->server)->udp.sock, pchBuffer, cchBuffer, 0, (struct sockaddr *) &addr, cAddr) == cchBuffer)
311     ret = LSCP_OK;
312     else
313     lscp_socket_perror("_lscp_connect_send: sendto");
314    
315     return ret;
316     }
317    
318    
319     static lscp_status_t _lscp_connect_ping ( lscp_connect_t *pConnect )
320     {
321     char szBuffer[LSCP_BUFSIZ];
322    
323     if (pConnect == NULL)
324     return LSCP_FAILED;
325     if (pConnect->sessid == NULL)
326     return LSCP_FAILED;
327    
328     #ifdef DEBUG
329     fprintf(stderr, "_lscp_connect_ping: pConnect=%p: addr=%s port=%d sessid=%s.\n", pConnect, inet_ntoa(pConnect->client.addr.sin_addr), pConnect->port, pConnect->sessid);
330     #endif
331    
332     sprintf(szBuffer, "PING %d %s\r\n", ntohs((pConnect->server)->udp.addr.sin_port), pConnect->sessid);
333    
334     return _lscp_connect_send(pConnect, szBuffer, strlen(szBuffer));
335     }
336    
337    
338     //-------------------------------------------------------------------------
339     // TCP service (stream oriented).
340    
341     static lscp_status_t _lscp_server_udp_recv ( lscp_server_t *pServer )
342     {
343     lscp_status_t ret = LSCP_FAILED;
344     struct sockaddr_in addr;
345     int cAddr;
346     char achBuffer[LSCP_BUFSIZ];
347     int cchBuffer;
348     lscp_connect_t *pConnect;
349    
350     cAddr = sizeof(addr);
351     cchBuffer = recvfrom(pServer->udp.sock, achBuffer, sizeof(achBuffer), 0, (struct sockaddr *) &addr, &cAddr);
352     if (cchBuffer > 0) {
353     #ifdef DEBUG
354     lscp_socket_trace("_lscp_server_udp_recv: recvfrom", &addr, achBuffer, cchBuffer);
355     #endif
356     // Just do a simple check for PONG events (ignore sessid).
357     if (strncmp(achBuffer, "PONG ", 5) == 0) {
358     pConnect = _lscp_connect_list_find_addr(&(pServer->connects), &addr);
359     if (pConnect)
360     pConnect->ping = 0;
361     }
362     ret = LSCP_OK;
363     }
364     else lscp_socket_perror("_lscp_server_udp_recv: recvfrom");
365    
366     return ret;
367     }
368    
369    
370     static void _lscp_server_thread_proc ( lscp_server_t *pServer )
371     {
372     lscp_socket_t sock;
373     struct sockaddr_in addr;
374     int cAddr;
375     lscp_connect_t *pConnect;
376    
377     #ifdef DEBUG
378     fprintf(stderr, "_lscp_server_thread_proc: Server listening for connections.\n");
379     #endif
380    
381     while (pServer->tcp.iState) {
382     cAddr = sizeof(struct sockaddr_in);
383     sock = accept(pServer->tcp.sock, (struct sockaddr *) &addr, &cAddr);
384     if (sock == INVALID_SOCKET) {
385     lscp_socket_perror("_lscp_server_thread_proc: accept");
386     pServer->tcp.iState = 0;
387     } else {
388     pConnect = _lscp_connect_create(pServer, sock, &addr, cAddr);
389     if (pConnect) {
390     _lscp_connect_list_append(&(pServer->connects), pConnect);
391     (*pServer->pfnCallback)(pConnect, NULL, LSCP_CONNECT_OPEN, pServer->pvData);
392     }
393     }
394     }
395    
396     #ifdef DEBUG
397     fprintf(stderr, "_lscp_server_thread_proc: Server closing.\n");
398     #endif
399     }
400    
401    
402     static void _lscp_server_select_proc ( lscp_server_t *pServer )
403     {
404     fd_set master_fds; // Master file descriptor list.
405     fd_set select_fds; // temp file descriptor list for select().
406     int fd, fdmax; // Maximum file descriptor number.
407     struct timeval tv; // For specifying a timeout value.
408     int iSelect; // Holds select return status.
409    
410     struct timeval tv1, tv2; // To compute delta timeouts.
411    
412     lscp_socket_t sock;
413     struct sockaddr_in addr;
414     int cAddr;
415     lscp_connect_t *pConnect;
416    
417     #ifdef DEBUG
418     fprintf(stderr, "_lscp_server_select_proc: Server listening for connections.\n");
419     #endif
420     FD_ZERO(&master_fds);
421     FD_ZERO(&select_fds);
422    
423     // Add the listeners to the master set
424     FD_SET((unsigned int) pServer->tcp.sock, &master_fds);
425     FD_SET((unsigned int) pServer->udp.sock, &master_fds);
426    
427     // Keep track of the biggest file descriptor;
428     // So far, it's ourself, the listener.
429     if ((int) pServer->udp.sock > (int) pServer->tcp.sock)
430     fdmax = (int) pServer->udp.sock;
431     else
432     fdmax = (int) pServer->tcp.sock;
433    
434     // To start counting for regular watchdog simulation.
435     gettimeofday(&tv1, NULL);
436     gettimeofday(&tv2, NULL);
437    
438     // Main loop...
439     while (pServer->tcp.iState) {
440    
441     // Use a copy of the master.
442     select_fds = master_fds;
443     // Use the timeout feature for watchdoggin.
444     tv.tv_sec = LSCP_SERVER_SLEEP - (tv2.tv_sec - tv1.tv_sec);
445     tv.tv_usec = 0;
446     // Wait for events...
447     iSelect = select(fdmax + 1, &select_fds, NULL, NULL, &tv);
448    
449     // Check later id it's time for ping time...
450     gettimeofday(&tv2, NULL);
451    
452     if (iSelect < 0) {
453     lscp_socket_perror("_lscp_server_select_proc: select");
454     pServer->tcp.iState = 0;
455     }
456     else if (iSelect > 0) {
457     // Run through the existing connections looking for data to read...
458     for (fd = 0; fd < fdmax + 1; fd++) {
459     if (FD_ISSET(fd, &select_fds)) { // We got one!!
460     // Is it ourselves, the TCP listener?
461     if (fd == (int) pServer->tcp.sock) {
462     // Accept the connection...
463     cAddr = sizeof(struct sockaddr_in);
464     sock = accept(pServer->tcp.sock, (struct sockaddr *) &addr, &cAddr);
465     if (sock == INVALID_SOCKET) {
466     lscp_socket_perror("_lscp_server_select_proc: accept");
467     pServer->tcp.iState = 0;
468     } else {
469     // Add to master set.
470     FD_SET((unsigned int) sock, &master_fds);
471     // Keep track of the maximum.
472     if ((int) sock > fdmax)
473     fdmax = (int) sock;
474     // And do create the client connection entry.
475     pConnect = _lscp_connect_create(pServer, sock, &addr, cAddr);
476     if (pConnect) {
477     _lscp_connect_list_append(&(pServer->connects), pConnect);
478     (*pServer->pfnCallback)(pConnect, NULL, LSCP_CONNECT_OPEN, pServer->pvData);
479     }
480     }
481     // Done with one new connection.
482     } else if (fd == (int) pServer->udp.sock) {
483     // Or to the UDP listener?
484     if (_lscp_server_udp_recv(pServer) != LSCP_OK)
485     pServer->tcp.iState = 0;
486     // Done with UDP transaction.
487     } else {
488     // Otherwise it's trivial transaction...
489     lscp_mutex_lock(pServer->connects.mutex);
490     // Find the connection on our cache...
491     pConnect = _lscp_connect_list_find_sock(&(pServer->connects), (lscp_socket_t) fd);
492     // Handle data from a client.
493     if (_lscp_connect_recv(pConnect) != LSCP_OK) {
494     // Say bye bye!
495     if (pConnect) {
496     (*pServer->pfnCallback)(pConnect, NULL, LSCP_CONNECT_CLOSE, pServer->pvData);
497     _lscp_connect_list_remove(&(pServer->connects), pConnect);
498     _lscp_connect_destroy(pConnect);
499     }
500     // Remove from master set.
501     FD_CLR((unsigned int) fd, &master_fds);
502     }
503     lscp_mutex_unlock(pServer->connects.mutex);
504     }
505     }
506     }
507     // Done (iSelect > 0)
508     }
509    
510     // Maybe select has timed out?
511     if (iSelect == 0 || (tv2.tv_sec - tv1.tv_sec > LSCP_SERVER_SLEEP)) {
512     // Let the pseudo-watchdog do it's stuff...
513     _lscp_watchdog_scan(pServer);
514     // Make it a new start...
515     gettimeofday(&tv1, NULL);
516     }
517     }
518    
519     #ifdef DEBUG
520     fprintf(stderr, "_lscp_server_select_proc: Server closing.\n");
521     #endif
522     }
523    
524    
525     static void _lscp_server_tcp_proc ( void *pvServer )
526     {
527     lscp_server_t *pServer = (lscp_server_t *) pvServer;
528    
529     if (pServer->mode == LSCP_SERVER_THREAD)
530     _lscp_server_thread_proc(pServer);
531     else
532     _lscp_server_select_proc(pServer);
533     }
534    
535    
536     //-------------------------------------------------------------------------
537     // UDP service (datagram oriented).
538    
539     static void _lscp_server_udp_proc ( void *pvServer )
540     {
541     lscp_server_t *pServer = (lscp_server_t *) pvServer;
542    
543     #ifdef DEBUG
544     fprintf(stderr, "_lscp_server_udp_proc: Server waiting for events.\n");
545     #endif
546    
547     while (pServer->udp.iState) {
548     if (_lscp_server_udp_recv(pServer) != LSCP_OK)
549     pServer->udp.iState = 0;
550     }
551    
552     #ifdef DEBUG
553     fprintf(stderr, "_lscp_server_udp_proc: Server closing.\n");
554     #endif
555     }
556    
557    
558     //-------------------------------------------------------------------------
559     // Watchdog thread procedure loop.
560    
561     static void _lscp_watchdog_scan ( lscp_server_t *pServer )
562     {
563     lscp_connect_t *p, *pNext;
564    
565     lscp_mutex_lock(pServer->connects.mutex);
566    
567     for (p = pServer->connects.first; p; p = pNext) {
568     pNext = p->next;
569     if (p->port > 0) {
570     if (p->ping >= LSCP_SERVER_RETRY) {
571     fprintf(stderr, "_lscp_watchdog_scan: addr=%s port=%d: Zombie connection about to close.\n", inet_ntoa(p->client.addr.sin_addr), ntohs(p->client.addr.sin_port));
572     _lscp_connect_list_remove(&(pServer->connects), p);
573     _lscp_connect_destroy(p);
574     } else {
575     p->ping++;
576     _lscp_connect_ping(p);
577     }
578     }
579     }
580    
581     lscp_mutex_unlock(pServer->connects.mutex);
582     }
583    
584    
585     static void _lscp_watchdog_proc ( void *pvServer )
586     {
587     lscp_server_t *pServer = (lscp_server_t *) pvServer;
588    
589     #ifdef DEBUG
590     fprintf(stderr, "_lscp_watchdog_proc: Watchdog thread started.\n");
591     #endif
592    
593     while (pServer->iWatchdog) {
594    
595     #if defined(WIN32)
596     Sleep(pServer->iSleep * 1000);
597     #else
598     sleep(pServer->iSleep);
599     #endif
600     _lscp_watchdog_scan(pServer);
601     }
602    
603     #ifdef DEBUG
604     fprintf(stderr, "_lscp_watchdog_proc: Watchdog thread terminated.\n");
605     #endif
606     }
607    
608    
609     //-------------------------------------------------------------------------
610     // Server versioning teller fuunction.
611    
612     /** Retrieve the current server library version string. */
613     const char* lscp_server_package (void) { return LSCP_PACKAGE; }
614    
615     /** Retrieve the current server library version string. */
616     const char* lscp_server_version (void) { return LSCP_VERSION; }
617    
618     /** Retrieve the current server library build timestamp string. */
619     const char* lscp_server_build (void) { return __DATE__ " " __TIME__; }
620    
621    
622     //-------------------------------------------------------------------------
623     // Server sockets.
624    
625     /**
626     * Create a server instance, listening on the given port for client
627     * connections. A server callback function must be suplied that will
628     * handle every and each client request.
629     *
630     * @param iPort Port number where the server will bind for listening.
631     * @param pfnCallback Callback function to receive and handle client requests.
632     * @param pvData Server context opaque data, that will be passed
633     * to the callback function without change.
634     *
635     * @returns The new server instance pointer @ref lscp_server_t if successfull,
636     * which shall be used on all subsequent server calls, NULL otherwise.
637     */
638     lscp_server_t* lscp_server_create ( int iPort, lscp_server_proc_t pfnCallback, void *pvData )
639     {
640     return lscp_server_create_ex(iPort, pfnCallback, pvData, LSCP_SERVER_SELECT);
641     }
642    
643    
644     /**
645     * Create a server instance, listening on the given port for client
646     * connections. A server callback function must be suplied that will
647     * handle every and each client request. A server threading model
648     * maybe specified either as multi-threaded (one thread per client)
649     * or single thread multiplex mode (one thread serves all clients).
650     *
651     * @param iPort Port number where the server will bind for listening.
652     * @param pfnCallback Callback function to receive and handle client requests.
653     * @param pvData Server context opaque data, that will be passed
654     * to the callback function without change.
655     * @param mode Server mode of operation, regarding the internal
656     * threading model, either @ref LSCP_SERVER_THREAD for
657     * a multi-threaded server, or @ref LSCP_SERVER_SELECT
658     * for a single-threaded multiplexed server.
659     *
660     * @returns The new server instance pointer if successfull, which shall be
661     * used on all subsequent server calls, NULL otherwise.
662     */
663     lscp_server_t* lscp_server_create_ex ( int iPort, lscp_server_proc_t pfnCallback, void *pvData, lscp_server_mode_t mode )
664     {
665     lscp_server_t *pServer;
666     lscp_socket_t sock;
667     struct sockaddr_in addr;
668     int cAddr;
669     int iSockOpt = (-1);
670    
671     if (pfnCallback == NULL) {
672     fprintf(stderr, "lscp_server_create: Invalid server callback function.\n");
673     return NULL;
674     }
675    
676     // Allocate server descriptor...
677    
678     pServer = (lscp_server_t *) malloc(sizeof(lscp_server_t));
679     if (pServer == NULL) {
680     fprintf(stderr, "lscp_server_create: Out of memory.\n");
681     return NULL;
682     }
683     memset(pServer, 0, sizeof(lscp_server_t));
684    
685     _lscp_connect_list_init(&(pServer->connects));
686    
687     pServer->mode = mode;
688     pServer->pfnCallback = pfnCallback;
689     pServer->pvData = pvData;
690    
691     #ifdef DEBUG
692     fprintf(stderr, "lscp_server_create: pServer=%p: iPort=%d.\n", pServer, iPort);
693     #endif
694    
695     // Prepare the TCP stream server socket...
696    
697     sock = socket(AF_INET, SOCK_STREAM, 0);
698     if (sock == INVALID_SOCKET) {
699     lscp_socket_perror("lscp_server_create: tcp: socket");
700     free(pServer);
701     return NULL;
702     }
703    
704     if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char *) &iSockOpt, sizeof(int)) == SOCKET_ERROR)
705     lscp_socket_perror("lscp_server_create: tcp: setsockopt(SO_REUSEADDR)");
706     #if defined(WIN32)
707     if (setsockopt(sock, SOL_SOCKET, SO_DONTLINGER, (char *) &iSockOpt, sizeof(int)) == SOCKET_ERROR)
708     lscp_socket_perror("lscp_server_create: tcp: setsockopt(SO_DONTLINGER)");
709     #endif
710    
711     #ifdef DEBUG
712     lscp_socket_getopts("lscp_server_create: tcp", sock);
713     #endif
714    
715     cAddr = sizeof(struct sockaddr_in);
716     memset((char *) &addr, 0, cAddr);
717     addr.sin_family = AF_INET;
718     addr.sin_addr.s_addr = htonl(INADDR_ANY);
719     addr.sin_port = htons((short) iPort);
720    
721     if (bind(sock, (const struct sockaddr *) &addr, cAddr) == SOCKET_ERROR) {
722     lscp_socket_perror("lscp_server_create: tcp: bind");
723     closesocket(sock);
724     free(pServer);
725     return NULL;
726     }
727    
728     if (listen(sock, 10) == SOCKET_ERROR) {
729     lscp_socket_perror("lscp_server_create: tcp: listen");
730     closesocket(sock);
731     free(pServer);
732     return NULL;
733     }
734    
735     if (iPort == 0) {
736     if (getsockname(sock, (struct sockaddr *) &addr, &cAddr) == SOCKET_ERROR) {
737     lscp_socket_perror("lscp_server_create: tcp: getsockname");
738     closesocket(sock);
739     free(pServer);
740     }
741     // Make TCP and UDP ports equal?
742     iPort = ntohs(addr.sin_port);
743     }
744    
745     lscp_socket_agent_init(&(pServer->tcp), sock, &addr, cAddr);
746    
747     #ifdef DEBUG
748     fprintf(stderr, "lscp_server_create: tcp: sock=%d addr=%s port=%d.\n", pServer->tcp.sock, inet_ntoa(pServer->tcp.addr.sin_addr), ntohs(pServer->tcp.addr.sin_port));
749     #endif
750    
751     // Prepare the UDP datagram server socket...
752    
753     sock = socket(AF_INET, SOCK_DGRAM, 0);
754     if (sock == INVALID_SOCKET) {
755     lscp_socket_perror("lscp_server_create: udp: socket");
756     lscp_socket_agent_free(&(pServer->tcp));
757     free(pServer);
758     return NULL;
759     }
760    
761     if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char *) &iSockOpt, sizeof(int)) == SOCKET_ERROR)
762     lscp_socket_perror("lscp_server_create: udp: setsockopt(SO_REUSEADDR)");
763    
764     #ifdef DEBUG
765     lscp_socket_getopts("lscp_server_create: udp", sock);
766     #endif
767    
768     cAddr = sizeof(struct sockaddr_in);
769     memset((char *) &addr, 0, cAddr);
770     addr.sin_family = AF_INET;
771     addr.sin_addr.s_addr = htonl(INADDR_ANY);
772     addr.sin_port = htons((short) iPort);
773    
774     if (bind(sock, (const struct sockaddr *) &addr, cAddr) == SOCKET_ERROR) {
775     lscp_socket_perror("lscp_server_create: udp: bind");
776     lscp_socket_agent_free(&(pServer->tcp));
777     closesocket(sock);
778     free(pServer);
779     return NULL;
780     }
781    
782     if (iPort == 0) {
783     if (getsockname(sock, (struct sockaddr *) &addr, &cAddr) == SOCKET_ERROR) {
784     lscp_socket_perror("lscp_server_create: udp: getsockname");
785     lscp_socket_agent_free(&(pServer->tcp));
786     closesocket(sock);
787     free(pServer);
788     return NULL;
789     }
790     }
791    
792     lscp_socket_agent_init(&(pServer->udp), sock, &addr, cAddr);
793    
794     #ifdef DEBUG
795     fprintf(stderr, "lscp_server_create: udp: sock=%d addr=%s port=%d.\n", pServer->udp.sock, inet_ntoa(pServer->udp.addr.sin_addr), ntohs(pServer->udp.addr.sin_port));
796     #endif
797    
798     // Now's finally time to startup threads...
799    
800     // TCP/Main service thread...
801     if (lscp_socket_agent_start(&(pServer->tcp), _lscp_server_tcp_proc, pServer, 0) != LSCP_OK) {
802     lscp_socket_agent_free(&(pServer->tcp));
803     lscp_socket_agent_free(&(pServer->udp));
804     free(pServer);
805     return NULL;
806     }
807    
808     if (pServer->mode == LSCP_SERVER_THREAD) {
809     // UDP service thread...
810     if (lscp_socket_agent_start(&(pServer->udp), _lscp_server_udp_proc, pServer, 0) != LSCP_OK) {
811     lscp_socket_agent_free(&(pServer->tcp));
812     lscp_socket_agent_free(&(pServer->udp));
813     free(pServer);
814     return NULL;
815     }
816     // Watchdog thread...
817     pServer->iWatchdog = 1;
818     pServer->iSleep = LSCP_SERVER_SLEEP;
819     pServer->pWatchdog = lscp_thread_create(_lscp_watchdog_proc, pServer, 0);
820     }
821    
822     // Finally we've some success...
823     return pServer;
824     }
825    
826    
827     /**
828     * Wait for a server instance to terminate graciously.
829     *
830     * @param pServer Pointer to server instance structure.
831     */
832     lscp_status_t lscp_server_join ( lscp_server_t *pServer )
833     {
834     if (pServer == NULL)
835     return LSCP_FAILED;
836    
837     #ifdef DEBUG
838     fprintf(stderr, "lscp_server_join: pServer=%p.\n", pServer);
839     #endif
840    
841     // if (pServer->mode == LSCP_SERVER_THREAD) {
842     // lscp_thread_join(pServer->pWatchdog);
843     // lscp_socket_agent_join(&(pServer->udp));
844     // }
845     lscp_socket_agent_join(&(pServer->tcp));
846    
847     return LSCP_OK;
848     }
849    
850    
851     /**
852     * Terminate and destroy a server instance.
853     *
854     * @param pServer Pointer to server instance structure.
855     */
856     lscp_status_t lscp_server_destroy ( lscp_server_t *pServer )
857     {
858     if (pServer == NULL)
859     return LSCP_FAILED;
860    
861     #ifdef DEBUG
862     fprintf(stderr, "lscp_server_destroy: pServer=%p.\n", pServer);
863     #endif
864    
865     if (pServer->mode == LSCP_SERVER_THREAD) {
866     pServer->iWatchdog = 0;
867     lscp_thread_destroy(pServer->pWatchdog);
868     }
869     lscp_socket_agent_free(&(pServer->udp));
870     lscp_socket_agent_free(&(pServer->tcp));
871     _lscp_connect_list_free(&(pServer->connects));
872    
873     free(pServer);
874    
875     return LSCP_OK;
876     }
877    
878    
879     /**
880     * Send an event message to all subscribed clients.
881     *
882     * @param pServer Pointer to server instance structure.
883     * @param pchBuffer Pointer to data to be sent to all clients.
884     * @param cchBuffer Length of the data to be sent in bytes.
885     *
886     * @returns LSCP_OK on success, LSCP_FAILED otherwise.
887     */
888     lscp_status_t lscp_server_broadcast ( lscp_server_t *pServer, const char *pchBuffer, int cchBuffer )
889     {
890     lscp_connect_t *p;
891    
892     if (pServer == NULL)
893     return LSCP_FAILED;
894     if (pchBuffer == NULL || cchBuffer < 1)
895     return LSCP_FAILED;
896    
897     lscp_mutex_lock(pServer->connects.mutex);
898    
899     for (p = pServer->connects.first; p; p = p->next) {
900     if (p->port > 0 && p->ping == 0)
901     _lscp_connect_send(p, pchBuffer, cchBuffer);
902     }
903    
904     lscp_mutex_unlock(pServer->connects.mutex);
905    
906     return LSCP_OK;
907     }
908    
909    
910     /**
911     * Send response for the current client callback request.
912     *
913     * @param pConnect Pointer to client connection instance structure.
914     * @param pchBuffer Pointer to data to be sent to the client as response.
915     * @param cchBuffer Length of the response data to be sent in bytes.
916     *
917     * @returns LSCP_OK on success, LSCP_FAILED otherwise.
918     */
919     lscp_status_t lscp_server_result ( lscp_connect_t *pConnect, const char *pchBuffer, int cchBuffer )
920     {
921     lscp_status_t ret = LSCP_FAILED;
922    
923     if (pConnect == NULL)
924     return ret;
925     if (pchBuffer == NULL || cchBuffer < 1)
926     return ret;
927    
928     if (send(pConnect->client.sock, pchBuffer, cchBuffer, 0) != cchBuffer)
929     lscp_socket_perror("lscp_server_result");
930     else
931     ret = LSCP_OK;
932    
933     return ret;
934     }
935    
936    
937     /**
938     * Register client as a subscriber of event broadcast messages.
939     *
940     * @param pConnect Pointer to client connection instance structure.
941     * @param iPort UDP port number of the requesting client connection.
942     *
943     * @returns LSCP_OK on success, LSCP_FAILED otherwise.
944     */
945     lscp_status_t lscp_server_subscribe ( lscp_connect_t *pConnect, int iPort )
946     {
947     char szSessID[32];
948    
949     if (pConnect == NULL)
950     return LSCP_FAILED;
951     if (iPort == 0 || pConnect->port > 0 || pConnect->sessid)
952     return LSCP_FAILED;
953    
954     // Generate a psudo-unique session-id.
955     sprintf(szSessID, "%08x", ((unsigned int) pConnect->server << 8) ^ (unsigned int) pConnect);
956    
957     pConnect->port = iPort;
958     pConnect->ping = 0;
959     pConnect->sessid = strdup(szSessID);
960    
961     return _lscp_connect_ping(pConnect);
962     }
963    
964    
965     /**
966     * Deregister client as subscriber of event broadcast messages.
967     *
968     * @param pConnect Pointer to client connection instance structure.
969     * @param pszSessID Session identifier of the requesting client connection.
970     *
971     * @returns LSCP_OK on success, LSCP_FAILED otherwise.
972     */
973     lscp_status_t lscp_server_unsubscribe ( lscp_connect_t *pConnect, const char *pszSessID )
974     {
975     if (pConnect == NULL)
976     return LSCP_FAILED;
977     if (pConnect->port == 0 || pConnect->sessid == NULL)
978     return LSCP_FAILED;
979    
980     // Session ids must match.
981     if (strcmp(pszSessID, pConnect->sessid) != 0)
982     return LSCP_FAILED;
983    
984     free(pConnect->sessid);
985     pConnect->sessid = NULL;
986     pConnect->ping = 0;
987     pConnect->port = 0;
988    
989     return LSCP_OK;
990     }
991    
992    
993     // end of server.c

  ViewVC Help
Powered by ViewVC