From 010723cb02b26c608537fc537d5e963ff6402f9e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?IOhannes=20m=20zm=C3=B6lnig?= Date: Tue, 23 Mar 2010 11:54:21 +0000 Subject: forked mrpeach's "net" svn path=/trunk/externals/iem/iemnet/; revision=13240 --- udpsend.c | 257 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 257 insertions(+) create mode 100644 udpsend.c (limited to 'udpsend.c') diff --git a/udpsend.c b/udpsend.c new file mode 100644 index 0000000..98db672 --- /dev/null +++ b/udpsend.c @@ -0,0 +1,257 @@ +/* udpsend.c 20060424. Martin Peach did it based on x_net.c. x_net.c header follows: */ +/* Copyright (c) 1997-1999 Miller Puckette. +* For information on usage and redistribution, and for a DISCLAIMER OF ALL +* WARRANTIES, see the file, "LICENSE.txt," in this distribution. */ + +/* network */ + +#include "m_pd.h" +#include "s_stuff.h" + +#include +#include +#ifdef _WIN32 +#include +#else +#include +#include +#include +#include +#include +#endif + +static t_class *udpsend_class; + +typedef struct _udpsend +{ + t_object x_obj; + int x_fd; +} t_udpsend; + +void udpsend_setup(void); +static void udpsend_free(t_udpsend *x); +static void udpsend_send(t_udpsend *x, t_symbol *s, int argc, t_atom *argv); +static void udpsend_disconnect(t_udpsend *x); +static void udpsend_connect(t_udpsend *x, t_symbol *hostname, t_floatarg fportno); +static void *udpsend_new(void); + +static void *udpsend_new(void) +{ + t_udpsend *x = (t_udpsend *)pd_new(udpsend_class); + outlet_new(&x->x_obj, &s_float); + x->x_fd = -1; + return (x); +} + +static void udpsend_connect(t_udpsend *x, t_symbol *hostname, + t_floatarg fportno) +{ + struct sockaddr_in server; + struct hostent *hp; + int sockfd; + int portno = fportno; + int broadcast = 1;/* nonzero is true */ + + if (x->x_fd >= 0) + { + error("udpsend: already connected"); + return; + } + + /* create a socket */ + sockfd = socket(AF_INET, SOCK_DGRAM, 0); +#ifdef DEBUG + fprintf(stderr, "udpsend_connect: send socket %d\n", sockfd); +#endif + 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))) + { + pd_error(x, "couldn't switch to broadcast mode"); + } +#endif /* SO_BROADCAST */ + + /* connect socket using hostname provided in command line */ + server.sin_family = AF_INET; + hp = gethostbyname(hostname->s_name); + if (hp == 0) + { + post("udpsend: bad host?\n"); + return; + } + memcpy((char *)&server.sin_addr, (char *)hp->h_addr, hp->h_length); + + /* assign client port number */ + server.sin_port = htons((u_short)portno); + + post("udpsend: 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_fd = sockfd; + outlet_float(x->x_obj.ob_outlet, 1); +} + +static void udpsend_disconnect(t_udpsend *x) +{ + if (x->x_fd >= 0) + { + sys_closesocket(x->x_fd); + x->x_fd = -1; + outlet_float(x->x_obj.ob_outlet, 0); + } +} + +static void udpsend_send(t_udpsend *x, t_symbol *s, int argc, t_atom *argv) +{ +#define BYTE_BUF_LEN 65536 // arbitrary maximum similar to max IP packet size + static char byte_buf[BYTE_BUF_LEN]; + int d; + int i, j; + unsigned char c; + float f, e; + char *bp; + int length, sent; + int result; + static double lastwarntime; + static double pleasewarn; + double timebefore; + double timeafter; + int late; + char fpath[FILENAME_MAX]; + FILE *fptr; + +#ifdef DEBUG + post("s: %s", s->s_name); + post("argc: %d", argc); +#endif + for (i = j = 0; i < argc; ++i) + { + if (argv[i].a_type == A_FLOAT) + { + f = argv[i].a_w.w_float; + d = (int)f; + e = f - d; + if (e != 0) + { + error("udpsend_send: item %d (%f) is not an integer", i, f); + return; + } + c = (unsigned char)d; + if (c != d) + { + error("udpsend_send: item %d (%f) is not between 0 and 255", i, f); + return; + } +#ifdef DEBUG + post("udpsend_send: argv[%d]: %d", i, c); +#endif + byte_buf[j++] = c; + } + else if (argv[i].a_type == A_SYMBOL) + { + + atom_string(&argv[i], fpath, FILENAME_MAX); +#ifdef DEBUG + post ("udpsend fname: %s", fpath); +#endif + fptr = fopen(fpath, "rb"); + if (fptr == NULL) + { + post("udpsend: unable to open \"%s\"", fpath); + return; + } + rewind(fptr); +#ifdef DEBUG + post("udpsend: d is %d", d); +#endif + while ((d = fgetc(fptr)) != EOF) + { + byte_buf[j++] = (char)(d & 0x0FF); +#ifdef DEBUG + post("udpsend: byte_buf[%d] = %d", j-1, byte_buf[j-1]); +#endif + if (j >= BYTE_BUF_LEN) + { + post ("udpsend: file too long, truncating at %lu", BYTE_BUF_LEN); + break; + } + } + fclose(fptr); + fptr = NULL; + post("udpsend: read \"%s\" length %d byte%s", fpath, j, ((d==1)?"":"s")); + } + else + { + error("udpsend_send: item %d is not a float or a file name", i); + return; + } + } + + length = j; + if ((x->x_fd >= 0) && (length > 0)) + { + for (bp = byte_buf, sent = 0; sent < length;) + { + timebefore = sys_getrealtime(); + result = send(x->x_fd, byte_buf, length-sent, 0); + timeafter = sys_getrealtime(); + late = (timeafter - timebefore > 0.005); + if (late || pleasewarn) + { + if (timeafter > lastwarntime + 2) + { + post("udpsend blocked %d msec", + (int)(1000 * ((timeafter - timebefore) + pleasewarn))); + pleasewarn = 0; + lastwarntime = timeafter; + } + else if (late) pleasewarn += timeafter - timebefore; + } + if (result <= 0) + { + sys_sockerror("udpsend"); + udpsend_disconnect(x); + break; + } + else + { + sent += result; + bp += result; + } + } + } + else error("udpsend: not connected"); +} + +static void udpsend_free(t_udpsend *x) +{ + udpsend_disconnect(x); +} + +void udpsend_setup(void) +{ + udpsend_class = class_new(gensym("udpsend"), (t_newmethod)udpsend_new, + (t_method)udpsend_free, + sizeof(t_udpsend), 0, 0); + class_addmethod(udpsend_class, (t_method)udpsend_connect, + gensym("connect"), A_SYMBOL, A_FLOAT, 0); + class_addmethod(udpsend_class, (t_method)udpsend_disconnect, + gensym("disconnect"), 0); + class_addmethod(udpsend_class, (t_method)udpsend_send, gensym("send"), + A_GIMME, 0); + class_addlist(udpsend_class, (t_method)udpsend_send); +} + +/* end udpsend.c*/ + -- cgit v1.2.1