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

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

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 132 by capela, Fri Jun 18 14:19:19 2004 UTC revision 869 by capela, Thu Jun 1 08:32:16 2006 UTC
# Line 2  Line 2 
2  //  //
3  /****************************************************************************  /****************************************************************************
4     liblscp - LinuxSampler Control Protocol API     liblscp - LinuxSampler Control Protocol API
5     Copyright (C) 2004, rncbc aka Rui Nuno Capela. All rights reserved.     Copyright (C) 2004-2006, rncbc aka Rui Nuno Capela. All rights reserved.
6    
7     This library is free software; you can redistribute it and/or     This library is free software; you can redistribute it and/or
8     modify it under the terms of the GNU Lesser General Public     modify it under the terms of the GNU Lesser General Public
# Line 22  Line 22 
22    
23  #include "server.h"  #include "server.h"
24    
25  #define LSCP_SERVER_RETRY   3           // Maximum number of unanswered PING retries.  #define LSCP_SERVER_SLEEP   30          // Period in seconds for watchdog wakeup (idle loop).
 #define LSCP_SERVER_SLEEP   30          // Period in seconds for watchdog wakeup.  
26    
27    
28  // Local prototypes.  // Local prototypes.
# Line 31  Line 30 
30  static lscp_connect_t  *_lscp_connect_create            (lscp_server_t *pServer, lscp_socket_t sock, struct sockaddr_in *pAddr, int cAddr);  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);  static lscp_status_t    _lscp_connect_destroy           (lscp_connect_t *pConnect);
32  static lscp_status_t    _lscp_connect_recv              (lscp_connect_t *pConnect);  static lscp_status_t    _lscp_connect_recv              (lscp_connect_t *pConnect);
 static lscp_status_t    _lscp_connect_send              (lscp_connect_t *pConnect, const char *pchBuffer, int cchBuffer);  
 static lscp_status_t    _lscp_connect_ping              (lscp_connect_t *pConnect);  
33    
34  static void             _lscp_connect_list_append       (lscp_connect_list_t *pList, lscp_connect_t *pItem);  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);  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);  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);  static void             _lscp_connect_list_free         (lscp_connect_list_t *pList);
 static lscp_connect_t  *_lscp_connect_list_find_addr    (lscp_connect_list_t *pList, struct sockaddr_in *pAddr);  
38  static lscp_connect_t  *_lscp_connect_list_find_sock    (lscp_connect_list_t *pList, lscp_socket_t sock);  static lscp_connect_t  *_lscp_connect_list_find_sock    (lscp_connect_list_t *pList, lscp_socket_t sock);
39    
 static lscp_status_t    _lscp_server_evt_recv           (lscp_server_t *pServer);  
   
40  static void             _lscp_server_thread_proc        (lscp_server_t *pServer);  static void             _lscp_server_thread_proc        (lscp_server_t *pServer);
41  static void             _lscp_server_select_proc        (lscp_server_t *pServer);  static void             _lscp_server_select_proc        (lscp_server_t *pServer);
42    
43  static void             _lscp_server_cmd_proc           (void *pvServer);  static void             _lscp_server_agent_proc         (void *pvServer);
 static void             _lscp_server_evt_proc           (void *pvServer);  
   
 static void             _lscp_watchdog_scan             (lscp_server_t *pServer);  
   
 static void             _lscp_watchdog_proc             (void *pvServer);  
44    
 #if defined(WIN32)  
 #include <time.h>  
 #undef  gettimeofday  
 #define gettimeofday(p,n)  {(p)->tv_sec = (long) (clock() / CLOCKS_PER_SEC); (p)->tv_usec = 0;}  
 #else  
 #include <sys/time.h>  
 #endif  
45    
46  //-------------------------------------------------------------------------  //-------------------------------------------------------------------------
47  // Server-side client connection list methods.  // Server-side client connection list methods.
# Line 158  static void _lscp_connect_list_free ( ls Line 140  static void _lscp_connect_list_free ( ls
140  }  }
141    
142    
 static lscp_connect_t *_lscp_connect_list_find_addr ( lscp_connect_list_t *pList, struct sockaddr_in *pAddr )  
 {  
     int iPort = ntohs(pAddr->sin_port);  
     const char *pszAddr = inet_ntoa(pAddr->sin_addr);  
     lscp_connect_t *p;  
   
 //  fprintf(stderr, "_lscp_connect_list_find_addr: pList=%p addr=%s port=%d.\n", pList, inet_ntoa(pAddr->sin_addr), ntohs(pAddr->sin_port));  
   
     for (p = pList->first; p; p = p->next) {  
         if (iPort == p->port && strcmp(pszAddr, inet_ntoa(p->client.addr.sin_addr)) == 0)  
             return p;  
     }  
   
     return NULL;  
 }  
   
   
143  static lscp_connect_t *_lscp_connect_list_find_sock ( lscp_connect_list_t *pList, lscp_socket_t sock )  static lscp_connect_t *_lscp_connect_list_find_sock ( lscp_connect_list_t *pList, lscp_socket_t sock )
144  {  {
145      lscp_connect_t *p;      lscp_connect_t *p;
# Line 197  static void _lscp_connect_proc ( void *p Line 162  static void _lscp_connect_proc ( void *p
162      lscp_connect_t *pConnect = (lscp_connect_t *) pvConnect;      lscp_connect_t *pConnect = (lscp_connect_t *) pvConnect;
163      lscp_server_t  *pServer  = pConnect->server;      lscp_server_t  *pServer  = pConnect->server;
164    
165      while (pServer->cmd.iState && pConnect->client.iState) {      while (pServer->agent.iState && pConnect->client.iState) {
166          if (_lscp_connect_recv(pConnect) != LSCP_OK)          if (_lscp_connect_recv(pConnect) != LSCP_OK)
167              pConnect->client.iState = 0;              pConnect->client.iState = 0;
168      }      }
# Line 225  static lscp_connect_t *_lscp_connect_cre Line 190  static lscp_connect_t *_lscp_connect_cre
190      memset(pConnect, 0, sizeof(lscp_connect_t));      memset(pConnect, 0, sizeof(lscp_connect_t));
191    
192      pConnect->server = pServer;      pConnect->server = pServer;
193        pConnect->events = LSCP_EVENT_NONE;
194    
195  #ifdef DEBUG  #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));      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));
# Line 257  static lscp_status_t _lscp_connect_destr Line 223  static lscp_status_t _lscp_connect_destr
223    
224      lscp_socket_agent_free(&(pConnect->client));      lscp_socket_agent_free(&(pConnect->client));
225    
     if (pConnect->sessid)  
         free(pConnect->sessid);  
   
226      free(pConnect);      free(pConnect);
227    
228      return ret;      return ret;
# Line 290  lscp_status_t _lscp_connect_recv ( lscp_ Line 253  lscp_status_t _lscp_connect_recv ( lscp_
253  }  }
254    
255    
 static lscp_status_t _lscp_connect_send ( lscp_connect_t *pConnect, const char *pchBuffer, int cchBuffer )  
 {  
     lscp_status_t ret = LSCP_FAILED;  
     struct sockaddr_in addr;  
     int cAddr;  
   
     if (pConnect == NULL)  
         return ret;  
     if (pchBuffer == NULL || cchBuffer < 1)  
         return ret;  
     if (pConnect->port == 0)  
         return ret;  
   
     cAddr = sizeof(struct sockaddr_in);  
     memcpy((char *) &addr, (char *) &(pConnect->client.addr), cAddr);  
     addr.sin_port = htons((short) pConnect->port);  
   
     if (sendto((pConnect->server)->evt.sock, pchBuffer, cchBuffer, 0, (struct sockaddr *) &addr, cAddr) == cchBuffer)  
         ret = LSCP_OK;  
     else  
         lscp_socket_perror("_lscp_connect_send: sendto");  
   
     return ret;  
 }  
   
   
 static lscp_status_t _lscp_connect_ping ( lscp_connect_t *pConnect )  
 {  
     char szBuffer[LSCP_BUFSIZ];  
   
     if (pConnect == NULL)  
         return LSCP_FAILED;  
     if (pConnect->sessid == NULL)  
         return LSCP_FAILED;  
   
 #ifdef DEBUG  
     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);  
 #endif  
   
     sprintf(szBuffer, "PING %d %s\r\n", ntohs((pConnect->server)->evt.addr.sin_port), pConnect->sessid);  
   
     return _lscp_connect_send(pConnect, szBuffer, strlen(szBuffer));  
 }  
   
   
256  //-------------------------------------------------------------------------  //-------------------------------------------------------------------------
257  // Command service (stream oriented).  // Command service (stream oriented).
258    
 static lscp_status_t _lscp_server_evt_recv ( lscp_server_t *pServer )  
 {  
     lscp_status_t ret = LSCP_FAILED;  
     struct sockaddr_in addr;  
     int  cAddr;  
     char achBuffer[LSCP_BUFSIZ];  
     int  cchBuffer;  
     lscp_connect_t *pConnect;  
   
     cAddr = sizeof(addr);  
     cchBuffer = recvfrom(pServer->evt.sock, achBuffer, sizeof(achBuffer), 0, (struct sockaddr *) &addr, &cAddr);  
     if (cchBuffer > 0) {  
 #ifdef DEBUG  
         lscp_socket_trace("_lscp_server_evt_recv: recvfrom", &addr, achBuffer, cchBuffer);  
 #endif  
         // Just do a simple check for PONG events (ignore sessid).  
         if (strncmp(achBuffer, "PONG ", 5) == 0) {  
             pConnect = _lscp_connect_list_find_addr(&(pServer->connects), &addr);  
             if (pConnect)  
                 pConnect->ping = 0;  
         }  
         ret = LSCP_OK;  
     }  
     else lscp_socket_perror("_lscp_server_evt_recv: recvfrom");  
   
     return ret;  
 }  
   
   
259  static void _lscp_server_thread_proc ( lscp_server_t *pServer )  static void _lscp_server_thread_proc ( lscp_server_t *pServer )
260  {  {
261      lscp_socket_t sock;      lscp_socket_t sock;
262      struct sockaddr_in addr;      struct sockaddr_in addr;
263      int cAddr;      socklen_t cAddr;
264      lscp_connect_t *pConnect;      lscp_connect_t *pConnect;
265    
266  #ifdef DEBUG  #ifdef DEBUG
267      fprintf(stderr, "_lscp_server_thread_proc: Server listening for connections.\n");      fprintf(stderr, "_lscp_server_thread_proc: Server listening for connections.\n");
268  #endif  #endif
269    
270      while (pServer->cmd.iState) {      while (pServer->agent.iState) {
271          cAddr = sizeof(struct sockaddr_in);          cAddr = sizeof(struct sockaddr_in);
272          sock = accept(pServer->cmd.sock, (struct sockaddr *) &addr, &cAddr);          sock = accept(pServer->agent.sock, (struct sockaddr *) &addr, &cAddr);
273          if (sock == INVALID_SOCKET) {          if (sock == INVALID_SOCKET) {
274              lscp_socket_perror("_lscp_server_thread_proc: accept");              lscp_socket_perror("_lscp_server_thread_proc: accept");
275              pServer->cmd.iState = 0;              pServer->agent.iState = 0;
276          } else {          } else {
277              pConnect = _lscp_connect_create(pServer, sock, &addr, cAddr);              pConnect = _lscp_connect_create(pServer, sock, &addr, cAddr);
278              if (pConnect) {              if (pConnect) {
# Line 407  static void _lscp_server_select_proc ( l Line 296  static void _lscp_server_select_proc ( l
296      struct timeval tv;  // For specifying a timeout value.      struct timeval tv;  // For specifying a timeout value.
297      int iSelect;        // Holds select return status.      int iSelect;        // Holds select return status.
298    
     struct timeval tv1, tv2;    // To compute delta timeouts.  
   
299      lscp_socket_t sock;      lscp_socket_t sock;
300      struct sockaddr_in addr;      struct sockaddr_in addr;
301      int cAddr;      socklen_t cAddr;
302      lscp_connect_t *pConnect;      lscp_connect_t *pConnect;
303    
304  #ifdef DEBUG  #ifdef DEBUG
# Line 420  static void _lscp_server_select_proc ( l Line 307  static void _lscp_server_select_proc ( l
307      FD_ZERO(&master_fds);      FD_ZERO(&master_fds);
308      FD_ZERO(&select_fds);      FD_ZERO(&select_fds);
309    
310      // Add the listeners to the master set      // Add the listener to the master set
311      FD_SET((unsigned int) pServer->cmd.sock, &master_fds);      FD_SET((unsigned int) pServer->agent.sock, &master_fds);
     FD_SET((unsigned int) pServer->evt.sock, &master_fds);  
312    
313      // Keep track of the biggest file descriptor;      // Keep track of the biggest file descriptor;
314      // So far, it's ourself, the listener.      // So far, it's ourself, the listener.
315      if ((int) pServer->evt.sock > (int) pServer->cmd.sock)      fdmax = (int) pServer->agent.sock;
         fdmax = (int) pServer->evt.sock;  
     else  
         fdmax = (int) pServer->cmd.sock;  
   
     // To start counting for regular watchdog simulation.  
     gettimeofday(&tv1, NULL);  
     gettimeofday(&tv2, NULL);  
316    
317      // Main loop...      // Main loop...
318      while (pServer->cmd.iState) {      while (pServer->agent.iState) {
319    
320          // Use a copy of the master.          // Use a copy of the master.
321          select_fds = master_fds;          select_fds = master_fds;
322          // Use the timeout feature for watchdoggin.          // Use the timeout feature for watchdoggin.
323          tv.tv_sec = LSCP_SERVER_SLEEP - (tv2.tv_sec - tv1.tv_sec);          tv.tv_sec = LSCP_SERVER_SLEEP;
324          tv.tv_usec = 0;          tv.tv_usec = 0;
325          // Wait for events...          // Wait for events...
326          iSelect = select(fdmax + 1, &select_fds, NULL, NULL, &tv);          iSelect = select(fdmax + 1, &select_fds, NULL, NULL, &tv);
327    
         // Check later id it's time for ping time...  
         gettimeofday(&tv2, NULL);  
   
328          if (iSelect < 0) {          if (iSelect < 0) {
329              lscp_socket_perror("_lscp_server_select_proc: select");              lscp_socket_perror("_lscp_server_select_proc: select");
330              pServer->cmd.iState = 0;              pServer->agent.iState = 0;
331          }          }
332          else if (iSelect > 0) {          else if (iSelect > 0) {
333              // Run through the existing connections looking for data to read...              // Run through the existing connections looking for data to read...
334              for (fd = 0; fd < fdmax + 1; fd++) {              for (fd = 0; fd < fdmax + 1; fd++) {
335                  if (FD_ISSET(fd, &select_fds)) {    // We got one!!                  if (FD_ISSET(fd, &select_fds)) {    // We got one!!
336                      // Is it ourselves, the command listener?                      // Is it ourselves, the command listener?
337                      if (fd == (int) pServer->cmd.sock) {                      if (fd == (int) pServer->agent.sock) {
338                          // Accept the connection...                          // Accept the connection...
339                          cAddr = sizeof(struct sockaddr_in);                          cAddr = sizeof(struct sockaddr_in);
340                          sock = accept(pServer->cmd.sock, (struct sockaddr *) &addr, &cAddr);                          sock = accept(pServer->agent.sock, (struct sockaddr *) &addr, &cAddr);
341                          if (sock == INVALID_SOCKET) {                          if (sock == INVALID_SOCKET) {
342                              lscp_socket_perror("_lscp_server_select_proc: accept");                              lscp_socket_perror("_lscp_server_select_proc: accept");
343                              pServer->cmd.iState = 0;                              pServer->agent.iState = 0;
344                          } else {                          } else {
345                              // Add to master set.                              // Add to master set.
346                              FD_SET((unsigned int) sock, &master_fds);                              FD_SET((unsigned int) sock, &master_fds);
# Line 479  static void _lscp_server_select_proc ( l Line 355  static void _lscp_server_select_proc ( l
355                              }                              }
356                          }                          }
357                          // Done with one new connection.                          // Done with one new connection.
                     } else if (fd == (int) pServer->evt.sock) {  
                         // Or from the event listener?  
                         if (_lscp_server_evt_recv(pServer) != LSCP_OK)  
                             pServer->cmd.iState = 0;  
                         // Done with event transaction.  
358                      } else {                      } else {
359                          // Otherwise it's trivial transaction...                          // Otherwise it's trivial transaction...
360                          lscp_mutex_lock(pServer->connects.mutex);                          lscp_mutex_lock(pServer->connects.mutex);
# Line 506  static void _lscp_server_select_proc ( l Line 377  static void _lscp_server_select_proc ( l
377              }              }
378              // Done (iSelect > 0)              // Done (iSelect > 0)
379          }          }
   
         // Maybe select has timed out?  
         if (iSelect == 0 || (tv2.tv_sec - tv1.tv_sec > LSCP_SERVER_SLEEP)) {  
             // Let the pseudo-watchdog do it's stuff...  
             _lscp_watchdog_scan(pServer);  
             // Make it a new start...  
             gettimeofday(&tv1, NULL);  
         }  
380      }      }
381    
382  #ifdef DEBUG  #ifdef DEBUG
# Line 522  static void _lscp_server_select_proc ( l Line 385  static void _lscp_server_select_proc ( l
385  }  }
386    
387    
388  static void _lscp_server_cmd_proc ( void *pvServer )  static void _lscp_server_agent_proc ( void *pvServer )
389  {  {
390      lscp_server_t *pServer = (lscp_server_t *) pvServer;      lscp_server_t *pServer = (lscp_server_t *) pvServer;
391    
# Line 534  static void _lscp_server_cmd_proc ( void Line 397  static void _lscp_server_cmd_proc ( void
397    
398    
399  //-------------------------------------------------------------------------  //-------------------------------------------------------------------------
 // Event service (datagram oriented).  
   
 static void _lscp_server_evt_proc ( void *pvServer )  
 {  
     lscp_server_t *pServer = (lscp_server_t *) pvServer;  
   
 #ifdef DEBUG  
     fprintf(stderr, "_lscp_server_evt_proc: Server waiting for events.\n");  
 #endif  
   
     while (pServer->evt.iState) {  
         if (_lscp_server_evt_recv(pServer) != LSCP_OK)  
             pServer->evt.iState = 0;  
     }  
   
 #ifdef DEBUG  
     fprintf(stderr, "_lscp_server_evt_proc: Server closing.\n");  
 #endif  
 }  
   
   
 //-------------------------------------------------------------------------  
 // Watchdog thread procedure loop.  
   
 static void _lscp_watchdog_scan ( lscp_server_t *pServer )  
 {  
     lscp_connect_t *p, *pNext;  
   
     lscp_mutex_lock(pServer->connects.mutex);  
   
     for (p = pServer->connects.first; p; p = pNext) {  
         pNext = p->next;  
         if (p->port > 0) {  
             if (p->ping >= LSCP_SERVER_RETRY) {  
                 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));  
                 _lscp_connect_list_remove(&(pServer->connects), p);  
                 _lscp_connect_destroy(p);  
             } else {  
                 p->ping++;  
                 _lscp_connect_ping(p);  
             }  
         }  
     }  
   
     lscp_mutex_unlock(pServer->connects.mutex);  
 }  
   
   
 static void _lscp_watchdog_proc ( void *pvServer )  
 {  
     lscp_server_t *pServer = (lscp_server_t *) pvServer;  
   
 #ifdef DEBUG  
     fprintf(stderr, "_lscp_watchdog_proc: Watchdog thread started.\n");  
 #endif  
   
     while (pServer->iWatchdog) {  
   
 #if defined(WIN32)  
         Sleep(pServer->iSleep * 1000);  
 #else  
         sleep(pServer->iSleep);  
 #endif  
         _lscp_watchdog_scan(pServer);  
     }  
   
 #ifdef DEBUG  
     fprintf(stderr, "_lscp_watchdog_proc: Watchdog thread terminated.\n");  
 #endif  
 }  
   
   
 //-------------------------------------------------------------------------  
400  // Server versioning teller fuunction.  // Server versioning teller fuunction.
401    
402  /** Retrieve the current server library version string. */  /** Retrieve the current server library version string. */
# Line 696  lscp_server_t* lscp_server_create_ex ( i Line 486  lscp_server_t* lscp_server_create_ex ( i
486    
487      sock = socket(AF_INET, SOCK_STREAM, 0);      sock = socket(AF_INET, SOCK_STREAM, 0);
488      if (sock == INVALID_SOCKET) {      if (sock == INVALID_SOCKET) {
489          lscp_socket_perror("lscp_server_create: cmd: socket");          lscp_socket_perror("lscp_server_create: socket");
490          free(pServer);          free(pServer);
491          return NULL;          return NULL;
492      }      }
493    
494      if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char *) &iSockOpt, sizeof(int)) == SOCKET_ERROR)      if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char *) &iSockOpt, sizeof(int)) == SOCKET_ERROR)
495          lscp_socket_perror("lscp_server_create: cmd: setsockopt(SO_REUSEADDR)");          lscp_socket_perror("lscp_server_create: setsockopt(SO_REUSEADDR)");
496  #if defined(WIN32)  #if defined(WIN32)
497      if (setsockopt(sock, SOL_SOCKET, SO_DONTLINGER, (char *) &iSockOpt, sizeof(int)) == SOCKET_ERROR)      if (setsockopt(sock, SOL_SOCKET, SO_DONTLINGER, (char *) &iSockOpt, sizeof(int)) == SOCKET_ERROR)
498          lscp_socket_perror("lscp_server_create: cmd: setsockopt(SO_DONTLINGER)");          lscp_socket_perror("lscp_server_create: setsockopt(SO_DONTLINGER)");
499  #endif  #endif
500    
501  #ifdef DEBUG  #ifdef DEBUG
502      lscp_socket_getopts("lscp_server_create: cmd", sock);      lscp_socket_getopts("lscp_server_create", sock);
503  #endif  #endif
504    
505      cAddr = sizeof(struct sockaddr_in);      cAddr = sizeof(struct sockaddr_in);
# Line 719  lscp_server_t* lscp_server_create_ex ( i Line 509  lscp_server_t* lscp_server_create_ex ( i
509      addr.sin_port = htons((short) iPort);      addr.sin_port = htons((short) iPort);
510    
511      if (bind(sock, (const struct sockaddr *) &addr, cAddr) == SOCKET_ERROR) {      if (bind(sock, (const struct sockaddr *) &addr, cAddr) == SOCKET_ERROR) {
512          lscp_socket_perror("lscp_server_create: cmd: bind");          lscp_socket_perror("lscp_server_create: bind");
513          closesocket(sock);          closesocket(sock);
514          free(pServer);          free(pServer);
515          return NULL;          return NULL;
516      }      }
517    
518      if (listen(sock, 10) == SOCKET_ERROR) {      if (listen(sock, 10) == SOCKET_ERROR) {
519          lscp_socket_perror("lscp_server_create: cmd: listen");          lscp_socket_perror("lscp_server_create: listen");
         closesocket(sock);  
         free(pServer);  
         return NULL;  
     }  
   
     if (iPort == 0) {  
         if (getsockname(sock, (struct sockaddr *) &addr, &cAddr) == SOCKET_ERROR) {  
             lscp_socket_perror("lscp_server_create: cmd: getsockname");  
             closesocket(sock);  
             free(pServer);  
         }  
         // Make command and event ports equal?  
         iPort = ntohs(addr.sin_port);  
     }  
   
     lscp_socket_agent_init(&(pServer->cmd), sock, &addr, cAddr);  
   
 #ifdef DEBUG  
     fprintf(stderr, "lscp_server_create: cmd: sock=%d addr=%s port=%d.\n", pServer->cmd.sock, inet_ntoa(pServer->cmd.addr.sin_addr), ntohs(pServer->cmd.addr.sin_port));  
 #endif  
   
     // Prepare the event datagram server socket...  
   
     sock = socket(AF_INET, SOCK_DGRAM, 0);  
     if (sock == INVALID_SOCKET) {  
         lscp_socket_perror("lscp_server_create: evt: socket");  
         lscp_socket_agent_free(&(pServer->cmd));  
         free(pServer);  
         return NULL;  
     }  
   
     if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char *) &iSockOpt, sizeof(int)) == SOCKET_ERROR)  
         lscp_socket_perror("lscp_server_create: evt: setsockopt(SO_REUSEADDR)");  
   
 #ifdef DEBUG  
     lscp_socket_getopts("lscp_server_create: evt", sock);  
 #endif  
   
     cAddr = sizeof(struct sockaddr_in);  
     memset((char *) &addr, 0, cAddr);  
     addr.sin_family = AF_INET;  
     addr.sin_addr.s_addr = htonl(INADDR_ANY);  
     addr.sin_port = htons((short) iPort);  
   
     if (bind(sock, (const struct sockaddr *) &addr, cAddr) == SOCKET_ERROR) {  
         lscp_socket_perror("lscp_server_create: evt: bind");  
         lscp_socket_agent_free(&(pServer->cmd));  
520          closesocket(sock);          closesocket(sock);
521          free(pServer);          free(pServer);
522          return NULL;          return NULL;
# Line 781  lscp_server_t* lscp_server_create_ex ( i Line 524  lscp_server_t* lscp_server_create_ex ( i
524    
525      if (iPort == 0) {      if (iPort == 0) {
526          if (getsockname(sock, (struct sockaddr *) &addr, &cAddr) == SOCKET_ERROR) {          if (getsockname(sock, (struct sockaddr *) &addr, &cAddr) == SOCKET_ERROR) {
527              lscp_socket_perror("lscp_server_create: evt: getsockname");              lscp_socket_perror("lscp_server_create: getsockname");
             lscp_socket_agent_free(&(pServer->cmd));  
528              closesocket(sock);              closesocket(sock);
529              free(pServer);              free(pServer);
             return NULL;  
530          }          }
531      }      }
532    
533      lscp_socket_agent_init(&(pServer->evt), sock, &addr, cAddr);      lscp_socket_agent_init(&(pServer->agent), sock, &addr, cAddr);
534    
535  #ifdef DEBUG  #ifdef DEBUG
536      fprintf(stderr, "lscp_server_create: evt: sock=%d addr=%s port=%d.\n", pServer->evt.sock, inet_ntoa(pServer->evt.addr.sin_addr), ntohs(pServer->evt.addr.sin_port));      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  #endif
538    
539      // Now's finally time to startup threads...      // Now's finally time to startup threads...
540    
541      // Command service thread...      // Command service thread...
542      if (lscp_socket_agent_start(&(pServer->cmd), _lscp_server_cmd_proc, pServer, 0) != LSCP_OK) {      if (lscp_socket_agent_start(&(pServer->agent), _lscp_server_agent_proc, pServer, 0) != LSCP_OK) {
543          lscp_socket_agent_free(&(pServer->cmd));          lscp_socket_agent_free(&(pServer->agent));
         lscp_socket_agent_free(&(pServer->evt));  
544          free(pServer);          free(pServer);
545          return NULL;          return NULL;
546      }      }
547    
     if (pServer->mode == LSCP_SERVER_THREAD) {  
         // Event service thread...  
         if (lscp_socket_agent_start(&(pServer->evt), _lscp_server_evt_proc, pServer, 0) != LSCP_OK) {  
             lscp_socket_agent_free(&(pServer->cmd));  
             lscp_socket_agent_free(&(pServer->evt));  
             free(pServer);  
             return NULL;  
         }  
         // Watchdog thread...  
         pServer->iWatchdog = 1;  
         pServer->iSleep    = LSCP_SERVER_SLEEP;  
         pServer->pWatchdog = lscp_thread_create(_lscp_watchdog_proc, pServer, 0);  
     }  
   
548      // Finally we've some success...      // Finally we've some success...
549      return pServer;      return pServer;
550  }  }
# Line 838  lscp_status_t lscp_server_join ( lscp_se Line 564  lscp_status_t lscp_server_join ( lscp_se
564      fprintf(stderr, "lscp_server_join: pServer=%p.\n", pServer);      fprintf(stderr, "lscp_server_join: pServer=%p.\n", pServer);
565  #endif  #endif
566    
567  //  if (pServer->mode == LSCP_SERVER_THREAD) {      lscp_socket_agent_join(&(pServer->agent));
 //      lscp_thread_join(pServer->pWatchdog);  
 //      lscp_socket_agent_join(&(pServer->evt));  
 //  }  
     lscp_socket_agent_join(&(pServer->cmd));  
