Sigrid Solveig Haflínudóttircrude openbsd+openal port3ce12953 years agoHistory
1406 lines · 32.7 KB · C
RawDownload
/* *  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.

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t