/[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 98 by capela, Tue Jun 1 11:13:56 2004 UTC revision 178 by capela, Tue Jul 6 15:52:25 2004 UTC
# 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_udp_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_tcp_proc           (void *pvServer);  static void             _lscp_server_agent_proc         (void *pvServer);
 static void             _lscp_server_udp_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->tcp.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    
226      if (pConnect->sessid)  #ifdef DEBUG
227          free(pConnect->sessid);      fprintf(stderr, "<%p> Done.\n", pConnect);
228    #endif
229    
230      free(pConnect);      free(pConnect);
231    
# Line 290  lscp_status_t _lscp_connect_recv ( lscp_ Line 257  lscp_status_t _lscp_connect_recv ( lscp_
257  }  }
258    
259    
 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)->udp.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)->udp.addr.sin_port), pConnect->sessid);  
   
     return _lscp_connect_send(pConnect, szBuffer, strlen(szBuffer));  
 }  
   
   
260  //-------------------------------------------------------------------------  //-------------------------------------------------------------------------
261  // TCP service (stream oriented).  // Command service (stream oriented).
   
 static lscp_status_t _lscp_server_udp_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->udp.sock, achBuffer, sizeof(achBuffer), 0, (struct sockaddr *) &addr, &cAddr);  
     if (cchBuffer > 0) {  
 #ifdef DEBUG  
         lscp_socket_trace("_lscp_server_udp_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_udp_recv: recvfrom");  
   
     return ret;  
 }  
   
