void *lo_server_recv_raw_stream(lo_server s, size_t *size) { struct sockaddr_storage addr; socklen_t addr_len = sizeof(addr); char buffer[LO_MAX_MSG_SIZE]; int32_t read_size; int ret; void *data = NULL; int sock; #ifdef WIN32 if(!initWSock()) return NULL; fd_set ps; FD_ZERO(&ps); FD_SET(s->socket,&ps); if(select(1,&ps,NULL,NULL,NULL) == SOCKET_ERROR) return NULL; #else struct pollfd ps; ps.fd = s->socket; ps.events = POLLIN | POLLPRI; ps.revents = 0; poll(&ps, 1, -1); #endif sock = accept(s->socket, (struct sockaddr *)&addr, &addr_len); ret = recv(sock, &read_size, sizeof(read_size), 0); read_size = ntohl(read_size); if (read_size > LO_MAX_MSG_SIZE) { close(sock); lo_throw(s, LO_TOOBIG, "Message too large", "recv()"); return NULL; } ret = recv(sock, buffer, read_size, 0); //close(sock); if (ret <= 0) { return NULL; } data = malloc(ret); memcpy(data, buffer, ret); if (size) *size = ret; return data; }
int lo_server_recv_noblock(lo_server s, int timeout) { int sched_timeout = lo_server_next_event_delay(s) * 1000; #ifdef WIN32 fd_set ps; struct timeval stimeout; #else struct pollfd ps; #endif #ifdef WIN32 int res,to; if(!initWSock()) return 0; to = timeout > sched_timeout ? sched_timeout : timeout; stimeout.tv_sec = to/1000; stimeout.tv_usec = (to%1000)*1000; FD_ZERO(&ps); FD_SET(s->socket,&ps); res = select(1,&ps,NULL,NULL,&stimeout); if(res == SOCKET_ERROR) return 0; if (res || lo_server_next_event_delay(s) < 0.01) return lo_server_recv(s); #else ps.fd = s->socket; ps.events = POLLIN | POLLPRI | POLLERR | POLLHUP; ps.revents = 0; poll(&ps, 1, timeout > sched_timeout ? sched_timeout : timeout); if (ps.revents == POLLERR || ps.revents == POLLHUP) { return 0; } if (ps.revents || lo_server_next_event_delay(s) < 0.01) { return lo_server_recv(s); } #endif return 0; }
void *lo_server_recv_raw(lo_server s, size_t *size) { char buffer[LO_MAX_MSG_SIZE]; int ret; void *data = NULL; #ifdef WIN32 if(!initWSock()) return NULL; #endif s->addr_len = sizeof(s->addr); ret = recvfrom(s->socket, buffer, LO_MAX_MSG_SIZE, 0, (struct sockaddr *)&s->addr, &s->addr_len); if (ret <= 0) { return NULL; } data = malloc(ret); memcpy(data, buffer, ret); if (size) *size = ret; return data; }
static int send_data(lo_address a, lo_server from, char *data, const size_t data_len) { ssize_t ret = 0; int sock = -1; #if defined(WIN32) || defined(_MSC_VER) if (!initWSock()) return -1; #endif if (data_len > LO_MAX_MSG_SIZE) { a->errnum = 99; a->errstr = "Attempted to send message in excess of maximum " "message size"; return -1; } // Resolve the destination address, if not done already if (!a->ai) { ret = lo_address_resolve(a); if (ret) return ret; } // Re-use existing socket? if (from && a->protocol == LO_UDP) { sock = from->sockets[0].fd; } else if (a->protocol == LO_UDP && lo_client_sockets.udp != -1) { sock = lo_client_sockets.udp; } else { if (a->socket == -1) { ret = create_socket(a); if (ret) return ret; // If we are sending TCP, we may later receive on sending // socket, so add it to the from server's socket list. if (from && a->protocol == LO_TCP && (a->socket >= from->sources_len || from->sources[a->socket].host == NULL)) { lo_server_add_socket(from, a->socket, a, 0, 0); // If a socket is added to the server, the server is // now responsible for closing it. a->ownsocket = 0; } } sock = a->socket; } if (a->protocol == LO_TCP && !(a->flags & LO_SLIP)) { // For TCP only, send the length of the following data int32_t size = htonl(data_len); ret = send(sock, (const void*)&size, sizeof(size), MSG_NOSIGNAL); } // Send the data if (ret != -1) { if (a->protocol == LO_UDP) { struct addrinfo* ai; if (a->addr.size == sizeof(struct in_addr)) { setsockopt(sock, IPPROTO_IP, IP_MULTICAST_IF, (const char*)&a->addr.a, a->addr.size); } #ifdef ENABLE_IPV6 else if (a->addr.size == sizeof(struct in6_addr)) { setsockopt(sock, IPPROTO_IP, IPV6_MULTICAST_IF, (const char*)&a->addr.a, a->addr.size); } #endif if (a->ttl >= 0) { unsigned char ttl = (unsigned char) a->ttl; setsockopt(sock, IPPROTO_IP, IP_MULTICAST_TTL, (const char*)&ttl, sizeof(ttl)); } ai = a->ai; do { ret = sendto(sock, data, data_len, MSG_NOSIGNAL, ai->ai_addr, ai->ai_addrlen); ai = ai->ai_next; } while (ret == -1 && ai != NULL); if (ret == -1 && ai != NULL && a->ai!=ai) a->ai = ai; } else { struct addrinfo* ai = a->ai; size_t len = data_len; if (a->flags & LO_SLIP) data = (char*)slip_encode((unsigned char*)data, &len); do { ret = send(sock, data, len, MSG_NOSIGNAL); if (a->protocol == LO_TCP) ai = ai->ai_next; else ai = 0; } while (ret == -1 && ai != NULL); if (ret == -1 && ai != NULL && a->ai!=ai) a->ai = ai; if (a->flags & LO_SLIP) free(data); } } if (ret == -1) { if (a->protocol == LO_TCP) { if (from) lo_server_del_socket(from, -1, a->socket); closesocket(a->socket); a->socket = -1; } a->errnum = geterror(); a->errstr = NULL; } else { a->errnum = 0; a->errstr = NULL; } return ret; }
int send_data(lo_address a, lo_server from, char *data, const size_t data_len) { int ret=0; int sock=-1; #ifdef WIN32 if(!initWSock()) return -1; #endif if (data_len > LO_MAX_MSG_SIZE) { a->errnum = 99; a->errstr = "Attempted to send message in excess of maximum " "message size"; return -1; } // Resolve the destination address, if not done already if (!a->ai) { ret = resolve_address( a ); if (ret) return ret; } // Re-use existing socket? if (from) { sock = from->sockets[0].fd; } else if (a->protocol == LO_UDP && lo_client_sockets.udp!=-1) { sock = lo_client_sockets.udp; } else { if (a->socket==-1) { ret = create_socket( a ); if (ret) return ret; } sock = a->socket; } // Send Length of the following data if (a->protocol == LO_TCP) { int32_t size = htonl(data_len); ret = send(sock, &size, sizeof(size), MSG_NOSIGNAL); } // Send the data if (a->protocol == LO_UDP) { if (a->ttl >= 0) { unsigned char ttl = (unsigned char)a->ttl; setsockopt(sock,IPPROTO_IP,IP_MULTICAST_TTL,&ttl,sizeof(ttl)); } ret = sendto(sock, data, data_len, MSG_NOSIGNAL, a->ai->ai_addr, a->ai->ai_addrlen); } else { ret = send(sock, data, data_len, MSG_NOSIGNAL); } if (a->protocol == LO_TCP && ret == -1) { close(a->socket); a->socket=-1; } if (ret == -1) { a->errnum = geterror(); a->errstr = NULL; } else { a->errnum = 0; a->errstr = NULL; } return ret; }
int lo_server_recv(lo_server s) { void *data; size_t size; char *path; char *types; double sched_time = lo_server_next_event_delay(s); #ifdef WIN32 fd_set ps; struct timeval stimeout; int res; #else struct pollfd ps; #endif again: if (sched_time > 0.01) { if (sched_time > 10.0) { sched_time = 10.0; } #ifdef WIN32 if(!initWSock()) return 0; ps.fd_count = 1; ps.fd_array[0] = s->socket; stimeout.tv_sec = sched_time; stimeout.tv_usec = (sched_time-stimeout.tv_sec)*1.e6; res = select(1,&ps,NULL,NULL,&stimeout); if(res == SOCKET_ERROR) { return 0; } if(!res) { sched_time = lo_server_next_event_delay(s); if (sched_time > 0.01) { goto again; } return dispatch_queued(s); } #else ps.fd = s->socket; ps.events = POLLIN | POLLPRI | POLLERR | POLLHUP; ps.revents = 0; poll(&ps, 1, (int)(sched_time * 1000.0)); if (ps.revents == POLLERR || ps.revents == POLLHUP) { return 0; } if (!ps.revents) { sched_time = lo_server_next_event_delay(s); if (sched_time > 0.01) { goto again; } return dispatch_queued(s); } #endif } else { return dispatch_queued(s); } if (s->protocol == LO_TCP) { data = lo_server_recv_raw_stream(s, &size); } else { data = lo_server_recv_raw(s, &size); } if (!data) { return 0; } path = data; types = data + lo_strsize(path); if (!strcmp(path, "#bundle")) { char *pos = types; uint32_t len; lo_timetag ts, now; lo_timetag_now(&now); ts.sec = lo_otoh32(*((uint32_t *)pos)); pos += 4; ts.frac = lo_otoh32(*((uint32_t *)pos)); pos += 4; while (pos - (char *)data < size) { len = lo_otoh32(*((uint32_t *)pos)); pos += 4; /* test for immedaite dispatch */ if ((ts.sec == 0 && ts.frac == 1) || lo_timetag_diff(ts, now) <= 0.0) { types = pos + lo_strsize(pos); dispatch_method(s, pos, types + 1, types + lo_strsize(types)); } else { queue_data(s, ts, pos, len); } pos += len; } free(data); return size; } else if (*types != ',') { lo_throw(s, LO_ENOTYPE, "Missing typetag", path); return -1; } dispatch_method(s, path, types+1, data); free(data); return size; }
lo_server lo_server_new_with_proto(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]; #ifdef WIN32 if(!initWSock()) return NULL; #endif s = calloc(1, sizeof(struct _lo_server)); 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->socket = -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->socket = socket(PF_UNIX, SOCK_DGRAM, 0); if (s->socket == -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, 107); if ((ret = bind(s->socket, (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 DISABLE_IPV6 hints.ai_family = PF_INET; #else hints.ai_family = PF_UNSPEC; #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() + time(NULL)) % 10000); } if (ai) { freeaddrinfo(ai); } 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->socket = -1; s->port = 0; for (it = ai; it && s->socket == -1; it = it->ai_next) { used = it; s->socket = socket(it->ai_family, hints.ai_socktype, 0); } if (s->socket == -1) { int err = geterror(); used = NULL; lo_throw(s, err, strerror(err), "socket()"); lo_server_free(s); return NULL; } if ((ret = bind(s->socket, 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); if (proto == LO_TCP) { listen(s->socket, 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->socket; } else if (proto == LO_TCP) { lo_client_sockets.tcp = s->socket; } /* Try it the IPV6 friendly way first */ hostname[0] = '\0'; 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'; } /* 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_recv(lo_server s) { void *data; size_t size; double sched_time = lo_server_next_event_delay(s); int i; #ifdef HAVE_SELECT #ifndef HAVE_POLL fd_set ps; struct timeval stimeout; int res,nfds=0; #endif #endif again: if (sched_time > 0.01) { if (sched_time > 10.0) { sched_time = 10.0; } #ifdef HAVE_POLL for (i=0; i < s->sockets_len; i++) { s->sockets[i].events = POLLIN | POLLPRI | POLLERR | POLLHUP; s->sockets[i].revents = 0; } poll(s->sockets, s->sockets_len, (int)(sched_time * 1000.0)); for (i=0; i < s->sockets_len; i++) { if ( s->sockets[i].revents == POLLERR || s->sockets[i].revents == POLLHUP) return 0; if (s->sockets[i].revents) break; } if (i >= s->sockets_len) { sched_time = lo_server_next_event_delay(s); if (sched_time > 0.01) goto again; return dispatch_queued(s); } #else #ifdef HAVE_SELECT if(!initWSock()) return 0; FD_ZERO(&ps); for (i=0; i < s->sockets_len; i++) { FD_SET(s->sockets[i].fd,&ps); if (s->sockets[i].fd > nfds) nfds = s->sockets[i].fd; } stimeout.tv_sec = sched_time; stimeout.tv_usec = (sched_time-stimeout.tv_sec)*1.e6; res = select(nfds+1,&ps,NULL,NULL,&stimeout); if(res == SOCKET_ERROR) { return 0; } if(!res) { sched_time = lo_server_next_event_delay(s); if (sched_time > 0.01) goto again; return dispatch_queued(s); } #endif #endif } else { return dispatch_queued(s); } if (s->protocol == LO_TCP) { data = lo_server_recv_raw_stream(s, &size); } else { data = lo_server_recv_raw(s, &size); } if (!data) { return 0; } if (lo_server_dispatch_data(s, data, size) < 0) { free(data); return -1; } free(data); return size; }
void *lo_server_recv_raw_stream(lo_server s, size_t *size) { struct sockaddr_storage addr; socklen_t addr_len = sizeof(addr); char buffer[LO_MAX_MSG_SIZE]; int32_t read_size; int ret=0, i; void *data = NULL; int sock = -1; int repeat = 1; #ifdef HAVE_SELECT #ifndef HAVE_POLL fd_set ps; int nfds=0; #endif #endif /* check sockets in reverse order so that already-open sockets * have priority. this allows checking for closed sockets even * when new connections are being requested. it also allows to * continue looping through the list of sockets after closing and * deleting a socket, since deleting sockets doesn't affect the * order of the array to the left of the index. */ #ifdef HAVE_POLL for (i=0; i < s->sockets_len; i++) { s->sockets[i].events = POLLIN | POLLPRI; s->sockets[i].revents = 0; } poll(s->sockets, s->sockets_len, -1); for (i=(s->sockets_len-1); i >= 0; --i) { if (s->sockets[i].revents == POLLERR || s->sockets[i].revents == POLLHUP) { if (i>0) { close(s->sockets[i].fd); lo_server_del_socket(s, i, s->sockets[i].fd); continue; } else return NULL; } if (s->sockets[i].revents) { sock = s->sockets[i].fd; #else #ifdef HAVE_SELECT if(!initWSock()) return NULL; FD_ZERO(&ps); for (i=(s->sockets_len-1); i >= 0; --i) { FD_SET(s->sockets[i].fd, &ps); if (s->sockets[i].fd > nfds) nfds = s->sockets[i].fd; } if (select(nfds+1,&ps,NULL,NULL,NULL) == SOCKET_ERROR) return NULL; for (i=0; i < s->sockets_len; i++) { if (FD_ISSET(s->sockets[i].fd, &ps)) { sock = s->sockets[i].fd; #endif #endif if (sock == -1 || !repeat) return NULL; /* zeroeth socket is listening for new connections */ if (sock == s->sockets[0].fd) { sock = accept(sock, (struct sockaddr *)&addr, &addr_len); i = lo_server_add_socket(s, sock); /* only repeat this loop for sockets other than the listening * socket, (otherwise i will be wrong next time around) */ repeat = 0; } if (i<0) { close(sock); return NULL; } ret = recv(sock, &read_size, sizeof(read_size), 0); read_size = ntohl(read_size); if (read_size > LO_MAX_MSG_SIZE || ret <= 0) { close(sock); lo_server_del_socket(s, i, sock); if (ret > 0) lo_throw(s, LO_TOOBIG, "Message too large", "recv()"); continue; } ret = recv(sock, buffer, read_size, 0); if (ret <= 0) { close(sock); lo_server_del_socket(s, i, sock); continue; } /* end of loop over sockets: successfully read data */ break; } } data = malloc(ret); memcpy(data, buffer, ret); if (size) *size = ret; return data; } int lo_server_wait(lo_server s, int timeout) { int sched_timeout = lo_server_next_event_delay(s) * 1000; int i; #ifdef HAVE_SELECT #ifndef HAVE_POLL fd_set ps; struct timeval stimeout; #endif #endif #ifdef HAVE_POLL for (i=0; i < s->sockets_len; i++) { s->sockets[i].events = POLLIN | POLLPRI | POLLERR | POLLHUP; s->sockets[i].revents = 0; } poll(s->sockets, s->sockets_len, timeout > sched_timeout ? sched_timeout : timeout); if (lo_server_next_event_delay(s) < 0.01) return 1; for (i=0; i < s->sockets_len; i++) { if (s->sockets[i].revents == POLLERR || s->sockets[i].revents == POLLHUP) return 0; if (s->sockets[i].revents) return 1; } #else #ifdef HAVE_SELECT int res,to,nfds=0; if(!initWSock()) return 0; to = timeout > sched_timeout ? sched_timeout : timeout; stimeout.tv_sec = to/1000; stimeout.tv_usec = (to%1000)*1000; FD_ZERO(&ps); for (i=0; i < s->sockets_len; i++) { FD_SET(s->sockets[i].fd,&ps); if (s->sockets[i].fd > nfds) nfds = s->sockets[i].fd; } res = select(nfds+1,&ps,NULL,NULL,&stimeout); if(res == SOCKET_ERROR) return 0; if (res || lo_server_next_event_delay(s) < 0.01) return 1; #endif #endif return 0; } int lo_server_recv_noblock(lo_server s, int timeout) { int result = lo_server_wait(s,timeout); if (result>0) { return lo_server_recv(s); } else { return 0; } }