aboutsummaryrefslogtreecommitdiff
path: root/net
diff options
context:
space:
mode:
Diffstat (limited to 'net')
-rwxr-xr-xnet/tcpclient-help.pd72
-rwxr-xr-xnet/tcpreceive-help.pd20
-rwxr-xr-xnet/tcpsend-help.pd16
-rwxr-xr-xnet/tcpserver-help.pd72
-rwxr-xr-xnet/udpreceive-help.pd17
-rwxr-xr-xnet/udpsend-help.pd16
-rwxr-xr-xnet/x_net_tcp_client.c443
-rwxr-xr-xnet/x_net_tcp_server.c600
-rwxr-xr-xnet/x_net_tcpclient.c443
-rwxr-xr-xnet/x_net_tcpreceive.c313
-rwxr-xr-xnet/x_net_tcpsend.c221
-rwxr-xr-xnet/x_net_tcpserver.c619
-rwxr-xr-xnet/x_net_udpreceive.c161
-rwxr-xr-xnet/x_net_udpsend.c214
14 files changed, 3227 insertions, 0 deletions
diff --git a/net/tcpclient-help.pd b/net/tcpclient-help.pd
new file mode 100755
index 0000000..952ea84
--- /dev/null
+++ b/net/tcpclient-help.pd
@@ -0,0 +1,72 @@
+#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;
diff --git a/net/tcpreceive-help.pd b/net/tcpreceive-help.pd
new file mode 100755
index 0000000..b2d781d
--- /dev/null
+++ b/net/tcpreceive-help.pd
@@ -0,0 +1,20 @@
+#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;
diff --git a/net/tcpsend-help.pd b/net/tcpsend-help.pd
new file mode 100755
index 0000000..e61a322
--- /dev/null
+++ b/net/tcpsend-help.pd
@@ -0,0 +1,16 @@
+#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;
diff --git a/net/tcpserver-help.pd b/net/tcpserver-help.pd
new file mode 100755
index 0000000..33e4b13
--- /dev/null
+++ b/net/tcpserver-help.pd
@@ -0,0 +1,72 @@
+#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;
diff --git a/net/udpreceive-help.pd b/net/udpreceive-help.pd
new file mode 100755
index 0000000..b86e734
--- /dev/null
+++ b/net/udpreceive-help.pd
@@ -0,0 +1,17 @@
+#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;
diff --git a/net/udpsend-help.pd b/net/udpsend-help.pd
new file mode 100755
index 0000000..629eace
--- /dev/null
+++ b/net/udpsend-help.pd
@@ -0,0 +1,16 @@
+#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;
diff --git a/net/x_net_tcp_client.c b/net/x_net_tcp_client.c
new file mode 100755
index 0000000..366d421
--- /dev/null
+++ b/net/x_net_tcp_client.c
@@ -0,0 +1,443 @@
+/* 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 */
diff --git a/net/x_net_tcp_server.c b/net/x_net_tcp_server.c
new file mode 100755
index 0000000..4438215
--- /dev/null
+++ b/net/x_net_tcp_server.c
@@ -0,0 +1,600 @@
+/* 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);
+}
diff --git a/net/x_net_tcpclient.c b/net/x_net_tcpclient.c
new file mode 100755
index 0000000..366d421
--- /dev/null
+++ b/net/x_net_tcpclient.c
@@ -0,0 +1,443 @@
+/* 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 */
diff --git a/net/x_net_tcpreceive.c b/net/x_net_tcpreceive.c
new file mode 100755
index 0000000..d5884e1
--- /dev/null
+++ b/net/x_net_tcpreceive.c
@@ -0,0 +1,313 @@
+/* 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 */
+
diff --git a/net/x_net_tcpsend.c b/net/x_net_tcpsend.c
new file mode 100755
index 0000000..1a9937b
--- /dev/null
+++ b/net/x_net_tcpsend.c
@@ -0,0 +1,221 @@
+/* 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*/
diff --git a/net/x_net_tcpserver.c b/net/x_net_tcpserver.c
new file mode 100755
index 0000000..f6526c0
--- /dev/null
+++ b/net/x_net_tcpserver.c
@@ -0,0 +1,619 @@
+/* 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 */
diff --git a/net/x_net_udpreceive.c b/net/x_net_udpreceive.c
new file mode 100755
index 0000000..1aa9058
--- /dev/null
+++ b/net/x_net_udpreceive.c
@@ -0,0 +1,161 @@
+/* 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 */
+
diff --git a/net/x_net_udpsend.c b/net/x_net_udpsend.c
new file mode 100755
index 0000000..03c1f18
--- /dev/null
+++ b/net/x_net_udpsend.c
@@ -0,0 +1,214 @@
+/* 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*/
+