[PD-cvs] externals/mrpeach/net tcpclient.c, NONE, 1.1 tcpreceive.c, NONE, 1.1 tcpsend.c, NONE, 1.1 tcpserver.c, NONE, 1.1 udpreceive.c, NONE, 1.1 udpsend.c, NONE, 1.1 x_net_tcp_client.c, 1.1, NONE x_net_tcp_server.c, 1.1, NONE x_net_tcpclient.c, 1.1, NONE x_net_tcpreceive.c, 1.2, NONE x_net_tcpsend.c, 1.2, NONE x_net_tcpserver.c, 1.1, NONE x_net_udpreceive.c, 1.2, NONE x_net_udpsend.c, 1.2, NONE
Martin Peach
mrpeach at users.sourceforge.net
Thu Aug 24 08:51:18 CEST 2006
Update of /cvsroot/pure-data/externals/mrpeach/net
In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv8470
Added Files:
tcpclient.c tcpreceive.c tcpsend.c tcpserver.c udpreceive.c
udpsend.c
Removed Files:
x_net_tcp_client.c x_net_tcp_server.c x_net_tcpclient.c
x_net_tcpreceive.c x_net_tcpsend.c x_net_tcpserver.c
x_net_udpreceive.c x_net_udpsend.c
Log Message:
Renamed files without x_net_ prefix.
Removed extra copies of tcpserver and tcpclient
--- x_net_udpsend.c DELETED ---
--- x_net_tcpclient.c DELETED ---
--- x_net_udpreceive.c DELETED ---
--- NEW FILE: tcpsend.c ---
/* x_net_tcpsend.c 20060424 Martin Peach did it based on x_net.c. x_net.c header follows: */
/* Copyright (c) 1997-1999 Miller Puckette.
* For information on usage and redistribution, and for a DISCLAIMER OF ALL
* WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
/* network */
#include "m_pd.h"
#include "s_stuff.h"
#ifdef MSW
#include <winsock2.h>
#else
#include <sys/types.h>
#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*/
--- NEW FILE: tcpclient.c ---
/* x_net_tcp_client.c Martin Peach 20060508, working version 20060512 */
/* linux version 20060515 */
/* x_net_tcp_client.c is based on netclient: */
/* -------------------------- netclient ------------------------------------- */
/* */
/* Extended 'netsend', connects to 'netserver'. */
/* Uses child thread to connect to server. Thus needs pd0.35-test17 or later. */
/* Written by Olaf Matthes (olaf.matthes at gmx.de) */
/* Get source at http://www.akustische-kunst.org/puredata/maxlib/ */
/* */
/* This program is free software; you can redistribute it and/or */
/* modify it under the terms of the GNU General Public License */
/* as published by the Free Software Foundation; either version 2 */
/* of the License, or (at your option) any later version. */
/* */
/* This program is distributed in the hope that it will be useful, */
/* but WITHOUT ANY WARRANTY; without even the implied warranty of */
/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
/* GNU General Public License for more details. */
/* */
/* You should have received a copy of the GNU General Public License */
/* along with this program; if not, write to the Free Software */
/* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
/* */
/* Based on PureData by Miller Puckette and others. */
/* */
/* ---------------------------------------------------------------------------- */
//define DEBUG
#include "m_pd.h"
#include "s_stuff.h"
#include <stdio.h>
#include <sys/types.h>
#include <string.h>
#include <pthread.h>
#if defined(UNIX) || defined(unix)
#include <sys/socket.h>
#include <sys/errno.h>
#include <netinet/in.h>
#include <netdb.h>
#include <stdio.h>
#include <unistd.h>
#define SOCKET_ERROR -1
#else
#include <winsock2.h>
#endif
#define DEFPOLLTIME 20 /* check for input every 20 ms */
static t_class *tcpclient_class;
static char objName[] = "tcpclient";
#define MAX_UDP_RECEIVE 65536L // longer than data in maximum UDP packet
typedef struct _tcpclient
{
t_object x_obj;
t_clock *x_clock;
t_clock *x_poll;
t_outlet *x_msgout;
t_outlet *x_addrout;
t_outlet *x_outconnect;
int x_dump; // 1 = hexdump received bytes
int x_fd; // the socket
char *x_hostname; // address we want to connect to as text
int x_connectstate; // 0 = not connected, 1 = connected
int x_port; // port we're connected to
long x_addr; // address we're connected to as 32bit int
t_atom x_addrbytes[4]; // address we're connected to as 4 bytes
t_atom x_msgoutbuf[MAX_UDP_RECEIVE]; // received data as float atoms
unsigned char x_msginbuf[MAX_UDP_RECEIVE]; // received data as bytes
/* multithread stuff */
pthread_t x_threadid; /* id of child thread */
pthread_attr_t x_threadattr; /* attributes of child thread */
} t_tcpclient;
static void tcpclient_dump(t_tcpclient *x, t_float dump);
static void tcp_client_hexdump(unsigned char *buf, long len);
static void tcpclient_tick(t_tcpclient *x);
static void *tcpclient_child_connect(void *w);
static void tcpclient_connect(t_tcpclient *x, t_symbol *hostname, t_floatarg fportno);
static void tcpclient_disconnect(t_tcpclient *x);
static void tcpclient_send(t_tcpclient *x, t_symbol *s, int argc, t_atom *argv);
static void tcpclient_rcv(t_tcpclient *x);
static void tcpclient_poll(t_tcpclient *x);
static void *tcpclient_new(t_floatarg udpflag);
static void tcpclient_free(t_tcpclient *x);
#ifdef MSW
__declspec(dllexport)
#endif
void tcpclient_setup(void);
static void tcpclient_dump(t_tcpclient *x, t_float dump)
{
x->x_dump = (dump == 0)?0:1;
}
static void tcp_client_hexdump(unsigned char *buf, long len)
{
#define BYTES_PER_LINE 16
char hexStr[(3*BYTES_PER_LINE)+1];
char ascStr[BYTES_PER_LINE+1];
long i, j, k = 0L;
#ifdef DEBUG
post("tcp_client_hexdump %d", len);
#endif
while (k < len)
{
for (i = j = 0; i < BYTES_PER_LINE; ++i, ++k, j+=3)
{
if (k < len)
{
#ifdef MSW
sprintf_s(&hexStr[j], 4, "%02X ", buf[k]);
sprintf_s(&ascStr[i], 2, "%c", ((buf[k] >= 32) && (buf[k] <= 126))? buf[k]: '.');
#else
snprintf(&hexStr[j], 4, "%02X ", buf[k]);
snprintf(&ascStr[i], 2, "%c", ((buf[k] >= 32) && (buf[k] <= 126))? buf[k]: '.');
#endif
}
else
{ // the last line
#ifdef MSW
sprintf_s(&hexStr[j], 4, " ");
sprintf_s(&ascStr[i], 2, " ");
#else
snprintf(&hexStr[j], 4, " ");
snprintf(&ascStr[i], 2, " ");
#endif
}
}
post ("%s%s", hexStr, ascStr);
}
}
static void tcpclient_tick(t_tcpclient *x)
{
outlet_float(x->x_outconnect, 1);
}
static void *tcpclient_child_connect(void *w)
{
t_tcpclient *x = (t_tcpclient*) w;
struct sockaddr_in server;
struct hostent *hp;
int sockfd;
if (x->x_fd >= 0)
{
error("%s_connect: already connected", objName);
return (x);
}
/* create a socket */
sockfd = socket(AF_INET, SOCK_STREAM, 0);
#ifdef DEBUG
post("%s: send socket %d\n", objName, sockfd);
#endif
if (sockfd < 0)
{
sys_sockerror("tcpclient: socket");
return (x);
}
/* connect socket using hostname provided in command line */
server.sin_family = AF_INET;
hp = gethostbyname(x->x_hostname);
if (hp == 0)
{
sys_sockerror("tcpclient: bad host?\n");
return (x);
}
memcpy((char *)&server.sin_addr, (char *)hp->h_addr, hp->h_length);
/* assign client port number */
server.sin_port = htons((u_short)x->x_port);
post("%s: connecting socket %d to port %d", objName, sockfd, x->x_port);
/* try to connect */
if (connect(sockfd, (struct sockaddr *) &server, sizeof (server)) < 0)
{
sys_sockerror("tcpclient: connecting stream socket");
sys_closesocket(sockfd);
return (x);
}
x->x_fd = sockfd;
x->x_addr = ntohl(*(long *)hp->h_addr);
/* outlet_float is not threadsafe ! */
// outlet_float(x->x_obj.ob_outlet, 1);
x->x_connectstate = 1;
/* use callback instead to set outlet */
clock_delay(x->x_clock, 0);
return (x);
}
static void tcpclient_connect(t_tcpclient *x, t_symbol *hostname, t_floatarg fportno)
{
/* we get hostname and port and pass them on
to the child thread that establishes the connection */
x->x_hostname = hostname->s_name;
x->x_port = fportno;
x->x_connectstate = 0;
/* start child thread */
if(pthread_create(&x->x_threadid, &x->x_threadattr, tcpclient_child_connect, x) < 0)
post("%s: could not create new thread", objName);
}
static void tcpclient_disconnect(t_tcpclient *x)
{
if (x->x_fd >= 0)
{
sys_closesocket(x->x_fd);
x->x_fd = -1;
x->x_connectstate = 0;
outlet_float(x->x_outconnect, 0);
post("%s: disconnected", objName);
}
else post("%s: not connected", objName);
}
static void tcpclient_send(t_tcpclient *x, t_symbol *s, int argc, t_atom *argv)
{
static char byte_buf[65536];// arbitrary maximum similar to max IP packet size
int i, d;
unsigned char c;
float f, e;
char *bp;
int length, sent;
int result;
static double lastwarntime;
static double pleasewarn;
double timebefore;
double timeafter;
int late;
#ifdef DEBUG
post("s: %s", s->s_name);
post("argc: %d", argc);
#endif
for (i = 0; i < argc; ++i)
{
if (argv[i].a_type == A_FLOAT)
{
f = argv[i].a_w.w_float;
d = (int)f;
e = f - d;
#ifdef DEBUG
post("%s: argv[%d]: float:%f int:%d delta:%f", objName, i, f, d, e);
#endif
if (e != 0)
{
error("%s_send: item %d (%f) is not an integer", objName, i, f);
return;
}
if ((d < 0) || (d > 255))
{
error("%s: item %d (%f) is not between 0 and 255", objName, i, f);
return;
}
c = (unsigned char)d;
#ifdef DEBUG
post("%s_send: argv[%d]: %d", objName, i, c);
#endif
byte_buf[i] = c;
}
else
{
error("%s_send: item %d is not a float", objName, i);
return;
}
}
length = i;
if ((x->x_fd >= 0) && (length > 0))
{
for (bp = byte_buf, sent = 0; sent < length;)
{
timebefore = sys_getrealtime();
result = send(x->x_fd, byte_buf, length-sent, 0);
timeafter = sys_getrealtime();
late = (timeafter - timebefore > 0.005);
if (late || pleasewarn)
{
if (timeafter > lastwarntime + 2)
{
post("%s_send blocked %d msec", objName,
(int)(1000 * ((timeafter - timebefore) + pleasewarn)));
pleasewarn = 0;
lastwarntime = timeafter;
}
else if (late) pleasewarn += timeafter - timebefore;
}
if (result <= 0)
{
sys_sockerror("tcpclient_send");
tcpclient_disconnect(x);
break;
}
else
{
sent += result;
bp += result;
}
}
}
else error("%s: not connected", objName);
}
static void tcpclient_rcv(t_tcpclient *x)
{
int sockfd = x->x_fd;
int ret;
int i;
fd_set readset;
fd_set exceptset;
struct timeval ztout;
if(x->x_connectstate)
{
/* check if we can read/write from/to the socket */
FD_ZERO(&readset);
FD_ZERO(&exceptset);
FD_SET(x->x_fd, &readset );
FD_SET(x->x_fd, &exceptset );
ztout.tv_sec = 0;
ztout.tv_usec = 0;
ret = select(sockfd+1, &readset, NULL, &exceptset, &ztout);
if(ret < 0)
{
error("%s: unable to read from socket", objName);
sys_closesocket(sockfd);
return;
}
if(FD_ISSET(sockfd, &readset) || FD_ISSET(sockfd, &exceptset))
{
/* read from server */
ret = recv(sockfd, x->x_msginbuf, MAX_UDP_RECEIVE, 0);
if(ret > 0)
{
#ifdef DEBUG
x->x_msginbuf[ret] = 0;
post("%s: received %d bytes ", objName, ret);
#endif
if (x->x_dump)tcp_client_hexdump(x->x_msginbuf, ret);
for (i = 0; i < ret; ++i)
{
/* convert the bytes in the buffer to floats in a list */
x->x_msgoutbuf[i].a_w.w_float = (float)x->x_msginbuf[i];
}
/* find sender's ip address and output it */
x->x_addrbytes[0].a_w.w_float = (x->x_addr & 0xFF000000)>>24;
x->x_addrbytes[1].a_w.w_float = (x->x_addr & 0x0FF0000)>>16;
x->x_addrbytes[2].a_w.w_float = (x->x_addr & 0x0FF00)>>8;
x->x_addrbytes[3].a_w.w_float = (x->x_addr & 0x0FF);
outlet_list(x->x_addrout, &s_list, 4L, x->x_addrbytes);
/* send the list out the outlet */
if (ret > 1) outlet_list(x->x_msgout, &s_list, ret, x->x_msgoutbuf);
else outlet_float(x->x_msgout, x->x_msgoutbuf[0].a_w.w_float);
}
else
{
if (ret < 0)
{
sys_sockerror("tcpclient: recv");
tcpclient_disconnect(x);
}
else
{
post("%s: connection closed for socket %d\n", objName, sockfd);
tcpclient_disconnect(x);
}
}
}
}
else post("%s: not connected", objName);
}
static void tcpclient_poll(t_tcpclient *x)
{
if(x->x_connectstate)
tcpclient_rcv(x); /* try to read in case we're connected */
clock_delay(x->x_poll, DEFPOLLTIME); /* see you later */
}
static void *tcpclient_new(t_floatarg udpflag)
{
int i;
t_tcpclient *x = (t_tcpclient *)pd_new(tcpclient_class);
x->x_msgout = outlet_new(&x->x_obj, &s_anything); /* received data */
x->x_addrout = outlet_new(&x->x_obj, &s_list);
x->x_outconnect = outlet_new(&x->x_obj, &s_float); /* connection state */
x->x_clock = clock_new(x, (t_method)tcpclient_tick);
x->x_poll = clock_new(x, (t_method)tcpclient_poll);
x->x_fd = -1;
/* convert the bytes in the buffer to floats in a list */
for (i = 0; i < MAX_UDP_RECEIVE; ++i)
{
x->x_msgoutbuf[i].a_type = A_FLOAT;
x->x_msgoutbuf[i].a_w.w_float = 0;
}
for (i = 0; i < 4; ++i)
{
x->x_addrbytes[i].a_type = A_FLOAT;
x->x_addrbytes[i].a_w.w_float = 0;
}
x->x_addr = 0L;
/* prepare child thread */
if(pthread_attr_init(&x->x_threadattr) < 0)
post("%s: warning: could not prepare child thread", objName);
if(pthread_attr_setdetachstate(&x->x_threadattr, PTHREAD_CREATE_DETACHED) < 0)
post("%s: warning: could not prepare child thread", objName);
clock_delay(x->x_poll, 0); /* start polling the input */
return (x);
}
static void tcpclient_free(t_tcpclient *x)
{
tcpclient_disconnect(x);
clock_free(x->x_poll);
clock_free(x->x_clock);
}
#ifdef MSW
__declspec(dllexport)
#endif
void tcpclient_setup(void)
{
tcpclient_class = class_new(gensym(objName), (t_newmethod)tcpclient_new,
(t_method)tcpclient_free,
sizeof(t_tcpclient), 0, A_DEFFLOAT, 0);
class_addmethod(tcpclient_class, (t_method)tcpclient_connect, gensym("connect")
, A_SYMBOL, A_FLOAT, 0);
class_addmethod(tcpclient_class, (t_method)tcpclient_disconnect, gensym("disconnect"), 0);
class_addmethod(tcpclient_class, (t_method)tcpclient_send, gensym("send"), A_GIMME, 0);
class_addmethod(tcpclient_class, (t_method)tcpclient_rcv, gensym("receive"), 0);
class_addmethod(tcpclient_class, (t_method)tcpclient_rcv, gensym("rcv"), 0);
class_addmethod(tcpclient_class, (t_method)tcpclient_dump, gensym("dump"), A_FLOAT, 0);
}
/* end of x_net_tcp.c */
--- NEW FILE: udpsend.c ---
/* x_net_udpsend.c 20060424. Martin Peach did it based on x_net.c. x_net.c header follows: */
/* Copyright (c) 1997-1999 Miller Puckette.
* For information on usage and redistribution, and for a DISCLAIMER OF ALL
* WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
/* network */
#include "m_pd.h"
#include "s_stuff.h"
#include <stdio.h>
#include <string.h>
#ifdef MSW
#include <winsock2.h>
#else
#include <sys/types.h>
#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*/
--- x_net_tcpserver.c DELETED ---
--- NEW FILE: tcpserver.c ---
/* x_net_tcpserver.c Martin Peach 20060511 working version 20060512 */
/* 20060515 works on linux too... */
/* x_net_tcpserver.c is based on netserver: */
/* -------------------------- netserver ------------------------------------- */
/* */
/* A server for bidirectional communication from within Pd. */
/* Allows to send back data to specific clients connected to the server. */
/* Written by Olaf Matthes <olaf.matthes at 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 */
--- x_net_tcp_server.c DELETED ---
--- NEW FILE: udpreceive.c ---
/* x_net_udpreceive.c 20060424. Martin Peach did it based on x_net.c. x_net.c header follows: */
/* Copyright (c) 1997-1999 Miller Puckette.
* For information on usage and redistribution, and for a DISCLAIMER OF ALL
* WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
#include "m_pd.h"
#include "s_stuff.h"
#ifdef MSW
#include <winsock2.h>
#include <ws2tcpip.h>
#else
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <netdb.h>
#include <stdio.h>
#endif
/* ----------------------------- udpreceive ------------------------- */
static t_class *udpreceive_class;
#define MAX_UDP_RECEIVE 65536L // longer than data in maximum UDP packet
typedef struct _udpreceive
{
t_object x_obj;
t_outlet *x_msgout;
t_outlet *x_addrout;
int x_connectsocket;
t_atom x_addrbytes[4];
t_atom x_msgoutbuf[MAX_UDP_RECEIVE];
char x_msginbuf[MAX_UDP_RECEIVE];
} t_udpreceive;
#ifdef MSW
__declspec(dllexport)
#endif
void udpreceive_setup(void);
static void udpreceive_free(t_udpreceive *x);
static void *udpreceive_new(t_floatarg fportno);
static void udpreceive_read(t_udpreceive *x, int sockfd);
static void udpreceive_read(t_udpreceive *x, int sockfd)
{
int i, read = 0;
struct sockaddr_in from;
socklen_t fromlen = sizeof(from);
long addr;
read = recvfrom(sockfd, x->x_msginbuf, MAX_UDP_RECEIVE, 0, (struct sockaddr *)&from, &fromlen);
#ifdef DEBUG
post("udpreceive_read: read %lu x->x_connectsocket = %d",
read, x->x_connectsocket);
#endif
/* get the sender's ip */
addr = ntohl(from.sin_addr.s_addr);
x->x_addrbytes[0].a_w.w_float = (addr & 0xFF000000)>>24;
x->x_addrbytes[1].a_w.w_float = (addr & 0x0FF0000)>>16;
x->x_addrbytes[2].a_w.w_float = (addr & 0x0FF00)>>8;
x->x_addrbytes[3].a_w.w_float = (addr & 0x0FF);
outlet_list(x->x_addrout, &s_list, 4L, x->x_addrbytes);
if (read < 0)
{
sys_sockerror("udpreceive_read");
sys_closesocket(x->x_connectsocket);
return;
}
if (read > 0)
{
for (i = 0; i < read; ++i)
{
/* convert the bytes in the buffer to floats in a list */
x->x_msgoutbuf[i].a_w.w_float = (float)x->x_msginbuf[i];
}
/* send the list out the outlet */
if (read > 1) outlet_list(x->x_msgout, &s_list, read, x->x_msgoutbuf);
else outlet_float(x->x_msgout, x->x_msgoutbuf[0].a_w.w_float);
}
}
static void *udpreceive_new(t_floatarg fportno)
{
t_udpreceive *x;
struct sockaddr_in server;
int sockfd, portno = fportno;
int intarg, i;
/* create a socket */
sockfd = socket(AF_INET, SOCK_DGRAM, 0);
#ifdef DEBUG
post("udpreceive_new: socket %d port %d", sockfd, portno);
#endif
if (sockfd < 0)
{
sys_sockerror("udpreceive: socket");
return (0);
}
server.sin_family = AF_INET;
server.sin_addr.s_addr = INADDR_ANY;
/* ask OS to allow another Pd to repoen this port after we close it. */
intarg = 1;
if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR,
(char *)&intarg, sizeof(intarg)) < 0)
post("udpreceive: setsockopt (SO_REUSEADDR) failed");
/* assign server port number */
server.sin_port = htons((u_short)portno);
/* name the socket */
if (bind(sockfd, (struct sockaddr *)&server, sizeof(server)) < 0)
{
sys_sockerror("udpreceive: bind");
sys_closesocket(sockfd);
return (0);
}
x = (t_udpreceive *)pd_new(udpreceive_class);
x->x_msgout = outlet_new(&x->x_obj, &s_anything);
x->x_addrout = outlet_new(&x->x_obj, &s_list);
x->x_connectsocket = sockfd;
/* convert the bytes in the buffer to floats in a list */
for (i = 0; i < MAX_UDP_RECEIVE; ++i)
{
x->x_msgoutbuf[i].a_type = A_FLOAT;
x->x_msgoutbuf[i].a_w.w_float = 0;
}
for (i = 0; i < 4; ++i)
{
x->x_addrbytes[i].a_type = A_FLOAT;
x->x_addrbytes[i].a_w.w_float = 0;
}
sys_addpollfn(x->x_connectsocket, (t_fdpollfn)udpreceive_read, x);
return (x);
}
static void udpreceive_free(t_udpreceive *x)
{
if (x->x_connectsocket >= 0)
{
sys_rmpollfn(x->x_connectsocket);
sys_closesocket(x->x_connectsocket);
}
}
#ifdef MSW
__declspec(dllexport)
#endif
void udpreceive_setup(void)
{
udpreceive_class = class_new(gensym("udpreceive"),
(t_newmethod)udpreceive_new, (t_method)udpreceive_free,
sizeof(t_udpreceive), CLASS_NOINLET, A_DEFFLOAT, 0);
}
/* end x_net_udpreceive.c */
--- NEW FILE: tcpreceive.c ---
/* x_net_tcpreceive.c 20060424. Martin Peach did it based on x_net.c. x_net.c header follows: */
/* Copyright (c) 1997-1999 Miller Puckette.
* For information on usage and redistribution, and for a DISCLAIMER OF ALL
* WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
#include "m_pd.h"
#include "s_stuff.h"
#ifdef MSW
#include <winsock2.h>
#include <ws2tcpip.h> /* for socklen_t */
#else
#include <sys/types.h>
#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 */
--- x_net_tcpreceive.c DELETED ---
--- x_net_tcp_client.c DELETED ---
--- x_net_tcpsend.c DELETED ---
More information about the Pd-cvs
mailing list