/[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 963 by capela, Sun Dec 3 18:30:04 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 14  Line 14 
14     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15     Lesser General Public License for more details.     Lesser General Public License for more details.
16    
17     You should have received a copy of the GNU Lesser General Public     You should have received a copy of the GNU General Public License along
18     License along with this library; if not, write to the Free Software     with this program; if not, write to the Free Software Foundation, Inc.,
19     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA     51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20    
21  *****************************************************************************/  *****************************************************************************/
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 68  static void _lscp_connect_list_init ( ls Line 50  static void _lscp_connect_list_init ( ls
50  {  {
51  //  fprintf(stderr, "_lscp_connect_list_init: pList=%p.\n", pList);  //  fprintf(stderr, "_lscp_connect_list_init: pList=%p.\n", pList);
52    
53      pList->first = NULL;          pList->first = NULL;
54      pList->last  = NULL;          pList->last  = NULL;
55      pList->count = 0;          pList->count = 0;
56    
57      lscp_mutex_init(pList->mutex);          lscp_mutex_init(pList->mutex);
58  }  }
59    
60    
# Line 80  static void _lscp_connect_list_append ( Line 62  static void _lscp_connect_list_append (
62  {  {
63  //  fprintf(stderr, "_lscp_connect_list_append: pList=%p pItem=%p.\n", pList, pItem);  //  fprintf(stderr, "_lscp_connect_list_append: pList=%p pItem=%p.\n", pList, pItem);
64    
65      lscp_mutex_lock(pList->mutex);          lscp_mutex_lock(pList->mutex);
66    
67      pItem->prev = pList->last;          pItem->prev = pList->last;
68      pItem->next = NULL;          pItem->next = NULL;
69    
70      if (pList->last)          if (pList->last)
71          (pList->last)->next = pItem;                  (pList->last)->next = pItem;
72      else          else
73          pList->first = pItem;                  pList->first = pItem;
74    
75      pList->last = pItem;          pList->last = pItem;
76    
77      pList->count++;          pList->count++;
78    
79      lscp_mutex_unlock(pList->mutex);          lscp_mutex_unlock(pList->mutex);
80  }  }
81    
82    
# Line 102  static void _lscp_connect_list_remove ( Line 84  static void _lscp_connect_list_remove (
84  {  {
85  //  fprintf(stderr, "_lscp_connect_list_remove: pList=%p pItem=%p.\n", pList, pItem);  //  fprintf(stderr, "_lscp_connect_list_remove: pList=%p pItem=%p.\n", pList, pItem);
86    
87      if (pItem->next)          if (pItem->next)
88          (pItem->next)->prev = pItem->prev;                  (pItem->next)->prev = pItem->prev;
89      else          else
90          pList->last = pItem->prev;                  pList->last = pItem->prev;
91    
92      if (pItem->prev)          if (pItem->prev)
93          (pItem->prev)->next = pItem->next;                  (pItem->prev)->next = pItem->next;
94      else          else
95          pList->first = pItem->next;                  pList->first = pItem->next;
96    
97      pItem->next = NULL;          pItem->next = NULL;
98      pItem->prev = NULL;          pItem->prev = NULL;
99    
100      pList->count--;          pList->count--;
101  }  }
102    
103    
104  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 )
105  {  {
106      lscp_connect_t *p;          lscp_connect_t *p;
107    
108  //  fprintf(stderr, "_lscp_connect_list_remove_safe: pList=%p pItem=%p.\n", pList, pItem);  //  fprintf(stderr, "_lscp_connect_list_remove_safe: pList=%p pItem=%p.\n", pList, pItem);
109    
110      lscp_mutex_lock(pList->mutex);          lscp_mutex_lock(pList->mutex);
111    
112      for (p = pList->first; p; p = p->next) {          for (p = pList->first; p; p = p->next) {
113          if (p == pItem) {                  if (p == pItem) {
114              _lscp_connect_list_remove(pList, pItem);                          _lscp_connect_list_remove(pList, pItem);
115              break;                          break;
116          }                  }
117      }          }
118    
119      lscp_mutex_unlock(pList->mutex);          lscp_mutex_unlock(pList->mutex);
120  }  }
121    
122    
123  static void _lscp_connect_list_free ( lscp_connect_list_t *pList )  static void _lscp_connect_list_free ( lscp_connect_list_t *pList )
124  {  {
125      lscp_connect_t *p, *pNext;          lscp_connect_t *p, *pNext;
126    
127  //  fprintf(stderr, "_lscp_connect_list_free: pList=%p.\n", pList);  //  fprintf(stderr, "_lscp_connect_list_free: pList=%p.\n", pList);
128    
129      lscp_mutex_lock(pList->mutex);          lscp_mutex_lock(pList->mutex);
   
     for (p = pList->first; p; p = pNext) {  
         pNext = p->next;  
         _lscp_connect_list_remove(pList, p);  
         _lscp_connect_destroy(p);  
     }  
   
     lscp_mutex_unlock(pList->mutex);  
       
     lscp_mutex_destroy(pList->mutex);  
 }  
   
   
 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));  
130    
131      for (p = pList->first; p; p = p->next) {          for (p = pList->first; p; p = pNext) {
132          if (iPort == p->port && strcmp(pszAddr, inet_ntoa(p->client.addr.sin_addr)) == 0)                  pNext = p->next;
133              return p;                  _lscp_connect_list_remove(pList, p);
134      }                  _lscp_connect_destroy(p);
135            }
136      return NULL;  
137            lscp_mutex_unlock(pList->mutex);
138            
139            lscp_mutex_destroy(pList->mutex);
140  }  }
141    
142    
143  static lscp_connect_t *_lscp_connect_list_find_sock ( lscp_connect_list_t *pList, lscp_socket_t sock )  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;
146    
147  //  fprintf(stderr, "_lscp_connect_list_find_sock: pList=%p sock=%d.\n", pList, sock);  //  fprintf(stderr, "_lscp_connect_list_find_sock: pList=%p sock=%d.\n", pList, sock);
148    
149      for (p = pList->first; p; p = p->next) {          for (p = pList->first; p; p = p->next) {
150          if (sock == p->client.sock)                  if (sock == p->client.sock)
151              return p;                          return p;
152      }          }
153    
154      return NULL;          return NULL;
155  }  }
156    
157  //-------------------------------------------------------------------------  //-------------------------------------------------------------------------
# Line 194  static lscp_connect_t *_lscp_connect_lis Line 159  static lscp_connect_t *_lscp_connect_lis
159    
160  static void _lscp_connect_proc ( void *pvConnect )  static void _lscp_connect_proc ( void *pvConnect )
161  {  {
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      }          }
169    
170      (*pServer->pfnCallback)(pConnect, NULL, LSCP_CONNECT_CLOSE, pServer->pvData);          (*pServer->pfnCallback)(pConnect, NULL, LSCP_CONNECT_CLOSE, pServer->pvData);
171      _lscp_connect_list_remove_safe(&(pServer->connects), pConnect);          _lscp_connect_list_remove_safe(&(pServer->connects), pConnect);
172      closesocket(pConnect->client.sock);          closesocket(pConnect->client.sock);
173  }  }
174    
175  static lscp_connect_t *_lscp_connect_create ( lscp_server_t *pServer, lscp_socket_t sock, struct sockaddr_in *pAddr, int cAddr )  static lscp_connect_t *_lscp_connect_create ( lscp_server_t *pServer, lscp_socket_t sock, struct sockaddr_in *pAddr, int cAddr )
176  {  {
177      lscp_connect_t *pConnect;          lscp_connect_t *pConnect;
178    
179      if (pServer == NULL || sock == INVALID_SOCKET || pAddr == NULL) {          if (pServer == NULL || sock == INVALID_SOCKET || pAddr == NULL) {
180          fprintf(stderr, "_lscp_connect_create: Invalid connection arguments.\n");                  fprintf(stderr, "_lscp_connect_create: Invalid connection arguments.\n");
181          return NULL;                  return NULL;
182      }          }
183    
184      pConnect = (lscp_connect_t *) malloc(sizeof(lscp_connect_t));          pConnect = (lscp_connect_t *) malloc(sizeof(lscp_connect_t));
185      if (pConnect == NULL) {          if (pConnect == NULL) {
186          fprintf(stderr, "_lscp_connect_create: Out of memory.\n");                  fprintf(stderr, "_lscp_connect_create: Out of memory.\n");
187          closesocket(sock);                  closesocket(sock);
188          return NULL;                  return NULL;
189      }          }
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));
197  #endif  #endif
198    
199      lscp_socket_agent_init(&(pConnect->client), sock, pAddr, cAddr);          lscp_socket_agent_init(&(pConnect->client), sock, pAddr, cAddr);
200    
201      if (pServer->mode == LSCP_SERVER_THREAD) {          if (pServer->mode == LSCP_SERVER_THREAD) {
202          if (lscp_socket_agent_start(&(pConnect->client), _lscp_connect_proc, pConnect, 0) != LSCP_OK) {                  if (lscp_socket_agent_start(&(pConnect->client), _lscp_connect_proc, pConnect, 0) != LSCP_OK) {
203              closesocket(sock);                          closesocket(sock);
204              free(pConnect);                          free(pConnect);
205              return NULL;                          return NULL;
206          }                  }
207      }          }
208    
209      return pConnect;          return pConnect;
210  }  }
211    
212    
213  static lscp_status_t _lscp_connect_destroy ( lscp_connect_t *pConnect )  static lscp_status_t _lscp_connect_destroy ( lscp_connect_t *pConnect )
214  {  {
215      lscp_status_t ret = LSCP_FAILED;          lscp_status_t ret = LSCP_FAILED;
216    
217      if (pConnect == NULL)          if (pConnect == NULL)
218          return ret;                  return ret;
219    
220  #ifdef DEBUG  #ifdef DEBUG
221      fprintf(stderr, "_lscp_connect_destroy: pConnect=%p.\n", pConnect);          fprintf(stderr, "_lscp_connect_destroy: pConnect=%p.\n", pConnect);
222  #endif  #endif
223    
224      lscp_socket_agent_free(&(pConnect->client));          lscp_socket_agent_free(&(pConnect->client));
   
     if (pConnect->sessid)  
         free(pConnect->sessid);  
225    
226      free(pConnect);          free(pConnect);
227    
228      return ret;          return ret;
229  }  }
230    
231    
232  lscp_status_t _lscp_connect_recv ( lscp_connect_t *pConnect )  lscp_status_t _lscp_connect_recv ( lscp_connect_t *pConnect )
233  {  {
234      lscp_status_t ret = LSCP_FAILED;          lscp_status_t ret = LSCP_FAILED;
235      lscp_server_t *pServer;          lscp_server_t *pServer;
236      char achBuffer[LSCP_BUFSIZ];          char achBuffer[LSCP_BUFSIZ];
237      int cchBuffer;          int cchBuffer;
238    
239      if (pConnect == NULL)          if (pConnect == NULL)
240          return ret;                  return ret;
241    
242      pServer = pConnect->server;          pServer = pConnect->server;
243      if (pServer == NULL)          if (pServer == NULL)
244          return ret;                  return ret;
245    
246      cchBuffer = recv(pConnect->client.sock, achBuffer, sizeof(achBuffer), 0);          cchBuffer = recv(pConnect->client.sock, achBuffer, sizeof(achBuffer), 0);
247      if (cchBuffer > 0)          if (cchBuffer > 0)
248          ret = (*pServer->pfnCallback)(pConnect, achBuffer, cchBuffer, pServer->pvData);                  ret = (*pServer->pfnCallback)(pConnect, achBuffer, cchBuffer, pServer->pvData);
249      else if (cchBuffer < 0)          else if (cchBuffer < 0)
250          lscp_socket_perror("_lscp_connect_recv: recv");                  lscp_socket_perror("_lscp_connect_recv: recv");
   
     return ret;  
 }  
   
   
 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];  
