From c5e0079ae1323ad4c35d28f83ce732bb3820c46a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?IOhannes=20m=20zm=C3=B6lnig?= Date: Mon, 31 Aug 2015 22:11:51 +0000 Subject: un-threaded receive svn path=/trunk/externals/iem/iemnet/; revision=17543 --- Makefile | 4 +- iemnet.c | 130 +++++++---- iemnet.h | 97 ++++---- iemnet_data.c | 202 +++++++++++----- iemnet_data.h | 14 +- iemnet_notify.c | 120 ---------- iemnet_receiver.c | 265 +++++---------------- iemnet_sender.c | 161 ++++++++----- tcpclient.c | 254 +++++++++++--------- tcpreceive.c | 225 +++++++++--------- tcpsend.c | 90 +++---- tcpserver.c | 553 ++++++++++++++++++++++++++------------------ tests/sequence/01_server.pd | 118 +++++----- udpclient.c | 172 ++++++++------ udpreceive.c | 180 +++++++++----- udpsend.c | 87 ++++--- udpserver.c | 479 ++++++++++++++++++++++---------------- 17 files changed, 1691 insertions(+), 1460 deletions(-) delete mode 100644 iemnet_notify.c diff --git a/Makefile b/Makefile index 4bb04bc..41ec52d 100644 --- a/Makefile +++ b/Makefile @@ -8,7 +8,7 @@ LIBRARY_NAME = iemnet # objects, the matching .tcl file too SOURCES = tcpserver.c tcpclient.c tcpsend.c tcpreceive.c udpreceive.c udpsend.c udpclient.c udpserver.c -SHARED_SOURCES = iemnet.c iemnet_data.c iemnet_receiver.c iemnet_sender.c iemnet_notify.c +SHARED_SOURCES = iemnet.c iemnet_data.c iemnet_receiver.c iemnet_sender.c SHARED_HEADERS = iemnet_data.h iemnet.h # list all pd objects (i.e. myobject.pd) files here, and their helpfiles will @@ -231,6 +231,8 @@ ifeq (MINGW,$(findstring MINGW,$(UNAME))) DISTBINDIR=$(DISTDIR)-$(OS) endif +-include Makefile.local + # in case somebody manually set the HELPPATCHES above HELPPATCHES ?= $(SOURCES:.c=-help.pd) $(PDOBJECTS:.pd=-help.pd) diff --git a/iemnet.c b/iemnet.c index 8f3ba53..2ad4d70 100644 --- a/iemnet.c +++ b/iemnet.c @@ -1,7 +1,7 @@ /* iemnet * this file provides core infrastructure for the iemnet-objects * - * copyright (c) 2010-2011 IOhannes m zmölnig, IEM + * copyright (c) 2010-2011 IOhannes m zmölnig, IEM */ /* This program is free software; you can redistribute it and/or */ @@ -15,9 +15,8 @@ /* GNU General Public License for more details. */ /* */ /* You should have received a copy of the GNU General Public License */ -/* along with this program; if not, write to the Free Software */ -/* Foundation, Inc., */ -/* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ +/* along with this program; if not, see */ +/* http://www.gnu.org/licenses/ */ /* */ #define DEBUGLEVEL @@ -27,16 +26,37 @@ #include +/* close a socket properly */ +void iemnet__closesocket(int sockfd) +{ + if(sockfd >=0) { +#ifndef SHUT_RDWR +# define SHUT_RDWR 2 +#endif + int how=SHUT_RDWR; + int err = shutdown(sockfd, + how); /* needed on linux, since the recv won't shutdown on sys_closesocket() alone */ + if(err) { + perror("iemnet:socket-shutdown"); + } + sys_closesocket(sockfd); + } +} + -void iemnet__addrout(t_outlet*status_outlet, t_outlet*address_outlet, - long address, unsigned short port) { +/* various functions to send data to output in a uniform way */ +void iemnet__addrout(t_outlet*status_outlet, t_outlet*address_outlet, + long address, unsigned short port) +{ static t_atom addr[5]; static int firsttime=1; if(firsttime) { int i=0; - for(i=0; i<5; i++)SETFLOAT(addr+i, 0); + for(i=0; i<5; i++) { + SETFLOAT(addr+i, 0); + } firsttime=0; } @@ -46,29 +66,48 @@ void iemnet__addrout(t_outlet*status_outlet, t_outlet*address_outlet, addr[3].a_w.w_float = (address & 0x0FF); addr[4].a_w.w_float = port; - if(status_outlet )outlet_anything(status_outlet , gensym("address"), 5, addr); - if(address_outlet)outlet_list (address_outlet, gensym("list" ), 5, addr); + if(status_outlet ) { + outlet_anything(status_outlet , gensym("address"), 5, addr); + } + if(address_outlet) { + outlet_list (address_outlet, gensym("list" ), 5, addr); + } } -void iemnet__numconnout(t_outlet*status_outlet, t_outlet*numcon_outlet, int numconnections) { +void iemnet__numconnout(t_outlet*status_outlet, t_outlet*numcon_outlet, + int numconnections) +{ t_atom atom[1]; SETFLOAT(atom, numconnections); - if(status_outlet)outlet_anything(status_outlet , gensym("connections"), 1, atom); - if(numcon_outlet)outlet_float (numcon_outlet, numconnections); + if(status_outlet) { + outlet_anything(status_outlet , gensym("connections"), 1, atom); + } + if(numcon_outlet) { + outlet_float (numcon_outlet, numconnections); + } } -void iemnet__socketout(t_outlet*status_outlet, t_outlet*socket_outlet, int socketfd) { +void iemnet__socketout(t_outlet*status_outlet, t_outlet*socket_outlet, + int socketfd) +{ t_atom atom[1]; SETFLOAT(atom, socketfd); - if(status_outlet)outlet_anything(status_outlet , gensym("socket"), 1, atom); - if(socket_outlet)outlet_float (socket_outlet, socketfd); + if(status_outlet) { + outlet_anything(status_outlet , gensym("socket"), 1, atom); + } + if(socket_outlet) { + outlet_float (socket_outlet, socketfd); + } } -void iemnet__streamout(t_outlet*outlet, int argc, t_atom*argv, int stream) { - if(NULL==outlet)return; +void iemnet__streamout(t_outlet*outlet, int argc, t_atom*argv, int stream) +{ + if(NULL==outlet) { + return; + } if(stream) { while(argc-->0) { @@ -85,7 +124,8 @@ typedef struct _names { struct _names*next; } t_iemnet_names; static t_iemnet_names*namelist=0; -static int iemnet__nametaken(const char*namestring) { +static int iemnet__nametaken(const char*namestring) +{ t_symbol*name=gensym(namestring); t_iemnet_names*curname=namelist; t_iemnet_names*lastname=curname; @@ -102,16 +142,20 @@ static int iemnet__nametaken(const char*namestring) { curname->name=name; curname->next=0; - if(lastname) + if(lastname) { lastname->next=curname; - else + } else { namelist=curname; + } return 0; } -int iemnet__register(const char*name) { - if(iemnet__nametaken(name))return 0; +int iemnet__register(const char*name) +{ + if(iemnet__nametaken(name)) { + return 0; + } post("iemnet - networking with Pd: [%s]", name); #ifdef LIBRARY_VERSION post(" version "LIBRARY_VERSION""); @@ -140,46 +184,52 @@ void udpserver_setup(void); static int iemnet_debuglevel_=0; static pthread_mutex_t debug_mtx = PTHREAD_MUTEX_INITIALIZER; -void iemnet_debuglevel(void*x, t_float f) { +void iemnet_debuglevel(void*x, t_float f) +{ static int firsttime=1; #ifdef IEMNET_HAVE_DEBUG int debuglevel=(int)f; - pthread_mutex_lock(&debug_mtx); + pthread_mutex_lock(&debug_mtx); iemnet_debuglevel_=debuglevel; - pthread_mutex_unlock(&debug_mtx); + pthread_mutex_unlock(&debug_mtx); post("iemnet: setting debuglevel to %d", debuglevel); #else - if(firsttime)post("iemnet compiled without debug!"); + if(firsttime) { + post("iemnet compiled without debug!"); + } #endif firsttime=0; } -int iemnet_debug(int debuglevel, const char*file, unsigned int line, const char*function) { +int iemnet_debug(int debuglevel, const char*file, unsigned int line, + const char*function) +{ #ifdef IEMNET_HAVE_DEBUG int debuglevel_=0; - pthread_mutex_lock(&debug_mtx); + pthread_mutex_lock(&debug_mtx); debuglevel_=iemnet_debuglevel_; - pthread_mutex_unlock(&debug_mtx); + pthread_mutex_unlock(&debug_mtx); if(debuglevel_ & debuglevel) { - startpost("[%s:%d#%d] ", function, line, debuglevel); + startpost("[%s[%d]:%s#%d] ", file, line, function, debuglevel); return 1; } #endif return 0; } -IEMNET_EXTERN void iemnet_setup(void) { +IEMNET_EXTERN void iemnet_setup(void) +{ #ifdef _MSC_VER - tcpclient_setup(); - tcpreceive_setup(); - tcpsend_setup(); - tcpserver_setup(); - - udpclient_setup(); - udpreceive_setup(); - udpsend_setup(); - udpserver_setup(); + tcpclient_setup(); + tcpreceive_setup(); + tcpsend_setup(); + tcpserver_setup(); + + udpclient_setup(); + udpreceive_setup(); + udpsend_setup(); + udpserver_setup(); #endif } diff --git a/iemnet.h b/iemnet.h index 60cefa5..614b286 100644 --- a/iemnet.h +++ b/iemnet.h @@ -2,7 +2,7 @@ * iemnet * networking for Pd * - * (c) 2010 IOhannes m zmölnig + * (c) 2010 IOhannes m zmölnig * Institute of Electronic Music and Acoustics (IEM) * University of Music and Dramatic Arts (KUG), Graz, Austria * @@ -23,9 +23,8 @@ /* GNU General Public License for more details. */ /* */ /* You should have received a copy of the GNU General Public License */ -/* along with this program; if not, write to the Free Software */ -/* Foundation, Inc., */ -/* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ +/* along with this program; if not, see */ +/* http://www.gnu.org/licenses/ */ /* */ /* ---------------------------------------------------------------------------- */ @@ -66,28 +65,43 @@ EXTERN void sys_rmpollfn(int fd); typedef struct _iemnet_sender t_iemnet_sender; EXTERN_STRUCT _iemnet_sender; +/** + * user provided send function + * (defaults to just using send) + * this function is guaranteed to be called with a valid 'chunk', + * and the 'userdata' and 'sockfd' provided at sender-creation + */ +typedef int (*t_iemnet_sendfunction)(const void*userdata, int sockfd, + t_iemnet_chunk*chunk); + /** * create a sender to a given socket * * \param sock a previously opened socket + * \param sendfun a send()-implementation (or NULL, to use the default send/sendto based implementation) + * \param userdata pointer to optional userdata to be passsed to `sendfun` + * \param bool indicating whether this function is called from a subthread (1) or the mainthread (0) * \return pointer to a sender object * \note the socket must be writeable */ -t_iemnet_sender*iemnet__sender_create(int sock); +t_iemnet_sender*iemnet__sender_create(int sock, + t_iemnet_sendfunction sendfun, const void*userdata, + int); /** * destroy a sender to a given socket * destroying a sender will free all resources of the sender * * \param pointer to a sender object to be destroyed + * \param bool indicating whether this function is called from a subthread (1) or the mainthread (0) * * \note it will also close() the socket */ -void iemnet__sender_destroy(t_iemnet_sender*); +void iemnet__sender_destroy(t_iemnet_sender*, int); /** * send data over a socket * - * \param pointer to a sender object + * \param pointer to a sender object * \param pointer to a chunk of data to be sent * \return the current fill state of the send buffer * @@ -98,7 +112,7 @@ int iemnet__sender_send(t_iemnet_sender*, t_iemnet_chunk*); /** * query the fill state of the send buffer * - * \param pointer to a sender object + * \param pointer to a sender object * \return the current fill state of the send buffer */ int iemnet__sender_getsize(t_iemnet_sender*); @@ -114,9 +128,11 @@ EXTERN_STRUCT _iemnet_receiver; /** * callback function for receiving * whenever data arrives at the socket, a callback will be called synchronously + * if rawdata is NULL, this signifies that the socket has been closed */ -typedef void (*t_iemnet_receivecallback)(void*userdata, - t_iemnet_chunk*rawdata); +typedef void (*t_iemnet_receivecallback)(void*userdata + , t_iemnet_chunk*rawdata + ); /** * create a receiver object @@ -126,61 +142,40 @@ typedef void (*t_iemnet_receivecallback)(void*userdata, * \param sock the (readable) socket to receive from * \param data user data to be passed to callback * \param callback a callback function that is called on the caller's side + * \param subthread bool indicating whether this function is called from a subthread (1) or the mainthread (0) * * \note the callback will be scheduled in the caller's thread with clock_delay() */ -t_iemnet_receiver*iemnet__receiver_create(int sock, void*data, t_iemnet_receivecallback callback); +t_iemnet_receiver*iemnet__receiver_create(int sock, void*data, + t_iemnet_receivecallback callback, int subthread); /** * destroy a receiver at a given socket * destroying a receiver will free all resources of the receiver * * \param pointer to a receiver object to be destroyed + * \param bool indicating whether this function is called from a subthread (1) or the mainthread (0) * * \note it will also close() the socket */ -void iemnet__receiver_destroy(t_iemnet_receiver*); +void iemnet__receiver_destroy(t_iemnet_receiver*, int subthread); /** * query the fill state of the receive buffer * - * \param pointer to a receiver object + * \param pointer to a receiver object * \return the current fill state of the receive buffer */ int iemnet__receiver_getsize(t_iemnet_receiver*); -/** - * opaque data type used for a notification server - */ -#define t_iemnet_notifier struct _iemnet_notifier -EXTERN_STRUCT _iemnet_notifier; -t_iemnet_notifier*iemnet__notify_create(void); -void iemnet__notify_destroy(t_iemnet_notifier*x); +/* convenience functions */ /** - * opaque data type used for a notification client - */ -#define t_iemnet_notify struct _iemnet_notify -EXTERN_STRUCT _iemnet_notify; -void iemnet__notify_remove(t_iemnet_notify*notify); -/** - * callback function from main thread on notification - */ -typedef void (*t_iemnet_notifun)(void *data); -/** - * register a new notification callback with the 'notifier' server. - * on success, returns a notification client to be passed to iemnet__notify() - * on failure, returns NULL - */ -t_iemnet_notify*iemnet__notify_add(t_iemnet_notifier*notifier, t_iemnet_notifun fun, void*data); -/** - * tell mainthread that something happened with 'notify' client - * (will call the callback associated to 'notify' asap) + * properly close a socket fd + * + * \param sock socket to close */ -void iemnet__notify(t_iemnet_notify*notify); - - -/* convenience functions */ +void iemnet__closesocket(int fd); /** * output the address (IP, port) @@ -194,7 +189,8 @@ void iemnet__notify(t_iemnet_notify*notify); * * \note the address will be output as a 5 element list, with the 1st 4 elements denoting the quads of the IP address (as bytes) and the last element the port */ -void iemnet__addrout(t_outlet*status_outlet, t_outlet*address_outlet, long address, unsigned short port); +void iemnet__addrout(t_outlet*status_outlet, t_outlet*address_outlet, + long address, unsigned short port); /** * output the socket we received data from @@ -205,7 +201,8 @@ void iemnet__addrout(t_outlet*status_outlet, t_outlet*address_outlet, long addre * \param socket_outlet outlet for sockets only * \param sockfd the socket */ -void iemnet__socketout(t_outlet*status_outlet, t_outlet*socket_outlet, int sockfd); +void iemnet__socketout(t_outlet*status_outlet, t_outlet*socket_outlet, + int sockfd); /** * output the number of connections @@ -216,7 +213,8 @@ void iemnet__socketout(t_outlet*status_outlet, t_outlet*socket_outlet, int sockf * \param address_outlet outlet for numconnections only * \param numconnections the number of connections */ -void iemnet__numconnout(t_outlet*status_outlet, t_outlet*numconn_outlet, int numconnections); +void iemnet__numconnout(t_outlet*status_outlet, t_outlet*numconn_outlet, + int numconnections); /** * output a list as a stream (serialize) @@ -275,7 +273,8 @@ int iemnet__register(const char*name); #endif void iemnet_debuglevel(void*,t_float); -int iemnet_debug(int debuglevel, const char*file, unsigned int line, const char*function); +int iemnet_debug(int debuglevel, const char*file, unsigned int line, + const char*function); #define DEBUGMETHOD(c) class_addmethod(c, (t_method)iemnet_debuglevel, gensym("debug"), A_FLOAT, 0) @@ -284,9 +283,13 @@ int iemnet_debug(int debuglevel, const char*file, unsigned int line, const char* # undef DEBUG # define DEBUG if(iemnet_debug(DEBUGLEVEL, __FILE__, __LINE__, __FUNCTION__))post #else -static void debug_dummy(const char *format, ...) {;} +static void debug_dummy(const char *format, ...) +{ + ; +} # define DEBUG debug_dummy #endif +#define MARK() post("%s:%d [%s]", __FILE__, __LINE__, __FUNCTION__) #endif /* INCLUDE_IEMNET_H_ */ diff --git a/iemnet_data.c b/iemnet_data.c index 965a326..f0dea5f 100644 --- a/iemnet_data.c +++ b/iemnet_data.c @@ -4,7 +4,7 @@ * - wrappers for data "chunks" * - queues * - * copyright (c) 2010 IOhannes m zmölnig, IEM + * copyright (c) 2010 IOhannes m zmölnig, IEM */ /* This program is free software; you can redistribute it and/or */ @@ -18,9 +18,8 @@ /* GNU General Public License for more details. */ /* */ /* You should have received a copy of the GNU General Public License */ -/* along with this program; if not, write to the Free Software */ -/* Foundation, Inc., */ -/* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ +/* along with this program; if not, see */ +/* http://www.gnu.org/licenses/ */ /* */ #define DEBUGLEVEL 8 @@ -44,18 +43,27 @@ /* data handling */ -t_iemnet_floatlist*iemnet__floatlist_init(t_iemnet_floatlist*cl) { +t_iemnet_floatlist*iemnet__floatlist_init(t_iemnet_floatlist*cl) +{ unsigned int i; - if(NULL==cl)return NULL; - for(i=0; isize; i++) + if(NULL==cl) { + return NULL; + } + for(i=0; isize; i++) { SETFLOAT((cl->argv+i), 0.f); + } return cl; } -void iemnet__floatlist_destroy(t_iemnet_floatlist*cl) { - if(NULL==cl)return; - if(cl->argv) free(cl->argv); +void iemnet__floatlist_destroy(t_iemnet_floatlist*cl) +{ + if(NULL==cl) { + return; + } + if(cl->argv) { + free(cl->argv); + } cl->argv=NULL; cl->argc=0; cl->size=0; @@ -63,9 +71,13 @@ void iemnet__floatlist_destroy(t_iemnet_floatlist*cl) { free(cl); } -t_iemnet_floatlist*iemnet__floatlist_create(unsigned int size) { - t_iemnet_floatlist*result=(t_iemnet_floatlist*)malloc(sizeof(t_iemnet_floatlist)); - if(NULL==result)return NULL; +t_iemnet_floatlist*iemnet__floatlist_create(unsigned int size) +{ + t_iemnet_floatlist*result=(t_iemnet_floatlist*)malloc(sizeof( + t_iemnet_floatlist)); + if(NULL==result) { + return NULL; + } result->argv = (t_atom*)malloc(size*sizeof(t_atom)); if(NULL==result->argv) { @@ -81,7 +93,9 @@ t_iemnet_floatlist*iemnet__floatlist_create(unsigned int size) { return result; } -t_iemnet_floatlist*iemnet__floatlist_resize(t_iemnet_floatlist*cl, unsigned int size) { +t_iemnet_floatlist*iemnet__floatlist_resize(t_iemnet_floatlist*cl, + unsigned int size) +{ t_atom*tmp; if (NULL==cl) { return iemnet__floatlist_create(size); @@ -93,7 +107,9 @@ t_iemnet_floatlist*iemnet__floatlist_resize(t_iemnet_floatlist*cl, unsigned int } tmp=(t_atom*)malloc(size*sizeof(t_atom)); - if(NULL==tmp) return NULL; + if(NULL==tmp) { + return NULL; + } free(cl->argv); @@ -105,10 +121,15 @@ t_iemnet_floatlist*iemnet__floatlist_resize(t_iemnet_floatlist*cl, unsigned int return cl; } -void iemnet__chunk_destroy(t_iemnet_chunk*c) { - if(NULL==c)return; +void iemnet__chunk_destroy(t_iemnet_chunk*c) +{ + if(NULL==c) { + return; + } - if(c->data)free(c->data); + if(c->data) { + free(c->data); + } c->data=NULL; c->size=0; @@ -117,17 +138,26 @@ void iemnet__chunk_destroy(t_iemnet_chunk*c) { } -void iemnet__chunk_print(t_iemnet_chunk*c) { +void iemnet__chunk_print(t_iemnet_chunk*c) +{ unsigned int i=0; startpost("chunk[%p:%d]", c, c?c->size:0); - if(!c)return; - for(i=0; isize; i++) + if(!c) { + return; + } + for(i=0; isize; i++) { startpost(" %d", c->data[i]); + } endpost(); } -t_iemnet_chunk* iemnet__chunk_create_empty(int size) { - t_iemnet_chunk*result=(t_iemnet_chunk*)malloc(sizeof(t_iemnet_chunk)); +t_iemnet_chunk* iemnet__chunk_create_empty(int size) +{ + t_iemnet_chunk*result=NULL; + if(size<1) { + return NULL; + } + result=(t_iemnet_chunk*)malloc(sizeof(t_iemnet_chunk)); if(result) { result->size=size; result->data=(unsigned char*)malloc(sizeof(unsigned char)*size); @@ -142,12 +172,14 @@ t_iemnet_chunk* iemnet__chunk_create_empty(int size) { result->addr=0L; result->port=0; + result->family=AF_INET; } return result; } -t_iemnet_chunk* iemnet__chunk_create_data(int size, unsigned char*data) { +t_iemnet_chunk* iemnet__chunk_create_data(int size, unsigned char*data) +{ t_iemnet_chunk*result=iemnet__chunk_create_empty(size); if(result) { memcpy(result->data, data, result->size); @@ -156,20 +188,25 @@ t_iemnet_chunk* iemnet__chunk_create_data(int size, unsigned char*data) { } t_iemnet_chunk* iemnet__chunk_create_dataaddr(int size, - unsigned char*data, - struct sockaddr_in*addr) { + unsigned char*data, + struct sockaddr_in*addr) +{ t_iemnet_chunk*result=iemnet__chunk_create_data(size, data); if(result && addr) { result->addr = ntohl(addr->sin_addr.s_addr); result->port = ntohs(addr->sin_port); + result->family = addr->sin_family; } return result; } -t_iemnet_chunk* iemnet__chunk_create_list(int argc, t_atom*argv) { +t_iemnet_chunk* iemnet__chunk_create_list(int argc, t_atom*argv) +{ int i; t_iemnet_chunk*result=iemnet__chunk_create_empty(argc); - if(NULL==result)return NULL; + if(NULL==result) { + return NULL; + } for(i=0; isize, c->data); - result->addr=c->addr; - result->port=c->port; - + if(result) { + result->addr=c->addr; + result->port=c->port; + } return result; } -t_iemnet_floatlist*iemnet__chunk2list(t_iemnet_chunk*c, t_iemnet_floatlist*dest) { +t_iemnet_floatlist*iemnet__chunk2list(t_iemnet_chunk*c, + t_iemnet_floatlist*dest) +{ unsigned int i; - if(NULL==c)return NULL; + if(NULL==c) { + return NULL; + } dest=iemnet__floatlist_resize(dest, c->size); - if(NULL==dest)return NULL; + if(NULL==dest) { + return NULL; + } for(i=0; isize; i++) { dest->argv[i].a_w.w_float = c->data[i]; @@ -234,12 +281,14 @@ struct _iemnet_queue { int used; // use counter, so queue_finish can wait for blocking accesses to finish }; -static void queue_use_increment(t_iemnet_queue* _this) { +static void queue_use_increment(t_iemnet_queue* _this) +{ pthread_mutex_lock(&_this->usedmtx); _this->used++; pthread_mutex_unlock(&_this->usedmtx); } -static void queue_use_decrement(t_iemnet_queue* _this) { +static void queue_use_decrement(t_iemnet_queue* _this) +{ pthread_mutex_lock(&_this->usedmtx); _this->used--; pthread_cond_signal(&_this->usedcond); @@ -250,19 +299,24 @@ static void queue_use_decrement(t_iemnet_queue* _this) { * this will return the current queue size */ int queue_push( - t_iemnet_queue* const _this, - t_iemnet_chunk* const data - ) { + t_iemnet_queue* const _this, + t_iemnet_chunk* const data +) +{ t_node* tail; t_node* n=NULL; int size=-1; - if(NULL == _this)return size; + if(NULL == _this) { + return size; + } pthread_mutex_lock(&_this->mtx); size=_this->size; pthread_mutex_unlock(&_this->mtx); - if(NULL == data) return size; + if(NULL == data) { + return size; + } n=(t_node*)malloc(sizeof(t_node)); @@ -294,18 +348,21 @@ int queue_push( * OR the queue is "done" (in which case NULL is returned) */ t_iemnet_chunk* queue_pop_block( - t_iemnet_queue* const _this - ) { + t_iemnet_queue* const _this +) +{ t_node* head=0; t_iemnet_chunk*data=0; - if(NULL == _this)return NULL; + if(NULL == _this) { + return NULL; + } queue_use_increment(_this); pthread_mutex_lock(&_this->mtx); /* if the queue is empty, wait */ - if(NULL == _this->head) { + while(NULL == _this->head) { pthread_cond_wait(&_this->cond, &_this->mtx); /* somebody signaled us, that we should do some work * either the queue has been filled, or we are done... @@ -320,11 +377,13 @@ t_iemnet_chunk* queue_pop_block( head = _this->head; /* update _this */ - if (! (_this->head = head->next)) { - _this->tail = 0; - } - if(head && head->data) { - _this->size-=head->data->size; + if(head) { + if (! (_this->head = head->next)) { + _this->tail = 0; + } + if(head->data) { + _this->size-=head->data->size; + } } pthread_mutex_unlock(&_this->mtx); @@ -342,11 +401,14 @@ t_iemnet_chunk* queue_pop_block( * (note that despite of the name this does block for synchronization) */ t_iemnet_chunk* queue_pop_noblock( - t_iemnet_queue* const _this - ) { + t_iemnet_queue* const _this +) +{ t_node* head=0; t_iemnet_chunk*data=0; - if(NULL == _this)return NULL; + if(NULL == _this) { + return NULL; + } queue_use_increment(_this); pthread_mutex_lock(&_this->mtx); @@ -375,11 +437,13 @@ t_iemnet_chunk* queue_pop_noblock( return data; } -t_iemnet_chunk* queue_pop(t_iemnet_queue* const _this) { +t_iemnet_chunk* queue_pop(t_iemnet_queue* const _this) +{ return queue_pop_block(_this); } -int queue_getsize(t_iemnet_queue* const _this) { +int queue_getsize(t_iemnet_queue* const _this) +{ int size=-1; if(_this) { pthread_mutex_lock(&_this->mtx); @@ -388,9 +452,12 @@ int queue_getsize(t_iemnet_queue* const _this) { } return size; } -void queue_finish(t_iemnet_queue* q) { +void queue_finish(t_iemnet_queue* q) +{ DEBUG("queue_finish: %x", q); - if(NULL==q) return; + if(NULL==q) { + return; + } pthread_mutex_lock(&q->mtx); q->done=1; @@ -401,16 +468,20 @@ void queue_finish(t_iemnet_queue* q) { /* wait until queue is no longer used */ pthread_mutex_lock(&q->usedmtx); - while(q->used) pthread_cond_wait(&q->usedcond, &q->usedmtx); + while(q->used) { + pthread_cond_wait(&q->usedcond, &q->usedmtx); + } pthread_mutex_unlock(&q->usedmtx); DEBUG("queue_finished: %x", q); } -void queue_destroy(t_iemnet_queue* q) { +void queue_destroy(t_iemnet_queue* q) +{ t_iemnet_chunk*c=NULL; - if(NULL==q) + if(NULL==q) { return; + } DEBUG("queue destroy %x", q); queue_finish(q); @@ -434,13 +505,16 @@ void queue_destroy(t_iemnet_queue* q) { DEBUG("queue destroyed %x", q); } -t_iemnet_queue* queue_create(void) { +t_iemnet_queue* queue_create(void) +{ static pthread_mutex_t mtx = PTHREAD_MUTEX_INITIALIZER; static pthread_cond_t cond = PTHREAD_COND_INITIALIZER; t_iemnet_queue*q=(t_iemnet_queue*)malloc(sizeof(t_iemnet_queue)); DEBUG("queue create %x", q); - if(NULL==q)return NULL; + if(NULL==q) { + return NULL; + } q->head = NULL; q->tail = NULL; diff --git a/iemnet_data.h b/iemnet_data.h index f9a043c..80a8eed 100644 --- a/iemnet_data.h +++ b/iemnet_data.h @@ -2,7 +2,7 @@ * iemnet * networking for Pd * - * (c) 2010 IOhannes m zmölnig + * (c) 2010 IOhannes m zmölnig * Institute of Electronic Music and Acoustics (IEM) * University of Music and Dramatic Arts (KUG), Graz, Austria * @@ -23,9 +23,8 @@ /* GNU General Public License for more details. */ /* */ /* You should have received a copy of the GNU General Public License */ -/* along with this program; if not, write to the Free Software */ -/* Foundation, Inc., */ -/* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ +/* along with this program; if not, see */ +/* http://www.gnu.org/licenses/ */ /* */ /* ---------------------------------------------------------------------------- */ @@ -67,6 +66,7 @@ typedef struct _iemnet_chunk { long addr; unsigned short port; + short family; // AF_INET, AF_INET6 } t_iemnet_chunk; /** @@ -103,7 +103,8 @@ t_iemnet_chunk*iemnet__chunk_create_data(int size, unsigned char*data); * \param addr originating address (can be NULL) * \return a new chunk that holds a copy of data */ -t_iemnet_chunk*iemnet__chunk_create_dataaddr(int size, unsigned char*data, struct sockaddr_in*addr); +t_iemnet_chunk*iemnet__chunk_create_dataaddr(int size, unsigned char*data, + struct sockaddr_in*addr); /** * initialize a "chunk" (allocate memory,...) with given data * receiver address will be set to 0 @@ -130,7 +131,8 @@ t_iemnet_chunk*iemnet__chunk_create_chunk(t_iemnet_chunk*source); * \param dest the destination list * \return the destination list if all went well, else NULL */ -t_iemnet_floatlist*iemnet__chunk2list(t_iemnet_chunk*c, t_iemnet_floatlist*dest); +t_iemnet_floatlist*iemnet__chunk2list(t_iemnet_chunk*c, + t_iemnet_floatlist*dest); /** diff --git a/iemnet_notify.c b/iemnet_notify.c deleted file mode 100644 index 6bf6a1b..0000000 --- a/iemnet_notify.c +++ /dev/null @@ -1,120 +0,0 @@ -/* iemnet - * - * notify - * notifies mai thread that new data has arrived - * - * copyright (c) 2012 IOhannes m zmölnig, IEM - */ - -/* This program is free software; you can redistribute it and/or */ -/* modify it under the terms of the GNU General Public License */ -/* as published by the Free Software Foundation; either version 2 */ -/* 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 General Public License for more details. */ -/* */ -/* You should have received a copy of the GNU General Public License */ -/* along with this program; if not, write to the Free Software */ -/* Foundation, Inc., */ -/* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ -/* */ - -#define DEBUGLEVEL 4 - -#include "iemnet.h" -#include "iemnet_data.h" - -/* for pipe() */ -#include - -/* for printf() debugging */ -#include - -struct _iemnet_notify { - void*data; - t_iemnet_notifun fun; - struct _iemnet_notifier*parent; - struct _iemnet_notify*next; -}; - -static t_iemnet_notify*pollqueue=NULL; - -struct _iemnet_notifier { - int fd[2]; - struct _iemnet_notify*nodes; -}; - -static t_iemnet_notifier *masternotifier = NULL; - -/* notifies Pd that there is new data to fetch */ -void iemnet__notify(t_iemnet_notify*x) { - write(masternotifier->fd[1], x, sizeof(x)); -} - -static void pollfun(void*x, int fd) { - char buf[4096]; - int result=-1; - t_iemnet_notify*q; - result=read(fd, buf, sizeof(buf)); - for(q=pollqueue; q; q=q->next) { - (q->fun)(q->data); - } -} - -static void iemnet__notifier_print(t_iemnet_notifier*x) { - t_iemnet_notify*q; - for(q=pollqueue; q; q=q->next) { - printf("queue[%p]={fun:%p, data:%p, next:%p}\n", q, q->fun, q->data, q->next); - } -} -t_iemnet_notifier*iemnet__notify_create(void) { - if(masternotifier!=NULL) - return masternotifier; - masternotifier=(t_iemnet_notifier*)getbytes(sizeof(t_iemnet_notifier)); - if(!pipe(masternotifier->fd)) { - sys_addpollfn(masternotifier->fd[0], pollfun, masternotifier); - return masternotifier; - } - return NULL; -} -void iemnet__notify_destroy(t_iemnet_notifier*x) { - // nada -} - -t_iemnet_notify*iemnet__notify_add(t_iemnet_notifier*notifier, t_iemnet_notifun fun, void*data) { - /* add the given receiver to the poll-queue - * LATER: check whether it's already in there... - */ - t_iemnet_notify*q=(t_iemnet_notify*)getbytes(sizeof(t_iemnet_notify)); - q->fun =fun; - q->data=data; - q->parent=notifier; - q->next=pollqueue; - pollqueue=q; - //iemnet__notifier_print(notifier); - return q; -} -void iemnet__notify_remove(t_iemnet_notify*x) { - t_iemnet_notify*q=pollqueue; - t_iemnet_notify*last=NULL; - //iemnet__notifier_print(q->parent); - - for(q=pollqueue; q; q=q->next) { - if(q == x) { - if(last) { - last->next=q->next; - } else { - pollqueue=q->next; - } - q->fun =NULL; - q->data=NULL; - q->next=NULL; - freebytes(q, sizeof(*q)); - return; - } - last=q; - } -} diff --git a/iemnet_receiver.c b/iemnet_receiver.c index f9f3fa8..898bac8 100644 --- a/iemnet_receiver.c +++ b/iemnet_receiver.c @@ -2,9 +2,8 @@ * * receiver * receives data "chunks" from a socket - * possibly threaded * - * copyright (c) 2010 IOhannes m zmölnig, IEM + * copyright (c) 2010-2015 IOhannes m zmölnig, IEM */ /* This program is free software; you can redistribute it and/or */ @@ -18,9 +17,8 @@ /* GNU General Public License for more details. */ /* */ /* You should have received a copy of the GNU General Public License */ -/* along with this program; if not, write to the Free Software */ -/* Foundation, Inc., */ -/* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ +/* along with this program; if not, see */ +/* http://www.gnu.org/licenses/ */ /* */ #define DEBUGLEVEL 4 @@ -28,258 +26,115 @@ #include "iemnet.h" #include "iemnet_data.h" -#include -#include #include #include -#include - #define INBUFSIZE 65536L /* was 4096: size of receiving data buffer */ struct _iemnet_receiver { - pthread_t recthread; int sockfd; /* owned outside; you must call iemnet__receiver_destroy() before freeing socket yourself */ void*userdata; - t_iemnet_chunk*data; t_iemnet_receivecallback callback; - t_iemnet_queue*queue; - - int running; - int keepreceiving; - - pthread_mutex_t running_mtx, keeprec_mtx; - pthread_cond_t running_cond; - t_iemnet_notify*notifier; }; -static t_iemnet_notifier*receivenotifier=NULL; - -/* the workhorse of the family */ -static void*iemnet__receiver_readthread(void*arg) { - unsigned int i=0; - int result = 0; - t_iemnet_receiver*receiver=(t_iemnet_receiver*)arg; - int sockfd=receiver->sockfd; - t_iemnet_queue*q=receiver->queue; +static void pollfun(void*z, int fd) +{ + // read data from socket and call callback + t_iemnet_receiver*rec=(t_iemnet_receiver*)z; unsigned char data[INBUFSIZE]; unsigned int size=INBUFSIZE; + t_iemnet_chunk*chunk=NULL; + int result = 0; + int local_errno = 0; struct sockaddr_in from; socklen_t fromlen = sizeof(from); int recv_flags=0; - - struct timeval timout; - fd_set readset; - FD_ZERO(&readset); - FD_SET(sockfd, &readset); - - for(i=0; irunning=1; - - pthread_mutex_lock (&receiver->running_mtx); - pthread_cond_signal (&receiver->running_cond); - pthread_mutex_unlock(&receiver->running_mtx); - - while(1) { - t_iemnet_chunk*c=NULL; - fd_set rs; - - pthread_mutex_lock(&receiver->keeprec_mtx); - if(!receiver->keepreceiving) { - pthread_mutex_unlock(&receiver->keeprec_mtx); - break; - } - pthread_mutex_unlock(&receiver->keeprec_mtx); - - fromlen = sizeof(from); - rs=readset; - timout.tv_sec=0; - timout.tv_usec=1000; - #ifdef MSG_DONTWAIT - recv_flags|=MSG_DONTWAIT; + recv_flags|=MSG_DONTWAIT; #endif - select(sockfd+1, &rs, NULL, NULL, - &timout); - if (!FD_ISSET(sockfd, &rs))continue; - - DEBUG("select can read"); - - //fprintf(stderr, "reading %d bytes...\n", size); - //result = recv(sockfd, data, size, 0); - - result = recvfrom(sockfd, data, size, recv_flags, (struct sockaddr *)&from, &fromlen); - //fprintf(stderr, "read %d bytes...\n", result); - DEBUG("recfrom %d bytes: %p", result, data); - c= iemnet__chunk_create_dataaddr(result, (result>0)?data:NULL, &from); - DEBUG("pushing"); - queue_push(q, c); - DEBUG("signalling"); - iemnet__notify(receiver->notifier); - - - if(result<=0) break; - - DEBUG("rereceive"); - } - // oha - DEBUG("readthread loop termination: %d", result); - //if(result>=0)iemnet_signalNewData(receiver); - - pthread_mutex_lock(&receiver->running_mtx); - receiver->running=0; - pthread_mutex_unlock(&receiver->running_mtx); - - DEBUG("read thread terminated"); - return NULL; + errno=0; + result = recvfrom(rec->sockfd, data, size, recv_flags, + (struct sockaddr *)&from, &fromlen); + local_errno=errno; + //fprintf(stderr, "read %d bytes...\n", result); + DEBUG("recvfrom %d bytes: %d %p %d", result, rec->sockfd, data, size); + DEBUG("errno=%d", local_errno); + chunk = iemnet__chunk_create_dataaddr(result, (result>0)?data:NULL, &from); + + // call the callback with a NULL-chunk to signal a disconnect event. + (rec->callback)(rec->userdata, chunk); + + iemnet__chunk_destroy(chunk); } -/* callback from Pd's main thread to fetch queued data */ -static void iemnet__receiver_tick(t_iemnet_receiver *x) +t_iemnet_receiver*iemnet__receiver_create(int sock, void*userdata, + t_iemnet_receivecallback callback, int subthread) { - int running=0, keepreceiving=0; - // received data - t_iemnet_chunk*c=queue_pop_noblock(x->queue); - DEBUG("tick got chunk %p", c); - - while(NULL!=c) { - (x->callback)(x->userdata, c); - iemnet__chunk_destroy(c); - c=queue_pop_noblock(x->queue); - } - DEBUG("tick cleanup"); - - pthread_mutex_lock(&x->running_mtx); - running = x->running; - pthread_mutex_unlock(&x->running_mtx); - - DEBUG("tick running %d", running); - if(!running) { - // read terminated - pthread_mutex_lock(&x->keeprec_mtx); - keepreceiving=x->keepreceiving; - pthread_mutex_unlock(&x->keeprec_mtx); - - /* keepreceiving is set, if receiver is not yet in shutdown mode */ - if(keepreceiving) - x->callback(x->userdata, NULL); - } - DEBUG("tick DONE"); -} - -int iemnet__receiver_getsize(t_iemnet_receiver*x) { - int size=-1; - if(x && x->queue) - size=queue_getsize(x->queue); - - return size; -} - - -t_iemnet_receiver*iemnet__receiver_create(int sock, void*userdata, t_iemnet_receivecallback callback) { - static pthread_mutex_t mtx = PTHREAD_MUTEX_INITIALIZER; - t_iemnet_receiver*rec=(t_iemnet_receiver*)malloc(sizeof(t_iemnet_receiver)); - - if(NULL==receivenotifier) - receivenotifier=iemnet__notify_create(); + t_iemnet_receiver*rec=(t_iemnet_receiver*)malloc(sizeof( + t_iemnet_receiver)); DEBUG("create new receiver for 0x%X:%d", userdata, sock); //fprintf(stderr, "new receiver for %d\t%x\t%x\n", sock, userdata, callback); if(rec) { - t_iemnet_chunk*data=NULL; - int res=0; - - data=iemnet__chunk_create_empty(INBUFSIZE); - if(NULL==data) { - iemnet__receiver_destroy(rec); - DEBUG("create receiver failed"); - return NULL; - } - - rec->keepreceiving=1; rec->sockfd=sock; rec->userdata=userdata; - rec->data=data; rec->callback=callback; - pthread_mutex_init(&rec->running_mtx , 0); - pthread_mutex_init(&rec->keeprec_mtx , 0); - - pthread_cond_init(&rec->running_cond, 0); - - rec->running=1; - - rec->queue = queue_create(); - rec->notifier = iemnet__notify_add(receivenotifier, (t_iemnet_notifun)iemnet__receiver_tick, rec); + if(subthread) { + sys_lock(); + } + sys_addpollfn(sock, pollfun, rec); + if(subthread) { + sys_unlock(); + } - /* start the recv thread */ - pthread_mutex_lock(&rec->running_mtx); - res=pthread_create(&rec->recthread, 0, iemnet__receiver_readthread, rec); - if(!res)pthread_cond_wait(&rec->running_cond, &rec->running_mtx); - pthread_mutex_unlock(&rec->running_mtx); } //fprintf(stderr, "new receiver created\n"); return rec; } - -void iemnet__receiver_destroy(t_iemnet_receiver*rec) { - static int instance=0; - int inst=instance++; - +void iemnet__receiver_destroy(t_iemnet_receiver*rec, int subthread) +{ int sockfd; - DEBUG("[%d] destroy receiver %x", inst, rec); - if(NULL==rec)return; - pthread_mutex_lock(&rec->keeprec_mtx); - if(!rec->keepreceiving) { - pthread_mutex_unlock(&rec->keeprec_mtx); + if(NULL==rec) { return; - } - rec->keepreceiving=0; - pthread_mutex_unlock(&rec->keeprec_mtx); + } sockfd=rec->sockfd; - pthread_join(rec->recthread, NULL); - iemnet__notify_remove(rec->notifier); - - DEBUG("[%d] really destroying receiver %x -> %d", inst, rec, sockfd); - - if(sockfd>=0) { - /* this doesn't alway make recvfrom() return! - * - try polling - * - try sending a signal with pthread_kill() ? - */ - - shutdown(sockfd, 2); /* needed on linux, since the recv won't shutdown on sys_closesocket() alone */ - sys_closesocket(sockfd); + if(subthread) { + sys_lock(); } - DEBUG("[%d] closed socket %d", inst, sockfd); - - rec->sockfd=-1; + sys_rmpollfn(rec->sockfd); - // empty the queue - DEBUG("[%d] tick %d", inst, rec->running); - iemnet__receiver_tick(rec); - queue_destroy(rec->queue); - DEBUG("[%d] tack", inst); + // FIXXME: read any remaining bytes from the socket - if(rec->data)iemnet__chunk_destroy(rec->data); + if(subthread) { + sys_unlock(); + } - pthread_mutex_destroy(&rec->running_mtx); - pthread_mutex_destroy(&rec->keeprec_mtx); - pthread_cond_destroy(&rec->running_cond); + DEBUG("[%p] really destroying receiver %d", sockfd); + //iemnet__closesocket(sockfd); + DEBUG("[%p] closed socket %d", rec, sockfd); + rec->sockfd=-1; rec->userdata=NULL; - rec->data=NULL; rec->callback=NULL; - rec->queue=NULL; free(rec); rec=NULL; - DEBUG("[%d] destroyed receiver", inst); +} + + +/* just dummy, since we don't maintain a queue any more */ +int iemnet__receiver_getsize(t_iemnet_receiver*x) +{ + if(x) { + return 0; + } + return -1; } diff --git a/iemnet_sender.c b/iemnet_sender.c index 0e4f866..8cf1d14 100644 --- a/iemnet_sender.c +++ b/iemnet_sender.c @@ -4,7 +4,7 @@ * sends data "chunks" to a socket * possibly threaded * - * copyright (c) 2010 IOhannes m zmölnig, IEM + * copyright (c) 2010 IOhannes m zmölnig, IEM */ /* This program is free software; you can redistribute it and/or */ @@ -18,9 +18,8 @@ /* GNU General Public License for more details. */ /* */ /* You should have received a copy of the GNU General Public License */ -/* along with this program; if not, write to the Free Software */ -/* Foundation, Inc., */ -/* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ +/* along with this program; if not, see */ +/* http://www.gnu.org/licenses/ */ /* */ #define DEBUGLEVEL 2 @@ -54,11 +53,11 @@ static int debug_lockcount=0; # define UNLOCK(x) pthread_mutex_unlock(x) #endif - /* draft: - * - there is a sender thread for each open connection - * - the main thread just adds chunks to each sender threads processing queue - * - the sender thread tries to send the queue as fast as possible - */ +/* draft: + * - there is a sender thread for each open connection + * - the main thread just adds chunks to each sender threads processing queue + * - the sender thread tries to send the queue as fast as possible + */ struct _iemnet_sender { pthread_t thread; @@ -68,62 +67,92 @@ struct _iemnet_sender { int keepsending; // indicates whether we want to thread to continue or to terminate int isrunning; + const void*userdata; /* user provided data */ + t_iemnet_sendfunction sendfun; /* user provided send function */ + pthread_mutex_t mtx; /* mutex to protect isrunning,.. */ }; /* the workhorse of the family */ -static int iemnet__sender_dosend(int sockfd, t_iemnet_queue*q) { + +static int iemnet__sender_defaultsend(const void*x, int sockfd, + t_iemnet_chunk*c) +{ + int result=-1; + struct sockaddr_in to; socklen_t tolen = sizeof(to); - t_iemnet_chunk*c=queue_pop_block(q); - if(c) { - unsigned char*data=c->data; - unsigned int size=c->size; - - int result=-1; + unsigned char*data=c->data; + unsigned int size=c->size; - // fprintf(stderr, "sending %d bytes at %x to %d\n", size, data, sockfd); - if(c->port) { - DEBUG("sending %d bytes to %x:%d", size, c->addr, c->port); + int flags = 0; +#ifdef __linux__ + flags |= MSG_NOSIGNAL; +#endif - to.sin_addr.s_addr=htonl(c->addr); - to.sin_port =htons(c->port); - result = sendto(sockfd, data, size, 0, (struct sockaddr *)&to, tolen); - } else { - DEBUG("sending %d bytes", size); - result = send(sockfd, data, size, 0); - } - if(result<0) { - // broken pipe - return 0; - } + // fprintf(stderr, "sending %d bytes at %x to %d\n", size, data, sockfd); + if(c->port) { + DEBUG("sending %d bytes to %x:%d @%d", size, c->addr, c->port, c->family); - // shouldn't we do something with the result here? - DEBUG("sent %d bytes", result); - iemnet__chunk_destroy(c); + to.sin_addr.s_addr=htonl(c->addr); + to.sin_port =htons(c->port); + to.sin_family =c->family; + result = sendto(sockfd, + data, size, /* DATA */ + flags, /* FLAGS */ + (struct sockaddr *)&to, tolen); /* DESTADDR */ } else { + DEBUG("sending %d bytes", size); + result = send(sockfd, + data, size, /* DATA */ + flags); /* FLAGS */ + } + if(result<0) { + // broken pipe return 0; } + + // shouldn't we do something with the result here? + DEBUG("sent %d bytes", result); return 1; } -static void*iemnet__sender_sendthread(void*arg) { +static void*iemnet__sender_sendthread(void*arg) +{ t_iemnet_sender*sender=(t_iemnet_sender*)arg; int sockfd=-1; t_iemnet_queue*q=NULL; + t_iemnet_chunk*c=NULL; + t_iemnet_sendfunction dosend=iemnet__sender_defaultsend; + const void*userdata=NULL; LOCK(&sender->mtx); - sockfd=sender->sockfd; q=sender->queue; + userdata=sender->userdata; + if(NULL!=sender->sendfun) { + dosend=sender->sendfun; + } + + sockfd=sender->sockfd; + + while(sender->keepsending) { UNLOCK(&sender->mtx); - if(!iemnet__sender_dosend(sockfd, q)){ - LOCK(&sender->mtx); - break; + + c=queue_pop_block(q); + if(c) { + if(!dosend(userdata, sockfd, c)) { + iemnet__chunk_destroy(c); + + LOCK(&sender->mtx); + break; + } + iemnet__chunk_destroy(c); + c=NULL; } LOCK(&sender->mtx); } @@ -133,7 +162,8 @@ static void*iemnet__sender_sendthread(void*arg) { return NULL; } -int iemnet__sender_send(t_iemnet_sender*s, t_iemnet_chunk*c) { +int iemnet__sender_send(t_iemnet_sender*s, t_iemnet_chunk*c) +{ t_iemnet_queue*q=0; int size=-1; LOCK (&s->mtx); @@ -150,10 +180,11 @@ int iemnet__sender_send(t_iemnet_sender*s, t_iemnet_chunk*c) { return size; } -void iemnet__sender_destroy(t_iemnet_sender*s) { +void iemnet__sender_destroy(t_iemnet_sender*s, int subthread) +{ int sockfd=-1; /* simple protection against recursive calls: - * s->keepsending is only set to "0" in here, + * s->keepsending is only set to "0" in here, * so if it is false, we know that we are already being called */ DEBUG("destroy sender %x with queue %x (%d)", s, s->queue, s->keepsending); @@ -178,11 +209,7 @@ void iemnet__sender_destroy(t_iemnet_sender*s) { queue_finish(s->queue); DEBUG("queue finished"); - - if(sockfd>=0) { - int err=shutdown(sockfd, 2); /* needed on linux, since the recv won't shutdown on sys_closesocket() alone */ - sys_closesocket(sockfd); - } + //iemnet__closesocket(sockfd); pthread_join(s->thread, NULL); DEBUG("thread joined"); @@ -191,18 +218,23 @@ void iemnet__sender_destroy(t_iemnet_sender*s) { pthread_mutex_destroy (&s->mtx); memset(s, 0, sizeof(t_iemnet_sender)); + s->sockfd = -1; free(s); s=NULL; DEBUG("destroyed sender"); } -t_iemnet_sender*iemnet__sender_create(int sock) { +t_iemnet_sender*iemnet__sender_create(int sock, + t_iemnet_sendfunction sendfun, const void*userdata, + int subthread) +{ static pthread_mutex_t mtx = PTHREAD_MUTEX_INITIALIZER; - t_iemnet_sender*result=(t_iemnet_sender*)malloc(sizeof(t_iemnet_sender)); + t_iemnet_sender*result=(t_iemnet_sender*)calloc(1, + sizeof(t_iemnet_sender)); int res=0; DEBUG("create sender %x", result); - if(NULL==result){ + if(NULL==result) { DEBUG("create sender failed"); return NULL; } @@ -211,23 +243,28 @@ t_iemnet_sender*iemnet__sender_create(int sock) { result->sockfd = sock; result->keepsending =1; result->isrunning=1; + result->sendfun=sendfun; + result->userdata=userdata; DEBUG("create_sender queue=%x", result->queue); memcpy(&result->mtx , &mtx, sizeof(pthread_mutex_t)); res=pthread_create(&result->thread, 0, iemnet__sender_sendthread, result); if(0==res) { - } else { // something went wrong + queue_destroy(result->queue); + free(result); + return NULL; } DEBUG("created sender"); return result; } -int iemnet__sender_getlasterror(t_iemnet_sender*x) { - x=NULL; +/* coverity[param_set_but_not_used]: as x is there for potentially more specific implentations in the future */ +int iemnet__sender_getlasterror(t_iemnet_sender*x) +{ #ifdef _WIN32 return WSAGetLastError(); #endif @@ -235,27 +272,35 @@ int iemnet__sender_getlasterror(t_iemnet_sender*x) { } -int iemnet__sender_getsockopt(t_iemnet_sender*s, int level, int optname, void *optval, socklen_t*optlen) { +int iemnet__sender_getsockopt(t_iemnet_sender*s, int level, int optname, + void *optval, socklen_t*optlen) +{ int result=getsockopt(s->sockfd, level, optname, optval, optlen); if(result!=0) { - post("%s: getsockopt returned %d", __FUNCTION__, iemnet__sender_getlasterror(s)); + post("%s: getsockopt returned %d", __FUNCTION__, + iemnet__sender_getlasterror(s)); } return result; } -int iemnet__sender_setsockopt(t_iemnet_sender*s, int level, int optname, const void*optval, socklen_t optlen) { +int iemnet__sender_setsockopt(t_iemnet_sender*s, int level, int optname, + const void*optval, socklen_t optlen) +{ int result=setsockopt(s->sockfd, level, optname, optval, optlen); if(result!=0) { - post("%s: setsockopt returned %d", __FUNCTION__, iemnet__sender_getlasterror(s)); + post("%s: setsockopt returned %d", __FUNCTION__, + iemnet__sender_getlasterror(s)); } return result; } -int iemnet__sender_getsize(t_iemnet_sender*x) { +int iemnet__sender_getsize(t_iemnet_sender*x) +{ int size=-1; - if(x && x->queue) + if(x && x->queue) { size=queue_getsize(x->queue); + } return size; } diff --git a/tcpclient.c b/tcpclient.c index 6939bbc..a1519b1 100644 --- a/tcpclient.c +++ b/tcpclient.c @@ -1,5 +1,5 @@ /* tcpclient.c - * copyright (c) 2010 IOhannes m zmölnig, IEM + * copyright (c) 2010 IOhannes m zmölnig, IEM * copyright (c) 2006-2010 Martin Peach * copyright (c) 2004 Olaf Matthes */ @@ -18,9 +18,8 @@ /* GNU General Public License for more details. */ /* */ /* You should have received a copy of the GNU General Public License */ -/* along with this program; if not, write to the Free Software */ -/* Foundation, Inc., */ -/* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ +/* along with this program; if not, see */ +/* http://www.gnu.org/licenses/ */ /* */ /* ---------------------------------------------------------------------------- */ @@ -29,14 +28,11 @@ #include "iemnet.h" #include -#include - static t_class *tcpclient_class; static char objName[] = "tcpclient"; -typedef struct _tcpclient -{ +typedef struct _tcpclient { t_object x_obj; t_clock *x_clock; t_outlet *x_msgout; @@ -55,11 +51,8 @@ typedef struct _tcpclient int x_port; // port we're connected to long x_addr; // address we're connected to as 32bit int - /* multithread stuff */ - pthread_t x_threadid; /* id of child thread */ - pthread_attr_t x_threadattr; /* attributes of child thread */ - t_iemnet_floatlist *x_floatlist; + t_iemnet_floatlist *x_floatlist; } t_tcpclient; @@ -91,114 +84,135 @@ static void tcpclient_info(t_tcpclient *x) } /* connection handling */ - -static void *tcpclient_child_connect(void *w) +static int tcpclient_do_disconnect(int fd, t_iemnet_sender*sender, + t_iemnet_receiver*receiver) +{ + if(sender) { + iemnet__sender_destroy(sender, 0); + sender=NULL; + } + if(receiver) { + iemnet__receiver_destroy(receiver, 0); + receiver=NULL; + } + if (fd >= 0) { + iemnet__closesocket(fd); + return 1; + } + return 0; +} +static int tcpclient_do_connect(const char*host, unsigned short port, + t_tcpclient*x, + t_iemnet_sender**senderOUT, t_iemnet_receiver**receiverOUT, long*addrOUT) { - t_tcpclient *x = (t_tcpclient*) w; struct sockaddr_in server; struct hostent *hp; - int sockfd; - - t_iemnet_sender*sender; + int sockfd=-1; + t_iemnet_sender* sender; t_iemnet_receiver*receiver; - if (x->x_fd >= 0) - { - error("%s_connect: already connected", objName); - return (x); - } - - /* create a socket */ - sockfd = socket(AF_INET, SOCK_STREAM, 0); - DEBUG("send socket %d\n", sockfd); - if (sockfd < 0) - { - sys_sockerror("tcpclient: socket"); - return (x); - } /* connect socket using hostname provided in command line */ + memset(&server, 0, sizeof(server)); server.sin_family = AF_INET; - hp = gethostbyname(x->x_hostname); - if (hp == 0) - { - sys_sockerror("tcpclient: bad host?\n"); - return (x); - } + hp = gethostbyname(host); + if (hp == 0) { + sys_sockerror("tcpclient: bad host?\n"); + return (-1); + } memcpy((char *)&server.sin_addr, (char *)hp->h_addr, hp->h_length); + sockfd = socket(AF_INET, SOCK_STREAM, 0); + if (sockfd < 0) { + sys_sockerror("tcpclient: socket"); + return (sockfd); + } + /* assign client port number */ - server.sin_port = htons((u_short)x->x_port); + server.sin_port = htons((u_short)port); /* try to connect */ - if (connect(sockfd, (struct sockaddr *) &server, sizeof (server)) < 0) - { - sys_sockerror("tcpclient: connecting stream socket"); - sys_closesocket(sockfd); - return (x); - } - - sender=iemnet__sender_create(sockfd); - receiver=iemnet__receiver_create(sockfd, x, tcpclient_receive_callback); - - /* update the tcpclient-object (thread safe) */ - sys_lock(); - x->x_fd = sockfd; - x->x_addr = ntohl(*(long *)hp->h_addr); - - x->x_sender=sender; - x->x_receiver=receiver; + if (connect(sockfd, (struct sockaddr *) &server, sizeof (server)) < 0) { + sys_sockerror("tcpclient: connecting stream socket"); + iemnet__closesocket(sockfd); + return (-1); + } - x->x_connectstate = 1; + sender=iemnet__sender_create(sockfd, NULL, NULL, 0); + receiver=iemnet__receiver_create(sockfd, x, tcpclient_receive_callback, + 0); - /* use callback to set outlet in main thread */ - clock_delay(x->x_clock, 0); - sys_unlock(); - return (x); + if(addrOUT) { + *addrOUT= ntohl(*(long *)hp->h_addr); + } + if(senderOUT) { + *senderOUT=sender; + } + if(receiverOUT) { + *receiverOUT=receiver; + } + return sockfd; } + static void tcpclient_tick(t_tcpclient *x) { - outlet_float(x->x_connectout, 1); + outlet_float(x->x_connectout, 1); } static void tcpclient_disconnect(t_tcpclient *x); -static void tcpclient_connect(t_tcpclient *x, t_symbol *hostname, t_floatarg fportno) +static void tcpclient_connect(t_tcpclient *x, t_symbol *hostname, + t_floatarg fportno) { - if(x->x_fd>=0)tcpclient_disconnect(x); + long addr=0; + int state; + if(x->x_hostname || x->x_port) { + state=tcpclient_do_disconnect(x->x_fd, x->x_sender, x->x_receiver); + if(state) { + outlet_float(x->x_connectout, 0); + } else { + if(!x->x_port) { + pd_error(x, "[%s]: not connected", objName); + } + } + } + /* we get hostname and port and pass them on to the child thread that establishes the connection */ x->x_hostname = hostname->s_name; x->x_port = fportno; - x->x_connectstate = 0; - /* start child thread */ - if(pthread_create(&x->x_threadid, &x->x_threadattr, tcpclient_child_connect, x) < 0) - error("%s: could not create new thread", objName); + + + state=tcpclient_do_connect(x->x_hostname, x->x_port, x, + &x->x_sender, &x->x_receiver, + &x->x_addr); + x->x_connectstate=(state>0); + x->x_fd=state; + if(state>0) { + outlet_float(x->x_connectout, 1); + } + } static void tcpclient_disconnect(t_tcpclient *x) { - if (x->x_fd >= 0) - { - int fd=x->x_fd; - x->x_fd = -1; + if(x->x_hostname || x->x_port) { + int state=tcpclient_do_disconnect(x->x_fd, x->x_sender, x->x_receiver); - DEBUG("disconnecting %x", x); - if(x->x_sender)iemnet__sender_destroy(x->x_sender); x->x_sender=NULL; - if(x->x_receiver)iemnet__receiver_destroy(x->x_receiver); x->x_receiver=NULL; - DEBUG("disconnect cleaning up %x", x); - sys_closesocket(fd); - - - x->x_connectstate = 0; - outlet_float(x->x_connectout, 0); + if(!state && !x->x_port) { + pd_error(x, "[%s]: not connected", objName); } - else pd_error(x, "%s: not connected", objName); + } + outlet_float(x->x_connectout, 0); + + x->x_port=0; + x->x_hostname=NULL; } /* sending/receiving */ -static void tcpclient_send(t_tcpclient *x, t_symbol *s, int argc, t_atom *argv) +static void tcpclient_send(t_tcpclient *x, t_symbol *s, int argc, + t_atom *argv) { int size=0; t_atom output_atom; @@ -211,39 +225,70 @@ static void tcpclient_send(t_tcpclient *x, t_symbol *s, int argc, t_atom *argv) iemnet__chunk_destroy(chunk); SETFLOAT(&output_atom, size); - outlet_anything( x->x_statusout, gensym("sent"), 1, &output_atom); + outlet_anything( x->x_statusout, gensym("sendbuffersize"), 1, + &output_atom); if(size<0) { tcpclient_disconnect(x); } } -static void tcpclient_receive_callback(void*y, t_iemnet_chunk*c) { +static void tcpclient_receive_callback(void*y, t_iemnet_chunk*c) +{ t_tcpclient *x=(t_tcpclient*)y; if(c) { iemnet__addrout(x->x_statusout, x->x_addrout, x->x_addr, x->x_port); - x->x_floatlist=iemnet__chunk2list(c, x->x_floatlist); // get's destroyed in the dtor - iemnet__streamout(x->x_msgout, x->x_floatlist->argc, x->x_floatlist->argv, x->x_serialize); + x->x_floatlist=iemnet__chunk2list(c, + x->x_floatlist); // get's destroyed in the dtor + iemnet__streamout(x->x_msgout, x->x_floatlist->argc, x->x_floatlist->argv, + x->x_serialize); } else { // disconnected tcpclient_disconnect(x); } } -static void tcpclient_serialize(t_tcpclient *x, t_floatarg doit) { +static void tcpclient_serialize(t_tcpclient *x, t_floatarg doit) +{ x->x_serialize=doit; } /* constructor/destructor */ +static void tcpclient_free_simple(t_tcpclient *x) +{ + if(x->x_clock) { + clock_free(x->x_clock); + } + x->x_clock=NULL; + if(x->x_floatlist) { + iemnet__floatlist_destroy(x->x_floatlist); + } + x->x_floatlist=NULL; + + if(x->x_msgout) { + outlet_free(x->x_msgout); + } + if(x->x_addrout) { + outlet_free(x->x_addrout); + } + if(x->x_connectout) { + outlet_free(x->x_connectout); + } + if(x->x_statusout) { + outlet_free(x->x_statusout); + } +} static void *tcpclient_new(void) { t_tcpclient *x = (t_tcpclient *)pd_new(tcpclient_class); x->x_msgout = outlet_new(&x->x_obj, 0); /* received data */ x->x_addrout = outlet_new(&x->x_obj, gensym("list")); - x->x_connectout = outlet_new(&x->x_obj, gensym("float")); /* connection state */ - x->x_statusout = outlet_new(&x->x_obj, 0);/* last outlet for everything else */ + x->x_connectout = outlet_new(&x->x_obj, + gensym("float")); /* connection state */ + x->x_statusout = outlet_new(&x->x_obj, + 0);/* last outlet for everything else */ x->x_serialize=1; @@ -258,36 +303,34 @@ static void *tcpclient_new(void) x->x_clock = clock_new(x, (t_method)tcpclient_tick); x->x_floatlist=iemnet__floatlist_create(1024); - /* prepare child thread */ - if(pthread_attr_init(&x->x_threadattr) < 0) - error("%s: warning: could not prepare child thread", objName); - if(pthread_attr_setdetachstate(&x->x_threadattr, PTHREAD_CREATE_DETACHED) < 0) - error("%s: warning: could not prepare child thread", objName); - - return (x); } static void tcpclient_free(t_tcpclient *x) { tcpclient_disconnect(x); - if(x->x_clock)clock_free(x->x_clock);x->x_clock=NULL; - if(x->x_floatlist)iemnet__floatlist_destroy(x->x_floatlist);x->x_floatlist=NULL; + tcpclient_free_simple(x); } IEMNET_EXTERN void tcpclient_setup(void) { - if(!iemnet__register(objName))return; + if(!iemnet__register(objName)) { + return; + } tcpclient_class = class_new(gensym(objName), (t_newmethod)tcpclient_new, (t_method)tcpclient_free, sizeof(t_tcpclient), 0, A_DEFFLOAT, 0); - class_addmethod(tcpclient_class, (t_method)tcpclient_connect, gensym("connect") + class_addmethod(tcpclient_class, (t_method)tcpclient_connect, + gensym("connect") , A_SYMBOL, A_FLOAT, 0); - class_addmethod(tcpclient_class, (t_method)tcpclient_disconnect, gensym("disconnect"), 0); + class_addmethod(tcpclient_class, (t_method)tcpclient_disconnect, + gensym("disconnect"), 0); - class_addmethod(tcpclient_class, (t_method)tcpclient_serialize, gensym("serialize"), A_FLOAT, 0); + class_addmethod(tcpclient_class, (t_method)tcpclient_serialize, + gensym("serialize"), A_FLOAT, 0); - class_addmethod(tcpclient_class, (t_method)tcpclient_send, gensym("send"), A_GIMME, 0); + class_addmethod(tcpclient_class, (t_method)tcpclient_send, gensym("send"), + A_GIMME, 0); class_addlist(tcpclient_class, (t_method)tcpclient_send); class_addbang(tcpclient_class, (t_method)tcpclient_info); @@ -297,7 +340,4 @@ IEMNET_EXTERN void tcpclient_setup(void) IEMNET_INITIALIZER(tcpclient_setup); - - - /* end of tcpclient.c */ diff --git a/tcpreceive.c b/tcpreceive.c index dc49d2d..a115a06 100644 --- a/tcpreceive.c +++ b/tcpreceive.c @@ -1,5 +1,5 @@ /* tcpreceive.c - * copyright (c) 2010 IOhannes m zmölnig, IEM + * copyright (c) 2010 IOhannes m zmölnig, IEM * copyright (c) 2006-2010 Martin Peach * copyright (c) Miller Puckette */ @@ -18,9 +18,8 @@ /* GNU General Public License for more details. */ /* */ /* You should have received a copy of the GNU General Public License */ -/* along with this program; if not, write to the Free Software */ -/* Foundation, Inc., */ -/* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ +/* along with this program; if not, see */ +/* http://www.gnu.org/licenses/ */ /* */ #define DEBUGLEVEL 1 @@ -33,14 +32,15 @@ static const char*objName="tcpreceive"; # include #endif +#include + /* ----------------------------- tcpreceive ------------------------- */ static t_class *tcpreceive_class; #define MAX_CONNECTIONS 128 // this is going to cause trouble down the line...:( -typedef struct _tcpconnection -{ +typedef struct _tcpconnection { long addr; unsigned short port; int socket; @@ -48,8 +48,7 @@ typedef struct _tcpconnection t_iemnet_receiver*receiver; } t_tcpconnection; -typedef struct _tcpreceive -{ +typedef struct _tcpreceive { t_object x_obj; t_outlet *x_msgout; t_outlet *x_addrout; @@ -63,14 +62,17 @@ typedef struct _tcpreceive int x_nconnections; t_tcpconnection x_connection[MAX_CONNECTIONS]; - t_iemnet_floatlist *x_floatlist; + t_iemnet_floatlist *x_floatlist; } t_tcpreceive; -static int tcpreceive_find_socket(t_tcpreceive *x, int fd) { +static int tcpreceive_find_socket(t_tcpreceive *x, int fd) +{ int i; for (i = 0; i < MAX_CONNECTIONS; ++i) - if (x->x_connection[i].socket == fd)return i; + if (x->x_connection[i].socket == fd) { + return i; + } return -1; } @@ -82,14 +84,18 @@ static void tcpreceive_read_callback(void *w, t_iemnet_chunk*c) t_tcpconnection*y=(t_tcpconnection*)w; t_tcpreceive*x=NULL; int index=-1; - if(NULL==y || NULL==(x=y->owner))return; + if(NULL==y || NULL==(x=y->owner)) { + return; + } index=tcpreceive_find_socket(x, y->socket); if(index>=0) { if(c) { // TODO?: outlet info about connection - x->x_floatlist=iemnet__chunk2list(c, x->x_floatlist); // gets destroyed in the dtor - iemnet__streamout(x->x_msgout, x->x_floatlist->argc, x->x_floatlist->argv, x->x_serialize); + x->x_floatlist=iemnet__chunk2list(c, + x->x_floatlist); // gets destroyed in the dtor + iemnet__streamout(x->x_msgout, x->x_floatlist->argc, x->x_floatlist->argv, + x->x_serialize); } else { // disconnected tcpreceive_disconnect(x, index); @@ -99,25 +105,25 @@ static void tcpreceive_read_callback(void *w, t_iemnet_chunk*c) /* tcpreceive_addconnection tries to add the socket fd to the list */ /* returns 1 on success, else 0 */ -static int tcpreceive_addconnection(t_tcpreceive *x, int fd, long addr, unsigned short port) +static int tcpreceive_addconnection(t_tcpreceive *x, int fd, long addr, + unsigned short port) { int i; - for (i = 0; i < MAX_CONNECTIONS; ++i) - { - if (x->x_connection[i].socket == -1) - { - x->x_connection[i].socket = fd; - x->x_connection[i].addr = addr; - x->x_connection[i].port = port; - x->x_connection[i].owner = x; - x->x_connection[i].receiver= - iemnet__receiver_create(fd, - x->x_connection+i, - tcpreceive_read_callback); - - return 1; - } + for (i = 0; i < MAX_CONNECTIONS; ++i) { + if (x->x_connection[i].socket == -1) { + x->x_connection[i].socket = fd; + x->x_connection[i].addr = addr; + x->x_connection[i].port = port; + x->x_connection[i].owner = x; + x->x_connection[i].receiver= + iemnet__receiver_create(fd, + x->x_connection+i, + tcpreceive_read_callback, + 0); + + return 1; } + } return 0; } @@ -133,38 +139,31 @@ static void tcpreceive_connectpoll(t_tcpreceive *x) int fd; fd = accept(x->x_connectsocket, (struct sockaddr *)&from, &fromlen); - if (fd < 0) error("[%s] accept failed", objName); - else - { - // t_socketreceiver *y = socketreceiver_new((void *)x, - // (t_socketnotifier)tcpreceive_notify, - // 0, 0); - - /* get the sender's ip */ - addr = ntohl(from.sin_addr.s_addr); - port = ntohs(from.sin_port); - if (tcpreceive_addconnection(x, fd, addr, port)) - { - x->x_nconnections++; - outlet_float(x->x_connectout, x->x_nconnections); - iemnet__addrout(x->x_statout, x->x_addrout, addr, port); - } - else - { - error ("[%s] Too many connections", objName); - sys_closesocket(fd); - } + if (fd < 0) { + error("[%s] accept failed", objName); + } else { + /* get the sender's ip */ + addr = ntohl(from.sin_addr.s_addr); + port = ntohs(from.sin_port); + if (tcpreceive_addconnection(x, fd, addr, port)) { + x->x_nconnections++; + outlet_float(x->x_connectout, x->x_nconnections); + iemnet__addrout(x->x_statout, x->x_addrout, addr, port); + } else { + error ("[%s] Too many connections", objName); + iemnet__closesocket(fd); } + } } static int tcpreceive_disconnect(t_tcpreceive *x, int id) { if(id>=0 && id < MAX_CONNECTIONS && x->x_connection[id].port>0) { - iemnet__receiver_destroy(x->x_connection[id].receiver); + iemnet__receiver_destroy(x->x_connection[id].receiver, 0); x->x_connection[id].receiver=NULL; - sys_closesocket(x->x_connection[id].socket); + iemnet__closesocket(x->x_connection[id].socket); x->x_connection[id].socket = -1; x->x_connection[id].addr = 0L; @@ -182,10 +181,9 @@ static void tcpreceive_disconnect_all(t_tcpreceive *x) { int i; - for (i = 0; i < MAX_CONNECTIONS; i++) - { - tcpreceive_disconnect(x, i); - } + for (i = 0; i < MAX_CONNECTIONS; i++) { + tcpreceive_disconnect(x, i); + } } @@ -196,13 +194,11 @@ static void tcpreceive_disconnect_all(t_tcpreceive *x) static int tcpreceive_disconnect_socket(t_tcpreceive *x, int fd) { int i; - for (i = 0; i < MAX_CONNECTIONS; ++i) - { - if (x->x_connection[i].socket == fd) - { - return tcpreceive_disconnect(x, i); - } + for (i = 0; i < MAX_CONNECTIONS; ++i) { + if (x->x_connection[i].socket == fd) { + return tcpreceive_disconnect(x, i); } + } return 0; } @@ -214,6 +210,7 @@ static void tcpreceive_port(t_tcpreceive*x, t_floatarg fportno) socklen_t serversize=sizeof(server); int sockfd = x->x_connectsocket; int intarg; + memset(&server, 0, sizeof(server)); SETFLOAT(ap, -1); if(x->x_port == portno) { @@ -223,7 +220,7 @@ static void tcpreceive_port(t_tcpreceive*x, t_floatarg fportno) /* cleanup any open ports */ if(sockfd>=0) { sys_rmpollfn(sockfd); - sys_closesocket(sockfd); + iemnet__closesocket(sockfd); x->x_connectsocket=-1; x->x_port=-1; } @@ -239,7 +236,7 @@ static void tcpreceive_port(t_tcpreceive*x, t_floatarg fportno) #ifdef SO_REUSEADDR intarg = 1; if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, - (char *)&intarg, sizeof(intarg)) + (char *)&intarg, sizeof(intarg)) < 0) { error("[%s]: setsockopt (SO_REUSEADDR) failed", objName); } @@ -247,7 +244,7 @@ static void tcpreceive_port(t_tcpreceive*x, t_floatarg fportno) #ifdef SO_REUSEPORT intarg = 1; if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEPORT, - (char *)&intarg, sizeof(intarg)) + (char *)&intarg, sizeof(intarg)) < 0) { error("[%s]: setsockopt (SO_REUSEPORT) failed", objName); } @@ -256,8 +253,9 @@ static void tcpreceive_port(t_tcpreceive*x, t_floatarg fportno) /* Stream (TCP) sockets are set NODELAY */ intarg = 1; if (setsockopt(sockfd, IPPROTO_TCP, TCP_NODELAY, - (char *)&intarg, sizeof(intarg)) < 0) + (char *)&intarg, sizeof(intarg)) < 0) { post("[%s]: setsockopt (TCP_NODELAY) failed", objName); + } server.sin_family = AF_INET; @@ -265,30 +263,26 @@ static void tcpreceive_port(t_tcpreceive*x, t_floatarg fportno) server.sin_port = htons((u_short)portno); /* name the socket */ - if (bind(sockfd, (struct sockaddr *)&server, serversize) < 0) - { - sys_sockerror("[tcpreceive] bind failed"); - sys_closesocket(sockfd); - sockfd = -1; - outlet_anything(x->x_statout, gensym("port"), 1, ap); - return; - } + if (bind(sockfd, (struct sockaddr *)&server, serversize) < 0) { + sys_sockerror("[tcpreceive] bind failed"); + iemnet__closesocket(sockfd); + sockfd = -1; + outlet_anything(x->x_statout, gensym("port"), 1, ap); + return; + } /* streaming protocol */ - if (listen(sockfd, 5) < 0) - { - sys_sockerror("[tcpreceive] listen"); - sys_closesocket(sockfd); - sockfd = -1; - outlet_anything(x->x_statout, gensym("port"), 1, ap); - return; - } - else - { - sys_addpollfn(sockfd, - (t_fdpollfn)tcpreceive_connectpoll, - x); // wait for new connections - } + if (listen(sockfd, 5) < 0) { + sys_sockerror("[tcpreceive] listen"); + iemnet__closesocket(sockfd); + sockfd = -1; + outlet_anything(x->x_statout, gensym("port"), 1, ap); + return; + } else { + sys_addpollfn(sockfd, + (t_fdpollfn)tcpreceive_connectpoll, + x); // wait for new connections + } x->x_connectsocket = sockfd; x->x_port = portno; @@ -303,20 +297,24 @@ static void tcpreceive_port(t_tcpreceive*x, t_floatarg fportno) outlet_anything(x->x_statout, gensym("port"), 1, ap); } -static void tcpreceive_serialize(t_tcpreceive *x, t_floatarg doit) { +static void tcpreceive_serialize(t_tcpreceive *x, t_floatarg doit) +{ x->x_serialize=doit; } static void tcpreceive_free(t_tcpreceive *x) -{ /* is this ever called? */ - if (x->x_connectsocket >= 0) - { - sys_rmpollfn(x->x_connectsocket); - sys_closesocket(x->x_connectsocket); - } +{ + /* is this ever called? */ + if (x->x_connectsocket >= 0) { + sys_rmpollfn(x->x_connectsocket); + iemnet__closesocket(x->x_connectsocket); + } tcpreceive_disconnect_all(x); - if(x->x_floatlist)iemnet__floatlist_destroy(x->x_floatlist);x->x_floatlist=NULL; + if(x->x_floatlist) { + iemnet__floatlist_destroy(x->x_floatlist); + } + x->x_floatlist=NULL; } static void *tcpreceive_new(t_floatarg fportno) @@ -338,12 +336,11 @@ static void *tcpreceive_new(t_floatarg fportno) x->x_nconnections=0; /* clear the connection list */ - for (i = 0; i < MAX_CONNECTIONS; ++i) - { - x->x_connection[i].socket = -1; - x->x_connection[i].addr = 0L; - x->x_connection[i].port = 0; - } + for (i = 0; i < MAX_CONNECTIONS; ++i) { + x->x_connection[i].socket = -1; + x->x_connection[i].addr = 0L; + x->x_connection[i].port = 0; + } x->x_floatlist=iemnet__floatlist_create(1024); @@ -355,16 +352,20 @@ static void *tcpreceive_new(t_floatarg fportno) IEMNET_EXTERN void tcpreceive_setup(void) { - if(!iemnet__register(objName))return; + if(!iemnet__register(objName)) { + return; + } tcpreceive_class = class_new(gensym(objName), - (t_newmethod)tcpreceive_new, (t_method)tcpreceive_free, - sizeof(t_tcpreceive), - 0, - A_DEFFLOAT, 0); - - class_addmethod(tcpreceive_class, (t_method)tcpreceive_port, gensym("port"), A_DEFFLOAT, 0); - - class_addmethod(tcpreceive_class, (t_method)tcpreceive_serialize, gensym("serialize"), A_FLOAT, 0); + (t_newmethod)tcpreceive_new, (t_method)tcpreceive_free, + sizeof(t_tcpreceive), + 0, + A_DEFFLOAT, 0); + + class_addmethod(tcpreceive_class, (t_method)tcpreceive_port, + gensym("port"), A_DEFFLOAT, 0); + + class_addmethod(tcpreceive_class, (t_method)tcpreceive_serialize, + gensym("serialize"), A_FLOAT, 0); DEBUGMETHOD(tcpreceive_class); } diff --git a/tcpsend.c b/tcpsend.c index ae32f05..664137c 100644 --- a/tcpsend.c +++ b/tcpsend.c @@ -1,5 +1,5 @@ /* tcpsend.c - * copyright (c) 2010 IOhannes m zmölnig, IEM + * copyright (c) 2010 IOhannes m zmölnig, IEM * copyright (c) 2006-2010 Martin Peach * copyright (c) Miller Puckette */ @@ -18,9 +18,8 @@ /* GNU General Public License for more details. */ /* */ /* You should have received a copy of the GNU General Public License */ -/* along with this program; if not, write to the Free Software */ -/* Foundation, Inc., */ -/* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ +/* along with this program; if not, see */ +/* http://www.gnu.org/licenses/ */ /* */ #define DEBUGLEVEL 1 @@ -37,8 +36,7 @@ static const char objName[] = "tcpsend"; static t_class *tcpsend_class; -typedef struct _tcpsend -{ +typedef struct _tcpsend { t_object x_obj; int x_fd; t_iemnet_sender*x_sender; @@ -46,54 +44,55 @@ typedef struct _tcpsend static void tcpsend_disconnect(t_tcpsend *x) { - if (x->x_fd >= 0) - { - if(x->x_sender)iemnet__sender_destroy(x->x_sender); x->x_sender=NULL; - sys_closesocket(x->x_fd); - x->x_fd = -1; - outlet_float(x->x_obj.ob_outlet, 0); - post("tcpsend: disconnected"); + if (x->x_fd >= 0) { + if(x->x_sender) { + iemnet__sender_destroy(x->x_sender, 0); } + x->x_sender=NULL; + iemnet__closesocket(x->x_fd); + x->x_fd = -1; + outlet_float(x->x_obj.ob_outlet, 0); + //post("tcpsend: disconnected"); + } } static void tcpsend_connect(t_tcpsend *x, t_symbol *hostname, - t_floatarg fportno) + t_floatarg fportno) { struct sockaddr_in server; struct hostent *hp; int sockfd; int portno = fportno; int intarg; + memset(&server, 0, sizeof(server)); - if (x->x_fd >= 0) - { - error("tcpsend: already connected"); - return; - } + if (x->x_fd >= 0) { + error("tcpsend: already connected"); + return; + } /* create a socket */ sockfd = socket(AF_INET, SOCK_STREAM, 0); DEBUG("send socket %d\n", sockfd); - if (sockfd < 0) - { - sys_sockerror("tcpsend: socket"); - return; - } + if (sockfd < 0) { + sys_sockerror("tcpsend: socket"); + return; + } /* connect socket using hostname provided in command line */ server.sin_family = AF_INET; hp = gethostbyname(hostname->s_name); - if (hp == 0) - { - post("tcpsend: bad host?\n"); - return; - } + if (hp == 0) { + post("tcpsend: bad host?\n"); + return; + } /* for stream (TCP) sockets, specify "nodelay" */ intarg = 1; if (setsockopt(sockfd, IPPROTO_TCP, TCP_NODELAY, - (char *)&intarg, sizeof(intarg)) < 0) + (char *)&intarg, sizeof(intarg)) < 0) { post("tcpsend: setsockopt (TCP_NODELAY) failed\n"); + } memcpy((char *)&server.sin_addr, (char *)hp->h_addr, hp->h_length); @@ -102,15 +101,14 @@ static void tcpsend_connect(t_tcpsend *x, t_symbol *hostname, post("tcpsend: connecting to port %d", portno); /* try to connect. */ - if (connect(sockfd, (struct sockaddr *) &server, sizeof (server)) < 0) - { - sys_sockerror("tcpsend: connecting stream socket"); - sys_closesocket(sockfd); - return; - } + if (connect(sockfd, (struct sockaddr *) &server, sizeof (server)) < 0) { + sys_sockerror("tcpsend: connecting stream socket"); + iemnet__closesocket(sockfd); + return; + } x->x_fd = sockfd; - x->x_sender=iemnet__sender_create(sockfd); + x->x_sender=iemnet__sender_create(sockfd, NULL, NULL, 0); outlet_float(x->x_obj.ob_outlet, 1); } @@ -141,18 +139,20 @@ static void *tcpsend_new(void) IEMNET_EXTERN void tcpsend_setup(void) { - if(!iemnet__register(objName))return; - tcpsend_class = class_new(gensym(objName), - (t_newmethod)tcpsend_new, (t_method)tcpsend_free, - sizeof(t_tcpsend), - 0, 0); + if(!iemnet__register(objName)) { + return; + } + tcpsend_class = class_new(gensym(objName), + (t_newmethod)tcpsend_new, (t_method)tcpsend_free, + sizeof(t_tcpsend), + 0, 0); class_addmethod(tcpsend_class, (t_method)tcpsend_connect, - gensym("connect"), A_SYMBOL, A_FLOAT, 0); + gensym("connect"), A_SYMBOL, A_FLOAT, 0); class_addmethod(tcpsend_class, (t_method)tcpsend_disconnect, - gensym("disconnect"), 0); + gensym("disconnect"), 0); class_addmethod(tcpsend_class, (t_method)tcpsend_send, gensym("send"), - A_GIMME, 0); + A_GIMME, 0); class_addlist(tcpsend_class, (t_method)tcpsend_send); DEBUGMETHOD(tcpsend_class); diff --git a/tcpserver.c b/tcpserver.c index 59b6132..ca4f38e 100644 --- a/tcpserver.c +++ b/tcpserver.c @@ -1,5 +1,5 @@ /* tcpserver.c - * copyright (c) 2010 IOhannes m zmölnig, IEM + * copyright (c) 2010 IOhannes m zmölnig, IEM * copyright (c) 2006-2010 Martin Peach * copyright (c) 2004 Olaf Matthes */ @@ -19,9 +19,8 @@ /* GNU General Public License for more details. */ /* */ /* You should have received a copy of the GNU General Public License */ -/* along with this program; if not, write to the Free Software */ -/* Foundation, Inc., */ -/* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ +/* along with this program; if not, see */ +/* http://www.gnu.org/licenses/ */ /* */ /* ---------------------------------------------------------------------------- */ @@ -30,6 +29,8 @@ #include "iemnet.h" #include "iemnet_data.h" #include +#include +#include #define MAX_CONNECT 32 /* maximum number of connections */ @@ -38,45 +39,48 @@ static t_class *tcpserver_class; static const char objName[] = "tcpserver"; -typedef struct _tcpserver_socketreceiver -{ +typedef struct _tcpserver_socketreceiver { struct _tcpserver *sr_owner; long sr_host; unsigned short sr_port; - t_int sr_fd; + int sr_fd; t_iemnet_sender*sr_sender; t_iemnet_receiver*sr_receiver; } t_tcpserver_socketreceiver; -typedef struct _tcpserver -{ +typedef struct _tcpserver { t_object x_obj; t_outlet *x_msgout; t_outlet *x_connectout; t_outlet *x_sockout; // legacy t_outlet *x_addrout; // legacy - t_outlet *x_statout; + t_outlet *x_statout; int x_serialize; t_tcpserver_socketreceiver *x_sr[MAX_CONNECT]; /* socket per connection */ - t_int x_nconnections; + unsigned int x_nconnections; - t_int x_connectsocket; /* socket waiting for new connections */ - t_int x_port; + int + x_connectsocket; /* socket waiting for new connections */ + int x_port; - int x_defaulttarget; /* the default connection to send to; 0=broadcast; >0 use this client; <0 exclude this client */ - t_iemnet_floatlist *x_floatlist; + int + x_defaulttarget; /* the default connection to send to; 0=broadcast; >0 use this client; <0 exclude this client */ + t_iemnet_floatlist *x_floatlist; } t_tcpserver; static void tcpserver_receive_callback(void*x, t_iemnet_chunk*); -static t_tcpserver_socketreceiver *tcpserver_socketreceiver_new(t_tcpserver *owner, int sockfd, struct sockaddr_in*addr) +static t_tcpserver_socketreceiver *tcpserver_socketreceiver_new( + t_tcpserver *owner, int sockfd, struct sockaddr_in*addr) { - t_tcpserver_socketreceiver *x = (t_tcpserver_socketreceiver *)getbytes(sizeof(*x)); + t_tcpserver_socketreceiver *x = (t_tcpserver_socketreceiver *)getbytes( + sizeof(*x)); if(NULL==x) { - error("%s_socketreceiver: unable to allocate %d bytes", objName, (int)sizeof(*x)); + error("%s_socketreceiver: unable to allocate %d bytes", objName, + (int)sizeof(*x)); return NULL; } else { x->sr_owner=owner; @@ -86,8 +90,9 @@ static t_tcpserver_socketreceiver *tcpserver_socketreceiver_new(t_tcpserver *own x->sr_host=ntohl(addr->sin_addr.s_addr); x->sr_port=ntohs(addr->sin_port); - x->sr_sender=iemnet__sender_create(sockfd); - x->sr_receiver=iemnet__receiver_create(sockfd, x, tcpserver_receive_callback); + x->sr_sender=iemnet__sender_create(sockfd, NULL, NULL, 0); + x->sr_receiver=iemnet__receiver_create(sockfd, x, + tcpserver_receive_callback, 0); } return (x); } @@ -95,40 +100,41 @@ static t_tcpserver_socketreceiver *tcpserver_socketreceiver_new(t_tcpserver *own static void tcpserver_socketreceiver_free(t_tcpserver_socketreceiver *x) { DEBUG("freeing %x", x); - if (x != NULL) - { - int sockfd=x->sr_fd; - t_iemnet_sender*sender=x->sr_sender; - t_iemnet_receiver*receiver=x->sr_receiver; - - x->sr_owner=NULL; - x->sr_sender=NULL; - x->sr_receiver=NULL; - - x->sr_fd=-1; - - - if(sender) iemnet__sender_destroy(sender); - if(receiver)iemnet__receiver_destroy(receiver); - - sys_closesocket(sockfd); - - - freebytes(x, sizeof(*x)); + if (x != NULL) { + int sockfd=x->sr_fd; + t_iemnet_sender*sender=x->sr_sender; + t_iemnet_receiver*receiver=x->sr_receiver; + + x->sr_owner=NULL; + x->sr_sender=NULL; + x->sr_receiver=NULL; + + x->sr_fd=-1; + + + if(sender) { + iemnet__sender_destroy(sender, 0); + } + if(receiver) { + iemnet__receiver_destroy(receiver, 0); } + + iemnet__closesocket(sockfd); + + + freebytes(x, sizeof(*x)); + } DEBUG("freeed %x", x); } static int tcpserver_socket2index(t_tcpserver*x, int sockfd) { - int i=0; - for(i = 0; i < x->x_nconnections; i++) /* check if connection exists */ - { - if(x->x_sr[i]->sr_fd == sockfd) - { - return i; - } - } + unsigned int i=0; + for(i = 0; i < x->x_nconnections; i++) { /* check if connection exists */ + if(x->x_sr[i]->sr_fd == sockfd) { + return i; + } + } return -1; } @@ -138,28 +144,27 @@ static int tcpserver_socket2index(t_tcpserver*x, int sockfd) */ static int tcpserver_fixindex(t_tcpserver*x, int client) { - if(x->x_nconnections <= 0) - { - pd_error(x, "[%s]: no clients connected", objName); - return -1; - } - - if (!((client > 0) && (client <= x->x_nconnections))) - { - pd_error(x, "[%s] client %d out of range [1..%d]", objName, client, (int)(x->x_nconnections)); - return -1; - } + if(x->x_nconnections <= 0) { + pd_error(x, "[%s]: no clients connected", objName); + return -1; + } + + if (!((client > 0) && (client <= x->x_nconnections))) { + pd_error(x, "[%s] client %d out of range [1..%d]", objName, client, + (int)(x->x_nconnections)); + return -1; + } return (client-1); } /* ---------------- tcpserver info ---------------------------- */ -static void tcpserver_info_client(t_tcpserver *x, int client) +static void tcpserver_info_client(t_tcpserver *x, unsigned int client) { // "client " // "bufsize " static t_atom output_atom[4]; - if(x&&x->x_sr&&x->x_sr[client]) { + if(x&&clientx_sr[client]) { int sockfd = x->x_sr[client]->sr_fd; unsigned short port = x->x_sr[client]->sr_port; long address = x->x_sr[client]->sr_host; @@ -168,7 +173,7 @@ static void tcpserver_info_client(t_tcpserver *x, int client) int insize =iemnet__receiver_getsize(x->x_sr[client]->sr_receiver); int outsize=iemnet__sender_getsize (x->x_sr[client]->sr_sender ); - snprintf(hostname, MAXPDSTRING-1, "%d.%d.%d.%d", + snprintf(hostname, MAXPDSTRING-1, "%d.%d.%d.%d", (unsigned char)((address & 0xFF000000)>>24), (unsigned char)((address & 0x0FF0000)>>16), (unsigned char)((address & 0x0FF00)>>8), @@ -190,7 +195,8 @@ static void tcpserver_info_client(t_tcpserver *x, int client) } -static void tcpserver_info(t_tcpserver *x) { +static void tcpserver_info(t_tcpserver *x) +{ static t_atom output_atom[4]; int sockfd=x->x_connectsocket; @@ -218,25 +224,26 @@ static void tcpserver_info(t_tcpserver *x) { } -static void tcpserver_info_connection(t_tcpserver *x, t_tcpserver_socketreceiver*y) +static void tcpserver_info_connection(t_tcpserver *x, + t_tcpserver_socketreceiver*y) { iemnet__addrout(x->x_statout, x->x_addrout, y->sr_host, y->sr_port); outlet_float(x->x_sockout, y->sr_fd); } /* ---------------- main tcpserver (send) stuff --------------------- */ -static void tcpserver_disconnect_socket(t_tcpserver *x, t_floatarg fsocket); -static void tcpserver_send_bytes(t_tcpserver*x, int client, t_iemnet_chunk*chunk) +static void tcpserver_disconnect_socket(t_tcpserver *x, + t_floatarg fsocket); + +static void tcpserver_send_bytes_client(t_tcpserver*x, + t_tcpserver_socketreceiver*sr, int client, t_iemnet_chunk*chunk) { - DEBUG("send_bytes to %x -> %x[%d]", x, x->x_sr, client); - if(x->x_sr)DEBUG("client %X", x->x_sr[client]); - if(x && x->x_sr && x->x_sr[client]) { + if(sr) { t_atom output_atom[3]; int size=-1; - t_iemnet_sender*sender=sender=x->x_sr[client]->sr_sender; - int sockfd = x->x_sr[client]->sr_fd; - + t_iemnet_sender*sender=sr->sr_sender; + int sockfd = sr->sr_fd; if(sender) { size=iemnet__sender_send(sender, chunk); } @@ -244,7 +251,7 @@ static void tcpserver_send_bytes(t_tcpserver*x, int client, t_iemnet_chunk*chunk SETFLOAT(&output_atom[0], client+1); SETFLOAT(&output_atom[1], size); SETFLOAT(&output_atom[2], sockfd); - outlet_anything( x->x_statout, gensym("sent"), 3, output_atom); + outlet_anything( x->x_statout, gensym("sendbuffersize"), 3, output_atom); if(size<0) { // disconnected! @@ -253,74 +260,119 @@ static void tcpserver_send_bytes(t_tcpserver*x, int client, t_iemnet_chunk*chunk } } +static void tcpserver_send_bytes(t_tcpserver*x, int client, + t_iemnet_chunk*chunk) +{ + t_tcpserver_socketreceiver*sr=NULL; + if(x&&clientx_sr[client]; + } + DEBUG("send_bytes to %p[%d] -> %p", x, client, sr); + tcpserver_send_bytes_client(x, sr, client, chunk); +} +/* send the chunk to all non-null clients */ +static void tcpserver_send_bytes_clients(t_tcpserver*x, + t_tcpserver_socketreceiver**sr, unsigned int nsr, t_iemnet_chunk*chunk) +{ + unsigned int i=0; + for(i=0; ix_nconnections) { + return; + } - /* enumerate through the clients and send each the message */ - for(client = 0; client < x->x_nconnections; client++) /* check if connection exists */ - { - /* socket exists for this client */ - if(client!=but)tcpserver_send_bytes(x, client, chunk); - } + chunk=iemnet__chunk_create_list(argc, argv); + sr=(t_tcpserver_socketreceiver**)calloc(x->x_nconnections, + sizeof(t_tcpserver_socketreceiver*)); + + for(client=0; clientx_nconnections; client++) { + sr[client]=x->x_sr[client]; + } + + if(butx_nconnections) { + sr[but]=NULL; + } + + tcpserver_send_bytes_clients(x, sr, x->x_nconnections, chunk); + + free(sr); iemnet__chunk_destroy(chunk); } /* sends a message to a given client */ -static void tcpserver_send_toclient(t_tcpserver *x, int client, int argc, t_atom *argv) +static void tcpserver_send_toclient(t_tcpserver *x, unsigned int client, + int argc, t_atom *argv) { t_iemnet_chunk*chunk=iemnet__chunk_create_list(argc, argv); tcpserver_send_bytes(x, client, chunk); iemnet__chunk_destroy(chunk); } - - /* send message to client using client number note that the client numbers might change in case a client disconnects! */ /* clients start at 1 but our index starts at 0 */ -static void tcpserver_send_client(t_tcpserver *x, t_symbol *s, int argc, t_atom *argv) +static void tcpserver_send_client(t_tcpserver *x, t_symbol *s, int argc, + t_atom *argv) { int client=0; - - if (argc > 0) - { - client=tcpserver_fixindex(x, atom_getint(argv)); - if(client<0)return; - if(argc==1) { - tcpserver_info_client(x, client); - } else { - tcpserver_send_toclient(x, client, argc-1, argv+1); - } + + if (argc > 0) { + client=tcpserver_fixindex(x, atom_getint(argv)); + if(client<0) { return; } - else - { - for(client=0; clientx_nconnections; client++) - tcpserver_info_client(x, client); + if(argc==1) { + tcpserver_info_client(x, client); + } else { + tcpserver_send_toclient(x, client, argc-1, argv+1); + } + return; + } else { + unsigned int client; + for(client=0; clientx_nconnections; client++) { + tcpserver_info_client(x, client); } + } } /* broadcasts a message to all connected clients */ -static void tcpserver_broadcast(t_tcpserver *x, t_symbol *s, int argc, t_atom *argv) +static void tcpserver_broadcast(t_tcpserver *x, t_symbol *s, int argc, + t_atom *argv) { - int client; - t_iemnet_chunk*chunk=iemnet__chunk_create_list(argc, argv); + unsigned int client=0; + t_iemnet_chunk*chunk=NULL; + t_tcpserver_socketreceiver**sr=NULL; + if(!x || !x->x_nconnections) { + return; + } - /* enumerate through the clients and send each the message */ - for(client = 0; client < x->x_nconnections; client++) /* check if connection exists */ - { - /* socket exists for this client */ - tcpserver_send_bytes(x, client, chunk); - } + chunk=iemnet__chunk_create_list(argc, argv); + sr=(t_tcpserver_socketreceiver**)calloc(x->x_nconnections, + sizeof(t_tcpserver_socketreceiver*)); + + for(client=0; clientx_nconnections; client++) { + sr[client]=x->x_sr[client]; + } + + tcpserver_send_bytes_clients(x, sr, x->x_nconnections, chunk); + + free(sr); iemnet__chunk_destroy(chunk); } /* broadcasts a message to all connected clients */ -static void tcpserver_broadcastbut(t_tcpserver *x, t_symbol *s, int argc, t_atom *argv) +static void tcpserver_broadcastbut(t_tcpserver *x, t_symbol *s, int argc, + t_atom *argv) { int but=-1; //int client=0; @@ -329,32 +381,48 @@ static void tcpserver_broadcastbut(t_tcpserver *x, t_symbol *s, int argc, t_atom if(argc<2) { return; } - if((but=tcpserver_fixindex(x, atom_getint(argv)))<0)return; + if((but=tcpserver_fixindex(x, atom_getint(argv)))<0) { + return; + } tcpserver_send_butclient(x, but, argc-1, argv+1); } -static void tcpserver_defaultsend(t_tcpserver *x, t_symbol *s, int argc, t_atom *argv) +static void tcpserver_defaultsend(t_tcpserver *x, t_symbol *s, int argc, + t_atom *argv) { int client=-1; int sockfd=x->x_defaulttarget; - if(0==sockfd) - tcpserver_broadcast(x, s, argc, argv); - else if(sockfd>0) { + if(sockfd>0) { client=tcpserver_socket2index(x, sockfd); - tcpserver_send_toclient(x, client, argc, argv); + if(client>=0) { + tcpserver_send_toclient(x, client, argc, argv); + return; + } + pd_error(x, "[%s] illegal socket %d, switching to broadcast mode", objName, + sockfd); + x->x_defaulttarget=0; } else if(sockfd<0) { client=tcpserver_socket2index(x, -sockfd); - tcpserver_send_butclient(x, client, argc, argv); + if(client>=0) { + tcpserver_send_butclient(x, client, argc, argv); + return; + } + pd_error(x, "[%s] illegal !ocket %d, switching to broadcast mode", objName, + sockfd); + x->x_defaulttarget=0; } + + tcpserver_broadcast(x, s, argc, argv); } static void tcpserver_defaulttarget(t_tcpserver *x, t_floatarg f) { int sockfd=0; int rawclient=f; - int client=(rawclient<0)?(-rawclient):rawclient; + unsigned int client=(rawclient<0)?(-rawclient):rawclient; if(client > x->x_nconnections) { - error("[%s] target %d out of range [0..%d]", objName, client, (int)(x->x_nconnections)); + error("[%s] target %d out of range [0..%d]", objName, client, + (int)(x->x_nconnections)); return; } @@ -363,7 +431,9 @@ static void tcpserver_defaulttarget(t_tcpserver *x, t_floatarg f) sockfd=x->x_sr[client-1]->sr_fd; } - if(rawclient<0)sockfd=-sockfd; + if(rawclient<0) { + sockfd=-sockfd; + } x->x_defaulttarget=sockfd; } @@ -376,43 +446,42 @@ static void tcpserver_targetsocket(t_tcpserver *x, t_floatarg f) /* send message to client using socket number */ -static void tcpserver_send_socket(t_tcpserver *x, t_symbol *s, int argc, t_atom *argv) +static void tcpserver_send_socket(t_tcpserver *x, t_symbol *s, int argc, + t_atom *argv) { int client = -1; t_iemnet_chunk*chunk=NULL; if(argc) { client = tcpserver_socket2index(x, atom_getint(argv)); - if(client<0)return; + if(client<0) { + return; + } } else { pd_error(x, "%s_send: no socket specified", objName); return; } /* get socket number of connection (first element in list) */ - if(argc && argv->a_type == A_FLOAT) - { - int sockfd=atom_getint(argv); - client = tcpserver_socket2index(x, sockfd); - if(client < 0) - { - post("%s_send: no connection on socket %d", objName, sockfd); - return; - } - } - else - { - post("%s_send: no socket specified", objName); + if(argc && argv->a_type == A_FLOAT) { + int sockfd=atom_getint(argv); + client = tcpserver_socket2index(x, sockfd); + if(client < 0) { + post("%s_send: no connection on socket %d", objName, sockfd); return; } - + } else { + post("%s_send: no socket specified", objName); + return; + } + chunk=iemnet__chunk_create_list(argc-1, argv+1); tcpserver_send_bytes(x, client, chunk); iemnet__chunk_destroy(chunk); } -static void tcpserver_disconnect(t_tcpserver *x, int client) +static void tcpserver_disconnect(t_tcpserver *x, unsigned int client) { - int k; + unsigned int k; DEBUG("disconnect %x %d", x, client); tcpserver_info_connection(x, x->x_sr[client]); @@ -420,10 +489,9 @@ static void tcpserver_disconnect(t_tcpserver *x, int client) x->x_sr[client]=NULL; /* rearrange list now: move entries to close the gap */ - for(k = client; k < x->x_nconnections; k++) - { - x->x_sr[k] = x->x_sr[k + 1]; - } + for(k = client; k < x->x_nconnections; k++) { + x->x_sr[k] = x->x_sr[k + 1]; + } x->x_sr[k + 1]=NULL; x->x_nconnections--; @@ -437,7 +505,9 @@ static void tcpserver_disconnect_client(t_tcpserver *x, t_floatarg fclient) { int client = tcpserver_fixindex(x, fclient); - if(client<0)return; + if(client<0) { + return; + } tcpserver_disconnect(x, client); } @@ -446,8 +516,9 @@ static void tcpserver_disconnect_client(t_tcpserver *x, t_floatarg fclient) static void tcpserver_disconnect_socket(t_tcpserver *x, t_floatarg fsocket) { int id=tcpserver_socket2index(x, (int)fsocket); - if(id>=0) + if(id>=0) { tcpserver_disconnect_client(x, id+1); + } } @@ -455,23 +526,28 @@ static void tcpserver_disconnect_socket(t_tcpserver *x, t_floatarg fsocket) /* disconnect a client by socket */ static void tcpserver_disconnect_all(t_tcpserver *x) { - int id=x->x_nconnections; - while(--id>=0) { + unsigned int id; + for(id=0; idx_nconnections; id++) { tcpserver_disconnect(x, id); } } /* ---------------- main tcpserver (receive) stuff --------------------- */ -static void tcpserver_receive_callback(void *y0, - t_iemnet_chunk*c) { +static void tcpserver_receive_callback(void *y0, + t_iemnet_chunk*c) +{ t_tcpserver_socketreceiver *y=(t_tcpserver_socketreceiver*)y0; t_tcpserver*x=NULL; - if(NULL==y || NULL==(x=y->sr_owner))return; - + if(NULL==y || NULL==(x=y->sr_owner)) { + return; + } + if(c) { tcpserver_info_connection(x, y); - x->x_floatlist=iemnet__chunk2list(c, x->x_floatlist); // get's destroyed in the dtor - iemnet__streamout(x->x_msgout, x->x_floatlist->argc, x->x_floatlist->argv, x->x_serialize); + x->x_floatlist=iemnet__chunk2list(c, + x->x_floatlist); // get's destroyed in the dtor + iemnet__streamout(x->x_msgout, x->x_floatlist->argc, x->x_floatlist->argv, + x->x_serialize); } else { // disconnected int sockfd=y->sr_fd; @@ -486,25 +562,33 @@ static void tcpserver_connectpoll(t_tcpserver *x) { struct sockaddr_in incomer_address; socklen_t sockaddrl = sizeof( struct sockaddr ); - int fd = accept(x->x_connectsocket, (struct sockaddr*)&incomer_address, &sockaddrl); + int fd = accept(x->x_connectsocket, + (struct sockaddr*)&incomer_address, &sockaddrl); int i; - if (fd < 0) post("%s: accept failed", objName); - else - { - t_tcpserver_socketreceiver *y = tcpserver_socketreceiver_new((void *)x, fd, &incomer_address); - if (!y) - { - sys_closesocket(fd); - return; - } - x->x_nconnections++; - i = x->x_nconnections - 1; - x->x_sr[i] = y; - - tcpserver_info_connection(x, y); + if (fd < 0) { + post("%s: accept failed", objName); + } else { + t_tcpserver_socketreceiver *y = NULL; + if(x->x_nconnections>=MAX_CONNECT) { + pd_error(x, "%s: cannot handle more than %d connections, dropping", + objName, x->x_nconnections); + iemnet__closesocket(fd); } + + y = tcpserver_socketreceiver_new((void *)x, fd, &incomer_address); + if (!y) { + iemnet__closesocket(fd); + return; + } + x->x_nconnections++; + i = x->x_nconnections - 1; + x->x_sr[i] = y; + + tcpserver_info_connection(x, y); + } + outlet_float(x->x_connectout, x->x_nconnections); } @@ -515,6 +599,8 @@ static void tcpserver_port(t_tcpserver*x, t_floatarg fportno) struct sockaddr_in server; socklen_t serversize=sizeof(server); int sockfd = x->x_connectsocket; + memset(&server, 0, sizeof(server)); + SETFLOAT(ap, -1); if(x->x_port == portno) { return; @@ -523,14 +609,16 @@ static void tcpserver_port(t_tcpserver*x, t_floatarg fportno) /* cleanup any open ports */ if(sockfd>=0) { sys_rmpollfn(sockfd); - sys_closesocket(sockfd); + iemnet__closesocket(sockfd); x->x_connectsocket=-1; x->x_port=-1; } - sockfd = socket(AF_INET, SOCK_STREAM, 0); - + if(sockfd<0) { + sys_sockerror("[tcpserver]: cannot create TCP/IP socket"); + return; + } server.sin_family = AF_INET; @@ -540,27 +628,24 @@ static void tcpserver_port(t_tcpserver*x, t_floatarg fportno) /* assign server port number */ server.sin_port = htons((u_short)portno); /* name the socket */ - if (bind(sockfd, (struct sockaddr *)&server, serversize) < 0) - { - sys_sockerror("tcpserver: bind"); - sys_closesocket(sockfd); - outlet_anything(x->x_statout, gensym("port"), 1, ap); - return; - } + if (bind(sockfd, (struct sockaddr *)&server, serversize) < 0) { + sys_sockerror("tcpserver: bind"); + iemnet__closesocket(sockfd); + outlet_anything(x->x_statout, gensym("port"), 1, ap); + return; + } /* streaming protocol */ - if (listen(sockfd, 5) < 0) - { - sys_sockerror("tcpserver: listen"); - sys_closesocket(sockfd); - sockfd = -1; - outlet_anything(x->x_statout, gensym("port"), 1, ap); - return; - } - else - { - sys_addpollfn(sockfd, (t_fdpollfn)tcpserver_connectpoll, x); // wait for new connections - } + if (listen(sockfd, 5) < 0) { + sys_sockerror("tcpserver: listen"); + iemnet__closesocket(sockfd); + sockfd = -1; + outlet_anything(x->x_statout, gensym("port"), 1, ap); + return; + } else { + sys_addpollfn(sockfd, (t_fdpollfn)tcpserver_connectpoll, + x); // wait for new connections + } x->x_connectsocket = sockfd; x->x_port = portno; @@ -576,7 +661,8 @@ static void tcpserver_port(t_tcpserver*x, t_floatarg fportno) outlet_anything(x->x_statout, gensym("port"), 1, ap); } -static void tcpserver_serialize(t_tcpserver *x, t_floatarg doit) { +static void tcpserver_serialize(t_tcpserver *x, t_floatarg doit) +{ x->x_serialize=doit; } @@ -589,10 +675,12 @@ static void *tcpserver_new(t_floatarg fportno) x = (t_tcpserver *)pd_new(tcpserver_class); x->x_msgout = outlet_new(&x->x_obj, 0); /* 1st outlet for received data */ - x->x_connectout = outlet_new(&x->x_obj, gensym("float")); /* 2nd outlet for number of connected clients */ + x->x_connectout = outlet_new(&x->x_obj, + gensym("float")); /* 2nd outlet for number of connected clients */ x->x_sockout = outlet_new(&x->x_obj, gensym("float")); x->x_addrout = outlet_new(&x->x_obj, gensym("list" )); - x->x_statout = outlet_new(&x->x_obj, 0);/* 5th outlet for everything else */ + x->x_statout = outlet_new(&x->x_obj, + 0);/* 5th outlet for everything else */ x->x_serialize=1; @@ -600,14 +688,13 @@ static void *tcpserver_new(t_floatarg fportno) x->x_port = -1; x->x_nconnections = 0; - for(i = 0; i < MAX_CONNECT; i++) - { - x->x_sr[i] = NULL; - } + for(i = 0; i < MAX_CONNECT; i++) { + x->x_sr[i] = NULL; + } x->x_defaulttarget=0; - - + + x->x_floatlist=iemnet__floatlist_create(1024); tcpserver_port(x, fportno); @@ -619,46 +706,60 @@ static void tcpserver_free(t_tcpserver *x) { int i; - for(i = 0; i < MAX_CONNECT; i++) - { - if (NULL!=x->x_sr[i]) { - DEBUG("[%s] free %x", objName, x); - tcpserver_socketreceiver_free(x->x_sr[i]); - x->x_sr[i]=NULL; - } + for(i = 0; i < MAX_CONNECT; i++) { + if (NULL!=x->x_sr[i]) { + DEBUG("[%s] free %x", objName, x); + tcpserver_socketreceiver_free(x->x_sr[i]); + x->x_sr[i]=NULL; } - if (x->x_connectsocket >= 0) - { - sys_rmpollfn(x->x_connectsocket); - sys_closesocket(x->x_connectsocket); - } - if(x->x_floatlist)iemnet__floatlist_destroy(x->x_floatlist);x->x_floatlist=NULL; + } + if (x->x_connectsocket >= 0) { + sys_rmpollfn(x->x_connectsocket); + iemnet__closesocket(x->x_connectsocket); + } + if(x->x_floatlist) { + iemnet__floatlist_destroy(x->x_floatlist); + } + x->x_floatlist=NULL; } IEMNET_EXTERN void tcpserver_setup(void) { - if(!iemnet__register(objName))return; + if(!iemnet__register(objName)) { + return; + } - tcpserver_class = class_new(gensym(objName),(t_newmethod)tcpserver_new, (t_method)tcpserver_free, + tcpserver_class = class_new(gensym(objName),(t_newmethod)tcpserver_new, + (t_method)tcpserver_free, sizeof(t_tcpserver), 0, A_DEFFLOAT, 0); - class_addmethod(tcpserver_class, (t_method)tcpserver_disconnect_client, gensym("disconnectclient"), A_DEFFLOAT, 0); - class_addmethod(tcpserver_class, (t_method)tcpserver_disconnect_socket, gensym("disconnectsocket"), A_DEFFLOAT, 0); - class_addmethod(tcpserver_class, (t_method)tcpserver_disconnect_all, gensym("disconnect"), 0); - - class_addmethod(tcpserver_class, (t_method)tcpserver_send_socket, gensym("send"), A_GIMME, 0); - class_addmethod(tcpserver_class, (t_method)tcpserver_send_client, gensym("client"), A_GIMME, 0); - - class_addmethod(tcpserver_class, (t_method)tcpserver_broadcast, gensym("broadcast"), A_GIMME, 0); - - class_addmethod(tcpserver_class, (t_method)tcpserver_defaulttarget, gensym("target"), A_DEFFLOAT, 0); - class_addmethod(tcpserver_class, (t_method)tcpserver_targetsocket, gensym("targetsocket"), A_DEFFLOAT, 0); + class_addmethod(tcpserver_class, (t_method)tcpserver_disconnect_client, + gensym("disconnectclient"), A_DEFFLOAT, 0); + class_addmethod(tcpserver_class, (t_method)tcpserver_disconnect_socket, + gensym("disconnectsocket"), A_DEFFLOAT, 0); + class_addmethod(tcpserver_class, (t_method)tcpserver_disconnect_all, + gensym("disconnect"), 0); + + class_addmethod(tcpserver_class, (t_method)tcpserver_send_socket, + gensym("send"), A_GIMME, 0); + class_addmethod(tcpserver_class, (t_method)tcpserver_send_client, + gensym("client"), A_GIMME, 0); + + class_addmethod(tcpserver_class, (t_method)tcpserver_broadcast, + gensym("broadcast"), A_GIMME, 0); + + class_addmethod(tcpserver_class, (t_method)tcpserver_defaulttarget, + gensym("target"), A_DEFFLOAT, 0); + class_addmethod(tcpserver_class, (t_method)tcpserver_targetsocket, + gensym("targetsocket"), A_DEFFLOAT, 0); class_addlist (tcpserver_class, (t_method)tcpserver_defaultsend); - class_addmethod(tcpserver_class, (t_method)tcpserver_serialize, gensym("serialize"), A_FLOAT, 0); + class_addmethod(tcpserver_class, (t_method)tcpserver_serialize, + gensym("serialize"), A_FLOAT, 0); - class_addmethod(tcpserver_class, (t_method)tcpserver_port, gensym("port"), A_DEFFLOAT, 0); + class_addmethod(tcpserver_class, (t_method)tcpserver_port, gensym("port"), + A_DEFFLOAT, 0); class_addbang (tcpserver_class, (t_method)tcpserver_info); DEBUGMETHOD(tcpserver_class); diff --git a/tests/sequence/01_server.pd b/tests/sequence/01_server.pd index 8e84863..200e97b 100644 --- a/tests/sequence/01_server.pd +++ b/tests/sequence/01_server.pd @@ -1,59 +1,59 @@ -#N canvas 219 165 438 532 10; -#X obj 71 256 tcpserver 9999; -#X obj 71 278 t b; -#X obj 71 300 i; -#X obj 115 326 + 1; -#X obj 115 348 % 255; -#X obj 250 252 loadbang; -#X msg 71 388 broadcast \$1; -#X obj 71 429 list append; -#X obj 250 274 f 1024; -#X obj 250 296 t b f b; -#X obj 250 438 list prepend; -#X obj 273 319 until; -#X obj 273 341 f 255; -#X obj 273 363 list prepend; -#X obj 273 385 t l l; -#X msg 106 276 bang; -#X msg 321 250 bang; -#X obj 71 451 list trim; -#X obj 23 229 t a; -#X text 27 43 responds to any data from the client by sending pack -a stream consisting of a header and a dummy payload.; -#X text 31 84 the dummy payload is a number of 0xFF bytes; -#X obj 71 322 t f f; -#X text 32 99 the header is a single byte counting up from 0..254 (and -wrapping around); -#X floatatom 166 305 5 0 0 0 - - -; -#X obj 152 169 route sent; -#X obj 152 191 unpack 0 0 0; -#X floatatom 186 225 0 0 0 0 - - -; -#X floatatom 221 211 5 0 0 0 - - -; -#X connect 0 0 1 0; -#X connect 0 4 24 0; -#X connect 1 0 2 0; -#X connect 2 0 21 0; -#X connect 3 0 4 0; -#X connect 4 0 2 1; -#X connect 5 0 8 0; -#X connect 6 0 7 0; -#X connect 7 0 17 0; -#X connect 8 0 9 0; -#X connect 9 0 10 0; -#X connect 9 1 11 0; -#X connect 10 0 7 1; -#X connect 11 0 12 0; -#X connect 12 0 13 0; -#X connect 13 0 14 0; -#X connect 14 0 10 1; -#X connect 14 1 13 1; -#X connect 15 0 1 0; -#X connect 16 0 8 0; -#X connect 17 0 18 0; -#X connect 18 0 0 0; -#X connect 21 0 6 0; -#X connect 21 1 3 0; -#X connect 23 0 3 1; -#X connect 24 0 25 0; -#X connect 25 1 26 0; -#X connect 25 2 27 0; +#N canvas 219 165 438 532 10; +#X obj 71 256 tcpserver 9999; +#X obj 71 278 t b; +#X obj 71 300 i; +#X obj 115 326 + 1; +#X obj 115 348 % 255; +#X obj 250 252 loadbang; +#X msg 71 388 broadcast \$1; +#X obj 71 429 list append; +#X obj 250 274 f 1024; +#X obj 250 296 t b f b; +#X obj 250 438 list prepend; +#X obj 273 319 until; +#X obj 273 341 f 255; +#X obj 273 363 list prepend; +#X obj 273 385 t l l; +#X msg 106 276 bang; +#X msg 321 250 bang; +#X obj 71 451 list trim; +#X obj 23 229 t a; +#X text 27 43 responds to any data from the client by sending pack +a stream consisting of a header and a dummy payload.; +#X text 31 84 the dummy payload is a number of 0xFF bytes; +#X obj 71 322 t f f; +#X text 32 99 the header is a single byte counting up from 0..254 (and +wrapping around); +#X floatatom 166 305 5 0 0 0 - - -; +#X obj 152 169 route sent; +#X obj 152 191 unpack 0 0 0; +#X floatatom 186 225 0 0 0 0 - - -; +#X floatatom 221 211 5 0 0 0 - - -; +#X connect 0 0 1 0; +#X connect 0 4 24 0; +#X connect 1 0 2 0; +#X connect 2 0 21 0; +#X connect 3 0 4 0; +#X connect 4 0 2 1; +#X connect 5 0 8 0; +#X connect 6 0 7 0; +#X connect 7 0 17 0; +#X connect 8 0 9 0; +#X connect 9 0 10 0; +#X connect 9 1 11 0; +#X connect 10 0 7 1; +#X connect 11 0 12 0; +#X connect 12 0 13 0; +#X connect 13 0 14 0; +#X connect 14 0 10 1; +#X connect 14 1 13 1; +#X connect 15 0 1 0; +#X connect 16 0 8 0; +#X connect 17 0 18 0; +#X connect 18 0 0 0; +#X connect 21 0 6 0; +#X connect 21 1 3 0; +#X connect 23 0 3 1; +#X connect 24 0 25 0; +#X connect 25 1 26 0; +#X connect 25 2 27 0; diff --git a/udpclient.c b/udpclient.c index 4ebca84..b643fdc 100644 --- a/udpclient.c +++ b/udpclient.c @@ -1,5 +1,5 @@ /* udpclient.c - * copyright (c) 2010 IOhannes m zmölnig, IEM + * copyright (c) 2010 IOhannes m zmölnig, IEM */ /* */ @@ -16,9 +16,8 @@ /* GNU General Public License for more details. */ /* */ /* You should have received a copy of the GNU General Public License */ -/* along with this program; if not, write to the Free Software */ -/* Foundation, Inc., */ -/* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ +/* along with this program; if not, see */ +/* http://www.gnu.org/licenses/ */ /* */ /* ---------------------------------------------------------------------------- */ @@ -34,8 +33,7 @@ static t_class *udpclient_class; static const char objName[] = "udpclient"; -typedef struct _udpclient -{ +typedef struct _udpclient { t_object x_obj; t_clock *x_clock; t_outlet *x_msgout; @@ -58,7 +56,7 @@ typedef struct _udpclient pthread_t x_threadid; /* id of child thread */ pthread_attr_t x_threadattr; /* attributes of child thread */ - t_iemnet_floatlist *x_floatlist; + t_iemnet_floatlist *x_floatlist; } t_udpclient; @@ -68,47 +66,43 @@ static void udpclient_receive_callback(void *x, t_iemnet_chunk*); /* connection handling */ -static void *udpclient_child_connect(void *w) +static void *udpclient_doconnect(t_udpclient*x, int subthread) { - t_udpclient *x = (t_udpclient*) w; - struct sockaddr_in server; struct hostent *hp; int sockfd; int broadcast = 1;/* nonzero is true */ + memset(&server, 0, sizeof(server)); - if (x->x_sender) - { - error("[%s] already connected", objName); - return (x); - } + if (x->x_sender) { + error("[%s] already connected", objName); + return (x); + } /* create a socket */ sockfd = socket(AF_INET, SOCK_DGRAM, 0); DEBUG("send socket %d\n", sockfd); - if (sockfd < 0) - { - sys_sockerror("udpclient: socket"); - return (x); - } + if (sockfd < 0) { + sys_sockerror("udpclient: socket"); + return (x); + } /* Based on zmoelnig's patch 2221504: Enable sending of broadcast messages (if hostname is a broadcast address)*/ #ifdef SO_BROADCAST - if( 0 != setsockopt(sockfd, SOL_SOCKET, SO_BROADCAST, (const void *)&broadcast, sizeof(broadcast))) - { - error("[%s] couldn't switch to broadcast mode", objName); - } + if( 0 != setsockopt(sockfd, SOL_SOCKET, SO_BROADCAST, + (const void *)&broadcast, sizeof(broadcast))) { + error("[%s] couldn't switch to broadcast mode", objName); + } #endif /* SO_BROADCAST */ - + /* connect socket using hostname provided in command line */ server.sin_family = AF_INET; hp = gethostbyname(x->x_hostname); - if (hp == 0) - { - error("[%s] bad host '%s'?", objName, x->x_hostname); - return (x); - } + if (hp == 0) { + error("[%s] bad host '%s'?", objName, x->x_hostname); + return (x); + } memcpy((char *)&server.sin_addr, (char *)hp->h_addr, hp->h_length); /* assign client port number */ @@ -116,23 +110,29 @@ static void *udpclient_child_connect(void *w) DEBUG("connecting to port %d", x->x_port); /* try to connect. */ - if (connect(sockfd, (struct sockaddr *) &server, sizeof (server)) < 0) - { - sys_sockerror("udpclient: connecting stream socket"); - sys_closesocket(sockfd); - return (x); - } + if (connect(sockfd, (struct sockaddr *) &server, sizeof (server)) < 0) { + sys_sockerror("udpclient: connecting stream socket"); + iemnet__closesocket(sockfd); + return (x); + } x->x_fd = sockfd; x->x_addr = ntohl(*(long *)hp->h_addr); - x->x_sender=iemnet__sender_create(sockfd); - x->x_receiver=iemnet__receiver_create(sockfd, x, udpclient_receive_callback); + x->x_sender=iemnet__sender_create(sockfd, NULL, NULL, subthread); + x->x_receiver=iemnet__receiver_create(sockfd, x, + udpclient_receive_callback, subthread); x->x_connectstate = 1; clock_delay(x->x_clock, 0); return (x); } +static void *udpclient_child_connect(void *w) +{ + t_udpclient *x = (t_udpclient*) w; + udpclient_doconnect(x, 1); + return x; +} static void udpclient_tick(t_udpclient *x) { outlet_float(x->x_connectout, 1); @@ -141,38 +141,54 @@ static void udpclient_tick(t_udpclient *x) static void udpclient_disconnect(t_udpclient *x) { - if (x->x_fd >= 0) - { + if (x->x_fd >= 0) { - DEBUG("disconnect %x %x", x->x_sender, x->x_receiver); - if(x->x_receiver)iemnet__receiver_destroy(x->x_receiver); x->x_receiver=NULL; - if(x->x_sender)iemnet__sender_destroy(x->x_sender); x->x_sender=NULL; - - sys_closesocket(x->x_fd); - x->x_fd = -1; - x->x_connectstate = 0; - outlet_float(x->x_connectout, 0); + DEBUG("disconnect %x %x", x->x_sender, x->x_receiver); + if(x->x_receiver) { + iemnet__receiver_destroy(x->x_receiver, 0); + } + x->x_receiver=NULL; + if(x->x_sender) { + iemnet__sender_destroy(x->x_sender, 0); } - else pd_error(x, "[%s] not connected", objName); + x->x_sender=NULL; + + iemnet__closesocket(x->x_fd); + x->x_fd = -1; + x->x_connectstate = 0; + outlet_float(x->x_connectout, 0); + } else { + pd_error(x, "[%s] not connected", objName); + } } -static void udpclient_connect(t_udpclient *x, t_symbol *hostname, t_floatarg fportno) +static void udpclient_connect(t_udpclient *x, t_symbol *hostname, + t_floatarg fportno) { - if(x->x_fd>=0)udpclient_disconnect(x); + if(x->x_fd>=0) { + udpclient_disconnect(x); + } /* we get hostname and port and pass them on to the child thread that establishes the connection */ x->x_hostname = hostname->s_name; x->x_port = fportno; x->x_connectstate = 0; +#if 0 /* start child thread */ - if(pthread_create(&x->x_threadid, &x->x_threadattr, udpclient_child_connect, x) < 0) + if(pthread_create(&x->x_threadid, &x->x_threadattr, + udpclient_child_connect, x) < 0) { error("%s: could not create new thread", objName); + } +#else + udpclient_doconnect(x, 0); +#endif } /* sending/receiving */ -static void udpclient_send(t_udpclient *x, t_symbol *s, int argc, t_atom *argv) +static void udpclient_send(t_udpclient *x, t_symbol *s, int argc, + t_atom *argv) { int size=0; t_atom output_atom; @@ -185,16 +201,20 @@ static void udpclient_send(t_udpclient *x, t_symbol *s, int argc, t_atom *argv) iemnet__chunk_destroy(chunk); SETFLOAT(&output_atom, size); - outlet_anything( x->x_statusout, gensym("sent"), 1, &output_atom); + outlet_anything( x->x_statusout, gensym("sendbuffersize"), 1, + &output_atom); } -static void udpclient_receive_callback(void*y, t_iemnet_chunk*c) { +static void udpclient_receive_callback(void*y, t_iemnet_chunk*c) +{ t_udpclient *x=(t_udpclient*)y; if(c) { iemnet__addrout(x->x_statusout, x->x_addrout, x->x_addr, x->x_port); - x->x_floatlist=iemnet__chunk2list(c, x->x_floatlist); // gets destroyed in the dtor - outlet_list(x->x_msgout, gensym("list"),x->x_floatlist->argc, x->x_floatlist->argv); + x->x_floatlist=iemnet__chunk2list(c, + x->x_floatlist); // gets destroyed in the dtor + outlet_list(x->x_msgout, gensym("list"),x->x_floatlist->argc, + x->x_floatlist->argv); } else { // disconnected DEBUG("disconnected"); @@ -211,8 +231,10 @@ static void *udpclient_new(void) t_udpclient *x = (t_udpclient *)pd_new(udpclient_class); x->x_msgout = outlet_new(&x->x_obj, 0); /* received data */ x->x_addrout = outlet_new(&x->x_obj, gensym("list")); - x->x_connectout = outlet_new(&x->x_obj, gensym("float")); /* connection state */ - x->x_statusout = outlet_new(&x->x_obj, 0);/* last outlet for everything else */ + x->x_connectout = outlet_new(&x->x_obj, + gensym("float")); /* connection state */ + x->x_statusout = outlet_new(&x->x_obj, + 0);/* last outlet for everything else */ x->x_fd = -1; x->x_addr = 0L; @@ -226,11 +248,14 @@ static void *udpclient_new(void) x->x_floatlist=iemnet__floatlist_create(1024); /* prepare child thread */ - if(pthread_attr_init(&x->x_threadattr) < 0) + if(pthread_attr_init(&x->x_threadattr) < 0) { verbose(1, "[%s] warning: could not prepare child thread", objName); - if(pthread_attr_setdetachstate(&x->x_threadattr, PTHREAD_CREATE_DETACHED) < 0) + } + if(pthread_attr_setdetachstate(&x->x_threadattr, + PTHREAD_CREATE_DETACHED) < 0) { verbose(1, "[%s] warning: could not prepare child thread", objName); - + } + return (x); } @@ -238,20 +263,31 @@ static void *udpclient_new(void) static void udpclient_free(t_udpclient *x) { udpclient_disconnect(x); - if(x->x_clock)clock_free(x->x_clock);x->x_clock=NULL; - if(x->x_floatlist)iemnet__floatlist_destroy(x->x_floatlist);x->x_floatlist=NULL; + if(x->x_clock) { + clock_free(x->x_clock); + } + x->x_clock=NULL; + if(x->x_floatlist) { + iemnet__floatlist_destroy(x->x_floatlist); + } + x->x_floatlist=NULL; } IEMNET_EXTERN void udpclient_setup(void) { - if(!iemnet__register(objName))return; + if(!iemnet__register(objName)) { + return; + } udpclient_class = class_new(gensym(objName), (t_newmethod)udpclient_new, (t_method)udpclient_free, sizeof(t_udpclient), 0, A_DEFFLOAT, 0); - class_addmethod(udpclient_class, (t_method)udpclient_connect, gensym("connect") + class_addmethod(udpclient_class, (t_method)udpclient_connect, + gensym("connect") , A_SYMBOL, A_FLOAT, 0); - class_addmethod(udpclient_class, (t_method)udpclient_disconnect, gensym("disconnect"), 0); - class_addmethod(udpclient_class, (t_method)udpclient_send, gensym("send"), A_GIMME, 0); + class_addmethod(udpclient_class, (t_method)udpclient_disconnect, + gensym("disconnect"), 0); + class_addmethod(udpclient_class, (t_method)udpclient_send, gensym("send"), + A_GIMME, 0); class_addlist(udpclient_class, (t_method)udpclient_send); DEBUGMETHOD(udpclient_class); diff --git a/udpreceive.c b/udpreceive.c index e2a1c30..5fc092e 100644 --- a/udpreceive.c +++ b/udpreceive.c @@ -1,5 +1,5 @@ /* udpreceive.c - * copyright (c) 2010 IOhannes m zmölnig, IEM + * copyright (c) 2010 IOhannes m zmölnig, IEM * copyright (c) 2006-2010 Martin Peach * copyright (c) Miller Puckette */ @@ -18,22 +18,21 @@ /* GNU General Public License for more details. */ /* */ /* You should have received a copy of the GNU General Public License */ -/* along with this program; if not, write to the Free Software */ -/* Foundation, Inc., */ -/* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ +/* along with this program; if not, see */ +/* http://www.gnu.org/licenses/ */ #define DEBUGLEVEL 1 static const char objName[] = "udpreceive"; #include "iemnet.h" +#include /* ----------------------------- udpreceive ------------------------- */ static t_class *udpreceive_class; -typedef struct _udpreceive -{ +typedef struct _udpreceive { t_object x_obj; t_outlet *x_msgout; t_outlet *x_addrout; @@ -42,80 +41,84 @@ typedef struct _udpreceive int x_connectsocket; int x_port; t_iemnet_receiver*x_receiver; - t_iemnet_floatlist *x_floatlist; + t_iemnet_floatlist *x_floatlist; + + int x_reuseport, x_reuseaddr; } t_udpreceive; -static void udpreceive_read_callback(void*y, t_iemnet_chunk*c) { +static void udpreceive_read_callback(void*y, t_iemnet_chunk*c) +{ t_udpreceive*x=(t_udpreceive*)y; if(c) { iemnet__addrout(x->x_statout, x->x_addrout, c->addr, c->port); - x->x_floatlist=iemnet__chunk2list(c, x->x_floatlist); // gets destroyed in the dtor - outlet_list(x->x_msgout, gensym("list"), x->x_floatlist->argc, x->x_floatlist->argv); + x->x_floatlist=iemnet__chunk2list(c, + x->x_floatlist); // gets destroyed in the dtor + outlet_list(x->x_msgout, gensym("list"), x->x_floatlist->argc, + x->x_floatlist->argv); } else { post("[%s] nothing received", objName); } } -static void udpreceive_port(t_udpreceive*x, t_floatarg fportno) +static int udpreceive_setport(t_udpreceive*x, unsigned short portno) { - static t_atom ap[1]; - int portno = fportno; struct sockaddr_in server; socklen_t serversize=sizeof(server); int sockfd = x->x_connectsocket; int intarg; + memset(&server, 0, sizeof(server)); - SETFLOAT(ap, -1); if(x->x_port == portno) { - return; + return 1; } /* cleanup any open ports */ if(sockfd>=0) { - iemnet__receiver_destroy(x->x_receiver); + iemnet__receiver_destroy(x->x_receiver, 0); x->x_connectsocket=-1; x->x_port=-1; } sockfd = socket(AF_INET, SOCK_DGRAM, 0); if(sockfd<0) { - error("[%s]: unable to create socket", objName); - return; + pd_error(x, "[%s]: unable to create socket", objName); + return 0; } /* ask OS to allow another Pd to reopen this port after we close it. */ #ifdef SO_REUSEADDR - intarg = 1; - if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, - (char *)&intarg, sizeof(intarg)) - < 0) { - error("[%s]: setsockopt (SO_REUSEADDR) failed", objName); + if(x->x_reuseaddr) { + intarg = 1; + if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, + (void *)&intarg, sizeof(intarg)) + < 0) { + pd_error(x, "[%s]: setsockopt (SO_REUSEADDR) failed", objName); + } } #endif /* SO_REUSEADDR */ #ifdef SO_REUSEPORT - intarg = 1; - if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEPORT, - (char *)&intarg, sizeof(intarg)) - < 0) { - error("[%s]: setsockopt (SO_REUSEPORT) failed", objName); + if(x->x_reuseport) { + intarg = 1; + if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEPORT, + (void *)&intarg, sizeof(intarg)) + < 0) { + pd_error(x, "[%s]: setsockopt (SO_REUSEPORT) failed", objName); + } } #endif /* SO_REUSEPORT */ - server.sin_family = AF_INET; server.sin_addr.s_addr = INADDR_ANY; server.sin_port = htons((u_short)portno); /* name the socket */ - if (bind(sockfd, (struct sockaddr *)&server, serversize) < 0) - { - sys_sockerror("[udpreceive] bind failed"); - sys_closesocket(sockfd); - sockfd = -1; - outlet_anything(x->x_statout, gensym("port"), 1, ap); - return; - } + if (bind(sockfd, (struct sockaddr *)&server, serversize) < 0) { + sys_sockerror("[udpreceive] bind failed"); + iemnet__closesocket(sockfd); + sockfd = -1; + return 0; + } x->x_connectsocket = sockfd; x->x_port = portno; @@ -126,54 +129,115 @@ static void udpreceive_port(t_udpreceive*x, t_floatarg fportno) } x->x_receiver=iemnet__receiver_create(sockfd, - x, - udpreceive_read_callback); + x, + udpreceive_read_callback, + 0); + return 1; +} + +static void udpreceive_port(t_udpreceive*x, t_symbol*s, int argc, + t_atom*argv) +{ + t_atom ap[1]; + if(argc) { + if(argc>1 || A_FLOAT != argv->a_type) { + pd_error(x, "[%s] usage: port []", objName); + return; + } + SETFLOAT(ap, -1); + if(!udpreceive_setport(x, atom_getint(argv))) { + outlet_anything(x->x_statout, gensym("port"), 1, ap); + } + } SETFLOAT(ap, x->x_port); outlet_anything(x->x_statout, gensym("port"), 1, ap); } +static void udpreceive_optionI(t_udpreceive*x, t_symbol*s, int argc, + t_atom*argv) +{ + int*reuse=NULL; + if(gensym("reuseport")==s) { + reuse=&x->x_reuseport; + } + if(gensym("reuseaddr")==s) { + reuse=&x->x_reuseaddr; + } + + if(!reuse) { + pd_error(x, "[%s]: unknown option '%s'", objName, s->s_name); + return; + } + if(argc) { + if(1==argc && A_FLOAT == argv->a_type) { + *reuse=atom_getint(argv); + return; + } else { + pd_error(x, "[%s] usage: %s []", objName, s->s_name); + return; + } + } else { + t_atom ap[1]; + SETFLOAT(ap, *reuse); + outlet_anything(x->x_statout, s, 1, ap); + } +} static void *udpreceive_new(t_floatarg fportno) { - t_udpreceive*x = (t_udpreceive *)pd_new(udpreceive_class); + t_udpreceive*x = (t_udpreceive *)pd_new(udpreceive_class); + + x->x_msgout = outlet_new(&x->x_obj, 0); + x->x_addrout = outlet_new(&x->x_obj, gensym("list")); + x->x_statout = outlet_new(&x->x_obj, 0); - x->x_msgout = outlet_new(&x->x_obj, 0); - x->x_addrout = outlet_new(&x->x_obj, gensym("list")); - x->x_statout = outlet_new(&x->x_obj, 0); + x->x_connectsocket = -1; + x->x_port = -1; + x->x_receiver = NULL; - x->x_connectsocket = -1; - x->x_port = -1; - x->x_receiver = NULL; + x->x_reuseaddr = 1; + x->x_reuseport = 0; - x->x_floatlist=iemnet__floatlist_create(1024); + x->x_floatlist=iemnet__floatlist_create(1024); - udpreceive_port(x, fportno); + udpreceive_setport(x, fportno); - return (x); + return (x); } static void udpreceive_free(t_udpreceive *x) { - iemnet__receiver_destroy(x->x_receiver); + iemnet__receiver_destroy(x->x_receiver, 0); x->x_connectsocket=0; outlet_free(x->x_msgout); outlet_free(x->x_addrout); outlet_free(x->x_statout); - if(x->x_floatlist)iemnet__floatlist_destroy(x->x_floatlist);x->x_floatlist=NULL; + if(x->x_floatlist) { + iemnet__floatlist_destroy(x->x_floatlist); + } + x->x_floatlist=NULL; } IEMNET_EXTERN void udpreceive_setup(void) { - if(!iemnet__register(objName))return; - udpreceive_class = class_new(gensym(objName), - (t_newmethod)udpreceive_new, (t_method)udpreceive_free, - sizeof(t_udpreceive), 0, A_DEFFLOAT, 0); - - class_addmethod(udpreceive_class, (t_method)udpreceive_port, - gensym("port"), A_DEFFLOAT, 0); + if(!iemnet__register(objName)) { + return; + } + udpreceive_class = class_new(gensym(objName), + (t_newmethod)udpreceive_new, (t_method)udpreceive_free, + sizeof(t_udpreceive), 0, A_DEFFLOAT, 0); + + class_addmethod(udpreceive_class, (t_method)udpreceive_port, + gensym("port"), A_GIMME, 0); + + /* options for opening new sockets */ + class_addmethod(udpreceive_class, (t_method)udpreceive_optionI, + gensym("reuseaddr"), A_GIMME, 0); + class_addmethod(udpreceive_class, (t_method)udpreceive_optionI, + gensym("reuseport"), A_GIMME, 0); DEBUGMETHOD(udpreceive_class); } diff --git a/udpsend.c b/udpsend.c index 7def6cf..620f7c0 100644 --- a/udpsend.c +++ b/udpsend.c @@ -1,5 +1,5 @@ /* udpsend.c - * copyright (c) 2010 IOhannes m zmölnig, IEM + * copyright (c) 2010 IOhannes m zmölnig, IEM * copyright (c) 2006-2010 Martin Peach * copyright (c) Miller Puckette */ @@ -18,9 +18,8 @@ /* GNU General Public License for more details. */ /* */ /* You should have received a copy of the GNU General Public License */ -/* along with this program; if not, write to the Free Software */ -/* Foundation, Inc., */ -/* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ +/* along with this program; if not, see */ +/* http://www.gnu.org/licenses/ */ /* */ #define DEBUGLEVEL 1 @@ -32,44 +31,42 @@ static const char objName[] = "udpsend"; static t_class *udpsend_class; -typedef struct _udpsend -{ +typedef struct _udpsend { t_object x_obj; t_iemnet_sender*x_sender; } t_udpsend; static void udpsend_connect(t_udpsend *x, t_symbol *hostname, - t_floatarg fportno) + t_floatarg fportno) { struct sockaddr_in server; int sockfd; int portno = fportno; int broadcast = 1;/* nonzero is true */ + memset(&server, 0, sizeof(server)); - if (x->x_sender) - { - error("[%s] already connected", objName); - return; - } + if (x->x_sender) { + error("[%s] already connected", objName); + return; + } /* create a socket */ sockfd = socket(AF_INET, SOCK_DGRAM, 0); DEBUG("send socket %d\n", sockfd); - if (sockfd < 0) - { - sys_sockerror("[udpsend] socket"); - return; - } + if (sockfd < 0) { + sys_sockerror("[udpsend] socket"); + return; + } /* Based on zmoelnig's patch 2221504: Enable sending of broadcast messages (if hostname is a broadcast address)*/ #ifdef SO_BROADCAST - if( 0 != setsockopt(sockfd, SOL_SOCKET, SO_BROADCAST, (const void *)&broadcast, sizeof(broadcast))) - { - error("[%s] couldn't switch to broadcast mode", objName); - } + if( 0 != setsockopt(sockfd, SOL_SOCKET, SO_BROADCAST, + (const void *)&broadcast, sizeof(broadcast))) { + error("[%s] couldn't switch to broadcast mode", objName); + } #endif /* SO_BROADCAST */ - + /* connect socket using hostname provided in command line */ server.sin_family = AF_INET; @@ -82,20 +79,19 @@ static void udpsend_connect(t_udpsend *x, t_symbol *hostname, } else { struct addrinfo * res; for (res = addr; res != NULL; res = res->ai_next) { - struct sockaddr_in *sa = (struct sockaddr_in *) res->ai_addr; - int len = res->ai_addrlen; - // memcpy((char *)&server.sin_addr, (char *)res->ai_addr, hp->h_length); - // LATER check how to do that... + struct sockaddr_in *sa = (struct sockaddr_in *) res->ai_addr; + int len = res->ai_addrlen; + // memcpy((char *)&server.sin_addr, (char *)res->ai_addr, hp->h_length); + // LATER check how to do that... } } freeaddrinfo(addr); #else struct hostent *hp = gethostbyname(hostname->s_name); - if (hp == 0) - { - error("[%s] bad host '%s'?", objName, hostname->s_name); - return; - } + if (hp == 0) { + error("[%s] bad host '%s'?", objName, hostname->s_name); + return; + } memcpy((char *)&server.sin_addr, (char *)hp->h_addr, hp->h_length); #endif } while(0); @@ -105,20 +101,19 @@ static void udpsend_connect(t_udpsend *x, t_symbol *hostname, DEBUG("connecting to port %d", portno); /* try to connect. */ - if (connect(sockfd, (struct sockaddr *) &server, sizeof (server)) < 0) - { - sys_sockerror("[udpsend] connecting stream socket"); - sys_closesocket(sockfd); - return; - } - x->x_sender=iemnet__sender_create(sockfd); + if (connect(sockfd, (struct sockaddr *) &server, sizeof (server)) < 0) { + sys_sockerror("[udpsend] connecting stream socket"); + iemnet__closesocket(sockfd); + return; + } + x->x_sender=iemnet__sender_create(sockfd, NULL, NULL, 0); outlet_float(x->x_obj.ob_outlet, 1); } static void udpsend_disconnect(t_udpsend *x) { if(x->x_sender) { - iemnet__sender_destroy(x->x_sender); + iemnet__sender_destroy(x->x_sender, 0); x->x_sender=NULL; outlet_float(x->x_obj.ob_outlet, 0); } @@ -150,18 +145,20 @@ static void *udpsend_new(void) IEMNET_EXTERN void udpsend_setup(void) { - if(!iemnet__register(objName))return; + if(!iemnet__register(objName)) { + return; + } udpsend_class = class_new(gensym(objName), (t_newmethod)udpsend_new, - (t_method)udpsend_free, - sizeof(t_udpsend), 0, 0); + (t_method)udpsend_free, + sizeof(t_udpsend), 0, 0); class_addmethod(udpsend_class, (t_method)udpsend_connect, - gensym("connect"), A_SYMBOL, A_FLOAT, 0); + gensym("connect"), A_SYMBOL, A_FLOAT, 0); class_addmethod(udpsend_class, (t_method)udpsend_disconnect, - gensym("disconnect"), 0); + gensym("disconnect"), 0); class_addmethod(udpsend_class, (t_method)udpsend_send, gensym("send"), - A_GIMME, 0); + A_GIMME, 0); class_addlist(udpsend_class, (t_method)udpsend_send); DEBUGMETHOD(udpsend_class); } diff --git a/udpserver.c b/udpserver.c index 93bf10b..df4b389 100644 --- a/udpserver.c +++ b/udpserver.c @@ -2,7 +2,7 @@ * * listens on a UDP-socket for bi-directional communication * - * copyright (c) 2010 IOhannes m zmölnig, IEM + * copyright (c) 2010 IOhannes m zmölnig, IEM * copyright (c) 2006-2010 Martin Peach * copyright (c) 2004 Olaf Matthes */ @@ -22,9 +22,8 @@ /* GNU General Public License for more details. */ /* */ /* You should have received a copy of the GNU General Public License */ -/* along with this program; if not, write to the Free Software */ -/* Foundation, Inc., */ -/* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ +/* along with this program; if not, see */ +/* http://www.gnu.org/licenses/ */ /* */ /* ---------------------------------------------------------------------------- */ @@ -32,6 +31,7 @@ #include "iemnet.h" #include #include +#include #define MAX_CONNECT 32 /* maximum number of connections */ @@ -40,8 +40,7 @@ static t_class *udpserver_class; static const char objName[] = "udpserver"; -typedef struct _udpserver_sender -{ +typedef struct _udpserver_sender { struct _udpserver *sr_owner; long sr_host; @@ -50,8 +49,7 @@ typedef struct _udpserver_sender t_iemnet_sender*sr_sender; } t_udpserver_sender; -typedef struct _udpserver -{ +typedef struct _udpserver { t_object x_obj; t_outlet *x_msgout; t_outlet *x_connectout; @@ -62,19 +60,24 @@ typedef struct _udpserver t_udpserver_sender *x_sr[MAX_CONNECT]; /* socket per connection */ t_int x_nconnections; - t_int x_connectsocket; /* socket waiting for new connections */ + t_int + x_connectsocket; /* socket waiting for new connections */ t_int x_port; - unsigned char x_accept; /* whether we accept new connections or not */ + unsigned char + x_accept; /* whether we accept new connections or not */ - int x_defaulttarget; /* the default connection to send to; 0=broadcast; >0 use this client; <0 exclude this client */ + int + x_defaulttarget; /* the default connection to send to; 0=broadcast; >0 use this client; <0 exclude this client */ t_iemnet_receiver *x_receiver; t_iemnet_floatlist *x_floatlist; } t_udpserver; -static t_udpserver_sender *udpserver_sender_new(t_udpserver *owner, unsigned long host, unsigned short port) +static t_udpserver_sender *udpserver_sender_new(t_udpserver *owner, + unsigned long host, unsigned short port) { - t_udpserver_sender *x = (t_udpserver_sender *)malloc(sizeof(t_udpserver_sender)); + t_udpserver_sender *x = (t_udpserver_sender *)malloc(sizeof( + t_udpserver_sender)); if(NULL==x) { error("%s_sender: unable to allocate %d bytes", objName, (int)sizeof(*x)); return NULL; @@ -87,7 +90,7 @@ static t_udpserver_sender *udpserver_sender_new(t_udpserver *owner, unsigned lo x->sr_host=host; //ntohl(addr->sin_addr.s_addr); x->sr_port=port; //ntohs(addr->sin_port); - x->sr_sender=iemnet__sender_create(sockfd); + x->sr_sender=iemnet__sender_create(sockfd, NULL, NULL, 0); } return (x); } @@ -95,39 +98,40 @@ static t_udpserver_sender *udpserver_sender_new(t_udpserver *owner, unsigned lo static void udpserver_sender_free(t_udpserver_sender *x) { DEBUG("freeing %x", x); - if (x != NULL) - { - int sockfd=x->sr_fd; - t_iemnet_sender*sender=x->sr_sender; - - x->sr_owner=NULL; - x->sr_sender=NULL; + if (x != NULL) { + int sockfd=x->sr_fd; + t_iemnet_sender*sender=x->sr_sender; - x->sr_fd=-1; + x->sr_owner=NULL; + x->sr_sender=NULL; - free(x); + x->sr_fd=-1; - if(sender) iemnet__sender_destroy(sender); + free(x); - sys_closesocket(sockfd); + if(sender) { + iemnet__sender_destroy(sender, 0); } + + iemnet__closesocket(sockfd); + } + /* coverity[pass_freed_arg]: this is merely for debugging printout */ DEBUG("freeed %x", x); } -static t_udpserver_sender* udpserver_sender_copy(t_udpserver_sender*x) { +static t_udpserver_sender* udpserver_sender_copy(t_udpserver_sender*x) +{ return udpserver_sender_new(x->sr_owner,x->sr_host, x->sr_port); } static int udpserver_socket2index(t_udpserver*x, int sockfd) { int i=0; - for(i = 0; i < x->x_nconnections; i++) /* check if connection exists */ - { - if(x->x_sr[i]->sr_fd == sockfd) - { - return i; - } + for(i = 0; i < x->x_nconnections; i++) { /* check if connection exists */ + if(x->x_sr[i]->sr_fd == sockfd) { + return i; } + } return -1; } @@ -137,35 +141,42 @@ static int udpserver_socket2index(t_udpserver*x, int sockfd) */ static int udpserver_fixindex(t_udpserver*x, int client) { - if(x->x_nconnections <= 0) - { - pd_error(x, "[%s]: no clients connected", objName); - return -1; - } + if(x->x_nconnections <= 0) { + pd_error(x, "[%s]: no clients connected", objName); + return -1; + } - if (!((client > 0) && (client <= x->x_nconnections))) - { - pd_error(x, "[%s] client %d out of range [1..%d]", objName, client, (int)(x->x_nconnections)); - return -1; - } + if (!((client > 0) && (client <= x->x_nconnections))) { + pd_error(x, "[%s] client %d out of range [1..%d]", objName, client, + (int)(x->x_nconnections)); + return -1; + } return (client-1); } /* returns 1 if addr1==addr2, 0 otherwise */ -static int equal_addr(unsigned long host1, unsigned short port1, unsigned long host2, unsigned short port2) { +static int equal_addr(unsigned long host1, unsigned short port1, + unsigned long host2, unsigned short port2) +{ return ( - ((port1 == port2) && - (host1 == host2)) - ); + ((port1 == port2) && + (host1 == host2)) + ); } -static int udpserver__find_sender(t_udpserver*x, unsigned long host, unsigned short port) { +static int udpserver__find_sender(t_udpserver*x, unsigned long host, + unsigned short port) +{ int i=0; for(i=0; ix_nconnections; i++) { - if(NULL==x->x_sr[i])return -1; - if(equal_addr(host, port, x->x_sr[i]->sr_host, x->x_sr[i]->sr_port))return i; + if(NULL==x->x_sr[i]) { + return -1; + } + if(equal_addr(host, port, x->x_sr[i]->sr_host, x->x_sr[i]->sr_port)) { + return i; + } } return -1; } @@ -175,11 +186,13 @@ static int udpserver__find_sender(t_udpserver*x, unsigned long host, unsigned s * if not, add it to the list of registered senders */ static t_udpserver_sender* udpserver_sender_add(t_udpserver*x, - unsigned long host, unsigned short port ) + unsigned long host, unsigned short port ) { int id=-1; - if(!x->x_accept)return NULL; + if(!x->x_accept) { + return NULL; + } id=udpserver__find_sender(x, host, port); DEBUG("%X:%d -> %d", host, port, id); @@ -217,9 +230,10 @@ static t_udpserver_sender* udpserver_sender_add(t_udpserver*x, return NULL; } -static void udpserver_sender_remove(t_udpserver*x, int id) { - if(id>=0 && idx_nconnections && x->x_sr[id]) { - int i; +static void udpserver_sender_remove(t_udpserver*x, unsigned int id) +{ + if(idx_nconnections && x->x_sr[id]) { + unsigned int i; t_udpserver_sender* sdr=x->x_sr[id]; udpserver_sender_free(sdr); @@ -235,15 +249,13 @@ static void udpserver_sender_remove(t_udpserver*x, int id) { } - - /* ---------------- udpserver info ---------------------------- */ static void udpserver_info_client(t_udpserver *x, int client) { // "client " // "bufsize " static t_atom output_atom[4]; - if(x&&x->x_sr&&x->x_sr[client]) { + if(x&&clientx_sr[client]) { int sockfd = x->x_sr[client]->sr_fd; unsigned short port = x->x_sr[client]->sr_port; long address = x->x_sr[client]->sr_host; @@ -256,8 +268,8 @@ static void udpserver_info_client(t_udpserver *x, int client) (unsigned char)((address & 0xFF000000)>>24), (unsigned char)((address & 0x0FF0000)>>16), (unsigned char)((address & 0x0FF00)>>8), - (unsigned char)((address & 0x0FF)) - ); + (unsigned char)((address & 0x0FF)) + ); hostname[MAXPDSTRING-1]=0; SETFLOAT (output_atom+0, client+1); @@ -275,7 +287,8 @@ static void udpserver_info_client(t_udpserver *x, int client) } -static void udpserver_info(t_udpserver *x) { +static void udpserver_info(t_udpserver *x) +{ static t_atom output_atom[4]; int sockfd=x->x_connectsocket; @@ -287,10 +300,11 @@ static void udpserver_info(t_udpserver *x) { error("[%s] no valid sock", objName); } - if(x->x_port<=0) { struct sockaddr_in server; socklen_t serversize=sizeof(server); + memset(&server, 0, sizeof(server)); + if(!getsockname(sockfd, (struct sockaddr *)&server, &serversize)) { x->x_port=ntohs(server.sin_port); port=x->x_port; @@ -311,16 +325,20 @@ static void udpserver_info_connection(t_udpserver *x, t_udpserver_sender*y) } /* ---------------- main udpserver (send) stuff --------------------- */ -static void udpserver_disconnect_socket(t_udpserver *x, t_floatarg fsocket); -static void udpserver_send_bytes(t_udpserver*x, int client, t_iemnet_chunk*chunk) +static void udpserver_disconnect_socket(t_udpserver *x, + t_floatarg fsocket); +static void udpserver_send_bytes(t_udpserver*x, unsigned int client, + t_iemnet_chunk*chunk) { DEBUG("send_bytes to %x -> %x[%d]", x, x->x_sr, client); - if(x->x_sr)DEBUG("client %X", x->x_sr[client]); - if(x && x->x_sr && x->x_sr[client]) { + if(clientx_sr[client]); + } + if(x && clientx_sr[client]) { t_atom output_atom[3]; int size=0; - t_iemnet_sender*sender=sender=x->x_sr[client]->sr_sender; + t_iemnet_sender*sender=x->x_sr[client]->sr_sender; int sockfd = x->x_sr[client]->sr_fd; chunk->addr=x->x_sr[client]->sr_host; @@ -333,7 +351,7 @@ static void udpserver_send_bytes(t_udpserver*x, int client, t_iemnet_chunk*chunk SETFLOAT(&output_atom[0], client+1); SETFLOAT(&output_atom[1], size); SETFLOAT(&output_atom[2], sockfd); - outlet_anything( x->x_statout, gensym("sent"), 3, output_atom); + outlet_anything( x->x_statout, gensym("sendbuffersize"), 3, output_atom); if(size<0) { // disconnected! @@ -345,21 +363,25 @@ static void udpserver_send_bytes(t_udpserver*x, int client, t_iemnet_chunk*chunk /* broadcasts a message to all connected clients but the given one */ -static void udpserver_send_butclient(t_udpserver *x, int but, int argc, t_atom *argv) +static void udpserver_send_butclient(t_udpserver *x, unsigned int but, + int argc, t_atom *argv) { - int client=0; + unsigned int client=0; t_iemnet_chunk*chunk=iemnet__chunk_create_list(argc, argv); /* enumerate through the clients and send each the message */ - for(client = 0; client < x->x_nconnections; client++) /* check if connection exists */ - { - /* socket exists for this client */ - if(client!=but)udpserver_send_bytes(x, client, chunk); + for(client = 0; client < x->x_nconnections; + client++) { /* check if connection exists */ + /* socket exists for this client */ + if(client!=but) { + udpserver_send_bytes(x, client, chunk); } + } iemnet__chunk_destroy(chunk); } /* sends a message to a given client */ -static void udpserver_send_toclient(t_udpserver *x, int client, int argc, t_atom *argv) +static void udpserver_send_toclient(t_udpserver *x, unsigned int client, + int argc, t_atom *argv) { t_iemnet_chunk*chunk=iemnet__chunk_create_list(argc, argv); udpserver_send_bytes(x, client, chunk); @@ -371,71 +393,91 @@ static void udpserver_send_toclient(t_udpserver *x, int client, int argc, t_atom /* send message to client using client number note that the client numbers might change in case a client disconnects! */ /* clients start at 1 but our index starts at 0 */ -static void udpserver_send_client(t_udpserver *x, t_symbol *s, int argc, t_atom *argv) +static void udpserver_send_client(t_udpserver *x, t_symbol *s, int argc, + t_atom *argv) { int client=0; - if (argc > 0) - { - client=udpserver_fixindex(x, atom_getint(argv)); - if(client<0)return; - if(argc==1) { - udpserver_info_client(x, client); - } else { - udpserver_send_toclient(x, client, argc-1, argv+1); - } + if (argc > 0) { + client=udpserver_fixindex(x, atom_getint(argv)); + if(client<0) { return; } - else - { - for(client=0; clientx_nconnections; client++) - udpserver_info_client(x, client); + if(argc==1) { + udpserver_info_client(x, client); + } else { + udpserver_send_toclient(x, client, argc-1, argv+1); + } + return; + } else { + for(client=0; clientx_nconnections; client++) { + udpserver_info_client(x, client); } + } } /* broadcasts a message to all connected clients */ -static void udpserver_broadcast(t_udpserver *x, t_symbol *s, int argc, t_atom *argv) +static void udpserver_broadcast(t_udpserver *x, t_symbol *s, int argc, + t_atom *argv) { - int client; + unsigned int client; t_iemnet_chunk*chunk=iemnet__chunk_create_list(argc, argv); DEBUG("broadcasting to %d clients", x->x_nconnections); /* enumerate through the clients and send each the message */ - for(client = 0; client < x->x_nconnections; client++) /* check if connection exists */ - { - /* socket exists for this client */ - udpserver_send_bytes(x, client, chunk); - } + for(client = 0; client < x->x_nconnections; + client++) { /* check if connection exists */ + /* socket exists for this client */ + udpserver_send_bytes(x, client, chunk); + } iemnet__chunk_destroy(chunk); } /* broadcasts a message to all connected clients */ -static void udpserver_broadcastbut(t_udpserver *x, t_symbol *s, int argc, t_atom *argv) +static void udpserver_broadcastbut(t_udpserver *x, t_symbol *s, int argc, + t_atom *argv) { - int but=-1; + int but; if(argc<2) { return; } - if((but=udpserver_fixindex(x, atom_getint(argv)))<0)return; + if((but=udpserver_fixindex(x, atom_getint(argv)))<0) { + return; + } udpserver_send_butclient(x, but, argc-1, argv+1); } -static void udpserver_defaultsend(t_udpserver *x, t_symbol *s, int argc, t_atom *argv) +static void udpserver_defaultsend(t_udpserver *x, t_symbol *s, int argc, + t_atom *argv) { int client=-1; int sockfd=x->x_defaulttarget; DEBUG("sending to sockfd: %d", sockfd); - if(0==sockfd) - udpserver_broadcast(x, s, argc, argv); - else if(sockfd>0) { + if(sockfd>0) { client=udpserver_socket2index(x, sockfd); - udpserver_send_toclient(x, client, argc, argv); + if(client<0) { + pd_error(x, "[%s] illegal socket %d, switching to broadcast mode", objName, + sockfd); + x->x_defaulttarget=0; + } else { + udpserver_send_toclient(x, client, argc, argv); + return; + } } else if(sockfd<0) { client=udpserver_socket2index(x, -sockfd); - udpserver_send_butclient(x, client, argc, argv); + if(client<0) { + pd_error(x, "[%s] illegal !socket %d, switching to broadcast mode", + objName, sockfd); + x->x_defaulttarget=0; + } else { + udpserver_send_butclient(x, client, argc, argv); + return; + } } + + udpserver_broadcast(x, s, argc, argv); } static void udpserver_defaulttarget(t_udpserver *x, t_floatarg f) { @@ -444,7 +486,8 @@ static void udpserver_defaulttarget(t_udpserver *x, t_floatarg f) int client=(rawclient<0)?(-rawclient):rawclient; if(client > x->x_nconnections) { - error("[%s] target %d out of range [0..%d]", objName, client, (int)(x->x_nconnections)); + error("[%s] target %d out of range [0..%d]", objName, client, + (int)(x->x_nconnections)); return; } @@ -453,7 +496,9 @@ static void udpserver_defaulttarget(t_udpserver *x, t_floatarg f) sockfd=x->x_sr[client-1]->sr_fd; } - if(rawclient<0)sockfd=-sockfd; + if(rawclient<0) { + sockfd=-sockfd; + } x->x_defaulttarget=sockfd; } @@ -466,55 +511,62 @@ static void udpserver_targetsocket(t_udpserver *x, t_floatarg f) /* send message to client using socket number */ -static void udpserver_send_socket(t_udpserver *x, t_symbol *s, int argc, t_atom *argv) +static void udpserver_send_socket(t_udpserver *x, t_symbol *s, int argc, + t_atom *argv) { int client = -1; t_iemnet_chunk*chunk=NULL; if(argc) { client = udpserver_socket2index(x, atom_getint(argv)); - if(client<0)return; + if(client<0) { + return; + } } else { pd_error(x, "%s_send: no socket specified", objName); return; } /* get socket number of connection (first element in list) */ - if(argc && argv->a_type == A_FLOAT) - { - int sockfd=atom_getint(argv); - client = udpserver_socket2index(x, sockfd); - if(client < 0) - { - error("[%s]: no connection on socket %d", objName, sockfd); - return; - } - } - else - { - error("[%s]: no socket specified", objName); + if(argc && argv->a_type == A_FLOAT) { + int sockfd=atom_getint(argv); + client = udpserver_socket2index(x, sockfd); + if(client < 0) { + error("[%s]: no connection on socket %d", objName, sockfd); return; } + } else { + error("[%s]: no socket specified", objName); + return; + } chunk=iemnet__chunk_create_list(argc-1, argv+1); udpserver_send_bytes(x, client, chunk); iemnet__chunk_destroy(chunk); } -static void udpserver_disconnect(t_udpserver *x, int client) +static void udpserver_disconnect(t_udpserver *x, unsigned int client) { - t_udpserver_sender*sdr; + t_udpserver_sender*sdr=NULL; int conns; DEBUG("disconnect %x %d", x, client); - if(client<0 || client >= x->x_nconnections)return; + if(client >= x->x_nconnections) { + return; + } - sdr=udpserver_sender_copy(x->x_sr[client]); + sdr = (t_udpserver_sender *)calloc(1, sizeof(t_udpserver_sender)); + if(sdr) { + sdr->sr_host=x->x_sr[client]->sr_host; + sdr->sr_port=x->x_sr[client]->sr_port; + } udpserver_sender_remove(x, client); conns=x->x_nconnections; - - udpserver_info_connection(x, sdr); + if(sdr) { + udpserver_info_connection(x, sdr); + free(sdr); + } outlet_float(x->x_connectout, conns); } @@ -524,7 +576,9 @@ static void udpserver_disconnect_client(t_udpserver *x, t_floatarg fclient) { int client = udpserver_fixindex(x, fclient); - if(client<0)return; + if(client<0) { + return; + } udpserver_disconnect(x, client); } @@ -533,8 +587,9 @@ static void udpserver_disconnect_client(t_udpserver *x, t_floatarg fclient) static void udpserver_disconnect_socket(t_udpserver *x, t_floatarg fsocket) { int id=udpserver_socket2index(x, (int)fsocket); - if(id>=0) + if(id>=0) { udpserver_disconnect_client(x, id+1); + } } @@ -542,22 +597,26 @@ static void udpserver_disconnect_socket(t_udpserver *x, t_floatarg fsocket) /* disconnect a client by socket */ static void udpserver_disconnect_all(t_udpserver *x) { - int id=x->x_nconnections; - while(--id>=0) { + unsigned int id; + for(id=0; idx_nconnections; id++) { udpserver_disconnect(x, id); } } /* whether we should accept new connections */ -static void udpserver_accept(t_udpserver *x, t_float f) { +static void udpserver_accept(t_udpserver *x, t_float f) +{ x->x_accept=(unsigned char)f; } /* ---------------- main udpserver (receive) stuff --------------------- */ -static void udpserver_receive_callback(void *y, t_iemnet_chunk*c) { +static void udpserver_receive_callback(void *y, t_iemnet_chunk*c) +{ t_udpserver*x=(t_udpserver*)y; - if(NULL==y)return; + if(NULL==y) { + return; + } if(c) { int conns = x->x_nconnections; @@ -567,13 +626,15 @@ static void udpserver_receive_callback(void *y, t_iemnet_chunk*c) { DEBUG("added new sender from %d", c->port); if(sdr) { udpserver_info_connection(x, sdr); - x->x_floatlist=iemnet__chunk2list(c, x->x_floatlist); // gets destroyed in the dtor + x->x_floatlist=iemnet__chunk2list(c, + x->x_floatlist); // gets destroyed in the dtor /* here we might have a reentrancy problem */ if(conns!=x->x_nconnections) { outlet_float(x->x_connectout, x->x_nconnections); } - outlet_list(x->x_msgout, gensym("list"), x->x_floatlist->argc, x->x_floatlist->argv); + outlet_list(x->x_msgout, gensym("list"), x->x_floatlist->argc, + x->x_floatlist->argv); } } else { // disconnection never happens with a connectionless protocol like UDP @@ -592,28 +653,28 @@ static void udpserver_connectpoll(t_udpserver *x) // TODO: provide a way to not accept connection // idea: add a message "accept $1" to turn off/on acceptance of new connections - fd = accept(x->x_connectsocket, (struct sockaddr*)&incomer_address, &sockaddrl); + fd = accept(x->x_connectsocket, (struct sockaddr*)&incomer_address, + &sockaddrl); bug("connectpoll"); - if (fd < 0) error("[%s] accept failed", objName); - else - { - unsigned long host = ntohl(incomer_address.sin_addr.s_addr); - unsigned short port = ntohs(incomer_address.sin_port); - - t_udpserver_sender *y = udpserver_sender_new(x, host, port); - if (!y) - { - sys_closesocket(fd); - return; - } - x->x_nconnections++; - i = x->x_nconnections - 1; - x->x_sr[i] = y; + if (fd < 0) { + error("[%s] accept failed", objName); + } else { + unsigned long host = ntohl(incomer_address.sin_addr.s_addr); + unsigned short port = ntohs(incomer_address.sin_port); - udpserver_info_connection(x, y); + t_udpserver_sender *y = udpserver_sender_new(x, host, port); + if (!y) { + iemnet__closesocket(fd); + return; } + x->x_nconnections++; + i = x->x_nconnections - 1; + x->x_sr[i] = y; + + udpserver_info_connection(x, y); + } outlet_float(x->x_connectout, x->x_nconnections); } @@ -625,6 +686,8 @@ static void udpserver_port(t_udpserver*x, t_floatarg fportno) struct sockaddr_in server; socklen_t serversize=sizeof(server); int sockfd = x->x_connectsocket; + memset(&server, 0, sizeof(server)); + SETFLOAT(ap, -1); if(x->x_port == portno) { return; @@ -633,14 +696,17 @@ static void udpserver_port(t_udpserver*x, t_floatarg fportno) /* cleanup any open ports */ if(sockfd>=0) { //sys_rmpollfn(sockfd); - sys_closesocket(sockfd); + iemnet__closesocket(sockfd); x->x_connectsocket=-1; x->x_port=-1; } sockfd = socket(AF_INET, SOCK_DGRAM, 0); - + if(sockfd<0) { + sys_sockerror("[udpserver]: cannot create UDP socket"); + return; + } server.sin_family = AF_INET; @@ -650,17 +716,17 @@ static void udpserver_port(t_udpserver*x, t_floatarg fportno) /* assign server port number */ server.sin_port = htons((u_short)portno); /* name the socket */ - if (bind(sockfd, (struct sockaddr *)&server, serversize) < 0) - { - sys_sockerror("udpserver: bind"); - sys_closesocket(sockfd); - outlet_anything(x->x_statout, gensym("port"), 1, ap); - return; - } + if (bind(sockfd, (struct sockaddr *)&server, serversize) < 0) { + sys_sockerror("udpserver: bind"); + iemnet__closesocket(sockfd); + outlet_anything(x->x_statout, gensym("port"), 1, ap); + return; + } x->x_receiver=iemnet__receiver_create(sockfd, - x, - udpserver_receive_callback); + x, + udpserver_receive_callback, + 0); x->x_connectsocket = sockfd; x->x_port = portno; @@ -684,19 +750,20 @@ static void *udpserver_new(t_floatarg fportno) x = (t_udpserver *)pd_new(udpserver_class); x->x_msgout = outlet_new(&x->x_obj, 0); /* 1st outlet for received data */ - x->x_connectout = outlet_new(&x->x_obj, gensym("float")); /* 2nd outlet for number of connected clients */ + x->x_connectout = outlet_new(&x->x_obj, + gensym("float")); /* 2nd outlet for number of connected clients */ x->x_sockout = outlet_new(&x->x_obj, gensym("float")); x->x_addrout = outlet_new(&x->x_obj, gensym("list" )); - x->x_statout = outlet_new(&x->x_obj, 0);/* 5th outlet for everything else */ + x->x_statout = outlet_new(&x->x_obj, + 0);/* 5th outlet for everything else */ x->x_connectsocket = -1; x->x_port = -1; x->x_nconnections = 0; - for(i = 0; i < MAX_CONNECT; i++) - { - x->x_sr[i] = NULL; - } + for(i = 0; i < MAX_CONNECT; i++) { + x->x_sr[i] = NULL; + } x->x_defaulttarget=0; x->x_floatlist=iemnet__floatlist_create(1024); @@ -712,45 +779,59 @@ static void udpserver_free(t_udpserver *x) { int i; - for(i = 0; i < MAX_CONNECT; i++) - { - if (NULL!=x->x_sr[i]) { - DEBUG("[%s] free %x", objName, x); - udpserver_sender_free(x->x_sr[i]); - x->x_sr[i]=NULL; - } - } - if (x->x_connectsocket >= 0) - { - //sys_rmpollfn(x->x_connectsocket); - sys_closesocket(x->x_connectsocket); + for(i = 0; i < MAX_CONNECT; i++) { + if (NULL!=x->x_sr[i]) { + DEBUG("[%s] free %x", objName, x); + udpserver_sender_free(x->x_sr[i]); + x->x_sr[i]=NULL; } - if(x->x_floatlist)iemnet__floatlist_destroy(x->x_floatlist);x->x_floatlist=NULL; + } + if (x->x_connectsocket >= 0) { + //sys_rmpollfn(x->x_connectsocket); + iemnet__closesocket(x->x_connectsocket); + } + if(x->x_floatlist) { + iemnet__floatlist_destroy(x->x_floatlist); + } + x->x_floatlist=NULL; } IEMNET_EXTERN void udpserver_setup(void) { - if(!iemnet__register(objName))return; + if(!iemnet__register(objName)) { + return; + } error("[%s] does not work yet", objName); - udpserver_class = class_new(gensym(objName),(t_newmethod)udpserver_new, (t_method)udpserver_free, + udpserver_class = class_new(gensym(objName),(t_newmethod)udpserver_new, + (t_method)udpserver_free, sizeof(t_udpserver), 0, A_DEFFLOAT, 0); - class_addmethod(udpserver_class, (t_method)udpserver_disconnect_client, gensym("disconnectclient"), A_DEFFLOAT, 0); - class_addmethod(udpserver_class, (t_method)udpserver_disconnect_socket, gensym("disconnectsocket"), A_DEFFLOAT, 0); - class_addmethod(udpserver_class, (t_method)udpserver_disconnect_all, gensym("disconnect"), 0); - - class_addmethod(udpserver_class, (t_method)udpserver_accept, gensym("accept"), A_FLOAT, 0); - - class_addmethod(udpserver_class, (t_method)udpserver_send_socket, gensym("send"), A_GIMME, 0); - class_addmethod(udpserver_class, (t_method)udpserver_send_client, gensym("client"), A_GIMME, 0); - - class_addmethod(udpserver_class, (t_method)udpserver_broadcast, gensym("broadcast"), A_GIMME, 0); - - class_addmethod(udpserver_class, (t_method)udpserver_defaulttarget, gensym("target"), A_DEFFLOAT, 0); - class_addmethod(udpserver_class, (t_method)udpserver_targetsocket, gensym("targetsocket"), A_DEFFLOAT, 0); + class_addmethod(udpserver_class, (t_method)udpserver_disconnect_client, + gensym("disconnectclient"), A_DEFFLOAT, 0); + class_addmethod(udpserver_class, (t_method)udpserver_disconnect_socket, + gensym("disconnectsocket"), A_DEFFLOAT, 0); + class_addmethod(udpserver_class, (t_method)udpserver_disconnect_all, + gensym("disconnect"), 0); + + class_addmethod(udpserver_class, (t_method)udpserver_accept, + gensym("accept"), A_FLOAT, 0); + + class_addmethod(udpserver_class, (t_method)udpserver_send_socket, + gensym("send"), A_GIMME, 0); + class_addmethod(udpserver_class, (t_method)udpserver_send_client, + gensym("client"), A_GIMME, 0); + + class_addmethod(udpserver_class, (t_method)udpserver_broadcast, + gensym("broadcast"), A_GIMME, 0); + + class_addmethod(udpserver_class, (t_method)udpserver_defaulttarget, + gensym("target"), A_DEFFLOAT, 0); + class_addmethod(udpserver_class, (t_method)udpserver_targetsocket, + gensym("targetsocket"), A_DEFFLOAT, 0); class_addlist (udpserver_class, (t_method)udpserver_defaultsend); - class_addmethod(udpserver_class, (t_method)udpserver_port, gensym("port"), A_DEFFLOAT, 0); + class_addmethod(udpserver_class, (t_method)udpserver_port, gensym("port"), + A_DEFFLOAT, 0); class_addbang (udpserver_class, (t_method)udpserver_info); DEBUGMETHOD(udpserver_class); -- cgit v1.2.1