/* * Copyright (C) 2004 Steve Harris * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as * published by the Free Software Foundation; either version 2.1 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * $Id$ */ #ifdef HAVE_CONFIG_H#include "config.h"#endif #include <stdlib.h>#include <stdio.h>#include <string.h>#include <errno.h>#include <float.h>#include <sys/types.h>#include <time.h> #ifdef _MSC_VER#define _WINSOCKAPI_#define snprintf _snprintf#include <io.h> // 1.5.0.1 (ge) added for close#else#include <unistd.h>#endif #ifdef WIN32#include <winsock2.h>#include <ws2tcpip.h>#define EADDRINUSE WSAEADDRINUSE#else#include <netdb.h>#include <sys/socket.h>#ifdef HAVE_POLL#include <sys/poll.h>#endif#include <sys/un.h>#include <arpa/inet.h>#endif #ifdef WIN32#define geterror() WSAGetLastError()#else#define geterror() errno#endif #include "lo_types_internal.h"#include "lo_internal.h"#include "lo.h"#include "lo_throw.h" #define LO_HOST_SIZE 1024 typedef struct { lo_timetag ts; char *path; lo_message msg; void *next;} queued_msg_list; struct lo_cs lo_client_sockets = {-1, -1}; static int lo_can_coerce_spec(const char *a, const char *b);static int lo_can_coerce(char a, char b);static void dispatch_method(lo_server s, const char *path, lo_message msg);static int dispatch_queued(lo_server s);static void queue_data(lo_server s, lo_timetag ts, const char *path, lo_message msg);static lo_server lo_server_new_with_proto_internal(const char *group, const char *port, int proto, lo_err_handler err_h);static int lo_server_add_socket(lo_server s, int socket);static void lo_server_del_socket(lo_server s, int index, int socket);static int lo_server_join_multicast_group(lo_server s, const char *group); #ifdef WIN32#ifndef gai_strerror// Copied from the Win32 SDK // WARNING: The gai_strerror inline functions below use static buffers,// and hence are not thread-safe. We'll use buffers long enough to hold// 1k characters. Any system error messages longer than this will be// returned as empty strings. However 1k should work for the error codes// used by getaddrinfo().#define GAI_STRERROR_BUFFER_SIZE 1024 char *WSAAPI gai_strerrorA(int ecode){ DWORD dwMsgLen; static char buff[GAI_STRERROR_BUFFER_SIZE + 1]; dwMsgLen = FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM |FORMAT_MESSAGE_IGNORE_INSERTS |FORMAT_MESSAGE_MAX_WIDTH_MASK, NULL, ecode, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPSTR)buff, GAI_STRERROR_BUFFER_SIZE, NULL); return buff;}#endif static int stateWSock = -1; int initWSock(){ WORD reqversion; WSADATA wsaData; if(stateWSock >= 0) return stateWSock; /* TODO - which version of Winsock do we actually need? */ reqversion = MAKEWORD( 2, 2 ); if(WSAStartup(reqversion,&wsaData) != 0) { /* Couldn't initialize Winsock */ stateWSock = 0; } else if ( LOBYTE( wsaData.wVersion ) != LOBYTE(reqversion) || HIBYTE( wsaData.wVersion ) != HIBYTE(reqversion) ) { /* wrong version */ WSACleanup(); stateWSock = 0; } else stateWSock = 1; return stateWSock;}#endif lo_server lo_server_new(const char *port, lo_err_handler err_h){ return lo_server_new_with_proto(port, LO_DEFAULT, err_h);} lo_server lo_server_new_multicast(const char *group, const char *port, lo_err_handler err_h){ return lo_server_new_with_proto_internal(group, port, LO_UDP, err_h);} lo_server lo_server_new_with_proto(const char *port, int proto, lo_err_handler err_h){ return lo_server_new_with_proto_internal(NULL, port, proto, err_h);} lo_server lo_server_new_with_proto_internal(const char *group, const char *port, int proto, lo_err_handler err_h){ lo_server s; struct addrinfo *ai = NULL, *it, *used; struct addrinfo hints; int ret = -1; int tries = 0; char pnum[16]; const char *service; char hostname[LO_HOST_SIZE]; // Set real protocol, if Default is requested if (proto==LO_DEFAULT) {#ifndef WIN32 if (port && *port == '/') proto = LO_UNIX; else #endif proto = LO_UDP; } #ifdef WIN32 if(!initWSock()) return NULL;#endif s = calloc(1, sizeof(struct _lo_server)); if (!s) return 0; s->err_h = err_h; s->first = NULL; s->ai = NULL; s->hostname = NULL; s->protocol = proto; s->port = 0; s->path = NULL; s->queued = NULL; s->sockets_len = 1; s->sockets_alloc = 2; s->sockets = calloc(2, sizeof(*(s->sockets))); if (!s->sockets) { free(s); return 0; } s->sockets[0].fd = -1; memset(&hints, 0, sizeof(hints)); if (proto == LO_UDP) { hints.ai_socktype = SOCK_DGRAM; } else if (proto == LO_TCP) { hints.ai_socktype = SOCK_STREAM; } #ifndef WIN32 else if (proto == LO_UNIX) { struct sockaddr_un sa; s->sockets[0].fd = socket(PF_UNIX, SOCK_DGRAM, 0); if (s->sockets[0].fd == -1) { int err = geterror(); used = NULL; lo_throw(s, err, strerror(err), "socket()"); lo_server_free(s); return NULL; } sa.sun_family = AF_UNIX; strncpy(sa.sun_path, port, sizeof(sa.sun_path)-1); if ((ret = bind(s->sockets[0].fd, (struct sockaddr *)&sa, sizeof(sa))) < 0) { int err = geterror(); lo_throw(s, err, strerror(err), "bind()"); lo_server_free(s); return NULL; } s->path = strdup(port); return s; } #endif else { lo_throw(s, LO_UNKNOWNPROTO, "Unknown protocol", NULL); lo_server_free(s); return NULL; } #ifdef ENABLE_IPV6 hints.ai_family = PF_UNSPEC;#else hints.ai_family = PF_INET;#endif hints.ai_flags = AI_PASSIVE; if (!port) { service = pnum; } else { service = port; } do { if (!port) { /* not a good way to get random numbers, but its not critical */ snprintf(pnum, 15, "%ld", 10000 + ((unsigned int)rand() + (long)time(NULL)) % 10000); } if ((ret = getaddrinfo(NULL, service, &hints, &ai))) { lo_throw(s, ret, gai_strerror(ret), NULL); freeaddrinfo(ai); return NULL; } used = NULL; s->ai = ai; s->sockets[0].fd = -1; s->port = 0; for (it = ai; it && s->sockets[0].fd == -1; it = it->ai_next) { used = it; s->sockets[0].fd = socket(it->ai_family, hints.ai_socktype, 0); } if (s->sockets[0].fd == -1) { int err = geterror(); used = NULL; lo_throw(s, err, strerror(err), "socket()"); lo_server_free(s); return NULL; } /* Join multicast group if specified. */ /* This must be done before bind() on POSIX, but after bind() Windows. */#ifndef WIN32 if (group != NULL) if (lo_server_join_multicast_group(s, group)) return NULL;#endif if ((ret = bind(s->sockets[0].fd, used->ai_addr, used->ai_addrlen)) < 0) { int err = geterror(); if (err == EINVAL || err == EADDRINUSE) { used = NULL; continue; } lo_throw(s, err, strerror(err), "bind()"); lo_server_free(s); return NULL; } } while (!used && tries++ < 16); /* Join multicast group if specified (see above). */#ifdef WIN32 if (group != NULL) if (lo_server_join_multicast_group(s, group)) return NULL;#endif if (proto == LO_TCP) { listen(s->sockets[0].fd, 8); } if (!used) { lo_throw(s, LO_NOPORT, "cannot find free port", NULL); lo_server_free(s); return NULL; } if (proto == LO_UDP) { lo_client_sockets.udp = s->sockets[0].fd; } else if (proto == LO_TCP) { lo_client_sockets.tcp = s->sockets[0].fd; } /* Set hostname to empty string */ hostname[0] = '\0'; #ifdef ENABLE_IPV6 /* Try it the IPV6 friendly way first */ for (it = ai; it; it = it->ai_next) { if (getnameinfo(it->ai_addr, it->ai_addrlen, hostname, sizeof(hostname), NULL, 0, NI_NAMEREQD) == 0) { break; } } /* check to make sure getnameinfo() didn't just set the hostname to "::". Needed on Darwin. */ if (hostname[0] == ':') { hostname[0] = '\0'; }#endif /* Fallback to the oldschool (i.e. more reliable) way */ if (!hostname[0]) { struct hostent *he; gethostname(hostname, sizeof(hostname)); he = gethostbyname(hostname); if (he) { strncpy(hostname, he->h_name, sizeof(hostname)); } } /* soethings gone really wrong, just hope its local only */ if (!hostname[0]) { strcpy(hostname, "localhost"); } s->hostname = strdup(hostname); if (used->ai_family == PF_INET6) { struct sockaddr_in6 *addr = (struct sockaddr_in6 *)used->ai_addr; s->port = htons(addr->sin6_port); } else if (used->ai_family == PF_INET) { struct sockaddr_in *addr = (struct sockaddr_in *)used->ai_addr; s->port = htons(addr->sin_port); } else { lo_throw(s, LO_UNKNOWNPROTO, "unknown protocol family", NULL); s->port = atoi(port); } return s;} int lo_server_join_multicast_group(lo_server s, const char *group){ struct ip_mreq mreq; unsigned int yes = 1; memset(&mreq, 0, sizeof(mreq));#ifdef HAVE_INET_ATON if (inet_aton(group, &mreq.imr_multiaddr)==0) { int err = geterror(); lo_throw(s, err, strerror(err), "inet_aton()"); lo_server_free(s); return err; }#else mreq.imr_multiaddr.s_addr = inet_addr(group); if (mreq.imr_multiaddr.s_addr == INADDR_ANY || mreq.imr_multiaddr.s_addr == INADDR_NONE) { int err = geterror(); lo_throw(s, err, strerror(err), "inet_addr()"); lo_server_free(s); return err; }#endif mreq.imr_interface.s_addr=htonl(INADDR_ANY); if (setsockopt(s->sockets[0].fd,IPPROTO_IP,IP_ADD_MEMBERSHIP, &mreq,sizeof(mreq)) < 0) { int err = geterror(); lo_throw(s, err, strerror(err), "setsockopt(IP_ADD_MEMBERSHIP)"); lo_server_free(s); return err; } if (setsockopt(s->sockets[0].fd,SOL_SOCKET,SO_REUSEADDR, &yes,sizeof(yes)) < 0) { int err = geterror(); lo_throw(s, err, strerror(err), "setsockopt(SO_REUSEADDR)"); lo_server_free(s); return err; } #ifdef SO_REUSEPORT if (setsockopt(s->sockets[0].fd,SOL_SOCKET,SO_REUSEPORT, &yes,sizeof(yes)) < 0) { int err = geterror(); lo_throw(s, err, strerror(err), "setsockopt(SO_REUSEPORT)"); lo_server_free(s); return err; }#endif return 0;} void lo_server_free(lo_server s){ if (s) { lo_method it; lo_method next; int i; for (i=s->sockets_len-1; i >= 0; i--) { if (s->sockets[i].fd != -1) { if (s->protocol == LO_UDP && s->sockets[i].fd == lo_client_sockets.udp) { lo_client_sockets.udp = -1; } else if (s->protocol == LO_TCP && s->sockets[0].fd == lo_client_sockets.tcp) { lo_client_sockets.tcp = -1; } close(s->sockets[i].fd); s->sockets[i].fd = -1; } } if (s->ai) { freeaddrinfo(s->ai); s->ai=NULL; } if (s->hostname) { free(s->hostname); s->hostname = NULL; } if (s->path) { if (s->protocol == LO_UNIX) unlink( s->path ); free(s->path); s->path = NULL; } for (it = s->first; it; it = next) { next = it->next; free((char *)it->path); free((char *)it->typespec); free(it); } free(s->sockets);Lines 1–500 of 1406. Load more
/* * Copyright (C) 2004 Steve Harris * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as * published by the Free Software Foundation; either version 2.1 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * $Id$ */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include <stdlib.h> #include <stdio.h> #include <string.h> #include <errno.h> #include <float.h> #include <sys/types.h> #include <time.h> #ifdef _MSC_VER #define _WINSOCKAPI_ #define snprintf _snprintf #include <io.h> // 1.5.0.1 (ge) added for close #else #include <unistd.h> #endif #ifdef WIN32 #include <winsock2.h> #include <ws2tcpip.h> #define EADDRINUSE WSAEADDRINUSE #else #include <netdb.h> #include <sys/socket.h> #ifdef HAVE_POLL #include <sys/poll.h> #endif #include <sys/un.h> #include <arpa/inet.h> #endif #ifdef WIN32 #define geterror() WSAGetLastError() #else #define geterror() errno #endif #include "lo_types_internal.h" #include "lo_internal.h" #include "lo.h" #include "lo_throw.h" #define LO_HOST_SIZE 1024 typedef struct { lo_timetag ts; char *path; lo_message msg; void *next; } queued_msg_list; struct lo_cs lo_client_sockets = {-1, -1}; static int lo_can_coerce_spec(const char *a, const char *b); static int lo_can_coerce(char a, char b); static void dispatch_method(lo_server s, const char *path, lo_message msg); static int dispatch_queued(lo_server s); static void queue_data(lo_server s, lo_timetag ts, const char *path, lo_message msg); static lo_server lo_server_new_with_proto_internal(const char *group, const char *port, int proto, lo_err_handler err_h); static int lo_server_add_socket(lo_server s, int socket); static void lo_server_del_socket(lo_server s, int index, int socket); static int lo_server_join_multicast_group(lo_server s, const char *group); #ifdef WIN32 #ifndef gai_strerror // Copied from the Win32 SDK // WARNING: The gai_strerror inline functions below use static buffers, // and hence are not thread-safe. We'll use buffers long enough to hold // 1k characters. Any system error messages longer than this will be // returned as empty strings. However 1k should work for the error codes // used by getaddrinfo(). #define GAI_STRERROR_BUFFER_SIZE 1024 char *WSAAPI gai_strerrorA(int ecode) { DWORD dwMsgLen; static char buff[GAI_STRERROR_BUFFER_SIZE + 1]; dwMsgLen = FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM |FORMAT_MESSAGE_IGNORE_INSERTS |FORMAT_MESSAGE_MAX_WIDTH_MASK, NULL, ecode, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPSTR)buff, GAI_STRERROR_BUFFER_SIZE, NULL); return buff; } #endif static int stateWSock = -1; int initWSock() { WORD reqversion; WSADATA wsaData; if(stateWSock >= 0) return stateWSock; /* TODO - which version of Winsock do we actually need? */ reqversion = MAKEWORD( 2, 2 ); if(WSAStartup(reqversion,&wsaData) != 0) { /* Couldn't initialize Winsock */ stateWSock = 0; } else if ( LOBYTE( wsaData.wVersion ) != LOBYTE(reqversion) || HIBYTE( wsaData.wVersion ) != HIBYTE(reqversion) ) { /* wrong version */ WSACleanup(); stateWSock = 0; } else stateWSock = 1; return stateWSock; } #endif lo_server lo_server_new(const char *port, lo_err_handler err_h) { return lo_server_new_with_proto(port, LO_DEFAULT, err_h); } lo_server lo_server_new_multicast(const char *group, const char *port, lo_err_handler err_h) { return lo_server_new_with_proto_internal(group, port, LO_UDP, err_h); } lo_server lo_server_new_with_proto(const char *port, int proto, lo_err_handler err_h) { return lo_server_new_with_proto_internal(NULL, port, proto, err_h); } lo_server lo_server_new_with_proto_internal(const char *group, const char *port, int proto, lo_err_handler err_h) { lo_server s; struct addrinfo *ai = NULL, *it, *used; struct addrinfo hints; int ret = -1; int tries = 0; char pnum[16]; const char *service; char hostname[LO_HOST_SIZE]; // Set real protocol, if Default is requested if (proto==LO_DEFAULT) { #ifndef WIN32 if (port && *port == '/') proto = LO_UNIX; else #endif proto = LO_UDP; } #ifdef WIN32 if(!initWSock()) return NULL; #endif s = calloc(1, sizeof(struct _lo_server)); if (!s) return 0; s->err_h = err_h; s->first = NULL; s->ai = NULL; s->hostname = NULL; s->protocol = proto; s->port = 0; s->path = NULL; s->queued = NULL; s->sockets_len = 1; s->sockets_alloc = 2; s->sockets = calloc(2, sizeof(*(s->sockets))); if (!s->sockets) { free(s); return 0; } s->sockets[0].fd = -1; memset(&hints, 0, sizeof(hints)); if (proto == LO_UDP) { hints.ai_socktype = SOCK_DGRAM; } else if (proto == LO_TCP) { hints.ai_socktype = SOCK_STREAM; } #ifndef WIN32 else if (proto == LO_UNIX) { struct sockaddr_un sa; s->sockets[0].fd = socket(PF_UNIX, SOCK_DGRAM, 0); if (s->sockets[0].fd == -1) { int err = geterror(); used = NULL; lo_throw(s, err, strerror(err), "socket()"); lo_server_free(s); return NULL; } sa.sun_family = AF_UNIX; strncpy(sa.sun_path, port, sizeof(sa.sun_path)-1); if ((ret = bind(s->sockets[0].fd, (struct sockaddr *)&sa, sizeof(sa))) < 0) { int err = geterror(); lo_throw(s, err, strerror(err), "bind()"); lo_server_free(s); return NULL; } s->path = strdup(port); return s; } #endif else { lo_throw(s, LO_UNKNOWNPROTO, "Unknown protocol", NULL); lo_server_free(s); return NULL; } #ifdef ENABLE_IPV6 hints.ai_family = PF_UNSPEC; #else hints.ai_family = PF_INET; #endif hints.ai_flags = AI_PASSIVE; if (!port) { service = pnum; } else { service = port; } do { if (!port) { /* not a good way to get random numbers, but its not critical */ snprintf(pnum, 15, "%ld", 10000 + ((unsigned int)rand() + (long)time(NULL)) % 10000); } if ((ret = getaddrinfo(NULL, service, &hints, &ai))) { lo_throw(s, ret, gai_strerror(ret), NULL); freeaddrinfo(ai); return NULL; } used = NULL; s->ai = ai; s->sockets[0].fd = -1; s->port = 0; for (it = ai; it && s->sockets[0].fd == -1; it = it->ai_next) { used = it; s->sockets[0].fd = socket(it->ai_family, hints.ai_socktype, 0); } if (s->sockets[0].fd == -1) { int err = geterror(); used = NULL; lo_throw(s, err, strerror(err), "socket()"); lo_server_free(s); return NULL; } /* Join multicast group if specified. */ /* This must be done before bind() on POSIX, but after bind() Windows. */ #ifndef WIN32 if (group != NULL) if (lo_server_join_multicast_group(s, group)) return NULL; #endif if ((ret = bind(s->sockets[0].fd, used->ai_addr, used->ai_addrlen)) < 0) { int err = geterror(); if (err == EINVAL || err == EADDRINUSE) { used = NULL; continue; } lo_throw(s, err, strerror(err), "bind()"); lo_server_free(s); return NULL; } } while (!used && tries++ < 16); /* Join multicast group if specified (see above). */ #ifdef WIN32 if (group != NULL) if (lo_server_join_multicast_group(s, group)) return NULL; #endif if (proto == LO_TCP) { listen(s->sockets[0].fd, 8); } if (!used) { lo_throw(s, LO_NOPORT, "cannot find free port", NULL); lo_server_free(s); return NULL; } if (proto == LO_UDP) { lo_client_sockets.udp = s->sockets[0].fd; } else if (proto == LO_TCP) { lo_client_sockets.tcp = s->sockets[0].fd; } /* Set hostname to empty string */ hostname[0] = '\0'; #ifdef ENABLE_IPV6 /* Try it the IPV6 friendly way first */ for (it = ai; it; it = it->ai_next) { if (getnameinfo(it->ai_addr, it->ai_addrlen, hostname, sizeof(hostname), NULL, 0, NI_NAMEREQD) == 0) { break; } } /* check to make sure getnameinfo() didn't just set the hostname to "::". Needed on Darwin. */ if (hostname[0] == ':') { hostname[0] = '\0'; } #endif /* Fallback to the oldschool (i.e. more reliable) way */ if (!hostname[0]) { struct hostent *he; gethostname(hostname, sizeof(hostname)); he = gethostbyname(hostname); if (he) { strncpy(hostname, he->h_name, sizeof(hostname)); } } /* soethings gone really wrong, just hope its local only */ if (!hostname[0]) { strcpy(hostname, "localhost"); } s->hostname = strdup(hostname); if (used->ai_family == PF_INET6) { struct sockaddr_in6 *addr = (struct sockaddr_in6 *)used->ai_addr; s->port = htons(addr->sin6_port); } else if (used->ai_family == PF_INET) { struct sockaddr_in *addr = (struct sockaddr_in *)used->ai_addr; s->port = htons(addr->sin_port); } else { lo_throw(s, LO_UNKNOWNPROTO, "unknown protocol family", NULL); s->port = atoi(port); } return s; } int lo_server_join_multicast_group(lo_server s, const char *group) { struct ip_mreq mreq; unsigned int yes = 1; memset(&mreq, 0, sizeof(mreq)); #ifdef HAVE_INET_ATON if (inet_aton(group, &mreq.imr_multiaddr)==0) { int err = geterror(); lo_throw(s, err, strerror(err), "inet_aton()"); lo_server_free(s); return err; } #else mreq.imr_multiaddr.s_addr = inet_addr(group); if (mreq.imr_multiaddr.s_addr == INADDR_ANY || mreq.imr_multiaddr.s_addr == INADDR_NONE) { int err = geterror(); lo_throw(s, err, strerror(err), "inet_addr()"); lo_server_free(s); return err; } #endif mreq.imr_interface.s_addr=htonl(INADDR_ANY); if (setsockopt(s->sockets[0].fd,IPPROTO_IP,IP_ADD_MEMBERSHIP, &mreq,sizeof(mreq)) < 0) { int err = geterror(); lo_throw(s, err, strerror(err), "setsockopt(IP_ADD_MEMBERSHIP)"); lo_server_free(s); return err; } if (setsockopt(s->sockets[0].fd,SOL_SOCKET,SO_REUSEADDR, &yes,sizeof(yes)) < 0) { int err = geterror(); lo_throw(s, err, strerror(err), "setsockopt(SO_REUSEADDR)"); lo_server_free(s); return err; } #ifdef SO_REUSEPORT if (setsockopt(s->sockets[0].fd,SOL_SOCKET,SO_REUSEPORT, &yes,sizeof(yes)) < 0) { int err = geterror(); lo_throw(s, err, strerror(err), "setsockopt(SO_REUSEPORT)"); lo_server_free(s); return err; } #endif return 0; } void lo_server_free(lo_server s) { if (s) { lo_method it; lo_method next; int i; for (i=s->sockets_len-1; i >= 0; i--) { if (s->sockets[i].fd != -1) { if (s->protocol == LO_UDP && s->sockets[i].fd == lo_client_sockets.udp) { lo_client_sockets.udp = -1; } else if (s->protocol == LO_TCP && s->sockets[0].fd == lo_client_sockets.tcp) { lo_client_sockets.tcp = -1; } close(s->sockets[i].fd); s->sockets[i].fd = -1; } } if (s->ai) { freeaddrinfo(s->ai); s->ai=NULL; } if (s->hostname) { free(s->hostname); s->hostname = NULL; } if (s->path) { if (s->protocol == LO_UNIX) unlink( s->path ); free(s->path); s->path = NULL; } for (it = s->first; it; it = next) { next = it->next; free((char *)it->path); free((char *)it->typespec); free(it); } free(s->sockets);