251    
252      if (pConnect == NULL)          return ret;
         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));  
253  }  }
254    
255    
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) {
279                  _lscp_connect_list_append(&(pServer->connects), pConnect);                                  _lscp_connect_list_append(&(pServer->connects), pConnect);
280                  (*pServer->pfnCallback)(pConnect, NULL, LSCP_CONNECT_OPEN, pServer->pvData);                                  (*pServer->pfnCallback)(pConnect, NULL, LSCP_CONNECT_OPEN, pServer->pvData);
281              }                          }
282          }                  }
283      }          }
284    
285  #ifdef DEBUG  #ifdef DEBUG
286      fprintf(stderr, "_lscp_server_thread_proc: Server closing.\n");          fprintf(stderr, "_lscp_server_thread_proc: Server closing.\n");
287  #endif  #endif
288  }  }
289    
290    
291  static void _lscp_server_select_proc ( lscp_server_t *pServer )  static void _lscp_server_select_proc ( lscp_server_t *pServer )
292  {  {
293      fd_set master_fds;  // Master file descriptor list.          fd_set master_fds;  // Master file descriptor list.
294      fd_set select_fds;  // temp file descriptor list for select().          fd_set select_fds;  // temp file descriptor list for select().
295      int fd, fdmax;      // Maximum file descriptor number.          int fd, fdmax;      // Maximum file descriptor number.
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    
299      struct timeval tv1, tv2;    // To compute delta timeouts.          lscp_socket_t sock;
300            struct sockaddr_in addr;
301      lscp_socket_t sock;          socklen_t cAddr;
302      struct sockaddr_in addr;          lscp_connect_t *pConnect;
303      int cAddr;  
304      lscp_connect_t *pConnect;  #ifdef DEBUG
305            fprintf(stderr, "_lscp_server_select_proc: Server listening for connections.\n");
306  #ifdef DEBUG  #endif
307      fprintf(stderr, "_lscp_server_select_proc: Server listening for connections.\n");          FD_ZERO(&master_fds);
308  #endif          FD_ZERO(&select_fds);
309      FD_ZERO(&master_fds);  
310      FD_ZERO(&select_fds);          // Add the listener to the master set
311            FD_SET((unsigned int) pServer->agent.sock, &master_fds);
312      // Add the listeners to the master set  
313      FD_SET((unsigned int) pServer->cmd.sock, &master_fds);          // Keep track of the biggest file descriptor;
314      FD_SET((unsigned int) pServer->evt.sock, &master_fds);          // So far, it's ourself, the listener.
315            fdmax = (int) pServer->agent.sock;
316      // Keep track of the biggest file descriptor;  
317      // So far, it's ourself, the listener.          // Main loop...
318      if ((int) pServer->evt.sock > (int) pServer->cmd.sock)          while (pServer->agent.iState) {
319          fdmax = (int) pServer->evt.sock;  
320      else                  // Use a copy of the master.
321          fdmax = (int) pServer->cmd.sock;                  select_fds = master_fds;
322                    // Use the timeout feature for watchdoggin.
323      // To start counting for regular watchdog simulation.                  tv.tv_sec = LSCP_SERVER_SLEEP;
324      gettimeofday(&tv1, NULL);                  tv.tv_usec = 0;
325      gettimeofday(&tv2, NULL);                  // Wait for events...
326                    iSelect = select(fdmax + 1, &select_fds, NULL, NULL, &tv);
327      // Main loop...  
328      while (pServer->cmd.iState) {                  if (iSelect < 0) {
329                            lscp_socket_perror("_lscp_server_select_proc: select");
330          // Use a copy of the master.                          pServer->agent.iState = 0;
331          select_fds = master_fds;                  }
332          // Use the timeout feature for watchdoggin.                  else if (iSelect > 0) {
333          tv.tv_sec = LSCP_SERVER_SLEEP - (tv2.tv_sec - tv1.tv_sec);                          // Run through the existing connections looking for data to read...
334          tv.tv_usec = 0;                          for (fd = 0; fd < fdmax + 1; fd++) {
335          // Wait for events...                                  if (FD_ISSET(fd, &select_fds)) {    // We got one!!
336          iSelect = select(fdmax + 1, &select_fds, NULL, NULL, &tv);                                          // Is it ourselves, the command listener?
337                                            if (fd == (int) pServer->agent.sock) {
338          // Check later id it's time for ping time...                                                  // Accept the connection...
339          gettimeofday(&tv2, NULL);                                                  cAddr = sizeof(struct sockaddr_in);
340                                                    sock = accept(pServer->agent.sock, (struct sockaddr *) &addr, &cAddr);
341          if (iSelect < 0) {                                                  if (sock == INVALID_SOCKET) {
342              lscp_socket_perror("_lscp_server_select_proc: select");                                                          lscp_socket_perror("_lscp_server_select_proc: accept");
343              pServer->cmd.iState = 0;                                                          pServer->agent.iState = 0;
344          }                                                  } else {
345          else if (iSelect > 0) {                                                          // Add to master set.
346              // Run through the existing connections looking for data to read...                                                          FD_SET((unsigned int) sock, &master_fds);
347              for (fd = 0; fd < fdmax + 1; fd++) {                                                          // Keep track of the maximum.
348                  if (FD_ISSET(fd, &select_fds)) {    // We got one!!                                                          if ((int) sock > fdmax)
349                      // Is it ourselves, the command listener?                                                                  fdmax = (int) sock;
350                      if (fd == (int) pServer->cmd.sock) {                                                          // And do create the client connection entry.
351                          // Accept the connection...                                                          pConnect = _lscp_connect_create(pServer, sock, &addr, cAddr);
352                          cAddr = sizeof(struct sockaddr_in);                                                          if (pConnect) {
353                          sock = accept(pServer->cmd.sock, (struct sockaddr *) &addr, &cAddr);                                                                  _lscp_connect_list_append(&(pServer->connects), pConnect);
354                          if (sock == INVALID_SOCKET) {                                                                  (*pServer->pfnCallback)(pConnect, NULL, LSCP_CONNECT_OPEN, pServer->pvData);
355                              lscp_socket_perror("_lscp_server_select_proc: accept");                                                          }
356                              pServer->cmd.iState = 0;                                                  }
357                          } else {                                                  // Done with one new connection.
358                              // Add to master set.                                          } else {
359                              FD_SET((unsigned int) sock, &master_fds);                                                  // Otherwise it's trivial transaction...
360                              // Keep track of the maximum.                                                  lscp_mutex_lock(pServer->connects.mutex);
361                              if ((int) sock > fdmax)                                                  // Find the connection on our cache...
362                                  fdmax = (int) sock;                                                  pConnect = _lscp_connect_list_find_sock(&(pServer->connects), (lscp_socket_t) fd);
363                              // And do create the client connection entry.                                                  // Handle data from a client.
364                              pConnect = _lscp_connect_create(pServer, sock, &addr, cAddr);                                                  if (_lscp_connect_recv(pConnect) != LSCP_OK) {
365                              if (pConnect) {                                                          // Say bye bye!
366                                  _lscp_connect_list_append(&(pServer->connects), pConnect);                                                          if (pConnect) {
367                                  (*pServer->pfnCallback)(pConnect, NULL, LSCP_CONNECT_OPEN, pServer->pvData);                                                                  (*pServer->pfnCallback)(pConnect, NULL, LSCP_CONNECT_CLOSE, pServer->pvData);
368                              }                                                                  _lscp_connect_list_remove(&(pServer->connects), pConnect);
369                          }                                                                  _lscp_connect_destroy(pConnect);
370                          // Done with one new connection.                                                          }
371                      } else if (fd == (int) pServer->evt.sock) {                                                          // Remove from master set.
372                          // Or from the event listener?                                                          FD_CLR((unsigned int) fd, &master_fds);
373                          if (_lscp_server_evt_recv(pServer) != LSCP_OK)                                                  }
374                              pServer->cmd.iState = 0;                                                  lscp_mutex_unlock(pServer->connects.mutex);
375                          // Done with event transaction.                                          }
376                      } else {                                  }
377                          // Otherwise it's trivial transaction...                          }
378                          lscp_mutex_lock(pServer->connects.mutex);                          // Done (iSelect > 0)
379                          // Find the connection on our cache...                  }
380                          pConnect = _lscp_connect_list_find_sock(&(pServer->connects), (lscp_socket_t) fd);          }
381                          // Handle data from a client.  
382                          if (_lscp_connect_recv(pConnect) != LSCP_OK) {  #ifdef DEBUG
383                              // Say bye bye!          fprintf(stderr, "_lscp_server_select_proc: Server closing.\n");
384                              if (pConnect) {  #endif
385                                  (*pServer->pfnCallback)(pConnect, NULL, LSCP_CONNECT_CLOSE, pServer->pvData);  }
386                                  _lscp_connect_list_remove(&(pServer->connects), pConnect);  
387                                  _lscp_connect_destroy(pConnect);  
388                              }  static void _lscp_server_agent_proc ( void *pvServer )
389                              // Remove from master set.  {
390                              FD_CLR((unsigned int) fd, &master_fds);          lscp_server_t *pServer = (lscp_server_t *) pvServer;
391                          }  
392                          lscp_mutex_unlock(pServer->connects.mutex);          if (pServer->mode == LSCP_SERVER_THREAD)
393                      }                  _lscp_server_thread_proc(pServer);
394                  }          else
395              }                  _lscp_server_select_proc(pServer);
             // Done (iSelect > 0)  
         }  
   
         // 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);  
         }  
     }  
   
 #ifdef DEBUG  
     fprintf(stderr, "_lscp_server_select_proc: Server closing.\n");  
 #endif  
 }  
   
   
 static void _lscp_server_cmd_proc ( void *pvServer )  
 {  
     lscp_server_t *pServer = (lscp_server_t *) pvServer;  
   
     if (pServer->mode == LSCP_SERVER_THREAD)  
         _lscp_server_thread_proc(pServer);  
     else  
         _lscp_server_select_proc(pServer);  
 }  
   
   
 //-------------------------------------------------------------------------  
 // 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  
396  }  }
397    
398    
# Line 637  const char* lscp_server_build   (void) { Line 427  const char* lscp_server_build   (void) {
427   */   */
428  lscp_server_t* lscp_server_create ( int iPort, lscp_server_proc_t pfnCallback, void *pvData )  lscp_server_t* lscp_server_create ( int iPort, lscp_server_proc_t pfnCallback, void *pvData )
429  {  {
430      return lscp_server_create_ex(iPort, pfnCallback, pvData, LSCP_SERVER_SELECT);          return lscp_server_create_ex(iPort, pfnCallback, pvData, LSCP_SERVER_SELECT);
431  }  }
432    
433    
# Line 662  lscp_server_t* lscp_server_create ( int Line 452  lscp_server_t* lscp_server_create ( int
452   */   */
453  lscp_server_t* lscp_server_create_ex ( int iPort, lscp_server_proc_t pfnCallback, void *pvData, lscp_server_mode_t mode )  lscp_server_t* lscp_server_create_ex ( int iPort, lscp_server_proc_t pfnCallback, void *pvData, lscp_server_mode_t mode )
454  {  {
455      lscp_server_t *pServer;          lscp_server_t *pServer;
456      lscp_socket_t sock;          lscp_socket_t sock;
457      struct sockaddr_in addr;          struct sockaddr_in addr;
458      int cAddr;          socklen_t cAddr;
459      int iSockOpt = (-1);          int iSockOpt = (-1);
460    
461      if (pfnCallback == NULL) {          if (pfnCallback == NULL) {
462          fprintf(stderr, "lscp_server_create: Invalid server callback function.\n");                  fprintf(stderr, "lscp_server_create: Invalid server callback function.\n");
463          return NULL;                  return NULL;
464      }          }
465    
466      // Allocate server descriptor...          // Allocate server descriptor...
467    
468      pServer = (lscp_server_t *) malloc(sizeof(lscp_server_t));          pServer = (lscp_server_t *) malloc(sizeof(lscp_server_t));
469      if (pServer == NULL) {          if (pServer == NULL) {
470          fprintf(stderr, "lscp_server_create: Out of memory.\n");                  fprintf(stderr, "lscp_server_create: Out of memory.\n");
471          return NULL;                  return NULL;
472      }          }
473      memset(pServer, 0, sizeof(lscp_server_t));          memset(pServer, 0, sizeof(lscp_server_t));
474    
475      _lscp_connect_list_init(&(pServer->connects));          _lscp_connect_list_init(&(pServer->connects));
476    
477      pServer->mode = mode;          pServer->mode = mode;
478      pServer->pfnCallback = pfnCallback;          pServer->pfnCallback = pfnCallback;
479      pServer->pvData = pvData;          pServer->pvData = pvData;
480    
481  #ifdef DEBUG  #ifdef DEBUG
482      fprintf(stderr, "lscp_server_create: pServer=%p: iPort=%d.\n", pServer, iPort);          fprintf(stderr, "lscp_server_create: pServer=%p: iPort=%d.\n", pServer, iPort);
483  #endif  #endif
484    
485      // Prepare the command stream server socket...          // Prepare the command stream server socket...
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
500    
501    #ifdef DEBUG
502            lscp_socket_getopts("lscp_server_create", sock);
503  #endif  #endif
504    
505            cAddr = sizeof(struct sockaddr_in);
506            memset((char *) &addr, 0, cAddr);
507            addr.sin_family = AF_INET;
508            addr.sin_addr.s_addr = htonl(INADDR_ANY);
509            addr.sin_port = htons((short) iPort);
510    
511            if (bind(sock, (const struct sockaddr *) &addr, cAddr) == SOCKET_ERROR) {
512                    lscp_socket_perror("lscp_server_create: bind");
513                    closesocket(sock);
514                    free(pServer);
515                    return NULL;
516            }
517    
518            if (listen(sock, 10) == SOCKET_ERROR) {
519                    lscp_socket_perror("lscp_server_create: listen");
520                    closesocket(sock);
521                    free(pServer);
522                    return NULL;
523            }
524    
525            if (iPort == 0) {
526                    if (getsockname(sock, (struct sockaddr *) &addr, &cAddr) == SOCKET_ERROR) {
527                            lscp_socket_perror("lscp_server_create: getsockname");
528                            closesocket(sock);
529                            free(pServer);
530                    }
531            }
532    
533            lscp_socket_agent_init(&(pServer->agent), sock, &addr, cAddr);
534    
535  #ifdef DEBUG  #ifdef DEBUG
536      lscp_socket_getopts("lscp_server_create: cmd", sock);          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      cAddr = sizeof(struct sockaddr_in);          // Now's finally time to startup threads...
     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: cmd: bind");  
         closesocket(sock);  
         free(pServer);  
         return NULL;  
     }  
   
     if (listen(sock, 10) == SOCKET_ERROR) {  
         lscp_socket_perror("lscp_server_create: cmd: 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));  
         closesocket(sock);  
         free(pServer);  
         return NULL;  
     }  
   
     if (iPort == 0) {  
         if (getsockname(sock, (struct sockaddr *) &addr, &cAddr) == SOCKET_ERROR) {  
             lscp_socket_perror("lscp_server_create: evt: getsockname");  
             lscp_socket_agent_free(&(pServer->cmd));  
             closesocket(sock);  
             free(pServer);  
             return NULL;  
         }  
     }  
   
     lscp_socket_agent_init(&(pServer->evt), sock, &addr, cAddr);  
   
 #ifdef DEBUG  
     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));  
 #endif  
   
     // Now's finally time to startup threads...  
   
     // Command service thread...  
     if (lscp_socket_agent_start(&(pServer->cmd), _lscp_server_cmd_proc, pServer, 0) != LSCP_OK) {  
         lscp_socket_agent_free(&(pServer->cmd));  
         lscp_socket_agent_free(&(pServer->evt));  
         free(pServer);  
         return NULL;  
     }  
   
     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);  
     }  