568    
569      return LSCP_OK;      return LSCP_OK;
570  }  }
# Line 862  lscp_status_t lscp_server_destroy ( lscp Line 584  lscp_status_t lscp_server_destroy ( lscp
584      fprintf(stderr, "lscp_server_destroy: pServer=%p.\n", pServer);      fprintf(stderr, "lscp_server_destroy: pServer=%p.\n", pServer);
585  #endif  #endif
586    
     if (pServer->mode == LSCP_SERVER_THREAD) {  
         pServer->iWatchdog = 0;  
         lscp_thread_destroy(pServer->pWatchdog);  
     }  
     lscp_socket_agent_free(&(pServer->evt));  
     lscp_socket_agent_free(&(pServer->cmd));  
587      _lscp_connect_list_free(&(pServer->connects));      _lscp_connect_list_free(&(pServer->connects));
588        lscp_socket_agent_free(&(pServer->agent));
589    
590      free(pServer);      free(pServer);
591    
# Line 877  lscp_status_t lscp_server_destroy ( lscp Line 594  lscp_status_t lscp_server_destroy ( lscp
594    
595    
596  /**  /**
597   *  Send an event message to all subscribed clients.   *  Send an event notification message to all subscribed clients.
598   *   *
599   *  @param pServer      Pointer to server instance structure.   *  @param pServer  Pointer to server instance structure.
600   *  @param pchBuffer    Pointer to data to be sent to all clients.   *  @param event    Event type flag to send to all subscribed clients.
601   *  @param cchBuffer    Length of the data to be sent in bytes.   *  @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.   *  @returns LSCP_OK on success, LSCP_FAILED otherwise.
605   */   */
606  lscp_status_t lscp_server_broadcast ( lscp_server_t *pServer, const char *pchBuffer, int cchBuffer )  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;      lscp_connect_t *p;
609        const char *pszEvent;
610        char  achBuffer[LSCP_BUFSIZ];
611        int   cchBuffer;
612    
613      if (pServer == NULL)      if (pServer == NULL)
614          return LSCP_FAILED;          return LSCP_FAILED;
615      if (pchBuffer == NULL || cchBuffer < 1)      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;          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);      lscp_mutex_lock(pServer->connects.mutex);
637    
638      for (p = pServer->connects.first; p; p = p->next) {      for (p = pServer->connects.first; p; p = p->next) {
639          if (p->port > 0 && p->ping == 0)          if (p->events & event)
640              _lscp_connect_send(p, pchBuffer, cchBuffer);              send(p->client.sock, achBuffer, cchBuffer, 0);
641      }      }
642    
643      lscp_mutex_unlock(pServer->connects.mutex);      lscp_mutex_unlock(pServer->connects.mutex);
# Line 938  lscp_status_t lscp_server_result ( lscp_ Line 677  lscp_status_t lscp_server_result ( lscp_
677   *  Register client as a subscriber of event broadcast messages.   *  Register client as a subscriber of event broadcast messages.
678   *   *
679   *  @param pConnect Pointer to client connection instance structure.   *  @param pConnect Pointer to client connection instance structure.
680   *  @param iPort    UDP port number of the requesting client connection.   *  @param event    Event type flag of the requesting client subscription.
681   *   *
682   *  @returns LSCP_OK on success, LSCP_FAILED otherwise.   *  @returns LSCP_OK on success, LSCP_FAILED otherwise.
683   */   */
684  lscp_status_t lscp_server_subscribe ( lscp_connect_t *pConnect, int iPort )  lscp_status_t lscp_server_subscribe ( lscp_connect_t *pConnect, lscp_event_t event )
685  {  {
     char szSessID[32];  
   
686      if (pConnect == NULL)      if (pConnect == NULL)
687          return LSCP_FAILED;          return LSCP_FAILED;
688      if (iPort == 0 || pConnect->port > 0 || pConnect->sessid)      if (event == LSCP_EVENT_NONE)
689          return LSCP_FAILED;          return LSCP_FAILED;
690    
691      // Generate a psudo-unique session-id.      pConnect->events |= event;
     sprintf(szSessID, "%08x", ((unsigned int) pConnect->server << 8) ^ (unsigned int) pConnect);  
   
     pConnect->port = iPort;  
     pConnect->ping = 0;  
     pConnect->sessid = strdup(szSessID);  
692    
693      return _lscp_connect_ping(pConnect);      return LSCP_OK;
694  }  }
695    
696    
697  /**  /**
698   *  Deregister client as subscriber of event broadcast messages.   *  Deregister client as subscriber of event broadcast messages.
699   *   *
700   *  @param pConnect     Pointer to client connection instance structure.   *  @param pConnect Pointer to client connection instance structure.
701   *  @param pszSessID    Session identifier of the requesting client connection.   *  @param event    Event type flag of the requesting client unsubscription.
702   *   *
703   *  @returns LSCP_OK on success, LSCP_FAILED otherwise.   *  @returns LSCP_OK on success, LSCP_FAILED otherwise.
704  */  */
705  lscp_status_t lscp_server_unsubscribe ( lscp_connect_t *pConnect, const char *pszSessID )  lscp_status_t lscp_server_unsubscribe ( lscp_connect_t *pConnect, lscp_event_t event )
706  {  {
707      if (pConnect == NULL)      if (pConnect == NULL)
708          return LSCP_FAILED;          return LSCP_FAILED;
709      if (pConnect->port == 0 || pConnect->sessid == NULL)      if (event == LSCP_EVENT_NONE)
         return LSCP_FAILED;  
   
     // Session ids must match.  
     if (strcmp(pszSessID, pConnect->sessid) != 0)  
710          return LSCP_FAILED;          return LSCP_FAILED;
711    
712      free(pConnect->sessid);      pConnect->events &= ~event;
     pConnect->sessid = NULL;  
     pConnect->ping = 0;  
     pConnect->port = 0;  
713    
714      return LSCP_OK;      return LSCP_OK;
715  }  }

Legend:
Removed from v.132  
changed lines
  Added in v.869

  ViewVC Help
Powered by ViewVC