Update of /cvsroot/pure-data/externals/mrpeach/net In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv1850/mrpeach/net
Added Files: tcpclient-help.pd tcpreceive-help.pd tcpsend-help.pd tcpserver-help.pd udpreceive-help.pd udpsend-help.pd x_net_tcp_client.c x_net_tcp_server.c x_net_tcpclient.c x_net_tcpreceive.c x_net_tcpsend.c x_net_tcpserver.c x_net_udpreceive.c x_net_udpsend.c Log Message: Added the net, osc and sqosc~ directories
--- NEW FILE: x_net_udpsend.c --- /* x_net_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 <stdio.h> #include <string.h> #ifdef MSW #include <winsock2.h> #else #include <sys/socket.h> #include <netinet/in.h> #include <netinet/tcp.h> #include <netdb.h> #endif
static t_class *udpsend_class;
typedef struct _udpsend { t_object x_obj; int x_fd; } t_udpsend;
#ifdef MSW __declspec(dllexport) #endif 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;
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; } /* 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) { static char byte_buf[65536];// arbitrary maximum similar to max IP packet size int i, d; char c; float f, e; char *bp; int length, sent; int result; static double lastwarntime; static double pleasewarn; double timebefore; double timeafter; int late;
#ifdef DEBUG post("s: %s", s->s_name); post("argc: %d", argc); #endif for (i = 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[i] = c; } else { error("udpsend_send: item %d is not a float", i); return; } }
length = i; 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); }
#ifdef MSW __declspec(dllexport) #endif 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); }
/* end x_net_udpsend.c*/
--- NEW FILE: x_net_tcpclient.c --- /* x_net_tcp_client.c Martin Peach 20060508, working version 20060512 */ /* linux version 20060515 */ /* x_net_tcp_client.c is based on netclient: */ /* -------------------------- netclient ------------------------------------- */ /* */ /* Extended 'netsend', connects to 'netserver'. */ /* Uses child thread to connect to server. Thus needs pd0.35-test17 or later. */ /* Written by Olaf Matthes (olaf.matthes@gmx.de) */ /* Get source at http://www.akustische-kunst.org/puredata/maxlib/ */ /* */ /* 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /* */ /* Based on PureData by Miller Puckette and others. */ /* */ /* ---------------------------------------------------------------------------- */ //define DEBUG
#include "m_pd.h" #include "s_stuff.h"
#include <stdio.h> #include <sys/types.h> #include <string.h> #include <pthread.h> #if defined(UNIX) || defined(unix) #include <sys/socket.h> #include <sys/errno.h> #include <netinet/in.h> #include <netdb.h> #include <stdio.h> #include <unistd.h> #define SOCKET_ERROR -1 #else #include <winsock2.h> #endif
#define DEFPOLLTIME 20 /* check for input every 20 ms */
static t_class *tcpclient_class; static char objName[] = "tcpclient"; #define MAX_UDP_RECEIVE 65536L // longer than data in maximum UDP packet
typedef struct _tcpclient { t_object x_obj; t_clock *x_clock; t_clock *x_poll; t_outlet *x_msgout; t_outlet *x_addrout; t_outlet *x_outconnect; int x_dump; // 1 = hexdump received bytes 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 t_atom x_addrbytes[4]; // address we're connected to as 4 bytes t_atom x_msgoutbuf[MAX_UDP_RECEIVE]; // received data as float atoms unsigned char x_msginbuf[MAX_UDP_RECEIVE]; // received data as bytes /* multithread stuff */ pthread_t x_threadid; /* id of child thread */ pthread_attr_t x_threadattr; /* attributes of child thread */ } t_tcpclient;
static void tcpclient_dump(t_tcpclient *x, t_float dump); static void tcp_client_hexdump(unsigned char *buf, long len); static void tcpclient_tick(t_tcpclient *x); static void *tcpclient_child_connect(void *w); static void tcpclient_connect(t_tcpclient *x, t_symbol *hostname, t_floatarg fportno); static void tcpclient_disconnect(t_tcpclient *x); static void tcpclient_send(t_tcpclient *x, t_symbol *s, int argc, t_atom *argv); static void tcpclient_rcv(t_tcpclient *x); static void tcpclient_poll(t_tcpclient *x); static void *tcpclient_new(t_floatarg udpflag); static void tcpclient_free(t_tcpclient *x); #ifdef MSW __declspec(dllexport) #endif void tcpclient_setup(void);
static void tcpclient_dump(t_tcpclient *x, t_float dump) { x->x_dump = (dump == 0)?0:1; }
static void tcp_client_hexdump(unsigned char *buf, long len) { #define BYTES_PER_LINE 16 char hexStr[(3*BYTES_PER_LINE)+1]; char ascStr[BYTES_PER_LINE+1]; long i, j, k = 0L; #ifdef DEBUG post("tcp_client_hexdump %d", len); #endif while (k < len) { for (i = j = 0; i < BYTES_PER_LINE; ++i, ++k, j+=3) { if (k < len) { #ifdef MSW sprintf_s(&hexStr[j], 4, "%02X ", buf[k]); sprintf_s(&ascStr[i], 2, "%c", ((buf[k] >= 32) && (buf[k] <= 126))? buf[k]: '.'); #else snprintf(&hexStr[j], 4, "%02X ", buf[k]); snprintf(&ascStr[i], 2, "%c", ((buf[k] >= 32) && (buf[k] <= 126))? buf[k]: '.'); #endif } else { // the last line #ifdef MSW sprintf_s(&hexStr[j], 4, " "); sprintf_s(&ascStr[i], 2, " "); #else snprintf(&hexStr[j], 4, " "); snprintf(&ascStr[i], 2, " "); #endif } } post ("%s%s", hexStr, ascStr); } }
static void tcpclient_tick(t_tcpclient *x) { outlet_float(x->x_outconnect, 1); }
static void *tcpclient_child_connect(void *w) { t_tcpclient *x = (t_tcpclient*) w; struct sockaddr_in server; struct hostent *hp; int sockfd;
if (x->x_fd >= 0) { error("%s_connect: already connected", objName); return (x); }
/* create a socket */ sockfd = socket(AF_INET, SOCK_STREAM, 0); #ifdef DEBUG post("%s: send socket %d\n", objName, sockfd); #endif if (sockfd < 0) { sys_sockerror("tcpclient: socket"); return (x); } /* connect socket using hostname provided in command line */ server.sin_family = AF_INET; hp = gethostbyname(x->x_hostname); if (hp == 0) { sys_sockerror("tcpclient: bad host?\n"); return (x); } memcpy((char *)&server.sin_addr, (char *)hp->h_addr, hp->h_length);
/* assign client port number */ server.sin_port = htons((u_short)x->x_port);
post("%s: connecting socket %d to port %d", objName, sockfd, x->x_port); /* try to connect */ if (connect(sockfd, (struct sockaddr *) &server, sizeof (server)) < 0) { sys_sockerror("tcpclient: connecting stream socket"); sys_closesocket(sockfd); return (x); } x->x_fd = sockfd; x->x_addr = ntohl(*(long *)hp->h_addr); /* outlet_float is not threadsafe ! */ // outlet_float(x->x_obj.ob_outlet, 1); x->x_connectstate = 1; /* use callback instead to set outlet */ clock_delay(x->x_clock, 0); return (x); }
static void tcpclient_connect(t_tcpclient *x, t_symbol *hostname, t_floatarg fportno) { /* 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) post("%s: could not create new thread", objName); }
static void tcpclient_disconnect(t_tcpclient *x) { if (x->x_fd >= 0) { sys_closesocket(x->x_fd); x->x_fd = -1; x->x_connectstate = 0; outlet_float(x->x_outconnect, 0); post("%s: disconnected", objName); } else post("%s: not connected", objName); }
static void tcpclient_send(t_tcpclient *x, t_symbol *s, int argc, t_atom *argv) { static char byte_buf[65536];// arbitrary maximum similar to max IP packet size int i, d; 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;
#ifdef DEBUG post("s: %s", s->s_name); post("argc: %d", argc); #endif
for (i = 0; i < argc; ++i) { if (argv[i].a_type == A_FLOAT) { f = argv[i].a_w.w_float; d = (int)f; e = f - d; #ifdef DEBUG post("%s: argv[%d]: float:%f int:%d delta:%f", objName, i, f, d, e); #endif if (e != 0) { error("%s_send: item %d (%f) is not an integer", objName, i, f); return; } if ((d < 0) || (d > 255)) { error("%s: item %d (%f) is not between 0 and 255", objName, i, f); return; } c = (unsigned char)d; #ifdef DEBUG post("%s_send: argv[%d]: %d", objName, i, c); #endif byte_buf[i] = c; } else { error("%s_send: item %d is not a float", objName, i); return; } }
length = i; 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("%s_send blocked %d msec", objName, (int)(1000 * ((timeafter - timebefore) + pleasewarn))); pleasewarn = 0; lastwarntime = timeafter; } else if (late) pleasewarn += timeafter - timebefore; } if (result <= 0) { sys_sockerror("tcpclient_send"); tcpclient_disconnect(x); break; } else { sent += result; bp += result; } } } else error("%s: not connected", objName); }
static void tcpclient_rcv(t_tcpclient *x) { int sockfd = x->x_fd; int ret; int i; fd_set readset; fd_set exceptset; struct timeval ztout;
if(x->x_connectstate) { /* check if we can read/write from/to the socket */ FD_ZERO(&readset); FD_ZERO(&exceptset); FD_SET(x->x_fd, &readset ); FD_SET(x->x_fd, &exceptset );
ztout.tv_sec = 0; ztout.tv_usec = 0;
ret = select(sockfd+1, &readset, NULL, &exceptset, &ztout); if(ret < 0) { error("%s: unable to read from socket", objName); sys_closesocket(sockfd); return; } if(FD_ISSET(sockfd, &readset) || FD_ISSET(sockfd, &exceptset)) { /* read from server */ ret = recv(sockfd, x->x_msginbuf, MAX_UDP_RECEIVE, 0); if(ret > 0) { #ifdef DEBUG x->x_msginbuf[ret] = 0; post("%s: received %d bytes ", objName, ret); #endif if (x->x_dump)tcp_client_hexdump(x->x_msginbuf, ret); for (i = 0; i < ret; ++i) { /* convert the bytes in the buffer to floats in a list */ x->x_msgoutbuf[i].a_w.w_float = (float)x->x_msginbuf[i]; } /* find sender's ip address and output it */ x->x_addrbytes[0].a_w.w_float = (x->x_addr & 0xFF000000)>>24; x->x_addrbytes[1].a_w.w_float = (x->x_addr & 0x0FF0000)>>16; x->x_addrbytes[2].a_w.w_float = (x->x_addr & 0x0FF00)>>8; x->x_addrbytes[3].a_w.w_float = (x->x_addr & 0x0FF); outlet_list(x->x_addrout, &s_list, 4L, x->x_addrbytes); /* send the list out the outlet */ if (ret > 1) outlet_list(x->x_msgout, &s_list, ret, x->x_msgoutbuf); else outlet_float(x->x_msgout, x->x_msgoutbuf[0].a_w.w_float); } else { if (ret < 0) { sys_sockerror("tcpclient: recv"); tcpclient_disconnect(x); } else { post("%s: connection closed for socket %d\n", objName, sockfd); tcpclient_disconnect(x); } } } } else post("%s: not connected", objName); }
static void tcpclient_poll(t_tcpclient *x) { if(x->x_connectstate) tcpclient_rcv(x); /* try to read in case we're connected */ clock_delay(x->x_poll, DEFPOLLTIME); /* see you later */ }
static void *tcpclient_new(t_floatarg udpflag) { int i;
t_tcpclient *x = (t_tcpclient *)pd_new(tcpclient_class); x->x_msgout = outlet_new(&x->x_obj, &s_anything); /* received data */ x->x_addrout = outlet_new(&x->x_obj, &s_list); x->x_outconnect = outlet_new(&x->x_obj, &s_float); /* connection state */ x->x_clock = clock_new(x, (t_method)tcpclient_tick); x->x_poll = clock_new(x, (t_method)tcpclient_poll); x->x_fd = -1; /* convert the bytes in the buffer to floats in a list */ for (i = 0; i < MAX_UDP_RECEIVE; ++i) { x->x_msgoutbuf[i].a_type = A_FLOAT; x->x_msgoutbuf[i].a_w.w_float = 0; } for (i = 0; i < 4; ++i) { x->x_addrbytes[i].a_type = A_FLOAT; x->x_addrbytes[i].a_w.w_float = 0; } x->x_addr = 0L; /* prepare child thread */ if(pthread_attr_init(&x->x_threadattr) < 0) post("%s: warning: could not prepare child thread", objName); if(pthread_attr_setdetachstate(&x->x_threadattr, PTHREAD_CREATE_DETACHED) < 0) post("%s: warning: could not prepare child thread", objName); clock_delay(x->x_poll, 0); /* start polling the input */ return (x); }
static void tcpclient_free(t_tcpclient *x) { tcpclient_disconnect(x); clock_free(x->x_poll); clock_free(x->x_clock); }
#ifdef MSW __declspec(dllexport) #endif void tcpclient_setup(void) { 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") , A_SYMBOL, A_FLOAT, 0); class_addmethod(tcpclient_class, (t_method)tcpclient_disconnect, gensym("disconnect"), 0); class_addmethod(tcpclient_class, (t_method)tcpclient_send, gensym("send"), A_GIMME, 0); class_addmethod(tcpclient_class, (t_method)tcpclient_rcv, gensym("receive"), 0); class_addmethod(tcpclient_class, (t_method)tcpclient_rcv, gensym("rcv"), 0); class_addmethod(tcpclient_class, (t_method)tcpclient_dump, gensym("dump"), A_FLOAT, 0); }
/* end of x_net_tcp.c */
--- NEW FILE: x_net_udpreceive.c --- /* x_net_udpreceive.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. */
#include "m_pd.h" #include "s_stuff.h"
#ifdef MSW #include <winsock2.h> #include <ws2tcpip.h> #else #include <sys/socket.h> #include <netinet/in.h> #include <netinet/tcp.h> #include <netdb.h> #include <stdio.h> #endif
/* ----------------------------- udpreceive ------------------------- */
static t_class *udpreceive_class;
#define MAX_UDP_RECEIVE 65536L // longer than data in maximum UDP packet
typedef struct _udpreceive { t_object x_obj; t_outlet *x_msgout; t_outlet *x_addrout; int x_connectsocket; t_atom x_addrbytes[4]; t_atom x_msgoutbuf[MAX_UDP_RECEIVE]; char x_msginbuf[MAX_UDP_RECEIVE]; } t_udpreceive;
#ifdef MSW __declspec(dllexport) #endif void udpreceive_setup(void); static void udpreceive_free(t_udpreceive *x); static void *udpreceive_new(t_floatarg fportno); static void udpreceive_read(t_udpreceive *x, int sockfd);
static void udpreceive_read(t_udpreceive *x, int sockfd) { int i, read = 0; struct sockaddr_in from; socklen_t fromlen = sizeof(from); long addr;
read = recvfrom(sockfd, x->x_msginbuf, MAX_UDP_RECEIVE, 0, (struct sockaddr *)&from, &fromlen); #ifdef DEBUG post("udpreceive_read: read %lu x->x_connectsocket = %d", read, x->x_connectsocket); #endif /* get the sender's ip */ addr = ntohl(from.sin_addr.s_addr); x->x_addrbytes[0].a_w.w_float = (addr & 0xFF000000)>>24; x->x_addrbytes[1].a_w.w_float = (addr & 0x0FF0000)>>16; x->x_addrbytes[2].a_w.w_float = (addr & 0x0FF00)>>8; x->x_addrbytes[3].a_w.w_float = (addr & 0x0FF); outlet_list(x->x_addrout, &s_list, 4L, x->x_addrbytes);
if (read < 0) { sys_sockerror("udpreceive_read"); sys_closesocket(x->x_connectsocket); return; } if (read > 0) { for (i = 0; i < read; ++i) { /* convert the bytes in the buffer to floats in a list */ x->x_msgoutbuf[i].a_w.w_float = (float)x->x_msginbuf[i]; } /* 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) { t_udpreceive *x; struct sockaddr_in server; int sockfd, portno = fportno; int intarg, i;
/* create a socket */ sockfd = socket(AF_INET, SOCK_DGRAM, 0); #ifdef DEBUG post("udpreceive_new: socket %d port %d", sockfd, portno); #endif if (sockfd < 0) { sys_sockerror("udpreceive: socket"); return (0); } server.sin_family = AF_INET; server.sin_addr.s_addr = INADDR_ANY;
/* ask OS to allow another Pd to repoen this port after we close it. */ intarg = 1; if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, (char *)&intarg, sizeof(intarg)) < 0) post("udpreceive: setsockopt (SO_REUSEADDR) failed");
/* assign server port number */ server.sin_port = htons((u_short)portno);
/* name the socket */ if (bind(sockfd, (struct sockaddr *)&server, sizeof(server)) < 0) { sys_sockerror("udpreceive: bind"); sys_closesocket(sockfd); return (0); } 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_connectsocket = sockfd;
/* convert the bytes in the buffer to floats in a list */ for (i = 0; i < MAX_UDP_RECEIVE; ++i) { x->x_msgoutbuf[i].a_type = A_FLOAT; x->x_msgoutbuf[i].a_w.w_float = 0; } for (i = 0; i < 4; ++i) { x->x_addrbytes[i].a_type = A_FLOAT; x->x_addrbytes[i].a_w.w_float = 0; } sys_addpollfn(x->x_connectsocket, (t_fdpollfn)udpreceive_read, x); return (x); }
static void udpreceive_free(t_udpreceive *x) { if (x->x_connectsocket >= 0) { sys_rmpollfn(x->x_connectsocket); sys_closesocket(x->x_connectsocket); } }
#ifdef MSW __declspec(dllexport) #endif 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); }
/* end x_net_udpreceive.c */
--- NEW FILE: udpsend-help.pd --- #N canvas 58 443 538 316 12; #X msg 177 158 disconnect; #X msg 171 96 connect 127.0.0.1 9997; #X obj 171 207 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0 1; #X text 375 97 <--first; #X msg 67 129 send 0 1 2 3; #X text 10 38 udpsend sends bytes over a udp connection.; #X text 10 61 Used in conjunction with packOSC will send OSC over udp ; #X obj 171 184 udpsend; #X text 236 259 Martin Peach 2006/04/21; #X connect 0 0 7 0; #X connect 1 0 7 0; #X connect 4 0 7 0; #X connect 7 0 2 0;
--- NEW FILE: tcpclient-help.pd --- #N canvas 89 21 1092 501 12; #X msg 61 93 disconnect; #X obj 78 222 unpack 0 0 0 0; #X floatatom 78 245 3 0 0 0 - - -; #X floatatom 113 245 3 0 0 0 - - -; #X floatatom 149 245 3 0 0 0 - - -; #X floatatom 185 245 3 0 0 0 - - -; #X text 35 244 from; #X msg 45 30 connect 132.205.142.12 80; #X obj 45 170 tcpclient; #X msg 55 53 send 71 69 84 32 104 116 116 112 58 47 47 47 105 110 100 101 120 46 104 116 109 108 13 10; #X text 566 53 GET http:///index.html CRLF; #X obj 112 196 tgl 15 0 empty empty connected 18 7 0 8 -24198 -241291 -1 0 1; #X msg 160 115 dump $1; #X obj 160 96 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0 1 ; #X msg 231 139 receive; #X msg 295 139 recv; #X text 214 -21 connect with an IP address and port number; #X msg 23 5 connect www.concordia.ca 80; #X text 231 114 print received messages to main window in hexdump format ; #X text 131 171 tcpclient opens a tcp socket to send and receive bytes on; #X text 276 263 See also:; #X obj 354 263 netclient; #X msg 10 -20 connect 127.0.0.1 9997; #X obj 354 286 tcpreceive; #X text 574 285 can receive messages from tcpclient; #X text 442 263 is what tcpclient is based on; #X text 21 325 Received messages are output as a list of bytes; #X text 20 343 Attempting to print long messages output can hang pd! ; #X text 343 132 get any received data (not useful unless you need it faster than once per 20ms); #X text 445 93 semicolon-terminated string for netserver or netreceive ; #X msg 249 93 send 49 127 128 51 59; #X obj -86 317 textfile; #X msg -86 213 clear; #X msg -67 285 write tcpclientreceived.txt; #X obj -73 254 prepend add; #X obj -86 186 loadbang; #X text 575 342 2006/05/12 Martin Peach; #X obj 482 286 tcpserver; #X text 448 285 and; #X text -71 -82 tcpclient 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 connect 0 0 8 0; #X connect 1 0 2 0; #X connect 1 1 3 0; #X connect 1 2 4 0; #X connect 1 3 5 0; #X connect 7 0 8 0; #X connect 8 0 34 0; #X connect 8 1 1 0; #X connect 8 2 11 0; #X connect 9 0 8 0; #X connect 12 0 8 0; #X connect 13 0 12 0; #X connect 14 0 8 0; #X connect 15 0 8 0; #X connect 17 0 8 0; #X connect 22 0 8 0; #X connect 30 0 8 0; #X connect 32 0 31 0; #X connect 33 0 31 0; #X connect 34 0 31 0; #X connect 35 0 32 0;
--- NEW FILE: tcpserver-help.pd --- #N canvas 13 208 1115 644 12; #X msg 18 -6 print; #X obj 136 109 tcpserver 9997; #X floatatom 171 237 5 0 0 0 - - -; #X floatatom 286 191 5 0 0 0 - - -; #X obj 324 138 unpack 0 0 0 0; #X floatatom 324 161 3 0 0 0 - - -; #X floatatom 359 161 3 0 0 0 - - -; #X floatatom 395 161 3 0 0 0 - - -; #X floatatom 431 161 3 0 0 0 - - -; #X text 281 160 from; #X text 224 236 connections; #X obj 43 161 print received; #X msg 118 45 client 1 1 2 3; #X msg 86 20 broadcast 1 2 3; #X text 69 -6 list of connections; #X text 226 19 send to all clients; #X text 249 45 send to client 1; #X text 347 254 2006/05/11 Martin Peach; #X text 199 191 on socket; #X msg 140 71 send 504 1 2 3; #X text 273 71 send to client on socket 504; #X msg 564 -365 client 1 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19; #X msg 563 -340 client 1 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39; #X msg 563 -297 client 1 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59; #X msg 563 -255 client 1 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79; #X msg 561 -213 client 1 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99; #X msg 560 -170 client 1 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119; #X msg 559 -127 client 1 120 121 122 123 124 125 126 127 138 139 140 141 142 143 144 145 146 147 148 149; #X msg 559 -84 client 1 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169; #X msg 559 -39 client 1 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189; #X msg 558 5 client 1 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209; #X msg 558 47 client 1 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229; #X msg 558 89 client 1 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249; #X msg 558 134 client 1 250 251 252 253 254 255; #X connect 0 0 1 0; #X connect 1 0 11 0; #X connect 1 1 2 0; #X connect 1 2 3 0; #X connect 1 3 4 0; #X connect 4 0 5 0; #X connect 4 1 6 0; #X connect 4 2 7 0; #X connect 4 3 8 0; #X connect 12 0 1 0; #X connect 13 0 1 0; #X connect 19 0 1 0; #X connect 21 0 1 0; #X connect 22 0 1 0; #X connect 23 0 1 0; #X connect 24 0 1 0; #X connect 25 0 1 0; #X connect 26 0 1 0; #X connect 27 0 1 0; #X connect 28 0 1 0; #X connect 29 0 1 0; #X connect 30 0 1 0; #X connect 31 0 1 0; #X connect 32 0 1 0; #X connect 33 0 1 0;
--- NEW FILE: udpreceive-help.pd --- #N canvas 658 564 478 294 12; #X obj 222 119 unpack 0 0 0 0; #X floatatom 222 142 3 0 0 0 - - -; #X floatatom 257 142 3 0 0 0 - - -; #X floatatom 293 142 3 0 0 0 - - -; #X floatatom 329 142 3 0 0 0 - - -; #X text 179 141 from; #X obj 107 194 print message; #X obj 107 91 udpreceive 9997; #X text 32 16 udpreceive receives bytes over a udp connection.; #X text 265 235 Martin Peach 2006/04/21; #X connect 0 0 1 0; #X connect 0 1 2 0; #X connect 0 2 3 0; #X connect 0 3 4 0; #X connect 7 0 6 0; #X connect 7 1 0 0;
--- NEW FILE: x_net_tcpserver.c --- /* x_net_tcpserver.c Martin Peach 20060511 working version 20060512 */ /* 20060515 works on linux too... */ /* x_net_tcpserver.c is based on netserver: */ /* -------------------------- netserver ------------------------------------- */ /* */ /* A server for bidirectional communication from within Pd. */ /* Allows to send back data to specific clients connected to the server. */ /* Written by Olaf Matthes olaf.matthes@gmx.de */ /* Get source at http://www.akustische-kunst.org/puredata/maxlib */ /* */ /* 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /* */ /* Based on PureData by Miller Puckette and others. */ /* */ /* ---------------------------------------------------------------------------- */ //define DEBUG
#include "m_pd.h" #include "m_imp.h" #include "s_stuff.h"
//#include <sys/types.h> //#include <stdarg.h> //#include <signal.h> //#include <fcntl.h> //#include <errno.h> //#include <string.h> //#include <stdio.h> //#include <pthread.h> #if defined(UNIX) || defined(unix) #include <sys/socket.h> #include <netinet/in.h> #include <netinet/tcp.h> #include <arpa/inet.h> #include <netdb.h> #include <unistd.h> #include <stdlib.h> #include <sys/time.h> #define SOCKET_ERROR -1 #else //#include <io.h> //#include <fcntl.h> #include <winsock2.h> #endif
#define MAX_CONNECT 32 /* maximum number of connections */ #define INBUFSIZE 65536L /* was 4096: size of receiving data buffer */ #define MAX_UDP_RECEIVE 65536L /* longer than data in maximum UDP packet */
/* ----------------------------- tcpserver ------------------------- */
static t_class *tcpserver_class; static t_binbuf *inbinbuf; static char objName[] = "tcpserver";
typedef void (*t_tcpserver_socketnotifier)(void *x); typedef void (*t_tcpserver_socketreceivefn)(void *x, t_binbuf *b);
typedef struct _tcpserver_socketreceiver { unsigned char *sr_inbuf; int sr_inhead; int sr_intail; void *sr_owner; t_tcpserver_socketnotifier sr_notifier; t_tcpserver_socketreceivefn sr_socketreceivefn; } t_tcpserver_socketreceiver;
typedef struct _tcpserver { t_object x_obj; t_outlet *x_msgout; t_outlet *x_connectout; t_outlet *x_sockout; t_outlet *x_addrout; t_symbol *x_host[MAX_CONNECT]; t_int x_fd[MAX_CONNECT]; u_long x_addr[MAX_CONNECT]; t_tcpserver_socketreceiver *x_sr[MAX_CONNECT]; t_atom x_addrbytes[4]; t_int x_sock_fd; t_int x_connectsocket; t_int x_nconnections; t_atom x_msgoutbuf[MAX_UDP_RECEIVE]; char x_msginbuf[MAX_UDP_RECEIVE]; } t_tcpserver;
static t_tcpserver_socketreceiver *tcpserver_socketreceiver_new(void *owner, t_tcpserver_socketnotifier notifier, t_tcpserver_socketreceivefn socketreceivefn); static int tcpserver_socketreceiver_doread(t_tcpserver_socketreceiver *x); static void tcpserver_socketreceiver_read(t_tcpserver_socketreceiver *x, int fd); static void tcpserver_socketreceiver_free(t_tcpserver_socketreceiver *x); static void tcpserver_send(t_tcpserver *x, t_symbol *s, int argc, t_atom *argv); static void tcp_server_send_bytes(int sockfd, t_tcpserver *x, int argc, t_atom *argv); static void tcpserver_client_send(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); static void tcpserver_notify(t_tcpserver *x); static void tcpserver_connectpoll(t_tcpserver *x); static void tcpserver_print(t_tcpserver *x); static void *tcpserver_new(t_floatarg fportno); static void tcpserver_free(t_tcpserver *x); #ifdef MSW __declspec(dllexport) #endif void tcpserver_setup(void);
static t_tcpserver_socketreceiver *tcpserver_socketreceiver_new(void *owner, t_tcpserver_socketnotifier notifier, t_tcpserver_socketreceivefn socketreceivefn) { t_tcpserver_socketreceiver *x = (t_tcpserver_socketreceiver *)getbytes(sizeof(*x)); if (!x) { error("%s_socketreceiver: unable to allocate %d bytes", objName, sizeof(*x)); } else { x->sr_inhead = x->sr_intail = 0; x->sr_owner = owner; x->sr_notifier = notifier; x->sr_socketreceivefn = socketreceivefn; if (!(x->sr_inbuf = malloc(INBUFSIZE))) { freebytes(x, sizeof(*x)); x = NULL; error("%s_socketreceiver: unable to allocate %d bytes", objName, INBUFSIZE); } } return (x); }
/* this is in a separately called subroutine so that the buffer isn't sitting on the stack while the messages are getting passed. */ static int tcpserver_socketreceiver_doread(t_tcpserver_socketreceiver *x) { char messbuf[INBUFSIZE]; char *bp = messbuf; int indx, i; int inhead = x->sr_inhead; int intail = x->sr_intail; unsigned char c; t_tcpserver *y = x->sr_owner; unsigned char *inbuf = x->sr_inbuf;
if (intail == inhead) return (0); #ifdef DEBUG post ("%s_socketreceiver_doread: intail=%d inhead=%d", objName, intail, inhead); #endif
for (indx = intail, i = 0; indx != inhead; indx = (indx+1)&(INBUFSIZE-1), ++i) { c = *bp++ = inbuf[indx]; y->x_msgoutbuf[i].a_w.w_float = (float)c; } if (i > 1) outlet_list(y->x_msgout, &s_list, i, y->x_msgoutbuf); else outlet_float(y->x_msgout, y->x_msgoutbuf[0].a_w.w_float);
// intail = (indx+1)&(INBUFSIZE-1); x->sr_inhead = inhead; x->sr_intail = indx;//intail; return (1); }
static void tcpserver_socketreceiver_read(t_tcpserver_socketreceiver *x, int fd) { int readto = (x->sr_inhead >= x->sr_intail ? INBUFSIZE : x->sr_intail-1); int ret, i; t_tcpserver *y = x->sr_owner;
y->x_sock_fd = fd; /* the input buffer might be full. If so, drop the whole thing */ if (readto == x->sr_inhead) { post("%s: dropped message", objName); x->sr_inhead = x->sr_intail = 0; readto = INBUFSIZE; } else { ret = recv(fd, x->sr_inbuf + x->sr_inhead, readto - x->sr_inhead, 0); if (ret < 0) { sys_sockerror("tcpserver: recv"); if (x->sr_notifier) (*x->sr_notifier)(x->sr_owner); sys_rmpollfn(fd); sys_closesocket(fd); } else if (ret == 0) { post("%s: connection closed on socket %d", objName, fd); if (x->sr_notifier) (*x->sr_notifier)(x->sr_owner); sys_rmpollfn(fd); sys_closesocket(fd); } else { #ifdef DEBUG post ("%s_socketreceiver_read: ret = %d", objName, ret); #endif x->sr_inhead += ret; if (x->sr_inhead >= INBUFSIZE) x->sr_inhead = 0; /* output client's IP and socket no. */ for(i = 0; i < y->x_nconnections; i++) /* search for corresponding IP */ { if(y->x_fd[i] == y->x_sock_fd) { // outlet_symbol(x->x_connectionip, x->x_host[i]); /* find sender's ip address and output it */ y->x_addrbytes[0].a_w.w_float = (y->x_addr[i] & 0xFF000000)>>24; y->x_addrbytes[1].a_w.w_float = (y->x_addr[i] & 0x0FF0000)>>16; y->x_addrbytes[2].a_w.w_float = (y->x_addr[i] & 0x0FF00)>>8; y->x_addrbytes[3].a_w.w_float = (y->x_addr[i] & 0x0FF); outlet_list(y->x_addrout, &s_list, 4L, y->x_addrbytes); break; } } outlet_float(y->x_sockout, y->x_sock_fd); /* the socket number */ tcpserver_socketreceiver_doread(x); } } }
static void tcpserver_socketreceiver_free(t_tcpserver_socketreceiver *x) { if (x != NULL) { free(x->sr_inbuf); freebytes(x, sizeof(*x)); } }
/* ---------------- main tcpserver (send) stuff --------------------- */
static void tcp_server_send_bytes(int client, t_tcpserver *x, int argc, t_atom *argv) { static char byte_buf[MAX_UDP_RECEIVE];// arbitrary maximum similar to max IP packet size int i, d; 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; int sockfd = x->x_fd[client];
/* process & send data */ if(sockfd >= 0) { for (i = 0; i < argc; ++i) { if (argv[i].a_type == A_FLOAT) { f = argv[i].a_w.w_float; d = (int)f; e = f - d; #ifdef DEBUG post("%s: argv[%d]: float:%f int:%d delta:%f", objName, i, f, d, e); #endif if (e != 0) { error("%s: item %d (%f) is not an integer", objName, i, f); return; } if ((d < 0) || (d > 255)) { error("%s: item %d (%f) is not between 0 and 255", objName, i, f); return; } c = (unsigned char)d; /* make sure it doesn't become negative; this only matters for post() */ #ifdef DEBUG post("%s: argv[%d]: %d", objName, i, c); #endif byte_buf[i] = c; } else { error("%s: item %d is not a float", objName, i); return; } } length = i; if (length > 0) { for (bp = byte_buf, sent = 0; sent < length;) { timebefore = sys_getrealtime(); result = send(sockfd, byte_buf, length-sent, 0); timeafter = sys_getrealtime(); late = (timeafter - timebefore > 0.005); if (late || pleasewarn) { if (timeafter > lastwarntime + 2) { post("%s: send blocked %d msec", objName, (int)(1000 * ((timeafter - timebefore) + pleasewarn))); pleasewarn = 0; lastwarntime = timeafter; } else if (late) pleasewarn += timeafter - timebefore; } if (result <= 0) { sys_sockerror("tcpserver: send"); post("%s: could not send data to client %d", objName, client); break; } else { sent += result; bp += result; } } } } else post("%s: not a valid socket number (%d)", objName, sockfd); }
/* send message to client using socket number */ static void tcpserver_send(t_tcpserver *x, t_symbol *s, int argc, t_atom *argv) { int i, sockfd; int client = -1;
if(x->x_nconnections < 0) { post("%s: no clients connected", objName); return; } if(argc < 2) { post("%s: nothing to send", objName); return; } /* get socket number of connection (first element in list) */ if(argv[0].a_type == A_FLOAT) { sockfd = atom_getfloatarg(0, argc, argv); for(i = 0; i < x->x_nconnections; i++) /* check if connection exists */ { if(x->x_fd[i] == sockfd) { client = i; /* the client we're sending to */ break; } } if(client == -1) { post("%s: no connection on socket %d", objName, sockfd); return; } } else { post("%s: no socket specified", objName); return; } tcp_server_send_bytes(client, x, argc-1, &argv[1]); }
/* 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_client_send(t_tcpserver *x, t_symbol *s, int argc, t_atom *argv) { int client;
if(x->x_nconnections < 0) { post("%s: no clients connected", objName); return; } if(argc < 2) { post("%s: nothing to send", objName); return; } /* get number of client (first element in list) */ if(argv[0].a_type == A_FLOAT) client = atom_getfloatarg(0, argc, argv); else { post("%s: no client specified", objName); return; } if (!((client > 0) && (client < MAX_CONNECT))) { post("%s: client %d out of range [1..%d]", objName, client, MAX_CONNECT); return; } --client;/* zero based index*/ tcp_server_send_bytes(client, x, argc-1, &argv[1]); }
/* broadcasts a message to all connected clients */ static void tcpserver_broadcast(t_tcpserver *x, t_symbol *s, int argc, t_atom *argv) { int client;
/* enumerate through the clients and send each the message */ for(client = 0; client < x->x_nconnections; client++) /* check if connection exists */ { if(x->x_fd[client] >= 0) { /* socket exists for this client */ tcp_server_send_bytes(client, x, argc, argv); break; } } }
/* ---------------- main tcpserver (receive) stuff --------------------- */
static void tcpserver_notify(t_tcpserver *x) { int i, k;
/* remove connection from list */ for(i = 0; i < x->x_nconnections; i++) { if(x->x_fd[i] == x->x_sock_fd) { x->x_nconnections--; post("%s: "%s" removed from list of clients", objName, x->x_host[i]->s_name); x->x_host[i] = NULL; /* delete entry */ x->x_fd[i] = -1; tcpserver_socketreceiver_free(x->x_sr[i]); x->x_sr[i] = NULL;
/* rearrange list now: move entries to close the gap */ for(k = i; k < x->x_nconnections; k++) { x->x_host[k] = x->x_host[k + 1]; x->x_fd[k] = x->x_fd[k + 1]; } } } outlet_float(x->x_connectout, x->x_nconnections); }
static void tcpserver_connectpoll(t_tcpserver *x) { struct sockaddr_in incomer_address; int sockaddrl = (int) sizeof( struct sockaddr ); 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, (t_tcpserver_socketnotifier)tcpserver_notify, NULL);/* MP tcpserver_doit isn't used I think...*/ if (!y) { #ifdef MSW closesocket(fd); #else close(fd); #endif return; } sys_addpollfn(fd, (t_fdpollfn)tcpserver_socketreceiver_read, y); x->x_nconnections++; i = x->x_nconnections - 1; x->x_host[i] = gensym(inet_ntoa(incomer_address.sin_addr)); x->x_fd[i] = fd; x->x_sr[i] = y; post("%s: accepted connection from %s on socket %d", objName, x->x_host[i]->s_name, x->x_fd[i]); outlet_float(x->x_connectout, x->x_nconnections); outlet_float(x->x_sockout, x->x_fd[i]); /* the socket number */ x->x_addr[i] = ntohl(incomer_address.sin_addr.s_addr); x->x_addrbytes[0].a_w.w_float = (x->x_addr[i] & 0xFF000000)>>24; x->x_addrbytes[1].a_w.w_float = (x->x_addr[i] & 0x0FF0000)>>16; x->x_addrbytes[2].a_w.w_float = (x->x_addr[i] & 0x0FF00)>>8; x->x_addrbytes[3].a_w.w_float = (x->x_addr[i] & 0x0FF); outlet_list(x->x_addrout, &s_list, 4L, x->x_addrbytes); } }
static void tcpserver_print(t_tcpserver *x) { int i;
if(x->x_nconnections > 0) { post("%s: %d open connections:", objName, x->x_nconnections); for(i = 0; i < x->x_nconnections; i++) { post(" "%s" on socket %d", x->x_host[i]->s_name, x->x_fd[i]); } } else post("%s: no open connections", objName); }
static void *tcpserver_new(t_floatarg fportno) { t_tcpserver *x; int i; struct sockaddr_in server; int sockfd, portno = fportno;
/* create a socket */ sockfd = socket(AF_INET, SOCK_STREAM, 0); #ifdef DEBUG post("%s: receive socket %d", objName, sockfd); #endif if (sockfd < 0) { sys_sockerror("tcpserver: socket"); return (0); } server.sin_family = AF_INET; server.sin_addr.s_addr = INADDR_ANY; #ifdef IRIX /* this seems to work only in IRIX but is unnecessary in Linux. Not sure what NT needs in place of this. */ if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, 0, 0) < 0) post("setsockopt failed\n"); #endif /* assign server port number */ server.sin_port = htons((u_short)portno); /* name the socket */ if (bind(sockfd, (struct sockaddr *)&server, sizeof(server)) < 0) { sys_sockerror("tcpserver: bind"); sys_closesocket(sockfd); return (0); } x = (t_tcpserver *)pd_new(tcpserver_class); x->x_msgout = outlet_new(&x->x_obj, &s_anything); /* 1st outlet for received data */ /* streaming protocol */ if (listen(sockfd, 5) < 0) { sys_sockerror("tcpserver: listen"); sys_closesocket(sockfd); sockfd = -1; } else { sys_addpollfn(sockfd, (t_fdpollfn)tcpserver_connectpoll, x); x->x_connectout = outlet_new(&x->x_obj, &s_float); /* 2nd outlet for number of connected clients */ x->x_sockout = outlet_new(&x->x_obj, &s_float); /* 3rd outlet for socket number of current client */ x->x_addrout = outlet_new(&x->x_obj, &s_list); /* 4th outlet for ip address of current client */ inbinbuf = binbuf_new(); } x->x_connectsocket = sockfd; x->x_nconnections = 0; for(i = 0; i < MAX_CONNECT; i++) { x->x_fd[i] = -1; x->x_sr[i] = NULL; } /* prepare to convert the bytes in the buffer to floats in a list */ for (i = 0; i < MAX_UDP_RECEIVE; ++i) { x->x_msgoutbuf[i].a_type = A_FLOAT; x->x_msgoutbuf[i].a_w.w_float = 0; } for (i = 0; i < 4; ++i) { x->x_addrbytes[i].a_type = A_FLOAT; x->x_addrbytes[i].a_w.w_float = 0; }
return (x); }
static void tcpserver_free(t_tcpserver *x) { int i;
for(i = 0; i < MAX_CONNECT; i++) { if (x->x_fd[i] >= 0) { sys_rmpollfn(x->x_fd[i]); sys_closesocket(x->x_fd[i]); } if (x->x_sr[i] != NULL) tcpserver_socketreceiver_free(x->x_sr[i]); } if (x->x_connectsocket >= 0) { sys_rmpollfn(x->x_connectsocket); sys_closesocket(x->x_connectsocket); }
binbuf_free(inbinbuf); }
#ifdef MSW __declspec(dllexport) #endif void tcpserver_setup(void) { 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_print, gensym("print"), 0); class_addmethod(tcpserver_class, (t_method)tcpserver_send, gensym("send"), A_GIMME, 0); class_addmethod(tcpserver_class, (t_method)tcpserver_client_send, gensym("client"), A_GIMME, 0); class_addmethod(tcpserver_class, (t_method)tcpserver_broadcast, gensym("broadcast"), A_GIMME, 0); }
/* end of x_net_tcpserver.c */
--- NEW FILE: x_net_tcp_server.c --- /* x_net_tcpserver.c Martin Peach 20060511 working version 20060512 */ /* x_net_tcpserver.c is based on netserver: */ /* -------------------------- netserver ------------------------------------- */ /* */ /* A server for bidirectional communication from within Pd. */ /* Allows to send back data to specific clients connected to the server. */ /* Written by Olaf Matthes olaf.matthes@gmx.de */ /* Get source at http://www.akustische-kunst.org/puredata/maxlib */ /* */ /* 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /* */ /* Based on PureData by Miller Puckette and others. */ /* */ /* ---------------------------------------------------------------------------- */ //define DEBUG
#include "m_pd.h" #include "m_imp.h" #include "s_stuff.h"
//#include <sys/types.h> //#include <stdarg.h> //#include <signal.h> //#include <fcntl.h> //#include <errno.h> //#include <string.h> //#include <stdio.h> //#include <pthread.h> #if defined(UNIX) || defined(unix) #include <sys/socket.h> #include <netinet/in.h> #include <netinet/tcp.h> #include <arpa/inet.h> #include <netdb.h> #include <unistd.h> #include <stdlib.h> #include <sys/time.h> #define SOCKET_ERROR -1 #else //#include <io.h> //#include <fcntl.h> #include <winsock2.h> #endif
#define MAX_CONNECT 32 /* maximum number of connections */ #define INBUFSIZE 65536L /* was 4096: size of receiving data buffer */ #define MAX_UDP_RECEIVE 65536L /* longer than data in maximum UDP packet */
/* ----------------------------- tcpserver ------------------------- */
static t_class *tcpserver_class; static t_binbuf *inbinbuf; static char objName[] = "tcpserver";
typedef void (*t_tcpserver_socketnotifier)(void *x); typedef void (*t_tcpserver_socketreceivefn)(void *x, t_binbuf *b);
typedef struct _tcpserver { t_object x_obj; t_outlet *x_msgout; t_outlet *x_connectout; t_outlet *x_sockout; t_outlet *x_addrout; t_symbol *x_host[MAX_CONNECT]; t_int x_fd[MAX_CONNECT]; u_long x_addr[MAX_CONNECT]; t_atom x_addrbytes[4]; t_int x_sock_fd; t_int x_connectsocket; t_int x_nconnections; t_atom x_msgoutbuf[MAX_UDP_RECEIVE]; char x_msginbuf[MAX_UDP_RECEIVE]; } t_tcpserver;
typedef struct _tcpserver_socketreceiver { unsigned char *sr_inbuf; int sr_inhead; int sr_intail; void *sr_owner; t_tcpserver_socketnotifier sr_notifier; t_tcpserver_socketreceivefn sr_socketreceivefn; } t_tcpserver_socketreceiver;
static t_tcpserver_socketreceiver *tcpserver_socketreceiver_new(void *owner, t_tcpserver_socketnotifier notifier, t_tcpserver_socketreceivefn socketreceivefn); static int tcpserver_socketreceiver_doread(t_tcpserver_socketreceiver *x); static void tcpserver_socketreceiver_read(t_tcpserver_socketreceiver *x, int fd); static void tcpserver_socketreceiver_free(t_tcpserver_socketreceiver *x); static void tcpserver_send(t_tcpserver *x, t_symbol *s, int argc, t_atom *argv); static void tcp_server_send_bytes(int sockfd, t_tcpserver *x, int argc, t_atom *argv); static void tcpserver_client_send(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); static void tcpserver_notify(t_tcpserver *x); static void tcpserver_connectpoll(t_tcpserver *x); static void tcpserver_print(t_tcpserver *x); static void *tcpserver_new(t_floatarg fportno); static void tcpserver_free(t_tcpserver *x); #ifdef MSW __declspec(dllexport) #endif void tcpserver_setup(void);
static t_tcpserver_socketreceiver *tcpserver_socketreceiver_new(void *owner, t_tcpserver_socketnotifier notifier, t_tcpserver_socketreceivefn socketreceivefn) { t_tcpserver_socketreceiver *x = (t_tcpserver_socketreceiver *)getbytes(sizeof(*x)); if (!x) { error("%s_socketreceiver: unable to allocate %d bytes", objName, sizeof(*x)); } else { x->sr_inhead = x->sr_intail = 0; x->sr_owner = owner; x->sr_notifier = notifier; x->sr_socketreceivefn = socketreceivefn; if (!(x->sr_inbuf = malloc(INBUFSIZE))) { freebytes(x, sizeof(*x)); x = NULL; error("%s_socketreceiver: unable to allocate %d bytes", objName, INBUFSIZE); } } return (x); }
/* this is in a separately called subroutine so that the buffer isn't sitting on the stack while the messages are getting passed. */ static int tcpserver_socketreceiver_doread(t_tcpserver_socketreceiver *x) { char messbuf[INBUFSIZE]; char *bp = messbuf; int indx, i; int inhead = x->sr_inhead; int intail = x->sr_intail; unsigned char c; t_tcpserver *y = x->sr_owner; unsigned char *inbuf = x->sr_inbuf;
if (intail == inhead) return (0); #ifdef DEBUG post ("%s_socketreceiver_doread: intail=%d inhead=%d", objName, intail, inhead); #endif
for (indx = intail, i = 0; indx != inhead; indx = (indx+1)&(INBUFSIZE-1), ++i) { c = *bp++ = inbuf[indx]; y->x_msgoutbuf[i].a_w.w_float = (float)c; } if (i > 1) outlet_list(y->x_msgout, &s_list, i, y->x_msgoutbuf); else outlet_float(y->x_msgout, y->x_msgoutbuf[0].a_w.w_float);
// intail = (indx+1)&(INBUFSIZE-1); x->sr_inhead = inhead; x->sr_intail = indx;//intail; return (1); }
static void tcpserver_socketreceiver_read(t_tcpserver_socketreceiver *x, int fd) { char *semi; int readto = (x->sr_inhead >= x->sr_intail ? INBUFSIZE : x->sr_intail-1); int ret, i; t_tcpserver *y = x->sr_owner;
y->x_sock_fd = fd; /* the input buffer might be full. If so, drop the whole thing */ if (readto == x->sr_inhead) { post("%s: dropped message", objName); x->sr_inhead = x->sr_intail = 0; readto = INBUFSIZE; } else { ret = recv(fd, x->sr_inbuf + x->sr_inhead, readto - x->sr_inhead, 0); if (ret < 0) { sys_sockerror("tcpserver: recv"); if (x->sr_notifier) (*x->sr_notifier)(x->sr_owner); sys_rmpollfn(fd); sys_closesocket(fd); } else if (ret == 0) { post("%s: connection closed on socket %d", objName, fd); if (x->sr_notifier) (*x->sr_notifier)(x->sr_owner); sys_rmpollfn(fd); sys_closesocket(fd); } else { #ifdef DEBUG post ("%s_socketreceiver_read: ret = %d", objName, ret); #endif x->sr_inhead += ret; if (x->sr_inhead >= INBUFSIZE) x->sr_inhead = 0; /* output client's IP and socket no. */ for(i = 0; i < y->x_nconnections; i++) /* search for corresponding IP */ { if(y->x_fd[i] == y->x_sock_fd) { // outlet_symbol(x->x_connectionip, x->x_host[i]); /* find sender's ip address and output it */ y->x_addrbytes[0].a_w.w_float = (y->x_addr[i] & 0xFF000000)>>24; y->x_addrbytes[1].a_w.w_float = (y->x_addr[i] & 0x0FF0000)>>16; y->x_addrbytes[2].a_w.w_float = (y->x_addr[i] & 0x0FF00)>>8; y->x_addrbytes[3].a_w.w_float = (y->x_addr[i] & 0x0FF); outlet_list(y->x_addrout, &s_list, 4L, y->x_addrbytes); break; } } outlet_float(y->x_sockout, y->x_sock_fd); /* the socket number */ tcpserver_socketreceiver_doread(x); } } }
static void tcpserver_socketreceiver_free(t_tcpserver_socketreceiver *x) { free(x->sr_inbuf); freebytes(x, sizeof(*x)); }
/* ---------------- main tcpserver (send) stuff --------------------- */
static void tcp_server_send_bytes(int client, t_tcpserver *x, int argc, t_atom *argv) { static char byte_buf[MAX_UDP_RECEIVE];// arbitrary maximum similar to max IP packet size int i, d; 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; int sockfd = x->x_fd[client];
/* process & send data */ if(sockfd >= 0) { for (i = 0; i < argc; ++i) { if (argv[i].a_type == A_FLOAT) { f = argv[i].a_w.w_float; d = (int)f; e = f - d; #ifdef DEBUG post("%s: argv[%d]: float:%f int:%d delta:%f", objName, i, f, d, e); #endif if (e != 0) { error("%s: item %d (%f) is not an integer", objName, i, f); return; } if ((d < 0) || (d > 255)) { error("%s: item %d (%f) is not between 0 and 255", objName, i, f); return; } c = (unsigned char)d; /* make sure it doesn't become negative; this only matters for post() */ #ifdef DEBUG post("%s: argv[%d]: %d", objName, i, c); #endif byte_buf[i] = c; } else { error("%s: item %d is not a float", objName, i); return; } } length = i; if (length > 0) { for (bp = byte_buf, sent = 0; sent < length;) { timebefore = sys_getrealtime(); result = send(sockfd, byte_buf, length-sent, 0); timeafter = sys_getrealtime(); late = (timeafter - timebefore > 0.005); if (late || pleasewarn) { if (timeafter > lastwarntime + 2) { post("%s: send blocked %d msec", objName, (int)(1000 * ((timeafter - timebefore) + pleasewarn))); pleasewarn = 0; lastwarntime = timeafter; } else if (late) pleasewarn += timeafter - timebefore; } if (result <= 0) { sys_sockerror("tcpserver: send"); post("%s: could not send data to client %d", objName, client); break; } else { sent += result; bp += result; } } } } else post("%s: not a valid socket number (%d)", objName, sockfd); }
/* send message to client using socket number */ static void tcpserver_send(t_tcpserver *x, t_symbol *s, int argc, t_atom *argv) { int i, sockfd; int client = -1;
if(x->x_nconnections < 0) { post("%s: no clients connected", objName); return; } if(argc < 2) { post("%s: nothing to send", objName); return; } /* get socket number of connection (first element in list) */ if(argv[0].a_type == A_FLOAT) { sockfd = atom_getfloatarg(0, argc, argv); for(i = 0; i < x->x_nconnections; i++) /* check if connection exists */ { if(x->x_fd[i] == sockfd) { client = i; /* the client we're sending to */ break; } } if(client == -1) { post("%s: no connection on socket %d", objName, sockfd); return; } } else { post("%s: no socket specified", objName); return; } tcp_server_send_bytes(client, x, argc-1, &argv[1]); }
/* 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_client_send(t_tcpserver *x, t_symbol *s, int argc, t_atom *argv) { int sockfd, client;
if(x->x_nconnections < 0) { post("%s: no clients connected", objName); return; } if(argc < 2) { post("%s: nothing to send", objName); return; } /* get number of client (first element in list) */ if(argv[0].a_type == A_FLOAT) client = atom_getfloatarg(0, argc, argv); else { post("%s: no client specified", objName); return; } if (!((client > 0) && (client < MAX_CONNECT))) { post("%s: client %d out of range [1..%d]", objName, client, MAX_CONNECT); return; } --client;/* zero based index*/ tcp_server_send_bytes(client, x, argc-1, &argv[1]); }
/* broadcasts a message to all connected clients */ static void tcpserver_broadcast(t_tcpserver *x, t_symbol *s, int argc, t_atom *argv) { int client;
/* enumerate through the clients and send each the message */ for(client = 0; client < x->x_nconnections; client++) /* check if connection exists */ { if(x->x_fd[client] >= 0) { /* socket exists for this client */ tcp_server_send_bytes(client, x, argc, argv); break; } } }
/* ---------------- main tcpserver (receive) stuff --------------------- */
static void tcpserver_notify(t_tcpserver *x) { int i, k;
/* remove connection from list */ for(i = 0; i < x->x_nconnections; i++) { if(x->x_fd[i] == x->x_sock_fd) { x->x_nconnections--; post("%s: "%s" removed from list of clients", objName, x->x_host[i]->s_name); x->x_host[i] = NULL; /* delete entry */ x->x_fd[i] = -1; /* rearrange list now: move entries to close the gap */ for(k = i; k < x->x_nconnections; k++) { x->x_host[k] = x->x_host[k + 1]; x->x_fd[k] = x->x_fd[k + 1]; } } } outlet_float(x->x_connectout, x->x_nconnections); }
static void tcpserver_connectpoll(t_tcpserver *x) { struct sockaddr_in incomer_address; int sockaddrl = (int) sizeof( struct sockaddr ); 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, (t_tcpserver_socketnotifier)tcpserver_notify, NULL);/* MP tcpserver_doit isn't used I think...*/ if (!y) { #ifdef MSW closesocket(fd); #else close(fd); #endif return; } sys_addpollfn(fd, (t_fdpollfn)tcpserver_socketreceiver_read, y); x->x_nconnections++; i = x->x_nconnections - 1; x->x_host[i] = gensym(inet_ntoa(incomer_address.sin_addr)); x->x_fd[i] = fd; post("%s: accepted connection from %s on socket %d", objName, x->x_host[i]->s_name, x->x_fd[i]); outlet_float(x->x_connectout, x->x_nconnections); outlet_float(x->x_sockout, x->x_fd[i]); /* the socket number */ x->x_addr[i] = ntohl(incomer_address.sin_addr.s_addr); x->x_addrbytes[0].a_w.w_float = (x->x_addr[i] & 0xFF000000)>>24; x->x_addrbytes[1].a_w.w_float = (x->x_addr[i] & 0x0FF0000)>>16; x->x_addrbytes[2].a_w.w_float = (x->x_addr[i] & 0x0FF00)>>8; x->x_addrbytes[3].a_w.w_float = (x->x_addr[i] & 0x0FF); outlet_list(x->x_addrout, &s_list, 4L, x->x_addrbytes); } }
static void tcpserver_print(t_tcpserver *x) { int i;
if(x->x_nconnections > 0) { post("%s: %d open connections:", objName, x->x_nconnections); for(i = 0; i < x->x_nconnections; i++) { post(" "%s" on socket %d", x->x_host[i]->s_name, x->x_fd[i]); } } else post("%s: no open connections", objName); }
static void *tcpserver_new(t_floatarg fportno) { t_tcpserver *x; int i; struct sockaddr_in server; int sockfd, portno = fportno;
/* create a socket */ sockfd = socket(AF_INET, SOCK_STREAM, 0); #ifdef DEBUG post("%s: receive socket %d", objName, sockfd); #endif if (sockfd < 0) { sys_sockerror("tcpserver: socket"); return (0); } server.sin_family = AF_INET; server.sin_addr.s_addr = INADDR_ANY; #ifdef IRIX /* this seems to work only in IRIX but is unnecessary in Linux. Not sure what NT needs in place of this. */ if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, 0, 0) < 0) post("setsockopt failed\n"); #endif /* assign server port number */ server.sin_port = htons((u_short)portno); /* name the socket */ if (bind(sockfd, (struct sockaddr *)&server, sizeof(server)) < 0) { sys_sockerror("tcpserver: bind"); sys_closesocket(sockfd); return (0); } x = (t_tcpserver *)pd_new(tcpserver_class); x->x_msgout = outlet_new(&x->x_obj, &s_anything); /* 1st outlet for received data */ /* streaming protocol */ if (listen(sockfd, 5) < 0) { sys_sockerror("tcpserver: listen"); sys_closesocket(sockfd); sockfd = -1; } else { sys_addpollfn(sockfd, (t_fdpollfn)tcpserver_connectpoll, x); x->x_connectout = outlet_new(&x->x_obj, &s_float); /* 2nd outlet for number of connected clients */ x->x_sockout = outlet_new(&x->x_obj, &s_float); /* 3rd outlet for socket number of current client */ x->x_addrout = outlet_new(&x->x_obj, &s_list); /* 4th outlet for ip address of current client */ inbinbuf = binbuf_new(); } x->x_connectsocket = sockfd; x->x_nconnections = 0; for(i = 0; i < MAX_CONNECT; i++) x->x_fd[i] = -1; /* prepare to convert the bytes in the buffer to floats in a list */ for (i = 0; i < MAX_UDP_RECEIVE; ++i) { x->x_msgoutbuf[i].a_type = A_FLOAT; x->x_msgoutbuf[i].a_w.w_float = 0; } for (i = 0; i < 4; ++i) { x->x_addrbytes[i].a_type = A_FLOAT; x->x_addrbytes[i].a_w.w_float = 0; }
return (x); }
static void tcpserver_free(t_tcpserver *x) { int i;
for(i = 0; i < x->x_nconnections; i++) { sys_rmpollfn(x->x_fd[i]); sys_closesocket(x->x_fd[i]); } if (x->x_connectsocket >= 0) { sys_rmpollfn(x->x_connectsocket); sys_closesocket(x->x_connectsocket); } binbuf_free(inbinbuf); }
#ifdef MSW __declspec(dllexport) #endif void tcpserver_setup(void) { 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_print, gensym("print"), 0); class_addmethod(tcpserver_class, (t_method)tcpserver_send, gensym("send"), A_GIMME, 0); class_addmethod(tcpserver_class, (t_method)tcpserver_client_send, gensym("client"), A_GIMME, 0); class_addmethod(tcpserver_class, (t_method)tcpserver_broadcast, gensym("broadcast"), A_GIMME, 0); }
--- NEW FILE: tcpreceive-help.pd --- #N canvas 713 11 478 294 12; #X obj 212 117 unpack 0 0 0 0; #X floatatom 212 140 3 0 0 0 - - -; #X floatatom 247 140 3 0 0 0 - - -; #X floatatom 283 140 3 0 0 0 - - -; #X floatatom 319 140 3 0 0 0 - - -; #X text 169 139 from; #X obj 155 185 print message; #X obj 155 57 tcpreceive 9997; #X floatatom 270 96 5 0 0 0 - - -; #X text 316 94 connections; #X text 32 16 tcpreceive receives bytes over a tcp connection.; #X text 265 235 Martin Peach 2006/04/21; #X connect 0 0 1 0; #X connect 0 1 2 0; #X connect 0 2 3 0; #X connect 0 3 4 0; #X connect 7 0 6 0; #X connect 7 1 0 0; #X connect 7 2 8 0;
--- NEW FILE: x_net_tcpreceive.c --- /* x_net_tcpreceive.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. */
#include "m_pd.h" #include "s_stuff.h"
#ifdef MSW #include <winsock2.h> #include <ws2tcpip.h> /* for socklen_t */ #else #include <sys/socket.h> #include <netinet/in.h> #include <netinet/tcp.h> #include <netdb.h> #include <stdio.h> #endif
/* ----------------------------- tcpreceive ------------------------- */
static t_class *tcpreceive_class;
#define MAX_UDP_RECEIVE 65536L // longer than data in maximum UDP packet #define MAX_CONNECTIONS 128 // this is going to cause trouble down the line...:(
typedef struct _tcpconnection { long addr; int socket; } t_tcpconnection;
typedef struct _tcpreceive { t_object x_obj; t_outlet *x_msgout; t_outlet *x_addrout; t_outlet *x_connectout; int x_connectsocket; int x_nconnections; t_tcpconnection x_connection[MAX_CONNECTIONS]; t_atom x_addrbytes[4]; t_atom x_msgoutbuf[MAX_UDP_RECEIVE]; char x_msginbuf[MAX_UDP_RECEIVE]; } t_tcpreceive;
#ifdef MSW __declspec(dllexport) #endif void tcpreceive_setup(void); static void tcpreceive_free(t_tcpreceive *x); static void *tcpreceive_new(t_floatarg fportno); static void tcpreceive_read(t_tcpreceive *x, int sockfd); static void tcpreceive_connectpoll(t_tcpreceive *x); static int tcpreceive_addconnection(t_tcpreceive * x, int fd, long addr); static int tcpreceive_removeconnection(t_tcpreceive * x, int fd); static void tcpreceive_closeall(t_tcpreceive *x); static long tcpreceive_getconnection(t_tcpreceive * x, int fd);
static void tcpreceive_read(t_tcpreceive *x, int sockfd) { int i, read = 0; long addr;
// read = recvfrom(sockfd, x->x_msginbuf, MAX_UDP_RECEIVE, 0, (struct sockaddr *)&from, &fromlen); read = recv(sockfd, x->x_msginbuf, MAX_UDP_RECEIVE, 0); #ifdef DEBUG post("tcpreceive_read: read %lu x->x_connectsocket = %d", read, x->x_connectsocket); #endif if (read < 0) { sys_sockerror("tcpreceive_read: recv"); sys_rmpollfn(sockfd); sys_closesocket(sockfd); tcpreceive_removeconnection(x, sockfd); outlet_float(x->x_connectout, --x->x_nconnections); } else if (read == 0) { post("tcpreceive: EOF on socket %d\n", sockfd); sys_rmpollfn(sockfd); sys_closesocket(sockfd); tcpreceive_removeconnection(x, sockfd); outlet_float(x->x_connectout, --x->x_nconnections); } else if (read > 0) { for (i = 0; i < read; ++i) { /* convert the bytes in the buffer to floats in a list */ x->x_msgoutbuf[i].a_w.w_float = (float)x->x_msginbuf[i]; } /* find sender's ip address and output it */ addr = tcpreceive_getconnection(x, sockfd); x->x_addrbytes[0].a_w.w_float = (addr & 0xFF000000)>>24; x->x_addrbytes[1].a_w.w_float = (addr & 0x0FF0000)>>16; x->x_addrbytes[2].a_w.w_float = (addr & 0x0FF00)>>8; x->x_addrbytes[3].a_w.w_float = (addr & 0x0FF); outlet_list(x->x_addrout, &s_list, 4L, x->x_addrbytes); /* 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 *tcpreceive_new(t_floatarg fportno) { t_tcpreceive *x; struct sockaddr_in server; int sockfd, portno = fportno; int intarg, i;
/* create a socket */ sockfd = socket(AF_INET, SOCK_STREAM, 0); #ifdef DEBUG post("tcpreceive_new: socket %d port %d", sockfd, portno); #endif if (sockfd < 0) { sys_sockerror("tcpreceive: socket"); return (0); } server.sin_family = AF_INET; server.sin_addr.s_addr = INADDR_ANY;
/* ask OS to allow another Pd to repoen this port after we close it. */ intarg = 1; if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, (char *)&intarg, sizeof(intarg)) < 0) post("tcpreceive: setsockopt (SO_REUSEADDR) failed"); /* Stream (TCP) sockets are set NODELAY */ intarg = 1; if (setsockopt(sockfd, IPPROTO_TCP, TCP_NODELAY, (char *)&intarg, sizeof(intarg)) < 0) post("setsockopt (TCP_NODELAY) failed\n");
/* assign server port number */ server.sin_port = htons((u_short)portno);
/* name the socket */ if (bind(sockfd, (struct sockaddr *)&server, sizeof(server)) < 0) { sys_sockerror("tcpreceive: bind"); sys_closesocket(sockfd); return (0); } x = (t_tcpreceive *)pd_new(tcpreceive_class); x->x_msgout = outlet_new(&x->x_obj, &s_anything); x->x_addrout = outlet_new(&x->x_obj, &s_list); x->x_connectout = outlet_new(&x->x_obj, &s_float); /* clear the connection list */ for (i = 0; i < MAX_CONNECTIONS; ++i) { x->x_connection[i].socket = -1; x->x_connection[i].addr = 0L; } /* convert the bytes in the buffer to floats in a list */ for (i = 0; i < MAX_UDP_RECEIVE; ++i) { x->x_msgoutbuf[i].a_type = A_FLOAT; x->x_msgoutbuf[i].a_w.w_float = 0; } for (i = 0; i < 4; ++i) { x->x_addrbytes[i].a_type = A_FLOAT; x->x_addrbytes[i].a_w.w_float = 0; }
/* streaming protocol */ if (listen(sockfd, 5) < 0) { sys_sockerror("tcpreceive: listen"); sys_closesocket(sockfd); sockfd = -1; } else { sys_addpollfn(sockfd, (t_fdpollfn)tcpreceive_connectpoll, x); } x->x_connectsocket = sockfd; x->x_nconnections = 0;
//udp version... sys_addpollfn(x->x_connectsocket, (t_fdpollfn)tcpreceive_read, x); return (x); }
/* tcpreceive_connectpoll checks for incoming connection requests on the original socket */ /* a new socket is assigned */ static void tcpreceive_connectpoll(t_tcpreceive *x) { struct sockaddr_in from; socklen_t fromlen = sizeof(from); long addr; int fd;
fd = accept(x->x_connectsocket, (struct sockaddr *)&from, &fromlen); if (fd < 0) post("tcpreceive: accept failed"); 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); if (tcpreceive_addconnection(x, fd, addr)) { sys_addpollfn(fd, (t_fdpollfn)tcpreceive_read, x); outlet_float(x->x_connectout, ++x->x_nconnections); x->x_addrbytes[0].a_w.w_float = (addr & 0xFF000000)>>24; x->x_addrbytes[1].a_w.w_float = (addr & 0x0FF0000)>>16; x->x_addrbytes[2].a_w.w_float = (addr & 0x0FF00)>>8; x->x_addrbytes[3].a_w.w_float = (addr & 0x0FF); outlet_list(x->x_addrout, &s_list, 4L, x->x_addrbytes); } else { error ("tcpreceive: Too many connections"); sys_closesocket(fd); } } }
/* 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) { 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; return 1; } } return 0; }
/* tcpreceive_closeall closes all open sockets and deletes them from the list */ static void tcpreceive_closeall(t_tcpreceive *x) { int i;
for (i = 0; ((i < MAX_CONNECTIONS) && (x->x_nconnections > 0)); ++i) { if (x->x_connection[i].socket != -1) { post ("tcpreceive: closing socket %d", x->x_connection[i].socket); sys_rmpollfn(x->x_connection[i].socket); sys_closesocket(x->x_connection[i].socket); x->x_connection[i].socket = -1; x->x_connection[i].addr = 0L; outlet_float(x->x_connectout, --x->x_nconnections); } } }
/* tcpreceive_removeconnection tries to delete the socket fd from the list */ /* returns 1 on success, else 0 */ static int tcpreceive_removeconnection(t_tcpreceive *x, int fd) { int i; for (i = 0; i < MAX_CONNECTIONS; ++i) { if (x->x_connection[i].socket == fd) { x->x_connection[i].socket = -1; x->x_connection[i].addr = 0L; return 1; } } return 0; }
/* tcpreceive_getconnection tries to find the socket fd in the list */ /* returns addr on success, else 0 */ static long tcpreceive_getconnection(t_tcpreceive *x, int fd) { int i; for (i = 0; i < MAX_CONNECTIONS; ++i) { if (x->x_connection[i].socket == fd) return x->x_connection[i].addr; } return 0; }
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); } tcpreceive_closeall(x); }
#ifdef MSW __declspec(dllexport) #endif void tcpreceive_setup(void) { tcpreceive_class = class_new(gensym("tcpreceive"), (t_newmethod)tcpreceive_new, (t_method)tcpreceive_free, sizeof(t_tcpreceive), CLASS_NOINLET, A_DEFFLOAT, 0); }
/* end x_net_tcpreceive.c */
--- NEW FILE: x_net_tcp_client.c --- /* x_net_tcp_client.c Martin Peach 20060508, working version 20060512 */ /* linux version 20060515 */ /* x_net_tcp_client.c is based on netclient: */ /* -------------------------- netclient ------------------------------------- */ /* */ /* Extended 'netsend', connects to 'netserver'. */ /* Uses child thread to connect to server. Thus needs pd0.35-test17 or later. */ /* Written by Olaf Matthes (olaf.matthes@gmx.de) */ /* Get source at http://www.akustische-kunst.org/puredata/maxlib/ */ /* */ /* 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /* */ /* Based on PureData by Miller Puckette and others. */ /* */ /* ---------------------------------------------------------------------------- */ //define DEBUG
#include "m_pd.h" #include "s_stuff.h"
#include <stdio.h> #include <sys/types.h> #include <string.h> #include <pthread.h> #if defined(UNIX) || defined(unix) #include <sys/socket.h> #include <sys/errno.h> #include <netinet/in.h> #include <netdb.h> #include <stdio.h> #include <unistd.h> #define SOCKET_ERROR -1 #else #include <winsock2.h> #endif
#define DEFPOLLTIME 20 /* check for input every 20 ms */
static t_class *tcpclient_class; static char objName[] = "tcpclient"; #define MAX_UDP_RECEIVE 65536L // longer than data in maximum UDP packet
typedef struct _tcpclient { t_object x_obj; t_clock *x_clock; t_clock *x_poll; t_outlet *x_msgout; t_outlet *x_addrout; t_outlet *x_outconnect; int x_dump; // 1 = hexdump received bytes 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 t_atom x_addrbytes[4]; // address we're connected to as 4 bytes t_atom x_msgoutbuf[MAX_UDP_RECEIVE]; // received data as float atoms unsigned char x_msginbuf[MAX_UDP_RECEIVE]; // received data as bytes /* multithread stuff */ pthread_t x_threadid; /* id of child thread */ pthread_attr_t x_threadattr; /* attributes of child thread */ } t_tcpclient;
static void tcpclient_dump(t_tcpclient *x, t_float dump); static void tcp_client_hexdump(unsigned char *buf, long len); static void tcpclient_tick(t_tcpclient *x); static void *tcpclient_child_connect(void *w); static void tcpclient_connect(t_tcpclient *x, t_symbol *hostname, t_floatarg fportno); static void tcpclient_disconnect(t_tcpclient *x); static void tcpclient_send(t_tcpclient *x, t_symbol *s, int argc, t_atom *argv); static void tcpclient_rcv(t_tcpclient *x); static void tcpclient_poll(t_tcpclient *x); static void *tcpclient_new(t_floatarg udpflag); static void tcpclient_free(t_tcpclient *x); #ifdef MSW __declspec(dllexport) #endif void tcpclient_setup(void);
static void tcpclient_dump(t_tcpclient *x, t_float dump) { x->x_dump = (dump == 0)?0:1; }
static void tcp_client_hexdump(unsigned char *buf, long len) { #define BYTES_PER_LINE 16 char hexStr[(3*BYTES_PER_LINE)+1]; char ascStr[BYTES_PER_LINE+1]; long i, j, k = 0L; #ifdef DEBUG post("tcp_client_hexdump %d", len); #endif while (k < len) { for (i = j = 0; i < BYTES_PER_LINE; ++i, ++k, j+=3) { if (k < len) { #ifdef MSW sprintf_s(&hexStr[j], 4, "%02X ", buf[k]); sprintf_s(&ascStr[i], 2, "%c", ((buf[k] >= 32) && (buf[k] <= 126))? buf[k]: '.'); #else snprintf(&hexStr[j], 4, "%02X ", buf[k]); snprintf(&ascStr[i], 2, "%c", ((buf[k] >= 32) && (buf[k] <= 126))? buf[k]: '.'); #endif } else { // the last line #ifdef MSW sprintf_s(&hexStr[j], 4, " "); sprintf_s(&ascStr[i], 2, " "); #else snprintf(&hexStr[j], 4, " "); snprintf(&ascStr[i], 2, " "); #endif } } post ("%s%s", hexStr, ascStr); } }
static void tcpclient_tick(t_tcpclient *x) { outlet_float(x->x_outconnect, 1); }
static void *tcpclient_child_connect(void *w) { t_tcpclient *x = (t_tcpclient*) w; struct sockaddr_in server; struct hostent *hp; int sockfd;
if (x->x_fd >= 0) { error("%s_connect: already connected", objName); return (x); }
/* create a socket */ sockfd = socket(AF_INET, SOCK_STREAM, 0); #ifdef DEBUG post("%s: send socket %d\n", objName, sockfd); #endif if (sockfd < 0) { sys_sockerror("tcpclient: socket"); return (x); } /* connect socket using hostname provided in command line */ server.sin_family = AF_INET; hp = gethostbyname(x->x_hostname); if (hp == 0) { sys_sockerror("tcpclient: bad host?\n"); return (x); } memcpy((char *)&server.sin_addr, (char *)hp->h_addr, hp->h_length);
/* assign client port number */ server.sin_port = htons((u_short)x->x_port);
post("%s: connecting socket %d to port %d", objName, sockfd, x->x_port); /* try to connect */ if (connect(sockfd, (struct sockaddr *) &server, sizeof (server)) < 0) { sys_sockerror("tcpclient: connecting stream socket"); sys_closesocket(sockfd); return (x); } x->x_fd = sockfd; x->x_addr = ntohl(*(long *)hp->h_addr); /* outlet_float is not threadsafe ! */ // outlet_float(x->x_obj.ob_outlet, 1); x->x_connectstate = 1; /* use callback instead to set outlet */ clock_delay(x->x_clock, 0); return (x); }
static void tcpclient_connect(t_tcpclient *x, t_symbol *hostname, t_floatarg fportno) { /* 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) post("%s: could not create new thread", objName); }
static void tcpclient_disconnect(t_tcpclient *x) { if (x->x_fd >= 0) { sys_closesocket(x->x_fd); x->x_fd = -1; x->x_connectstate = 0; outlet_float(x->x_outconnect, 0); post("%s: disconnected", objName); } else post("%s: not connected", objName); }
static void tcpclient_send(t_tcpclient *x, t_symbol *s, int argc, t_atom *argv) { static char byte_buf[65536];// arbitrary maximum similar to max IP packet size int i, d; 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;
#ifdef DEBUG post("s: %s", s->s_name); post("argc: %d", argc); #endif
for (i = 0; i < argc; ++i) { if (argv[i].a_type == A_FLOAT) { f = argv[i].a_w.w_float; d = (int)f; e = f - d; #ifdef DEBUG post("%s: argv[%d]: float:%f int:%d delta:%f", objName, i, f, d, e); #endif if (e != 0) { error("%s_send: item %d (%f) is not an integer", objName, i, f); return; } if ((d < 0) || (d > 255)) { error("%s: item %d (%f) is not between 0 and 255", objName, i, f); return; } c = (unsigned char)d; #ifdef DEBUG post("%s_send: argv[%d]: %d", objName, i, c); #endif byte_buf[i] = c; } else { error("%s_send: item %d is not a float", objName, i); return; } }
length = i; 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("%s_send blocked %d msec", objName, (int)(1000 * ((timeafter - timebefore) + pleasewarn))); pleasewarn = 0; lastwarntime = timeafter; } else if (late) pleasewarn += timeafter - timebefore; } if (result <= 0) { sys_sockerror("tcpclient_send"); tcpclient_disconnect(x); break; } else { sent += result; bp += result; } } } else error("%s: not connected", objName); }
static void tcpclient_rcv(t_tcpclient *x) { int sockfd = x->x_fd; int ret; int i; fd_set readset; fd_set exceptset; struct timeval ztout;
if(x->x_connectstate) { /* check if we can read/write from/to the socket */ FD_ZERO(&readset); FD_ZERO(&exceptset); FD_SET(x->x_fd, &readset ); FD_SET(x->x_fd, &exceptset );
ztout.tv_sec = 0; ztout.tv_usec = 0;
ret = select(sockfd+1, &readset, NULL, &exceptset, &ztout); if(ret < 0) { error("%s: unable to read from socket", objName); sys_closesocket(sockfd); return; } if(FD_ISSET(sockfd, &readset) || FD_ISSET(sockfd, &exceptset)) { /* read from server */ ret = recv(sockfd, x->x_msginbuf, MAX_UDP_RECEIVE, 0); if(ret > 0) { #ifdef DEBUG x->x_msginbuf[ret] = 0; post("%s: received %d bytes ", objName, ret); #endif if (x->x_dump)tcp_client_hexdump(x->x_msginbuf, ret); for (i = 0; i < ret; ++i) { /* convert the bytes in the buffer to floats in a list */ x->x_msgoutbuf[i].a_w.w_float = (float)x->x_msginbuf[i]; } /* find sender's ip address and output it */ x->x_addrbytes[0].a_w.w_float = (x->x_addr & 0xFF000000)>>24; x->x_addrbytes[1].a_w.w_float = (x->x_addr & 0x0FF0000)>>16; x->x_addrbytes[2].a_w.w_float = (x->x_addr & 0x0FF00)>>8; x->x_addrbytes[3].a_w.w_float = (x->x_addr & 0x0FF); outlet_list(x->x_addrout, &s_list, 4L, x->x_addrbytes); /* send the list out the outlet */ if (ret > 1) outlet_list(x->x_msgout, &s_list, ret, x->x_msgoutbuf); else outlet_float(x->x_msgout, x->x_msgoutbuf[0].a_w.w_float); } else { if (ret < 0) { sys_sockerror("tcpclient: recv"); tcpclient_disconnect(x); } else { post("%s: connection closed for socket %d\n", objName, sockfd); tcpclient_disconnect(x); } } } } else post("%s: not connected", objName); }
static void tcpclient_poll(t_tcpclient *x) { if(x->x_connectstate) tcpclient_rcv(x); /* try to read in case we're connected */ clock_delay(x->x_poll, DEFPOLLTIME); /* see you later */ }
static void *tcpclient_new(t_floatarg udpflag) { int i;
t_tcpclient *x = (t_tcpclient *)pd_new(tcpclient_class); x->x_msgout = outlet_new(&x->x_obj, &s_anything); /* received data */ x->x_addrout = outlet_new(&x->x_obj, &s_list); x->x_outconnect = outlet_new(&x->x_obj, &s_float); /* connection state */ x->x_clock = clock_new(x, (t_method)tcpclient_tick); x->x_poll = clock_new(x, (t_method)tcpclient_poll); x->x_fd = -1; /* convert the bytes in the buffer to floats in a list */ for (i = 0; i < MAX_UDP_RECEIVE; ++i) { x->x_msgoutbuf[i].a_type = A_FLOAT; x->x_msgoutbuf[i].a_w.w_float = 0; } for (i = 0; i < 4; ++i) { x->x_addrbytes[i].a_type = A_FLOAT; x->x_addrbytes[i].a_w.w_float = 0; } x->x_addr = 0L; /* prepare child thread */ if(pthread_attr_init(&x->x_threadattr) < 0) post("%s: warning: could not prepare child thread", objName); if(pthread_attr_setdetachstate(&x->x_threadattr, PTHREAD_CREATE_DETACHED) < 0) post("%s: warning: could not prepare child thread", objName); clock_delay(x->x_poll, 0); /* start polling the input */ return (x); }
static void tcpclient_free(t_tcpclient *x) { tcpclient_disconnect(x); clock_free(x->x_poll); clock_free(x->x_clock); }
#ifdef MSW __declspec(dllexport) #endif void tcpclient_setup(void) { 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") , A_SYMBOL, A_FLOAT, 0); class_addmethod(tcpclient_class, (t_method)tcpclient_disconnect, gensym("disconnect"), 0); class_addmethod(tcpclient_class, (t_method)tcpclient_send, gensym("send"), A_GIMME, 0); class_addmethod(tcpclient_class, (t_method)tcpclient_rcv, gensym("receive"), 0); class_addmethod(tcpclient_class, (t_method)tcpclient_rcv, gensym("rcv"), 0); class_addmethod(tcpclient_class, (t_method)tcpclient_dump, gensym("dump"), A_FLOAT, 0); }
/* end of x_net_tcp.c */
--- NEW FILE: tcpsend-help.pd --- #N canvas 0 0 555 316 12; #X msg 177 158 disconnect; #X msg 171 96 connect 127.0.0.1 9997; #X obj 171 207 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0 1; #X obj 171 184 tcpsend; #X text 375 97 <--first; #X msg 67 129 send 0 1 2 3; #X text 10 38 tcpsend sends bytes over a tcp connection.; #X text 10 61 Used in conjunction with packOSC will send OSC over tcp ; #X text 236 259 Martin Peach 2006/04/21; #X connect 0 0 3 0; #X connect 1 0 3 0; #X connect 3 0 2 0; #X connect 5 0 3 0;
--- NEW FILE: x_net_tcpsend.c --- /* x_net_tcpsend.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"
#ifdef MSW #include <winsock2.h> #else #include <sys/socket.h> #include <netinet/in.h> #include <netinet/tcp.h> #include <netdb.h> #include <stdio.h> #include <string.h> #endif
static t_class *tcpsend_class;
typedef struct _tcpsend { t_object x_obj; int x_fd; } t_tcpsend;
#ifdef MSW __declspec(dllexport) #endif void tcpsend_setup(void); static void tcpsend_free(t_tcpsend *x); static void tcpsend_send(t_tcpsend *x, t_symbol *s, int argc, t_atom *argv); static void tcpsend_disconnect(t_tcpsend *x); static void tcpsend_connect(t_tcpsend *x, t_symbol *hostname, t_floatarg fportno); static void *tcpsend_new(void);
static void *tcpsend_new(void) { t_tcpsend *x = (t_tcpsend *)pd_new(tcpsend_class); outlet_new(&x->x_obj, &s_float); x->x_fd = -1; return (x); }
static void tcpsend_connect(t_tcpsend *x, t_symbol *hostname, t_floatarg fportno) { struct sockaddr_in server; struct hostent *hp; int sockfd; int portno = fportno; int intarg;
if (x->x_fd >= 0) { error("tcpsend: already connected"); return; }
/* create a socket */ sockfd = socket(AF_INET, SOCK_STREAM, 0); #ifdef DEBUG fprintf(stderr, "tcpsend_connect: send socket %d\n", sockfd); #endif 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; } /* for stream (TCP) sockets, specify "nodelay" */ intarg = 1; if (setsockopt(sockfd, IPPROTO_TCP, TCP_NODELAY, (char *)&intarg, sizeof(intarg)) < 0) post("tcpsend: setsockopt (TCP_NODELAY) failed\n");
memcpy((char *)&server.sin_addr, (char *)hp->h_addr, hp->h_length);
/* assign client port number */ server.sin_port = htons((u_short)portno);
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; } x->x_fd = sockfd; outlet_float(x->x_obj.ob_outlet, 1); }
static void tcpsend_disconnect(t_tcpsend *x) { if (x->x_fd >= 0) { sys_closesocket(x->x_fd); x->x_fd = -1; outlet_float(x->x_obj.ob_outlet, 0); post("tcpsend: disconnected"); } }
static void tcpsend_send(t_tcpsend *x, t_symbol *s, int argc, t_atom *argv) { static char byte_buf[65536];// arbitrary maximum similar to max IP packet size int i, d; char c; float f, e; char *bp; int length, sent; int result; static double lastwarntime; static double pleasewarn; double timebefore; double timeafter; int late;
#ifdef DEBUG post("s: %s", s->s_name); post("argc: %d", argc); #endif for (i = 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("tcpsend_send: item %d (%f) is not an integer", i, f); return; } c = (unsigned char)d; if (c != d) { error("tcpsend_send: item %d (%f) is not between 0 and 255", i, f); return; } #ifdef DEBUG post("tcpsend_send: argv[%d]: %d", i, c); #endif byte_buf[i] = c; } else { error("tcpsend_send: item %d is not a float", i); return; } }
length = i; 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("tcpsend blocked %d msec", (int)(1000 * ((timeafter - timebefore) + pleasewarn))); pleasewarn = 0; lastwarntime = timeafter; } else if (late) pleasewarn += timeafter - timebefore; } if (result <= 0) { sys_sockerror("tcpsend"); tcpsend_disconnect(x); break; } else { sent += result; bp += result; } } } else error("tcpsend: not connected"); }
static void tcpsend_free(t_tcpsend *x) { tcpsend_disconnect(x); }
#ifdef MSW __declspec(dllexport) #endif void tcpsend_setup(void) { tcpsend_class = class_new(gensym("tcpsend"), (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); class_addmethod(tcpsend_class, (t_method)tcpsend_disconnect, gensym("disconnect"), 0); class_addmethod(tcpsend_class, (t_method)tcpsend_send, gensym("send"), A_GIMME, 0); }
/* end x_net_tcpsend.c*/