540    
541      // Finally we've some success...          // Command service thread...
542      return pServer;          if (lscp_socket_agent_start(&(pServer->agent), _lscp_server_agent_proc, pServer, 0) != LSCP_OK) {
543                    lscp_socket_agent_free(&(pServer->agent));
544                    free(pServer);
545                    return NULL;
546            }
547    
548            // Finally we've some success...
549            return pServer;
550  }  }
551    
552    
# Line 831  lscp_server_t* lscp_server_create_ex ( i Line 557  lscp_server_t* lscp_server_create_ex ( i
557   */   */
558  lscp_status_t lscp_server_join ( lscp_server_t *pServer )  lscp_status_t lscp_server_join ( lscp_server_t *pServer )
559  {  {
560      if (pServer == NULL)          if (pServer == NULL)
561          return LSCP_FAILED;                  return LSCP_FAILED;
562    
563  #ifdef DEBUG  #ifdef DEBUG
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  }  }
571    
572    
# Line 855  lscp_status_t lscp_server_join ( lscp_se Line 577  lscp_status_t lscp_server_join ( lscp_se
577   */   */
578  lscp_status_t lscp_server_destroy ( lscp_server_t *pServer )  lscp_status_t lscp_server_destroy ( lscp_server_t *pServer )
579  {  {
580      if (pServer == NULL)          if (pServer == NULL)
581          return LSCP_FAILED;                  return LSCP_FAILED;
582    
583  #ifdef DEBUG  #ifdef DEBUG
584      fprintf(stderr, "lscp_server_destroy: pServer=%p.\n", pServer);          fprintf(stderr, "lscp_server_destroy: pServer=%p.\n", pServer);
585  #endif  #endif
586    
587      if (pServer->mode == LSCP_SERVER_THREAD) {          _lscp_connect_list_free(&(pServer->connects));
588          pServer->iWatchdog = 0;          lscp_socket_agent_free(&(pServer->agent));
         lscp_thread_destroy(pServer->pWatchdog);  
     }  
     lscp_socket_agent_free(&(pServer->evt));  
     lscp_socket_agent_free(&(pServer->cmd));  
     _lscp_connect_list_free(&(pServer->connects));  
589    
590      free(pServer);          free(pServer);
591    
592      return LSCP_OK;          return LSCP_OK;
593  }  }
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      if (pServer == NULL)          char  achBuffer[LSCP_BUFSIZ];
611          return LSCP_FAILED;          int   cchBuffer;
612      if (pchBuffer == NULL || cchBuffer < 1)  
613          return LSCP_FAILED;          if (pServer == NULL)
614                    return LSCP_FAILED;
615            if (pchData == NULL || cchData < 1)
616                    return LSCP_FAILED;
617    
618            // Which (single) event?
619            pszEvent = lscp_event_to_text(event);
620            if (pszEvent == NULL)
621                    return LSCP_FAILED;
622    
623            // Build the event message string...
624            cchBuffer = sprintf(achBuffer, "NOTIFY:%s:", pszEvent);
625            if (pchData) {
626                    if (cchData > LSCP_BUFSIZ - cchBuffer - 2)
627                            cchData = LSCP_BUFSIZ - cchBuffer - 2;
628                    strncpy(&achBuffer[cchBuffer], pchData, cchData);
629                    cchBuffer += cchData;
630            }
631            achBuffer[cchBuffer++] = '\r';
632            achBuffer[cchBuffer++] = '\n';
633    
634            // And do the direct broadcasting...
635            
636            lscp_mutex_lock(pServer->connects.mutex);
637    
638            for (p = pServer->connects.first; p; p = p->next) {
639                    if (p->events & event)
640                            send(p->client.sock, achBuffer, cchBuffer, 0);
641            }
642    
643      lscp_mutex_lock(pServer->connects.mutex);          lscp_mutex_unlock(pServer->connects.mutex);
644    
645      for (p = pServer->connects.first; p; p = p->next) {          return LSCP_OK;
         if (p->port > 0 && p->ping == 0)  
             _lscp_connect_send(p, pchBuffer, cchBuffer);  
     }  
   
     lscp_mutex_unlock(pServer->connects.mutex);  
   
     return LSCP_OK;  
