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-help.pd | 71 +++++++++++++------------ udpclient.c | 156 +++++++++++++++++++++++------------------------------- 2 files changed, 103 insertions(+), 124 deletions(-) diff --git a/udpclient-help.pd b/udpclient-help.pd index 18e6d3c..6cf60a6 100644 --- a/udpclient-help.pd +++ b/udpclient-help.pd @@ -1,35 +1,35 @@ -#N canvas 0 34 988 533 12; -#X msg 96 97 disconnect; -#X floatatom 255 351 3 0 0 0 - - -; -#X floatatom 284 351 3 0 0 0 - - -; -#X floatatom 311 351 3 0 0 0 - - -; -#X floatatom 336 351 3 0 0 0 - - -; +#N canvas 4 49 1100 592 12; +#X msg 116 117 disconnect; +#X floatatom 255 351 3 0 0 0 - - -, f 3; +#X floatatom 284 351 3 0 0 0 - - -, f 3; +#X floatatom 311 351 3 0 0 0 - - -, f 3; +#X floatatom 336 351 3 0 0 0 - - -, f 3; #X text 219 351 from; #X obj 275 307 tgl 15 0 empty empty connected 18 7 0 8 -24198 -241291 --1 1 1; -#X text 187 21 connect with an IP address and port number; +-1 0 1; +#X text 197 21 connect with an IP address and port number; #X text 44 257 See also:; #X msg 21 22 connect 127.0.0.1 9997; -#X text 364 156 semicolon-terminated string for netserver or netreceive +#X text 414 176 semicolon-terminated string for netserver or netreceive ; -#X text 302 182 'send' prefix is optional; +#X text 322 202 'send' prefix is optional; #X obj 235 412 spigot; #X obj 274 389 tgl 15 0 empty empty enable_print 18 7 0 8 -24198 -241291 --1 1 1; -#X floatatom 772 190 9 0 0 0 - - -; +-1 0 1; +#X floatatom 872 280 9 0 0 0 - - -, f 9; #X text 40 399 2010/03/01 Martin Peach; -#X text 418 440 Attempting to print long messages can hang Pd!; -#X obj 772 166 route sent; -#X text 844 190 sent bytes; -#X floatatom 772 347 3 0 0 0 - - -; -#X floatatom 826 347 3 0 0 0 - - -; -#X floatatom 799 347 3 0 0 0 - - -; -#X obj 772 268 route address; -#X obj 772 296 unpack f f f f f; -#X floatatom 853 347 3 0 0 0 - - -; -#X floatatom 881 321 6 0 0 0 - - -; -#X text 879 347 ip; -#X text 927 320 port; +#X text 438 440 Attempting to print long messages can hang Pd!; +#X obj 872 256 route sent; +#X text 944 280 sent bytes; +#X floatatom 872 437 3 0 0 0 - - -, f 3; +#X floatatom 926 437 3 0 0 0 - - -, f 3; +#X floatatom 899 437 3 0 0 0 - - -, f 3; +#X obj 872 358 route address; +#X obj 872 386 unpack f f f f f; +#X floatatom 953 437 3 0 0 0 - - -, f 3; +#X floatatom 981 411 6 0 0 0 - - -, f 6; +#X text 979 437 ip; +#X text 1027 430 port; #X obj 520 344 spigot; #X obj 559 321 tgl 15 0 empty empty enable_print 18 7 0 8 -24198 -241291 -1 0 1; @@ -43,21 +43,25 @@ net objects. all information is available via outlet#4 as well!; #X obj 235 441 print udpclient:received; #X obj 520 373 print udpclient:status; #X obj 255 328 unpack f f f f f; -#X floatatom 364 351 6 0 0 0 - - -; -#X msg 128 129 send 47 116 101 115 116 32 104 101 108 108 111 10; -#X msg 156 157 send 51 49 32 97 98 99 59 10; -#X text 482 128 /test hello (OSC message); -#X text 308 255 udpclient can be used for a bi-directional connection +#X floatatom 364 351 6 0 0 0 - - -, f 6; +#X msg 148 149 send 47 116 101 115 116 32 104 101 108 108 111 10; +#X msg 176 177 send 51 49 32 97 98 99 59 10; +#X text 552 148 /test hello (OSC message); +#X text 312 255 udpclient can be used for a bi-directional connection ; -#X msg 183 184 97 98 99 100 10; +#X msg 203 204 97 98 99 100 10; #X msg 47 48 connect swisstime.ethz.ch 13; -#X text 527 14 udpclient can connect to a server and send and receive +#X text 547 14 udpclient can connect to a server and send and receive messages as lists of bytes. Any integer value between 0 and 255 can be transmitted or received.; #X obj 295 281 s \$0.udpclient.o4; #X obj 520 298 r \$0.udpclient.o4; -#X obj 772 142 r \$0.udpclient.o4; -#X obj 772 242 r \$0.udpclient.o4; +#X obj 872 232 r \$0.udpclient.o4; +#X obj 872 332 r \$0.udpclient.o4; +#X msg 74 75 connect 127.0.0.1 7999 7999; +#X text 303 67 optional second argument to set the local port (where +we receive the returning messages) \; default is to choose any available +port.; #X connect 0 0 35 0; #X connect 9 0 35 0; #X connect 12 0 36 0; @@ -87,3 +91,4 @@ be transmitted or received.; #X connect 48 0 28 0; #X connect 49 0 17 0; #X connect 50 0 22 0; +#X connect 51 0 35 0; 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