From f628926f7ff2d494667bc14bc5d0cbcba02de5db Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?IOhannes=20m=20zm=C3=B6lnig?= Date: Tue, 1 Sep 2015 14:30:10 +0000 Subject: allow setting of local port svn path=/trunk/externals/iem/iemnet/; revision=17544 --- udpclient.c | 156 +++++++++++++++++++++++++----------------------------------- 1 file changed, 65 insertions(+), 91 deletions(-) (limited to 'udpclient.c') diff --git a/udpclient.c b/udpclient.c index b643fdc..d35dd3c 100644 --- a/udpclient.c +++ b/udpclient.c @@ -1,5 +1,5 @@ /* udpclient.c - * copyright (c) 2010 IOhannes m zmölnig, IEM + * copyright © 2010-2015 IOhannes m zmölnig, IEM */ /* */ @@ -32,10 +32,8 @@ static t_class *udpclient_class; static const char objName[] = "udpclient"; - typedef struct _udpclient { t_object x_obj; - t_clock *x_clock; t_outlet *x_msgout; t_outlet *x_addrout; t_outlet *x_connectout; @@ -44,26 +42,21 @@ typedef struct _udpclient { t_iemnet_sender*x_sender; t_iemnet_receiver*x_receiver; - int x_fd; // the socket char *x_hostname; // address we want to connect to as text int x_connectstate; // 0 = not connected, 1 = connected - int x_port; // port we're connected to - long x_addr; // address we're connected to as 32bit int - + u_short x_port; // port we're sending to + u_short x_sendport; // port we're sending from - /* multithread stuff */ - pthread_t x_threadid; /* id of child thread */ - pthread_attr_t x_threadattr; /* attributes of child thread */ + long x_addr; // address we're connected to as 32bit int t_iemnet_floatlist *x_floatlist; } t_udpclient; +/* forward declarations */ static void udpclient_receive_callback(void *x, t_iemnet_chunk*); - - /* connection handling */ static void *udpclient_doconnect(t_udpclient*x, int subthread) @@ -75,43 +68,55 @@ static void *udpclient_doconnect(t_udpclient*x, int subthread) memset(&server, 0, sizeof(server)); if (x->x_sender) { - error("[%s] already connected", objName); + iemnet_log(x, IEMNET_ERROR, "already connected"); return (x); } + /* connect socket using hostname provided in command line */ + hp = gethostbyname(x->x_hostname); + if (hp == 0) { + iemnet_log(x, IEMNET_ERROR, "bad host '%s'?", x->x_hostname); + return (x); + } + server.sin_family = AF_INET; + /* create a socket */ sockfd = socket(AF_INET, SOCK_DGRAM, 0); DEBUG("send socket %d\n", sockfd); if (sockfd < 0) { - sys_sockerror("udpclient: socket"); + iemnet_log(x, IEMNET_ERROR, "unable to create socket"); + sys_sockerror("socket"); return (x); } - /* Based on zmoelnig's patch 2221504: - Enable sending of broadcast messages (if hostname is a broadcast address)*/ + /* 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); + iemnet_log(x, IEMNET_ERROR, "unable to switch to broadcast mode"); + sys_sockerror("setsockopt"); } #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(x->x_sendport>0) { + server.sin_family = AF_INET; + server.sin_port = htons(x->x_sendport); + server.sin_addr.s_addr = INADDR_ANY; + if (bind(sockfd, (struct sockaddr *) &server, sizeof (server)) < 0) { + iemnet_log(x, IEMNET_ERROR, "unable to bind with sending port %d (continuing with random port)", x->x_sendport); + sys_sockerror("bind"); + } } - memcpy((char *)&server.sin_addr, (char *)hp->h_addr, hp->h_length); + /* try to connect. */ /* assign client port number */ - server.sin_port = htons((u_short)x->x_port); + memcpy((char *)&server.sin_addr, (char *)hp->h_addr, hp->h_length); + server.sin_port = htons(x->x_port); + DEBUG("connecting to %s:%d", x->x_hostname, x->x_port); - 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"); + iemnet_log(x, IEMNET_ERROR, "unable to connect to stream socket"); + sys_sockerror("connect"); iemnet__closesocket(sockfd); return (x); } @@ -123,48 +128,41 @@ static void *udpclient_doconnect(t_udpclient*x, int subthread) 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); + return (x); } - -static void udpclient_disconnect(t_udpclient *x) +static int udpclient_do_disconnect(t_udpclient *x) { - 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, 0); - } - x->x_receiver=NULL; - if(x->x_sender) { - iemnet__sender_destroy(x->x_sender, 0); - } - x->x_sender=NULL; + 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); + } + x->x_sender=NULL; - iemnet__closesocket(x->x_fd); - x->x_fd = -1; - x->x_connectstate = 0; - outlet_float(x->x_connectout, 0); + x->x_connectstate = 0; + if (x->x_fd < 0) { + return 0; + } + iemnet__closesocket(x->x_fd); + x->x_fd = -1; + return 1; +} +static void udpclient_disconnect(t_udpclient *x) { + if(!udpclient_do_disconnect(x)) { + iemnet_log(x, IEMNET_ERROR, "not connected"); } else { - pd_error(x, "[%s] not connected", objName); + outlet_float(x->x_connectout, 0); } } - static void udpclient_connect(t_udpclient *x, t_symbol *hostname, - t_floatarg fportno) + t_floatarg fportno, + t_floatarg fsndportno) { if(x->x_fd>=0) { udpclient_disconnect(x); @@ -173,20 +171,12 @@ static void udpclient_connect(t_udpclient *x, t_symbol *hostname, to the child thread that establishes the connection */ x->x_hostname = hostname->s_name; x->x_port = fportno; + x->x_sendport = (fsndportno>0)?fsndportno:0; x->x_connectstate = 0; -#if 0 - /* start child thread */ - 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) { @@ -212,7 +202,7 @@ static void udpclient_receive_callback(void*y, t_iemnet_chunk*c) 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 + x->x_floatlist); /* gets destroyed in the dtor */ outlet_list(x->x_msgout, gensym("list"),x->x_floatlist->argc, x->x_floatlist->argv); } else { @@ -229,12 +219,12 @@ static void udpclient_receive_callback(void*y, t_iemnet_chunk*c) 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_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 */ + gensym("float")); /* connection state */ x->x_statusout = outlet_new(&x->x_obj, - 0);/* last outlet for everything else */ + 0); /* last outlet for everything else */ x->x_fd = -1; x->x_addr = 0L; @@ -243,30 +233,14 @@ static void *udpclient_new(void) x->x_sender=NULL; x->x_receiver=NULL; - x->x_clock = clock_new(x, (t_method)udpclient_tick); - x->x_floatlist=iemnet__floatlist_create(1024); - /* prepare child thread */ - 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) { - verbose(1, "[%s] warning: could not prepare child thread", objName); - } - - return (x); } static void udpclient_free(t_udpclient *x) { - udpclient_disconnect(x); - if(x->x_clock) { - clock_free(x->x_clock); - } - x->x_clock=NULL; + udpclient_do_disconnect(x); if(x->x_floatlist) { iemnet__floatlist_destroy(x->x_floatlist); } @@ -283,7 +257,7 @@ IEMNET_EXTERN void udpclient_setup(void) sizeof(t_udpclient), 0, A_DEFFLOAT, 0); class_addmethod(udpclient_class, (t_method)udpclient_connect, gensym("connect") - , A_SYMBOL, A_FLOAT, 0); + , A_SYMBOL, A_FLOAT, A_DEFFLOAT, 0); class_addmethod(udpclient_class, (t_method)udpclient_disconnect, gensym("disconnect"), 0); class_addmethod(udpclient_class, (t_method)udpclient_send, gensym("send"), -- cgit v1.2.1