646  }  }
647    
648    
# Line 918  lscp_status_t lscp_server_broadcast ( ls Line 657  lscp_status_t lscp_server_broadcast ( ls
657   */   */
658  lscp_status_t lscp_server_result ( lscp_connect_t *pConnect, const char *pchBuffer, int cchBuffer )  lscp_status_t lscp_server_result ( lscp_connect_t *pConnect, const char *pchBuffer, int cchBuffer )
659  {  {
660      lscp_status_t ret = LSCP_FAILED;          lscp_status_t ret = LSCP_FAILED;
661    
662      if (pConnect == NULL)          if (pConnect == NULL)
663          return ret;                  return ret;
664      if (pchBuffer == NULL || cchBuffer < 1)          if (pchBuffer == NULL || cchBuffer < 1)
665          return ret;                  return ret;
666    
667      if (send(pConnect->client.sock, pchBuffer, cchBuffer, 0) != cchBuffer)          if (send(pConnect->client.sock, pchBuffer, cchBuffer, 0) != cchBuffer)
668          lscp_socket_perror("lscp_server_result");                  lscp_socket_perror("lscp_server_result");
669      else          else
670          ret = LSCP_OK;                  ret = LSCP_OK;
671    
672      return ret;          return ret;
673  }  }
674    
675    
# 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  {  {
686      char szSessID[32];          if (pConnect == NULL)
687                    return LSCP_FAILED;
688      if (pConnect == NULL)          if (event == LSCP_EVENT_NONE)
689          return LSCP_FAILED;                  return LSCP_FAILED;
     if (iPort == 0 || pConnect->port > 0 || pConnect->sessid)  
         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);  
692    
693      pConnect->port = iPort;          return LSCP_OK;
     pConnect->ping = 0;  
     pConnect->sessid = strdup(szSessID);  
   
     return _lscp_connect_ping(pConnect);  
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)
710          return LSCP_FAILED;                  return LSCP_FAILED;
711    
712      // Session ids must match.          pConnect->events &= ~event;
     if (strcmp(pszSessID, pConnect->sessid) != 0)  
         return LSCP_FAILED;  
   
     free(pConnect->sessid);  
     pConnect->sessid = NULL;  
     pConnect->ping = 0;  
     pConnect->port = 0;  
713    
714      return LSCP_OK;          return LSCP_OK;
715  }  }
716    
717    

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

  ViewVC Help
Powered by ViewVC