--- liblscp/trunk/examples/server.c 2004/06/01 11:13:56 98 +++ liblscp/trunk/examples/server.c 2004/07/06 15:52:25 178 @@ -22,8 +22,7 @@ #include "server.h" -#define LSCP_SERVER_RETRY 3 // Maximum number of unanswered PING retries. -#define LSCP_SERVER_SLEEP 30 // Period in seconds for watchdog wakeup. +#define LSCP_SERVER_SLEEP 30 // Period in seconds for watchdog wakeup (idle loop). // Local prototypes. @@ -31,35 +30,18 @@ static lscp_connect_t *_lscp_connect_create (lscp_server_t *pServer, lscp_socket_t sock, struct sockaddr_in *pAddr, int cAddr); static lscp_status_t _lscp_connect_destroy (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); static void _lscp_connect_list_append (lscp_connect_list_t *pList, lscp_connect_t *pItem); static void _lscp_connect_list_remove (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); 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); static lscp_connect_t *_lscp_connect_list_find_sock (lscp_connect_list_t *pList, lscp_socket_t sock); -static lscp_status_t _lscp_server_udp_recv (lscp_server_t *pServer); - static void _lscp_server_thread_proc (lscp_server_t *pServer); static void _lscp_server_select_proc (lscp_server_t *pServer); -static void _lscp_server_tcp_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); +static void _lscp_server_agent_proc (void *pvServer); -#if defined(WIN32) -#include -#undef gettimeofday -#define gettimeofday(p,n) {(p)->tv_sec = (long) (clock() / CLOCKS_PER_SEC); (p)->tv_usec = 0;} -#else -#include -#endif //------------------------------------------------------------------------- // Server-side client connection list methods. @@ -158,23 +140,6 @@ } -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; -} - - static lscp_connect_t *_lscp_connect_list_find_sock ( lscp_connect_list_t *pList, lscp_socket_t sock ) { lscp_connect_t *p; @@ -197,7 +162,7 @@ lscp_connect_t *pConnect = (lscp_connect_t *) pvConnect; lscp_server_t *pServer = pConnect->server; - while (pServer->tcp.iState && pConnect->client.iState) { + while (pServer->agent.iState && pConnect->client.iState) { if (_lscp_connect_recv(pConnect) != LSCP_OK) pConnect->client.iState = 0; } @@ -225,6 +190,7 @@ memset(pConnect, 0, sizeof(lscp_connect_t)); pConnect->server = pServer; + pConnect->events = LSCP_EVENT_NONE; #ifdef DEBUG 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)); @@ -257,8 +223,9 @@ lscp_socket_agent_free(&(pConnect->client)); - if (pConnect->sessid) - free(pConnect->sessid); +#ifdef DEBUG + fprintf(stderr, "<%p> Done.\n", pConnect); +#endif free(pConnect); @@ -290,82 +257,8 @@ } -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)); -} - - //------------------------------------------------------------------------- -// TCP 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; -} - +// Command service (stream oriented). static void _lscp_server_thread_proc ( lscp_server_t *pServer ) { @@ -378,12 +271,12 @@ fprintf(stderr, "_lscp_server_thread_proc: Server listening for connections.\n"); #endif - while (pServer->tcp.iState) { + while (pServer->agent.iState) { cAddr = sizeof(struct sockaddr_in); - sock = accept(pServer->tcp.sock, (struct sockaddr *) &addr, &cAddr); + sock = accept(pServer->agent.sock, (struct sockaddr *) &addr, &cAddr); if (sock == INVALID_SOCKET) { lscp_socket_perror("_lscp_server_thread_proc: accept"); - pServer->tcp.iState = 0; + pServer->agent.iState = 0; } else { pConnect = _lscp_connect_create(pServer, sock, &addr, cAddr); if (pConnect) { @@ -407,8 +300,6 @@ struct timeval tv; // For specifying a timeout value. int iSelect; // Holds select return status. - struct timeval tv1, tv2; // To compute delta timeouts. - lscp_socket_t sock; struct sockaddr_in addr; int cAddr; @@ -420,51 +311,40 @@ FD_ZERO(&master_fds); FD_ZERO(&select_fds); - // Add the listeners to the master set - FD_SET((unsigned int) pServer->tcp.sock, &master_fds); - FD_SET((unsigned int) pServer->udp.sock, &master_fds); + // Add the listener to the master set + FD_SET((unsigned int) pServer->agent.sock, &master_fds); // Keep track of the biggest file descriptor; // So far, it's ourself, the listener. - if ((int) pServer->udp.sock > (int) pServer->tcp.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); + fdmax = (int) pServer->agent.sock; // Main loop... - while (pServer->tcp.iState) { + while (pServer->agent.iState) { // Use a copy of the master. select_fds = master_fds; // Use the timeout feature for watchdoggin. - tv.tv_sec = LSCP_SERVER_SLEEP - (tv2.tv_sec - tv1.tv_sec); + tv.tv_sec = LSCP_SERVER_SLEEP; tv.tv_usec = 0; // Wait for events... iSelect = select(fdmax + 1, &select_fds, NULL, NULL, &tv); - // Check later id it's time for ping time... - gettimeofday(&tv2, NULL); - if (iSelect < 0) { lscp_socket_perror("_lscp_server_select_proc: select"); - pServer->tcp.iState = 0; + pServer->agent.iState = 0; } else if (iSelect > 0) { // Run through the existing connections looking for data to read... for (fd = 0; fd < fdmax + 1; fd++) { if (FD_ISSET(fd, &select_fds)) { // We got one!! - // Is it ourselves, the TCP listener? - if (fd == (int) pServer->tcp.sock) { + // Is it ourselves, the command listener? + if (fd == (int) pServer->agent.sock) { // Accept the connection... cAddr = sizeof(struct sockaddr_in); - sock = accept(pServer->tcp.sock, (struct sockaddr *) &addr, &cAddr); + sock = accept(pServer->agent.sock, (struct sockaddr *) &addr, &cAddr); if (sock == INVALID_SOCKET) { lscp_socket_perror("_lscp_server_select_proc: accept"); - pServer->tcp.iState = 0; + pServer->agent.iState = 0; } else { // Add to master set. FD_SET((unsigned int) sock, &master_fds); @@ -479,11 +359,6 @@ } } // 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. } else { // Otherwise it's trivial transaction... lscp_mutex_lock(pServer->connects.mutex); @@ -506,14 +381,6 @@ } // 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 @@ -522,7 +389,7 @@ } -static void _lscp_server_tcp_proc ( void *pvServer ) +static void _lscp_server_agent_proc ( void *pvServer ) { lscp_server_t *pServer = (lscp_server_t *) pvServer; @@ -534,79 +401,6 @@ //------------------------------------------------------------------------- -// 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 -} - - -//------------------------------------------------------------------------- // Server versioning teller fuunction. /** Retrieve the current server library version string. */ @@ -692,24 +486,24 @@ fprintf(stderr, "lscp_server_create: pServer=%p: iPort=%d.\n", pServer, iPort); #endif - // Prepare the TCP stream server socket... + // Prepare the command stream server socket... sock = socket(AF_INET, SOCK_STREAM, 0); if (sock == INVALID_SOCKET) { - lscp_socket_perror("lscp_server_create: tcp: socket"); + lscp_socket_perror("lscp_server_create: socket"); free(pServer); return NULL; } if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char *) &iSockOpt, sizeof(int)) == SOCKET_ERROR) - lscp_socket_perror("lscp_server_create: tcp: setsockopt(SO_REUSEADDR)"); + lscp_socket_perror("lscp_server_create: setsockopt(SO_REUSEADDR)"); #if defined(WIN32) if (setsockopt(sock, SOL_SOCKET, SO_DONTLINGER, (char *) &iSockOpt, sizeof(int)) == SOCKET_ERROR) - lscp_socket_perror("lscp_server_create: tcp: setsockopt(SO_DONTLINGER)"); + lscp_socket_perror("lscp_server_create: setsockopt(SO_DONTLINGER)"); #endif #ifdef DEBUG - lscp_socket_getopts("lscp_server_create: tcp", sock); + lscp_socket_getopts("lscp_server_create", sock); #endif cAddr = sizeof(struct sockaddr_in); @@ -719,61 +513,14 @@ addr.sin_port = htons((short) iPort); if (bind(sock, (const struct sockaddr *) &addr, cAddr) == SOCKET_ERROR) { - lscp_socket_perror("lscp_server_create: tcp: bind"); + lscp_socket_perror("lscp_server_create: bind"); closesocket(sock); free(pServer); return NULL; } if (listen(sock, 10) == SOCKET_ERROR) { - lscp_socket_perror("lscp_server_create: tcp: 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)); + lscp_socket_perror("lscp_server_create: listen"); closesocket(sock); free(pServer); return NULL; @@ -781,44 +528,27 @@ if (iPort == 0) { if (getsockname(sock, (struct sockaddr *) &addr, &cAddr) == SOCKET_ERROR) { - lscp_socket_perror("lscp_server_create: udp: getsockname"); - lscp_socket_agent_free(&(pServer->tcp)); + lscp_socket_perror("lscp_server_create: getsockname"); closesocket(sock); free(pServer); - return NULL; } } - lscp_socket_agent_init(&(pServer->udp), sock, &addr, cAddr); + lscp_socket_agent_init(&(pServer->agent), sock, &addr, cAddr); #ifdef DEBUG - 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)); #endif // Now's finally time to startup threads... - // TCP/Main service thread... - if (lscp_socket_agent_start(&(pServer->tcp), _lscp_server_tcp_proc, pServer, 0) != LSCP_OK) { - lscp_socket_agent_free(&(pServer->tcp)); - lscp_socket_agent_free(&(pServer->udp)); + // Command service thread... + if (lscp_socket_agent_start(&(pServer->agent), _lscp_server_agent_proc, pServer, 0) != LSCP_OK) { + lscp_socket_agent_free(&(pServer->agent)); free(pServer); return NULL; } - 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); - } - // Finally we've some success... return pServer; } @@ -838,11 +568,7 @@ fprintf(stderr, "lscp_server_join: pServer=%p.\n", pServer); #endif -// if (pServer->mode == LSCP_SERVER_THREAD) { -// lscp_thread_join(pServer->pWatchdog); -// lscp_socket_agent_join(&(pServer->udp)); -// } - lscp_socket_agent_join(&(pServer->tcp)); + lscp_socket_agent_join(&(pServer->agent)); return LSCP_OK; } @@ -862,13 +588,8 @@ fprintf(stderr, "lscp_server_destroy: pServer=%p.\n", pServer); #endif - 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)); _lscp_connect_list_free(&(pServer->connects)); + lscp_socket_agent_free(&(pServer->agent)); free(pServer); @@ -877,28 +598,50 @@ /** - * Send an event message to all subscribed clients. + * Send an event notification message to all subscribed clients. * - * @param pServer Pointer to server instance structure. - * @param pchBuffer Pointer to data to be sent to all clients. - * @param cchBuffer Length of the data to be sent in bytes. + * @param pServer Pointer to server instance structure. + * @param event Event type flag to send to all subscribed clients. + * @param pchData Pointer to event data to be sent to all clients. + * @param cchData Length of the event data to be sent in bytes. * * @returns LSCP_OK on success, LSCP_FAILED otherwise. */ -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 ) { lscp_connect_t *p; + const char *pszEvent; + char achBuffer[LSCP_BUFSIZ]; + int cchBuffer; if (pServer == NULL) return LSCP_FAILED; - if (pchBuffer == NULL || cchBuffer < 1) + if (pchData == NULL || cchData < 1) + return LSCP_FAILED; + + // Which (single) event? + pszEvent = lscp_event_to_text(event); + if (pszEvent == NULL) return LSCP_FAILED; + // Build the event message string... + cchBuffer = sprintf(achBuffer, "NOTIFY:%s:", pszEvent); + if (pchData) { + if (cchData > LSCP_BUFSIZ - cchBuffer - 2) + cchData = LSCP_BUFSIZ - cchBuffer - 2; + strncpy(&achBuffer[cchBuffer], pchData, cchData); + cchBuffer += cchData; + } + achBuffer[cchBuffer++] = '\r'; + achBuffer[cchBuffer++] = '\n'; + + // And do the direct broadcasting... + lscp_mutex_lock(pServer->connects.mutex); for (p = pServer->connects.first; p; p = p->next) { - if (p->port > 0 && p->ping == 0) - _lscp_connect_send(p, pchBuffer, cchBuffer); + if (p->events & event) + send(p->client.sock, achBuffer, cchBuffer, 0); } lscp_mutex_unlock(pServer->connects.mutex); @@ -937,54 +680,40 @@ /** * Register client as a subscriber of event broadcast messages. * - * @param pConnect Pointer to client connection instance structure. - * @param iPort UDP port number of the requesting client connection. + * @param pConnect Pointer to client connection instance structure. + * @param event Event type flag of the requesting client subscription. * * @returns LSCP_OK on success, LSCP_FAILED otherwise. */ -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 ) { - char szSessID[32]; - if (pConnect == NULL) return LSCP_FAILED; - if (iPort == 0 || pConnect->port > 0 || pConnect->sessid) + if (event == LSCP_EVENT_NONE) return LSCP_FAILED; - // Generate a psudo-unique session-id. - sprintf(szSessID, "%08x", ((unsigned int) pConnect->server << 8) ^ (unsigned int) pConnect); + pConnect->events |= event; - pConnect->port = iPort; - pConnect->ping = 0; - pConnect->sessid = strdup(szSessID); - - return _lscp_connect_ping(pConnect); + return LSCP_OK; } /** * Deregister client as subscriber of event broadcast messages. * - * @param pConnect Pointer to client connection instance structure. - * @param pszSessID Session identifier of the requesting client connection. + * @param pConnect Pointer to client connection instance structure. + * @param event Event type flag of the requesting client unsubscription. * * @returns LSCP_OK on success, LSCP_FAILED otherwise. */ -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 ) { if (pConnect == NULL) return LSCP_FAILED; - if (pConnect->port == 0 || pConnect->sessid == NULL) - return LSCP_FAILED; - - // Session ids must match. - if (strcmp(pszSessID, pConnect->sessid) != 0) + if (event == LSCP_EVENT_NONE) return LSCP_FAILED; - free(pConnect->sessid); - pConnect->sessid = NULL; - pConnect->ping = 0; - pConnect->port = 0; + pConnect->events &= ~event; return LSCP_OK; }