From dcbb66f06e30e0599519bb191e43b970fffdeab0 Mon Sep 17 00:00:00 2001 From: Martin Peach Date: Tue, 13 Jul 2010 17:59:12 +0000 Subject: Added support for multicasting. Added a status message to output total received bytes and multicast status on right outlet. Added received byte count on right outlet. Help patch updated. svn path=/trunk/externals/mrpeach/; revision=13708 --- net/udpreceive-help.pd | 63 ++++++++++++++++------- net/udpreceive.c | 135 +++++++++++++++++++++++++++++++++++++++++-------- 2 files changed, 159 insertions(+), 39 deletions(-) diff --git a/net/udpreceive-help.pd b/net/udpreceive-help.pd index a906e52..30de47c 100644 --- a/net/udpreceive-help.pd +++ b/net/udpreceive-help.pd @@ -1,19 +1,44 @@ -#N canvas 187 585 478 280 12; -#X floatatom 209 142 3 0 0 0 - - -; -#X floatatom 236 142 3 0 0 0 - - -; -#X floatatom 263 142 3 0 0 0 - - -; -#X floatatom 290 142 3 0 0 0 - - -; -#X text 166 141 from; -#X obj 107 186 print message; -#X obj 107 91 udpreceive 9997; -#X text 32 16 udpreceive receives bytes over a udp connection.; -#X floatatom 318 142 5 0 0 0 - - -; -#X obj 209 116 unpack 0 0 0 0 0; -#X text 265 235 Martin Peach 2008/11/05; -#X connect 6 0 5 0; -#X connect 6 1 9 0; -#X connect 9 0 0 0; -#X connect 9 1 1 0; -#X connect 9 2 2 0; -#X connect 9 3 3 0; -#X connect 9 4 8 0; +#N canvas 501 474 729 401 12; +#X floatatom 223 255 3 0 0 0 - - -; +#X floatatom 250 255 3 0 0 0 - - -; +#X floatatom 277 255 3 0 0 0 - - -; +#X floatatom 304 255 3 0 0 0 - - -; +#X text 180 254 from; +#X obj 7 143 print message; +#X obj 7 111 udpreceive 9997; +#X text 46 16 udpreceive receives bytes over a udp connection.; +#X floatatom 331 256 5 0 0 0 - - -; +#X obj 223 229 unpack 0 0 0 0 0; +#X msg 7 83 status; +#X obj 586 196 print xxxx; +#X floatatom 109 176 9 0 0 0 - - -; +#X floatatom 484 197 7 0 0 0 - - -; +#X text 302 311 Martin Peach 2010/07/13; +#X obj 281 169 route multicast multicast_loop multicast_ttl; +#X obj 281 202 tgl 15 0 empty empty empty 17 7 0 10 -262144 -1 -1 0 +1; +#X obj 382 202 tgl 15 0 empty empty empty 17 7 0 10 -262144 -1 -1 1 +1; +#X floatatom 166 202 9 0 0 0 - - -; +#X obj 109 143 route received total from; +#X text 84 40 creation arguments: port number to listen on (required) +; +#X text 223 59 IP address to accept from (optional); +#X text 221 80 specify a multicast address (from 224.0.0.0 to 239.255.255.255) +to use multicasting; +#X connect 6 0 5 0; +#X connect 6 1 19 0; +#X connect 9 0 0 0; +#X connect 9 1 1 0; +#X connect 9 2 2 0; +#X connect 9 3 3 0; +#X connect 9 4 8 0; +#X connect 10 0 6 0; +#X connect 15 0 16 0; +#X connect 15 1 17 0; +#X connect 15 2 13 0; +#X connect 15 3 11 0; +#X connect 19 0 12 0; +#X connect 19 1 18 0; +#X connect 19 2 9 0; +#X connect 19 3 15 0; diff --git a/net/udpreceive.c b/net/udpreceive.c index a9ac791..a6b5985 100644 --- a/net/udpreceive.c +++ b/net/udpreceive.c @@ -5,6 +5,7 @@ #include "m_pd.h" #include "s_stuff.h" +#include #ifdef _WIN32 #include @@ -27,18 +28,23 @@ static t_class *udpreceive_class; typedef struct _udpreceive { - t_object x_obj; - t_outlet *x_msgout; - t_outlet *x_addrout; - int x_connectsocket; - t_atom x_addrbytes[5]; - t_atom x_msgoutbuf[MAX_UDP_RECEIVE]; - char x_msginbuf[MAX_UDP_RECEIVE]; + t_object x_obj; + t_outlet *x_msgout; + t_outlet *x_addrout; + int x_connectsocket; + int x_multicast_joined; + unsigned int x_multicast_loop_state; + unsigned int x_multicast_ttl; + long x_total_received; + t_atom x_addrbytes[5]; + t_atom x_msgoutbuf[MAX_UDP_RECEIVE]; + char x_msginbuf[MAX_UDP_RECEIVE]; } t_udpreceive; void udpreceive_setup(void); static void udpreceive_free(t_udpreceive *x); -static void *udpreceive_new(t_floatarg fportno); +static void *udpreceive_new(t_symbol *s, int argc, t_atom *argv); +static void udpreceive_status(t_udpreceive *x); static void udpreceive_read(t_udpreceive *x, int sockfd); static void udpreceive_read(t_udpreceive *x, int sockfd) @@ -46,6 +52,7 @@ static void udpreceive_read(t_udpreceive *x, int sockfd) int i, read = 0; struct sockaddr_in from; socklen_t fromlen = sizeof(from); + t_atom output_atom; long addr; unsigned short port; @@ -63,7 +70,7 @@ static void udpreceive_read(t_udpreceive *x, int sockfd) x->x_addrbytes[2].a_w.w_float = (addr & 0x0FF00)>>8; x->x_addrbytes[3].a_w.w_float = (addr & 0x0FF); x->x_addrbytes[4].a_w.w_float = port; - outlet_list(x->x_addrout, &s_list, 5L, x->x_addrbytes); + outlet_anything(x->x_addrout, gensym("from"), 5L, x->x_addrbytes); if (read < 0) { @@ -78,19 +85,52 @@ static void udpreceive_read(t_udpreceive *x, int sockfd) /* convert the bytes in the buffer to floats in a list */ x->x_msgoutbuf[i].a_w.w_float = (float)(unsigned char)x->x_msginbuf[i]; } + x->x_total_received += read; + SETFLOAT(&output_atom, read); + outlet_anything(x->x_addrout, gensym("received"), 1, &output_atom); /* send the list out the outlet */ if (read > 1) outlet_list(x->x_msgout, &s_list, read, x->x_msgoutbuf); else outlet_float(x->x_msgout, x->x_msgoutbuf[0].a_w.w_float); } } -static void *udpreceive_new(t_floatarg fportno) +static void *udpreceive_new(t_symbol *s, int argc, t_atom *argv) { - t_udpreceive *x; - struct sockaddr_in server; - int sockfd, portno = fportno; - int intarg, i; + t_udpreceive *x; + struct sockaddr_in server; + struct hostent *hp; + struct ip_mreqn mreq; + int sockfd, portno = 0; + int multicast_joined = 0; + unsigned int multicast_loop_state; + unsigned int multicast_ttl; + unsigned int size; + int intarg, i; + char addr[256] = {'\0'}; +#ifdef DEBUG + post("udpreceive_new:argc is %d s is %s", argc, s->s_name); +#endif + for (i = 0; i < argc ;++i) + { + if (argv[i].a_type == A_FLOAT) + { +#ifdef DEBUG + post ("argv[%d] is a float: %f", i, argv[i].a_w.w_float); +#endif + portno = (int)argv[i].a_w.w_float; + } + else if (argv[i].a_type == A_SYMBOL) + { +#ifdef DEBUG + post ("argv[%d] is a symbol: %s", i, argv[i].a_w.w_symbol->s_name); +#endif + atom_string(&argv[i], addr, 256); + } + } +#ifdef DEBUG + post("Setting port %d, address %s", portno, addr); +#endif /* create a socket */ sockfd = socket(AF_INET, SOCK_DGRAM, 0); #ifdef DEBUG @@ -99,17 +139,48 @@ static void *udpreceive_new(t_floatarg fportno) if (sockfd < 0) { sys_sockerror("udpreceive: socket"); - return (0); + return 0; } server.sin_family = AF_INET; - server.sin_addr.s_addr = INADDR_ANY; - + if (addr[0] == 0) server.sin_addr.s_addr = INADDR_ANY; + else + { + hp = gethostbyname(addr); + if (hp == 0) + { + error("udpreceive: bad host?\n"); + return 0; + } + memcpy((char *)&server.sin_addr, (char *)hp->h_addr, hp->h_length); + } /* enable delivery of all multicast or broadcast (but not unicast) * UDP datagrams to all sockets bound to the same port */ intarg = 1; if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, (char *)&intarg, sizeof(intarg)) < 0) - post("udpreceive: setsockopt (SO_REUSEADDR) failed"); + error("udpreceive: setsockopt (SO_REUSEADDR) failed"); + + /* if a multicast address was specified, join the multicast group */ + /* hop count defaults to 1 so we won't leave the subnet*/ + if (0xE0000000 == (ntohl(server.sin_addr.s_addr) & 0xF0000000)) + { + mreq.imr_multiaddr.s_addr = server.sin_addr.s_addr; + mreq.imr_address.s_addr = INADDR_ANY; + mreq.imr_ifindex = 0; + if (setsockopt(sockfd, IPPROTO_IP, IP_ADD_MEMBERSHIP, + (char *)&mreq, sizeof(mreq)) < 0) + error("udpreceive: setsockopt (IP_ADD_MEMBERSHIP) failed"); + else + { + multicast_joined = 1; + post ("udpreceive: added to multicast group"); + multicast_loop_state = 0; + if (setsockopt(sockfd, IPPROTO_IP, IP_MULTICAST_LOOP, + &multicast_loop_state, sizeof(multicast_loop_state)) < 0) + error("udpreceive: setsockopt (IP_MULTICAST_LOOP) failed"); + } + } + /* assign server port number */ server.sin_port = htons((u_short)portno); @@ -123,7 +194,7 @@ static void *udpreceive_new(t_floatarg fportno) } x = (t_udpreceive *)pd_new(udpreceive_class); x->x_msgout = outlet_new(&x->x_obj, &s_anything); - x->x_addrout = outlet_new(&x->x_obj, &s_list); + x->x_addrout = outlet_new(&x->x_obj, &s_anything); x->x_connectsocket = sockfd; /* convert the bytes in the buffer to floats in a list */ @@ -137,10 +208,32 @@ static void *udpreceive_new(t_floatarg fportno) x->x_addrbytes[i].a_type = A_FLOAT; x->x_addrbytes[i].a_w.w_float = 0; } + getsockopt(sockfd, IPPROTO_IP, IP_MULTICAST_LOOP, &multicast_loop_state, &size); + //post("udpreceive: multicast loop state is %d", multicast_loop_state); + getsockopt(sockfd, IPPROTO_IP, IP_MULTICAST_TTL, &multicast_ttl, &size); + //post("udpreceive: multicast time to live is %d hop%s", multicast_ttl, (multicast_ttl == 1)?"":"s"); + x->x_multicast_joined = multicast_joined; + x->x_multicast_loop_state = multicast_loop_state; + x->x_multicast_ttl = multicast_ttl; + x->x_total_received = 0L; sys_addpollfn(x->x_connectsocket, (t_fdpollfn)udpreceive_read, x); return (x); } +static void udpreceive_status(t_udpreceive *x) +{ + t_atom output_atom; + + SETFLOAT(&output_atom, x->x_multicast_joined); + outlet_anything( x->x_addrout, gensym("multicast"), 1, &output_atom); + SETFLOAT(&output_atom, x->x_multicast_loop_state); + outlet_anything( x->x_addrout, gensym("multicast_loop"), 1, &output_atom); + SETFLOAT(&output_atom, x->x_multicast_ttl); + outlet_anything( x->x_addrout, gensym("multicast_ttl"), 1, &output_atom); + SETFLOAT(&output_atom, x->x_total_received); + outlet_anything( x->x_addrout, gensym("total"), 1, &output_atom); +} + static void udpreceive_free(t_udpreceive *x) { if (x->x_connectsocket >= 0) @@ -154,7 +247,9 @@ void udpreceive_setup(void) { udpreceive_class = class_new(gensym("udpreceive"), (t_newmethod)udpreceive_new, (t_method)udpreceive_free, - sizeof(t_udpreceive), CLASS_NOINLET, A_DEFFLOAT, 0); + sizeof(t_udpreceive), CLASS_DEFAULT, A_GIMME, 0); + class_addmethod(udpreceive_class, (t_method)udpreceive_status, + gensym("status"), 0); } /* end udpreceive.c */ -- cgit v1.2.1