262    
263  static void _lscp_server_thread_proc ( lscp_server_t *pServer )  static void _lscp_server_thread_proc ( lscp_server_t *pServer )
264  {  {
# Line 378  static void _lscp_server_thread_proc ( l Line 271  static void _lscp_server_thread_proc ( l
271      fprintf(stderr, "_lscp_server_thread_proc: Server listening for connections.\n");      fprintf(stderr, "_lscp_server_thread_proc: Server listening for connections.\n");
272  #endif  #endif
273    
274      while (pServer->tcp.iState) {      while (pServer->agent.iState) {
275          cAddr = sizeof(struct sockaddr_in);          cAddr = sizeof(struct sockaddr_in);
276          sock = accept(pServer->tcp.sock, (struct sockaddr *) &addr, &cAddr);          sock = accept(pServer->agent.sock, (struct sockaddr *) &addr, &cAddr);
277          if (sock == INVALID_SOCKET) {          if (sock == INVALID_SOCKET) {
278              lscp_socket_perror("_lscp_server_thread_proc: accept");              lscp_socket_perror("_lscp_server_thread_proc: accept");
279              pServer->tcp.iState = 0;              pServer->agent.iState = 0;
280          } else {          } else {
281              pConnect = _lscp_connect_create(pServer, sock, &addr, cAddr);              pConnect = _lscp_connect_create(pServer, sock, &addr, cAddr);
282              if (pConnect) {              if (pConnect) {
# Line 407  static void _lscp_server_select_proc ( l Line 300  static void _lscp_server_select_proc ( l
300      struct timeval tv;  // For specifying a timeout value.      struct timeval tv;  // For specifying a timeout value.
301      int iSelect;        // Holds select return status.      int iSelect;        // Holds select return status.
302    
     struct timeval tv1, tv2;    // To compute delta timeouts.  
   
303      lscp_socket_t sock;      lscp_socket_t sock;
304      struct sockaddr_in addr;      struct sockaddr_in addr;
305      int cAddr;      int cAddr;
# Line 420  static void _lscp_server_select_proc ( l Line 311  static void _lscp_server_select_proc ( l
311      FD_ZERO(&master_fds);      FD_ZERO(&master_fds);
312      FD_ZERO(&select_fds);      FD_ZERO(&select_fds);
313    
314      // Add the listeners to the master set      // Add the listener to the master set
315      FD_SET((unsigned int) pServer->tcp.sock, &master_fds);      FD_SET((unsigned int) pServer->agent.sock, &master_fds);
     FD_SET((unsigned int) pServer->udp.sock, &master_fds);  
316    
317      // Keep track of the biggest file descriptor;      // Keep track of the biggest file descriptor;
318      // So far, it's ourself, the listener.      // So far, it's ourself, the listener.
319      if ((int) pServer->udp.sock > (int) pServer->tcp.sock)      fdmax = (int) pServer->agent.sock;
         fdmax = (int) pServer->udp.sock;  
     else  
         fdmax = (int) pServer->tcp.sock;  
   
     // To start counting for regular watchdog simulation.  
     gettimeofday(&tv1, NULL);  
     gettimeofday(&tv2, NULL);  
320    
321      // Main loop...      // Main loop...
322      while (pServer->tcp.iState) {      while (pServer->agent.iState) {
323    
324          // Use a copy of the master.          // Use a copy of the master.
325          select_fds = master_fds;          select_fds = master_fds;
326          // Use the timeout feature for watchdoggin.          // Use the timeout feature for watchdoggin.
327          tv.tv_sec = LSCP_SERVER_SLEEP - (tv2.tv_sec - tv1.tv_sec);          tv.tv_sec = LSCP_SERVER_SLEEP;
328          tv.tv_usec = 0;          tv.tv_usec = 0;
329          // Wait for events...          // Wait for events...
330          iSelect = select(fdmax + 1, &select_fds, NULL, NULL, &tv);          iSelect = select(fdmax + 1, &select_fds, NULL, NULL, &tv);
331    
         // Check later id it's time for ping time...  
         gettimeofday(&tv2, NULL);  
   
332          if (iSelect < 0) {          if (iSelect < 0) {
333              lscp_socket_perror("_lscp_server_select_proc: select");              lscp_socket_perror("_lscp_server_select_proc: select");
334              pServer->tcp.iState = 0;              pServer->agent.iState = 0;
335          }          }
336          else if (iSelect > 0) {          else if (iSelect > 0) {
337              // Run through the existing connections looking for data to read...              // Run through the existing connections looking for data to read...
338              for (fd = 0; fd < fdmax + 1; fd++) {              for (fd = 0; fd < fdmax + 1; fd++) {
339                  if (FD_ISSET(fd, &select_fds)) {    // We got one!!                  if (FD_ISSET(fd, &select_fds)) {    // We got one!!
340                      // Is it ourselves, the TCP listener?                      // Is it ourselves, the command listener?
341                      if (fd == (int) pServer->tcp.sock) {                      if (fd == (int) pServer->agent.sock) {
342                          // Accept the connection...                          // Accept the connection...
343                          cAddr = sizeof(struct sockaddr_in);                          cAddr = sizeof(struct sockaddr_in);
344                          sock = accept(pServer->tcp.sock, (struct sockaddr *) &addr, &cAddr);                          sock = accept(pServer->agent.sock, (struct sockaddr *) &addr, &cAddr);
345                          if (sock == INVALID_SOCKET) {                          if (sock == INVALID_SOCKET) {
346                              lscp_socket_perror("_lscp_server_select_proc: accept");                              lscp_socket_perror("_lscp_server_select_proc: accept");
347                              pServer->tcp.iState = 0;                              pServer->agent.iState = 0;
348                          } else {                          } else {
349                              // Add to master set.                              // Add to master set.
350                              FD_SET((unsigned int) sock, &master_fds);                              FD_SET((unsigned int) sock, &master_fds);
# Line 479  static void _lscp_server_select_proc ( l Line 359  static void _lscp_server_select_proc ( l
359                              }                              }
360                          }                          }
361                          // Done with one new connection.                          // Done with one new connection.
                     } else if (fd == (int) pServer->udp.sock) {  
                         // Or to the UDP listener?  
                         if (_lscp_server_udp_recv(pServer) != LSCP_OK)  
                             pServer->tcp.iState = 0;  
                         // Done with UDP transaction.  
362                      } else {                      } else {
363                          // Otherwise it's trivial transaction...                          // Otherwise it's trivial transaction...
364                          lscp_mutex_lock(pServer->connects.mutex);                          lscp_mutex_lock(pServer->connects.mutex);
# Line 506  static void _lscp_server_select_proc ( l Line 381  static void _lscp_server_select_proc ( l
381              }              }
382              // Done (iSelect > 0)              // Done (iSelect > 0)
383          }          }
   
         // 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);  
         }  
384      }      }
385    
386  #ifdef DEBUG  #ifdef DEBUG
# Line 522  static void _lscp_server_select_proc ( l Line 389  static void _lscp_server_select_proc ( l
389  }  }
390    
391    
392  static void _lscp_server_tcp_proc ( void *pvServer )  static void _lscp_server_agent_proc ( void *pvServer )
393  {  {
394      lscp_server_t *pServer = (lscp_server_t *) pvServer;      lscp_server_t *pServer = (lscp_server_t *) pvServer;
395    
# Line 534  static void _lscp_server_tcp_proc ( void Line 401  static void _lscp_server_tcp_proc ( void
401    
402    
403  //-------------------------------------------------------------------------  //-------------------------------------------------------------------------
 // UDP service (datagram oriented).  
   
 static void _lscp_server_udp_proc ( void *pvServer )  
 {  
     lscp_server_t *pServer = (lscp_server_t *) pvServer;  
   
 #ifdef DEBUG  
     fprintf(stderr, "_lscp_server_udp_proc: Server waiting for events.\n");  
 #endif  
   
     while (pServer->udp.iState) {  
         if (_lscp_server_udp_recv(pServer) != LSCP_OK)  
             pServer->udp.iState = 0;  
     }  
   
 #ifdef DEBUG  
     fprintf(stderr, "_lscp_server_udp_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  
 }  
   
   
 //-------------------------------------------------------------------------  
404  // Server versioning teller fuunction.  // Server versioning teller fuunction.
405    
406  /** Retrieve the current server library version string. */  /** Retrieve the current server library version string. */
# Line 692  lscp_server_t* lscp_server_create_ex ( i Line 486  lscp_server_t* lscp_server_create_ex ( i
486      fprintf(stderr, "lscp_server_create: pServer=%p: iPort=%d.\n", pServer, iPort);      fprintf(stderr, "lscp_server_create: pServer=%p: iPort=%d.\n", pServer, iPort);
487  #endif  #endif
488    
489      // Prepare the TCP stream server socket...      // Prepare the command stream server socket...
490    
491      sock = socket(AF_INET, SOCK_STREAM, 0);      sock = socket(AF_INET, SOCK_STREAM, 0);
492      if (sock == INVALID_SOCKET) {      if (sock == INVALID_SOCKET) {
493          lscp_socket_perror("lscp_server_create: tcp: socket");          lscp_socket_perror("lscp_server_create: socket");
494          free(pServer);          free(pServer);
495          return NULL;          return NULL;
496      }      }
497    
498      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)
499          lscp_socket_perror("lscp_server_create: tcp: setsockopt(SO_REUSEADDR)");          lscp_socket_perror("lscp_server_create: setsockopt(SO_REUSEADDR)");
500  #if defined(WIN32)  #if defined(WIN32)
501      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)
502          lscp_socket_perror("lscp_server_create: tcp: setsockopt(SO_DONTLINGER)");          lscp_socket_perror("lscp_server_create: setsockopt(SO_DONTLINGER)");
503  #endif  #endif
504    
505  #ifdef DEBUG  #ifdef DEBUG
506      lscp_socket_getopts("lscp_server_create: tcp", sock);      lscp_socket_getopts("lscp_server_create", sock);
507  #endif  #endif
508    
509      cAddr = sizeof(struct sockaddr_in);      cAddr = sizeof(struct sockaddr_in);
# Line 719  lscp_server_t* lscp_server_create_ex ( i Line 513  lscp_server_t* lscp_server_create_ex ( i
513      addr.sin_port = htons((short) iPort);      addr.sin_port = htons((short) iPort);
514    
515      if (bind(sock, (const struct sockaddr *) &addr, cAddr) == SOCKET_ERROR) {      if (bind(sock, (const struct sockaddr *) &addr, cAddr) == SOCKET_ERROR) {
516          lscp_socket_perror("lscp_server_create: tcp: bind");          lscp_socket_perror("lscp_server_create: bind");
517          closesocket(sock);          closesocket(sock);
518          free(pServer);          free(pServer);
519          return NULL;          return NULL;
520      }      }
521    
522      if (listen(sock, 10) == SOCKET_ERROR) {      if (listen(sock, 10) == SOCKET_ERROR) {
523          lscp_socket_perror("lscp_server_create: tcp: 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: tcp: getsockname");  
             closesocket(sock);  
             free(pServer);  
         }  
         // Make TCP and UDP ports equal?  
         iPort = ntohs(addr.sin_port);  
     }  
   
     lscp_socket_agent_init(&(pServer->tcp), sock, &addr, cAddr);  
   
 #ifdef DEBUG  
     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));  
 #endif  
   
     // Prepare the UDP datagram server socket...  
   
     sock = socket(AF_INET, SOCK_DGRAM, 0);  
     if (sock == INVALID_SOCKET) {  
         lscp_socket_perror("lscp_server_create: udp: socket");  
         lscp_socket_agent_free(&(pServer->tcp));  
         free(pServer);  
         return NULL;  
     }  
   
     if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char *) &iSockOpt, sizeof(int)) == SOCKET_ERROR)  
         lscp_socket_perror("lscp_server_create: udp: setsockopt(SO_REUSEADDR)");  
   
 #ifdef DEBUG  
     lscp_socket_getopts("lscp_server_create: udp", 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: udp: bind");  
         lscp_socket_agent_free(&(pServer->tcp));  
524          closesocket(sock);          closesocket(sock);
525          free(pServer);          free(pServer);
526          return NULL;          return NULL;
# Line 781  lscp_server_t* lscp_server_create_ex ( i Line 528  lscp_server_t* lscp_server_create_ex ( i
528    
529      if (iPort == 0) {      if (iPort == 0) {
530          if (getsockname(sock, (struct sockaddr *) &addr, &cAddr) == SOCKET_ERROR) {          if (getsockname(sock, (struct sockaddr *) &addr, &cAddr) == SOCKET_ERROR) {
531              lscp_socket_perror("lscp_server_create: udp: getsockname");              lscp_socket_perror("lscp_server_create: getsockname");
             lscp_socket_agent_free(&(pServer->tcp));  
532              closesocket(sock);              closesocket(sock);
533              free(pServer);              free(pServer);
             return NULL;  
534          }          }
535      }      }
536    
537      lscp_socket_agent_init(&(pServer->udp), sock, &addr, cAddr);      lscp_socket_agent_init(&(pServer->agent), sock, &addr, cAddr);
538    
539  #ifdef DEBUG  #ifdef DEBUG
540      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));      fprintf(stderr, "lscp_server_create: sock=%d addr=%s port=%d.\n", pServer->agent.sock, inet_ntoa(pServer->agent.addr.sin_addr), ntohs(pServer->agent.addr.sin_port));
541  #endif  #endif
542    
543      // Now's finally time to startup threads...      // Now's finally time to startup threads...
544    
545      // TCP/Main service thread...      // Command service thread...
546      if (lscp_socket_agent_start(&(pServer->tcp), _lscp_server_tcp_proc, pServer, 0) != LSCP_OK) {      if (lscp_socket_agent_start(&(pServer->agent), _lscp_server_agent_proc, pServer, 0) != LSCP_OK) {
547          lscp_socket_agent_free(&(pServer->tcp));          lscp_socket_agent_free(&(pServer->agent));
         lscp_socket_agent_free(&(pServer->udp));  
548          free(pServer);          free(pServer);
549          return NULL;          return NULL;
550      }      }
551    
     if (pServer->mode == LSCP_SERVER_THREAD) {  
         // UDP service thread...  
         if (lscp_socket_agent_start(&(pServer->udp), _lscp_server_udp_proc, pServer, 0) != LSCP_OK) {  
             lscp_socket_agent_free(&(pServer->tcp));  
             lscp_socket_agent_free(&(pServer->udp));  
             free(pServer);  
             return NULL;  
         }  
         // Watchdog thread...  
         pServer->iWatchdog = 1;  
         pServer->iSleep    = LSCP_SERVER_SLEEP;  
         pServer->pWatchdog = lscp_thread_create(_lscp_watchdog_proc, pServer, 0);  
     }  
   
552      // Finally we've some success...      // Finally we've some success...
553      return pServer;      return pServer;
554  }  }
# Line 838  lscp_status_t lscp_server_join ( lscp_se Line 568  lscp_status_t lscp_server_join ( lscp_se
568      fprintf(stderr, "lscp_server_join: pServer=%p.\n", pServer);      fprintf(stderr, "lscp_server_join: pServer=%p.\n", pServer);
569  #endif  #endif
570    
571  //  if (pServer->mode == LSCP_SERVER_THREAD) {      lscp_socket_agent_join(&(pServer->agent));
 //      lscp_thread_join(pServer->pWatchdog);  
 //      lscp_socket_agent_join(&(pServer->udp));  
 //  }  
     lscp_socket_agent_join(&(pServer->tcp));  
572    
573      return LSCP_OK;      return LSCP_OK;
574  }  }
# Line 862  lscp_status_t lscp_server_destroy ( lscp Line 588  lscp_status_t lscp_server_destroy ( lscp
588      fprintf(stderr, "lscp_server_destroy: pServer=%p.\n", pServer);      fprintf(stderr, "lscp_server_destroy: pServer=%p.\n", pServer);
589  #endif  #endif
590    
     if (pServer->mode == LSCP_SERVER_THREAD) {  
         pServer->iWatchdog = 0;  
         lscp_thread_destroy(pServer->pWatchdog);  
     }  
     lscp_socket_agent_free(&(pServer->udp));  
     lscp_socket_agent_free(&(pServer->tcp));  
591      _lscp_connect_list_free(&(pServer->connects));      _lscp_connect_list_free(&(pServer->connects));
592        lscp_socket_agent_free(&(pServer->agent));
593    
594      free(pServer);      free(pServer);
595    
# Line 877  lscp_status_t lscp_server_destroy ( lscp Line 598  lscp_status_t lscp_server_destroy ( lscp
598    
599    
600  /**  /**
601   *  Send an event message to all subscribed clients.   *  Send an event notification message to all subscribed clients.
602   *   *
603   *  @param pServer      Pointer to server instance structure.   *  @param pServer  Pointer to server instance structure.
604   *  @param pchBuffer    Pointer to data to be sent to all clients.   *  @param event    Event type flag to send to all subscribed clients.
605   *  @param cchBuffer    Length of the data to be sent in bytes.   *  @param pchData  Pointer to event data to be sent to all clients.
606     *  @param cchData  Length of the event data to be sent in bytes.
607   *   *
608   *  @returns LSCP_OK on success, LSCP_FAILED otherwise.   *  @returns LSCP_OK on success, LSCP_FAILED otherwise.
609   */   */
610  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 )
611  {  {
612      lscp_connect_t *p;      lscp_connect_t *p;
613        const char *pszEvent;
614        char  achBuffer[LSCP_BUFSIZ];
615        int   cchBuffer;
616    
617      if (pServer == NULL)      if (pServer == NULL)
618          return LSCP_FAILED;          return LSCP_FAILED;
619      if (pchBuffer == NULL || cchBuffer < 1)      if (pchData == NULL || cchData < 1)
620            return LSCP_FAILED;
621    
622        // Which (single) event?
623        pszEvent = lscp_event_to_text(event);
624        if (pszEvent == NULL)
625          return LSCP_FAILED;          return LSCP_FAILED;
626    
627        // Build the event message string...
628        cchBuffer = sprintf(achBuffer, "NOTIFY:%s:", pszEvent);
629        if (pchData) {
630            if (cchData > LSCP_BUFSIZ - cchBuffer - 2)
631                cchData = LSCP_BUFSIZ - cchBuffer - 2;
632            strncpy(&achBuffer[cchBuffer], pchData, cchData);
633            cchBuffer += cchData;
634        }
635        achBuffer[cchBuffer++] = '\r';
636        achBuffer[cchBuffer++] = '\n';
637    
638        // And do the direct broadcasting...
639        
640      lscp_mutex_lock(pServer->connects.mutex);      lscp_mutex_lock(pServer->connects.mutex);
641    
642      for (p = pServer->connects.first; p; p = p->next) {      for (p = pServer->connects.first; p; p = p->next) {
643          if (p->port > 0 && p->ping == 0)          if (p->events & event)
644              _lscp_connect_send(p, pchBuffer, cchBuffer);              send(p->client.sock, achBuffer, cchBuffer, 0);
645      }      }
646    
647      lscp_mutex_unlock(pServer->connects.mutex);      lscp_mutex_unlock(pServer->connects.mutex);
# Line 937  lscp_status_t lscp_server_result ( lscp_ Line 680  lscp_status_t lscp_server_result ( lscp_
680  /**  /**
681   *  Register client as a subscriber of event broadcast messages.   *  Register client as a subscriber of event broadcast messages.
682   *   *
683   *  @param pConnect     Pointer to client connection instance structure.   *  @param pConnect Pointer to client connection instance structure.
684   *  @param iPort    UDP port number of the requesting client connection.   *  @param event    Event type flag of the requesting client subscription.
685   *   *
686   *  @returns LSCP_OK on success, LSCP_FAILED otherwise.   *  @returns LSCP_OK on success, LSCP_FAILED otherwise.
687   */   */
688  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 )
689  {  {
     char szSessID[32];  
   
690      if (pConnect == NULL)      if (pConnect == NULL)
691          return LSCP_FAILED;          return LSCP_FAILED;
692      if (iPort == 0 || pConnect->port > 0 || pConnect->sessid)      if (event == LSCP_EVENT_NONE)
693          return LSCP_FAILED;          return LSCP_FAILED;
694    
695      // Generate a psudo-unique session-id.      pConnect->events |= event;
     sprintf(szSessID, "%08x", ((unsigned int) pConnect->server << 8) ^ (unsigned int) pConnect);  
696    
697      pConnect->port = iPort;      return LSCP_OK;
     pConnect->ping = 0;  
     pConnect->sessid = strdup(szSessID);  
   
     return _lscp_connect_ping(pConnect);  
698  }  }
699    
700    
701  /**  /**
702   *  Deregister client as subscriber of event broadcast messages.   *  Deregister client as subscriber of event broadcast messages.
703   *   *
704   *  @param pConnect     Pointer to client connection instance structure.   *  @param pConnect Pointer to client connection instance structure.
705   *  @param pszSessID    Session identifier of the requesting client connection.   *  @param event    Event type flag of the requesting client unsubscription.
706   *   *
707   *  @returns LSCP_OK on success, LSCP_FAILED otherwise.   *  @returns LSCP_OK on success, LSCP_FAILED otherwise.
708  */  */
709  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 )
710  {  {
711      if (pConnect == NULL)      if (pConnect == NULL)
712          return LSCP_FAILED;          return LSCP_FAILED;
713      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)  
714          return LSCP_FAILED;          return LSCP_FAILED;
715    
716      free(pConnect->sessid);      pConnect->events &= ~event;
     pConnect->sessid = NULL;  
     pConnect->ping = 0;  
     pConnect->port = 0;  
717    
718      return LSCP_OK;      return LSCP_OK;
719  }  }

Legend:
Removed from v.98  
changed lines
  Added in v.178

  ViewVC Help
Powered by ViewVC