[PD-cvs] externals/mrpeach/net tcpclient-help.pd, NONE, 1.1 tcpreceive-help.pd, NONE, 1.1 tcpsend-help.pd, NONE, 1.1 tcpserver-help.pd, NONE, 1.1 udpreceive-help.pd, NONE, 1.1 udpsend-help.pd, NONE, 1.1 x_net_tcp_client.c, NONE, 1.1 x_net_tcp_server.c, NONE, 1.1 x_net_tcpclient.c, NONE, 1.1 x_net_tcpreceive.c, NONE, 1.1 x_net_tcpsend.c, NONE, 1.1 x_net_tcpserver.c, NONE, 1.1 x_net_udpreceive.c, NONE, 1.1 x_net_udpsend.c, NONE, 1.1

Martin Peach mrpeach at users.sourceforge.net
Wed Aug 16 22:22:24 CEST 2006


Update of /cvsroot/pure-data/externals/mrpeach/net
In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv1850/mrpeach/net

Added Files:
	tcpclient-help.pd tcpreceive-help.pd tcpsend-help.pd 
	tcpserver-help.pd udpreceive-help.pd udpsend-help.pd 
	x_net_tcp_client.c x_net_tcp_server.c x_net_tcpclient.c 
	x_net_tcpreceive.c x_net_tcpsend.c x_net_tcpserver.c 
	x_net_udpreceive.c x_net_udpsend.c 
Log Message:
Added the net, osc and sqosc~ directories


--- NEW FILE: x_net_udpsend.c ---
/* x_net_udpsend.c 20060424. Martin Peach did it based on x_net.c. x_net.c header follows: */
/* Copyright (c) 1997-1999 Miller Puckette.
* For information on usage and redistribution, and for a DISCLAIMER OF ALL
* WARRANTIES, see the file, "LICENSE.txt," in this distribution.  */

/* network */

#include "m_pd.h"
#include "s_stuff.h"

#include <stdio.h>
#include <string.h>
#ifdef MSW
#include <winsock2.h>
#else
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <netdb.h>
#endif

static t_class *udpsend_class;

typedef struct _udpsend
{
    t_object x_obj;
    int      x_fd;
} t_udpsend;

#ifdef MSW
__declspec(dllexport)
#endif
void udpsend_setup(void);
static void udpsend_free(t_udpsend *x);
static void udpsend_send(t_udpsend *x, t_symbol *s, int argc, t_atom *argv);
static void udpsend_disconnect(t_udpsend *x);
static void udpsend_connect(t_udpsend *x, t_symbol *hostname, t_floatarg fportno);
static void *udpsend_new(void);

static void *udpsend_new(void)
{
    t_udpsend *x = (t_udpsend *)pd_new(udpsend_class);
    outlet_new(&x->x_obj, &s_float);
    x->x_fd = -1;
    return (x);
}

static void udpsend_connect(t_udpsend *x, t_symbol *hostname,
    t_floatarg fportno)
{
    struct sockaddr_in  server;
    struct hostent      *hp;
    int                 sockfd;
    int                 portno = fportno;

    if (x->x_fd >= 0)
    {
        error("udpsend: already connected");
        return;
    }

    /* create a socket */
    sockfd = socket(AF_INET, SOCK_DGRAM, 0);
#ifdef DEBUG
    fprintf(stderr, "udpsend_connect: send socket %d\n", sockfd);
#endif
    if (sockfd < 0)
    {
        sys_sockerror("udpsend: socket");
        return;
    }
    /* connect socket using hostname provided in command line */
    server.sin_family = AF_INET;
    hp = gethostbyname(hostname->s_name);
    if (hp == 0)
    {
	    post("udpsend: bad host?\n");
        return;
    }
    memcpy((char *)&server.sin_addr, (char *)hp->h_addr, hp->h_length);

    /* assign client port number */
    server.sin_port = htons((u_short)portno);

    post("udpsend: connecting to port %d", portno);
    /* try to connect. */
    if (connect(sockfd, (struct sockaddr *) &server, sizeof (server)) < 0)
    {
        sys_sockerror("udpsend: connecting stream socket");
        sys_closesocket(sockfd);
        return;
    }
    x->x_fd = sockfd;
    outlet_float(x->x_obj.ob_outlet, 1);
}

static void udpsend_disconnect(t_udpsend *x)
{
    if (x->x_fd >= 0)
    {
        sys_closesocket(x->x_fd);
        x->x_fd = -1;
        outlet_float(x->x_obj.ob_outlet, 0);
    }
}

static void udpsend_send(t_udpsend *x, t_symbol *s, int argc, t_atom *argv)
{
    static char    byte_buf[65536];// arbitrary maximum similar to max IP packet size
    int            i, d;
    char           c;
    float          f, e;
    char           *bp;
    int            length, sent;
    int            result;
    static double  lastwarntime;
    static double  pleasewarn;
    double         timebefore;
    double         timeafter;
    int            late;

#ifdef DEBUG
    post("s: %s", s->s_name);
    post("argc: %d", argc);
#endif
    for (i = 0; i < argc; ++i)
    {
        if (argv[i].a_type == A_FLOAT)
        {
            f = argv[i].a_w.w_float;
            d = (int)f;
            e = f - d;
            if (e != 0)
            {
                error("udpsend_send: item %d (%f) is not an integer", i, f);
                return;
            }
	        c = (unsigned char)d;
	        if (c != d)
            {
                error("udpsend_send: item %d (%f) is not between 0 and 255", i, f);
                return;
            }
#ifdef DEBUG
	        post("udpsend_send: argv[%d]: %d", i, c);
#endif
	        byte_buf[i] = c;
        }
        else
	    {
            error("udpsend_send: item %d is not a float", i);
            return;
        }
    }

    length = i;
    if ((x->x_fd >= 0) && (length > 0))
    {
        for (bp = byte_buf, sent = 0; sent < length;)
        {
            timebefore = sys_getrealtime();
            result = send(x->x_fd, byte_buf, length-sent, 0);
            timeafter = sys_getrealtime();
            late = (timeafter - timebefore > 0.005);
            if (late || pleasewarn)
            {
                if (timeafter > lastwarntime + 2)
                {
                    post("udpsend blocked %d msec",
                        (int)(1000 * ((timeafter - timebefore) + pleasewarn)));
                    pleasewarn = 0;
                    lastwarntime = timeafter;
                }
                else if (late) pleasewarn += timeafter - timebefore;
            }
            if (result <= 0)
            {
                sys_sockerror("udpsend");
                udpsend_disconnect(x);
                break;
            }
            else
            {
                sent += result;
                bp += result;
	        }
        }
    }
    else error("udpsend: not connected");
}

static void udpsend_free(t_udpsend *x)
{
    udpsend_disconnect(x);
}

#ifdef MSW
__declspec(dllexport)
#endif
void udpsend_setup(void)
{
    udpsend_class = class_new(gensym("udpsend"), (t_newmethod)udpsend_new,
        (t_method)udpsend_free,
        sizeof(t_udpsend), 0, 0);
    class_addmethod(udpsend_class, (t_method)udpsend_connect,
        gensym("connect"), A_SYMBOL, A_FLOAT, 0);
    class_addmethod(udpsend_class, (t_method)udpsend_disconnect,
        gensym("disconnect"), 0);
    class_addmethod(udpsend_class, (t_method)udpsend_send, gensym("send"),
        A_GIMME, 0);
}

/* end x_net_udpsend.c*/


--- NEW FILE: x_net_tcpclient.c ---
/* x_net_tcp_client.c Martin Peach 20060508, working version 20060512 */
/* linux version 20060515 */
/* x_net_tcp_client.c is based on netclient: */
/* --------------------------  netclient  ------------------------------------- */
/*                                                                              */
/* Extended 'netsend', connects to 'netserver'.                                 */
/* Uses child thread to connect to server. Thus needs pd0.35-test17 or later.   */
/* Written by Olaf Matthes (olaf.matthes 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: x_net_udpreceive.c ---
/* x_net_udpreceive.c 20060424. Martin Peach did it based on x_net.c. x_net.c header follows: */
/* Copyright (c) 1997-1999 Miller Puckette.
* For information on usage and redistribution, and for a DISCLAIMER OF ALL
* WARRANTIES, see the file, "LICENSE.txt," in this distribution.  */

#include "m_pd.h"
#include "s_stuff.h"

#ifdef MSW
#include <winsock2.h>
#include <ws2tcpip.h>
#else
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <netdb.h>
#include <stdio.h>
#endif


/* ----------------------------- udpreceive ------------------------- */

static t_class *udpreceive_class;

#define MAX_UDP_RECEIVE 65536L // longer than data in maximum UDP packet

typedef struct _udpreceive
{
    t_object  x_obj;
    t_outlet  *x_msgout;
	t_outlet  *x_addrout;
    int       x_connectsocket;
    t_atom    x_addrbytes[4];
    t_atom    x_msgoutbuf[MAX_UDP_RECEIVE];
    char      x_msginbuf[MAX_UDP_RECEIVE];
} t_udpreceive;

#ifdef MSW
__declspec(dllexport)
#endif
void udpreceive_setup(void);
static void udpreceive_free(t_udpreceive *x);
static void *udpreceive_new(t_floatarg fportno);
static void udpreceive_read(t_udpreceive *x, int sockfd);

static void udpreceive_read(t_udpreceive *x, int sockfd)
{
    int                 i, read = 0;
    struct sockaddr_in  from;
    socklen_t           fromlen = sizeof(from);
	long                addr;

	read = recvfrom(sockfd, x->x_msginbuf, MAX_UDP_RECEIVE, 0, (struct sockaddr *)&from, &fromlen);
#ifdef DEBUG
    post("udpreceive_read: read %lu x->x_connectsocket = %d",
        read, x->x_connectsocket);
#endif
	/* get the sender's ip */
    addr = ntohl(from.sin_addr.s_addr);
    x->x_addrbytes[0].a_w.w_float = (addr & 0xFF000000)>>24;
    x->x_addrbytes[1].a_w.w_float = (addr & 0x0FF0000)>>16;
    x->x_addrbytes[2].a_w.w_float = (addr & 0x0FF00)>>8;
    x->x_addrbytes[3].a_w.w_float = (addr & 0x0FF);
    outlet_list(x->x_addrout, &s_list, 4L, x->x_addrbytes);

	if (read < 0)
    {
        sys_sockerror("udpreceive_read");
        sys_closesocket(x->x_connectsocket);
        return;
    }
    if (read > 0)
    {
        for (i = 0; i < read; ++i)
        {
            /* convert the bytes in the buffer to floats in a list */
            x->x_msgoutbuf[i].a_w.w_float = (float)x->x_msginbuf[i];
        }
        /* send the list out the outlet */
        if (read > 1) outlet_list(x->x_msgout, &s_list, read, x->x_msgoutbuf);
        else outlet_float(x->x_msgout, x->x_msgoutbuf[0].a_w.w_float);
    }
}

static void *udpreceive_new(t_floatarg fportno)
{
    t_udpreceive       *x;
    struct sockaddr_in server;
    int                sockfd, portno = fportno;
    int                intarg, i;

	/* create a socket */
    sockfd = socket(AF_INET, SOCK_DGRAM, 0);
#ifdef DEBUG
    post("udpreceive_new: socket %d port %d", sockfd, portno);
#endif
    if (sockfd < 0)
    {
        sys_sockerror("udpreceive: socket");
        return (0);
    }
    server.sin_family = AF_INET;
    server.sin_addr.s_addr = INADDR_ANY;

    /* ask OS to allow another Pd to repoen this port after we close it. */
    intarg = 1;
    if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR,
        (char *)&intarg, sizeof(intarg)) < 0)
        post("udpreceive: setsockopt (SO_REUSEADDR) failed");

    /* assign server port number */
    server.sin_port = htons((u_short)portno);

    /* name the socket */
    if (bind(sockfd, (struct sockaddr *)&server, sizeof(server)) < 0)
    {
        sys_sockerror("udpreceive: bind");
    	sys_closesocket(sockfd);
        return (0);
    }
    x = (t_udpreceive *)pd_new(udpreceive_class);
    x->x_msgout = outlet_new(&x->x_obj, &s_anything);
    x->x_addrout = outlet_new(&x->x_obj, &s_list);
    x->x_connectsocket = sockfd;

    /* convert the bytes in the buffer to floats in a list */
    for (i = 0; i < MAX_UDP_RECEIVE; ++i)
	{
		x->x_msgoutbuf[i].a_type = A_FLOAT;
		x->x_msgoutbuf[i].a_w.w_float = 0;
	}
    for (i = 0; i < 4; ++i)
    {
        x->x_addrbytes[i].a_type = A_FLOAT;
        x->x_addrbytes[i].a_w.w_float = 0;
    }
    sys_addpollfn(x->x_connectsocket, (t_fdpollfn)udpreceive_read, x);
    return (x);
}

static void udpreceive_free(t_udpreceive *x)
{
    if (x->x_connectsocket >= 0)
    {
        sys_rmpollfn(x->x_connectsocket);
        sys_closesocket(x->x_connectsocket);
    }
}

#ifdef MSW
__declspec(dllexport)
#endif
void udpreceive_setup(void)
{
    udpreceive_class = class_new(gensym("udpreceive"),
        (t_newmethod)udpreceive_new, (t_method)udpreceive_free,
        sizeof(t_udpreceive), CLASS_NOINLET, A_DEFFLOAT, 0);
}

/* end x_net_udpreceive.c */


--- NEW FILE: udpsend-help.pd ---
#N canvas 58 443 538 316 12;
#X msg 177 158 disconnect;
#X msg 171 96 connect 127.0.0.1 9997;
#X obj 171 207 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0
1;
#X text 375 97 <--first;
#X msg 67 129 send 0 1 2 3;
#X text 10 38 udpsend sends bytes over a udp connection.;
#X text 10 61 Used in conjunction with packOSC will send OSC over udp
;
#X obj 171 184 udpsend;
#X text 236 259 Martin Peach 2006/04/21;
#X connect 0 0 7 0;
#X connect 1 0 7 0;
#X connect 4 0 7 0;
#X connect 7 0 2 0;

--- NEW FILE: tcpclient-help.pd ---
#N canvas 89 21 1092 501 12;
#X msg 61 93 disconnect;
#X obj 78 222 unpack 0 0 0 0;
#X floatatom 78 245 3 0 0 0 - - -;
#X floatatom 113 245 3 0 0 0 - - -;
#X floatatom 149 245 3 0 0 0 - - -;
#X floatatom 185 245 3 0 0 0 - - -;
#X text 35 244 from;
#X msg 45 30 connect 132.205.142.12 80;
#X obj 45 170 tcpclient;
#X msg 55 53 send 71 69 84 32 104 116 116 112 58 47 47 47 105 110 100
101 120 46 104 116 109 108 13 10;
#X text 566 53 GET http:///index.html CRLF;
#X obj 112 196 tgl 15 0 empty empty connected 18 7 0 8 -24198 -241291
-1 0 1;
#X msg 160 115 dump \$1;
#X obj 160 96 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0 1
;
#X msg 231 139 receive;
#X msg 295 139 recv;
#X text 214 -21 connect with an IP address and port number;
#X msg 23 5 connect www.concordia.ca 80;
#X text 231 114 print received messages to main window in hexdump format
;
#X text 131 171 tcpclient opens a tcp socket to send and receive bytes
on;
#X text 276 263 See also:;
#X obj 354 263 netclient;
#X msg 10 -20 connect 127.0.0.1 9997;
#X obj 354 286 tcpreceive;
#X text 574 285 can receive messages from tcpclient;
#X text 442 263 is what tcpclient is based on;
#X text 21 325 Received messages are output as a list of bytes;
#X text 20 343 Attempting to print long messages output can hang pd!
;
#X text 343 132 get any received data (not useful unless you need it
faster than once per 20ms);
#X text 445 93 semicolon-terminated string for netserver or netreceive
;
#X msg 249 93 send 49 127 128 51 59;
#X obj -86 317 textfile;
#X msg -86 213 clear;
#X msg -67 285 write tcpclientreceived.txt;
#X obj -73 254 prepend add;
#X obj -86 186 loadbang;
#X text 575 342 2006/05/12 Martin Peach;
#X obj 482 286 tcpserver;
#X text 448 285 and;
#X text -71 -82 tcpclient can connect to a server and send and receive
messages as lists of bytes. Any integer value between 0 and 255 can
be transmitted or received.;
#X connect 0 0 8 0;
#X connect 1 0 2 0;
#X connect 1 1 3 0;
#X connect 1 2 4 0;
#X connect 1 3 5 0;
#X connect 7 0 8 0;
#X connect 8 0 34 0;
#X connect 8 1 1 0;
#X connect 8 2 11 0;
#X connect 9 0 8 0;
#X connect 12 0 8 0;
#X connect 13 0 12 0;
#X connect 14 0 8 0;
#X connect 15 0 8 0;
#X connect 17 0 8 0;
#X connect 22 0 8 0;
#X connect 30 0 8 0;
#X connect 32 0 31 0;
#X connect 33 0 31 0;
#X connect 34 0 31 0;
#X connect 35 0 32 0;

--- NEW FILE: tcpserver-help.pd ---
#N canvas 13 208 1115 644 12;
#X msg 18 -6 print;
#X obj 136 109 tcpserver 9997;
#X floatatom 171 237 5 0 0 0 - - -;
#X floatatom 286 191 5 0 0 0 - - -;
#X obj 324 138 unpack 0 0 0 0;
#X floatatom 324 161 3 0 0 0 - - -;
#X floatatom 359 161 3 0 0 0 - - -;
#X floatatom 395 161 3 0 0 0 - - -;
#X floatatom 431 161 3 0 0 0 - - -;
#X text 281 160 from;
#X text 224 236 connections;
#X obj 43 161 print received;
#X msg 118 45 client 1 1 2 3;
#X msg 86 20 broadcast 1 2 3;
#X text 69 -6 list of connections;
#X text 226 19 send to all clients;
#X text 249 45 send to client 1;
#X text 347 254 2006/05/11 Martin Peach;
#X text 199 191 on socket;
#X msg 140 71 send 504 1 2 3;
#X text 273 71 send to client on socket 504;
#X msg 564 -365 client 1 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
18 19;
#X msg 563 -340 client 1 20 21 22 23 24 25 26 27 28 29 30 31 32 33
34 35 36 37 38 39;
#X msg 563 -297 client 1 40 41 42 43 44 45 46 47 48 49 50 51 52 53
54 55 56 57 58 59;
#X msg 563 -255 client 1 60 61 62 63 64 65 66 67 68 69 70 71 72 73
74 75 76 77 78 79;
#X msg 561 -213 client 1 80 81 82 83 84 85 86 87 88 89 90 91 92 93
94 95 96 97 98 99;
#X msg 560 -170 client 1 100 101 102 103 104 105 106 107 108 109 110
111 112 113 114 115 116 117 118 119;
#X msg 559 -127 client 1 120 121 122 123 124 125 126 127 138 139 140
141 142 143 144 145 146 147 148 149;
#X msg 559 -84 client 1 150 151 152 153 154 155 156 157 158 159 160
161 162 163 164 165 166 167 168 169;
#X msg 559 -39 client 1 170 171 172 173 174 175 176 177 178 179 180
181 182 183 184 185 186 187 188 189;
#X msg 558 5 client 1 190 191 192 193 194 195 196 197 198 199 200 201
202 203 204 205 206 207 208 209;
#X msg 558 47 client 1 210 211 212 213 214 215 216 217 218 219 220
221 222 223 224 225 226 227 228 229;
#X msg 558 89 client 1 230 231 232 233 234 235 236 237 238 239 240
241 242 243 244 245 246 247 248 249;
#X msg 558 134 client 1 250 251 252 253 254 255;
#X connect 0 0 1 0;
#X connect 1 0 11 0;
#X connect 1 1 2 0;
#X connect 1 2 3 0;
#X connect 1 3 4 0;
#X connect 4 0 5 0;
#X connect 4 1 6 0;
#X connect 4 2 7 0;
#X connect 4 3 8 0;
#X connect 12 0 1 0;
#X connect 13 0 1 0;
#X connect 19 0 1 0;
#X connect 21 0 1 0;
#X connect 22 0 1 0;
#X connect 23 0 1 0;
#X connect 24 0 1 0;
#X connect 25 0 1 0;
#X connect 26 0 1 0;
#X connect 27 0 1 0;
#X connect 28 0 1 0;
#X connect 29 0 1 0;
#X connect 30 0 1 0;
#X connect 31 0 1 0;
#X connect 32 0 1 0;
#X connect 33 0 1 0;

--- NEW FILE: udpreceive-help.pd ---
#N canvas 658 564 478 294 12;
#X obj 222 119 unpack 0 0 0 0;
#X floatatom 222 142 3 0 0 0 - - -;
#X floatatom 257 142 3 0 0 0 - - -;
#X floatatom 293 142 3 0 0 0 - - -;
#X floatatom 329 142 3 0 0 0 - - -;
#X text 179 141 from;
#X obj 107 194 print message;
#X obj 107 91 udpreceive 9997;
#X text 32 16 udpreceive receives bytes over a udp connection.;
#X text 265 235 Martin Peach 2006/04/21;
#X connect 0 0 1 0;
#X connect 0 1 2 0;
#X connect 0 2 3 0;
#X connect 0 3 4 0;
#X connect 7 0 6 0;
#X connect 7 1 0 0;

--- NEW FILE: x_net_tcpserver.c ---
/* x_net_tcpserver.c Martin Peach 20060511 working version 20060512 */
/* 20060515 works on linux too... */
/* x_net_tcpserver.c is based on netserver: */
/* --------------------------  netserver  ------------------------------------- */
/*                                                                              */
/* A server for bidirectional communication from within Pd.                     */
/* Allows to send back data to specific clients connected to the server.        */
/* Written by Olaf Matthes <olaf.matthes 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 */

--- NEW FILE: x_net_tcp_server.c ---
/* x_net_tcpserver.c Martin Peach 20060511 working version 20060512 */
/* x_net_tcpserver.c is based on netserver: */
/* --------------------------  netserver  ------------------------------------- */
/*                                                                              */
/* A server for bidirectional communication from within Pd.                     */
/* Allows to send back data to specific clients connected to the server.        */
/* Written by Olaf Matthes <olaf.matthes 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
{
    t_object x_obj;
    t_outlet *x_msgout;
    t_outlet *x_connectout;
	t_outlet *x_sockout;
	t_outlet *x_addrout;
	t_symbol *x_host[MAX_CONNECT];
	t_int    x_fd[MAX_CONNECT];
    u_long   x_addr[MAX_CONNECT];
    t_atom   x_addrbytes[4];
    t_int    x_sock_fd;
    t_int    x_connectsocket;
    t_int    x_nconnections;
    t_atom   x_msgoutbuf[MAX_UDP_RECEIVE];
    char     x_msginbuf[MAX_UDP_RECEIVE];
} t_tcpserver;

typedef struct _tcpserver_socketreceiver
{
    unsigned char               *sr_inbuf;
    int                         sr_inhead;
    int                         sr_intail;
    void                        *sr_owner;
    t_tcpserver_socketnotifier  sr_notifier;
    t_tcpserver_socketreceivefn sr_socketreceivefn;
} t_tcpserver_socketreceiver;

static t_tcpserver_socketreceiver *tcpserver_socketreceiver_new(void *owner, t_tcpserver_socketnotifier notifier,
    t_tcpserver_socketreceivefn socketreceivefn);
static int tcpserver_socketreceiver_doread(t_tcpserver_socketreceiver *x);
static void tcpserver_socketreceiver_read(t_tcpserver_socketreceiver *x, int fd);
static void tcpserver_socketreceiver_free(t_tcpserver_socketreceiver *x);
static void tcpserver_send(t_tcpserver *x, t_symbol *s, int argc, t_atom *argv);
static void tcp_server_send_bytes(int sockfd, t_tcpserver *x, int argc, t_atom *argv);
static void tcpserver_client_send(t_tcpserver *x, t_symbol *s, int argc, t_atom *argv);
static void tcpserver_broadcast(t_tcpserver *x, t_symbol *s, int argc, t_atom *argv);
static void tcpserver_notify(t_tcpserver *x);
static void tcpserver_connectpoll(t_tcpserver *x);
static void tcpserver_print(t_tcpserver *x);
static void *tcpserver_new(t_floatarg fportno);
static void tcpserver_free(t_tcpserver *x);
#ifdef MSW
__declspec(dllexport)
#endif
void tcpserver_setup(void);

static t_tcpserver_socketreceiver *tcpserver_socketreceiver_new(void *owner, t_tcpserver_socketnotifier notifier,
    t_tcpserver_socketreceivefn socketreceivefn)
{
    t_tcpserver_socketreceiver *x = (t_tcpserver_socketreceiver *)getbytes(sizeof(*x));
    if (!x)
    {
        error("%s_socketreceiver: unable to allocate %d bytes", objName, sizeof(*x));
    }
    else
    {
        x->sr_inhead = x->sr_intail = 0;
        x->sr_owner = owner;
        x->sr_notifier = notifier;
        x->sr_socketreceivefn = socketreceivefn;
        if (!(x->sr_inbuf = malloc(INBUFSIZE)))
        {
            freebytes(x, sizeof(*x));
            x = NULL;
            error("%s_socketreceiver: unable to allocate %d bytes", objName, INBUFSIZE);
        }
    }
    return (x);
}

/* this is in a separately called subroutine so that the buffer isn't
   sitting on the stack while the messages are getting passed. */
static int tcpserver_socketreceiver_doread(t_tcpserver_socketreceiver *x)
{
    char            messbuf[INBUFSIZE];
    char            *bp = messbuf;
    int             indx, i;
    int             inhead = x->sr_inhead;
    int             intail = x->sr_intail;
    unsigned char   c;
    t_tcpserver     *y = x->sr_owner;
    unsigned char   *inbuf = x->sr_inbuf;

    if (intail == inhead) return (0);
#ifdef DEBUG
    post ("%s_socketreceiver_doread: intail=%d inhead=%d", objName, intail, inhead);
#endif

    for (indx = intail, i = 0; indx != inhead; indx = (indx+1)&(INBUFSIZE-1), ++i)
    {
        c = *bp++ = inbuf[indx];
        y->x_msgoutbuf[i].a_w.w_float = (float)c;
    }
    if (i > 1) outlet_list(y->x_msgout, &s_list, i, y->x_msgoutbuf);
    else outlet_float(y->x_msgout, y->x_msgoutbuf[0].a_w.w_float);

 //   intail = (indx+1)&(INBUFSIZE-1);
    x->sr_inhead = inhead;
    x->sr_intail = indx;//intail;
    return (1);
}

static void tcpserver_socketreceiver_read(t_tcpserver_socketreceiver *x, int fd)
{
    char        *semi;
    int         readto = (x->sr_inhead >= x->sr_intail ? INBUFSIZE : x->sr_intail-1);
    int         ret, i;
    t_tcpserver *y = x->sr_owner;

    y->x_sock_fd = fd;
    /* the input buffer might be full.  If so, drop the whole thing */
    if (readto == x->sr_inhead)
    {
        post("%s: dropped message", objName);
        x->sr_inhead = x->sr_intail = 0;
        readto = INBUFSIZE;
    }
    else
    {
        ret = recv(fd, x->sr_inbuf + x->sr_inhead,
            readto - x->sr_inhead, 0);
        if (ret < 0)
        {
            sys_sockerror("tcpserver: recv");
            if (x->sr_notifier) (*x->sr_notifier)(x->sr_owner);
            sys_rmpollfn(fd);
            sys_closesocket(fd);
        }
        else if (ret == 0)
        {
            post("%s: connection closed on socket %d", objName, fd);
            if (x->sr_notifier) (*x->sr_notifier)(x->sr_owner);
            sys_rmpollfn(fd);
            sys_closesocket(fd);
        }
        else
        {
#ifdef DEBUG
    post ("%s_socketreceiver_read: ret = %d", objName, ret);
#endif
            x->sr_inhead += ret;
            if (x->sr_inhead >= INBUFSIZE) x->sr_inhead = 0;
            /* output client's IP and socket no. */
            for(i = 0; i < y->x_nconnections; i++)	/* search for corresponding IP */
            {
                if(y->x_fd[i] == y->x_sock_fd)
                {
//                  outlet_symbol(x->x_connectionip, x->x_host[i]);
                    /* find sender's ip address and output it */
                    y->x_addrbytes[0].a_w.w_float = (y->x_addr[i] & 0xFF000000)>>24;
                    y->x_addrbytes[1].a_w.w_float = (y->x_addr[i] & 0x0FF0000)>>16;
                    y->x_addrbytes[2].a_w.w_float = (y->x_addr[i] & 0x0FF00)>>8;
                    y->x_addrbytes[3].a_w.w_float = (y->x_addr[i] & 0x0FF);
                    outlet_list(y->x_addrout, &s_list, 4L, y->x_addrbytes);
                    break;
                }
            }
            outlet_float(y->x_sockout, y->x_sock_fd);	/* the socket number */
            tcpserver_socketreceiver_doread(x);
        }
    }
}

static void tcpserver_socketreceiver_free(t_tcpserver_socketreceiver *x)
{
    free(x->sr_inbuf);
    freebytes(x, sizeof(*x));
}

/* ---------------- main tcpserver (send) stuff --------------------- */

static void tcp_server_send_bytes(int client, t_tcpserver *x, int argc, t_atom *argv)
{
    static char     byte_buf[MAX_UDP_RECEIVE];// arbitrary maximum similar to max IP packet size
    int             i, d;
    unsigned char   c;
    float           f, e;
    char            *bp;
    int             length, sent;
    int             result;
    static double   lastwarntime;
    static double   pleasewarn;
    double          timebefore;
    double          timeafter;
    int             late;
    int             sockfd = x->x_fd[client];

    /* process & send data */
    if(sockfd >= 0)
    {
        for (i = 0; i < argc; ++i)
        {
            if (argv[i].a_type == A_FLOAT)
            {
                f = argv[i].a_w.w_float;
                d = (int)f;
                e = f - d;
#ifdef DEBUG
                post("%s: argv[%d]: float:%f int:%d delta:%f", objName, i, f, d, e);
#endif
                if (e != 0)
                {
                    error("%s: item %d (%f) is not an integer", objName, i, f);
                    return;
                }
    	        if ((d < 0) || (d > 255))
                {
                    error("%s: item %d (%f) is not between 0 and 255", objName, i, f);
                    return;
                }
                c = (unsigned char)d; /* make sure it doesn't become negative; this only matters for post() */
#ifdef DEBUG
    	        post("%s: argv[%d]: %d", objName, i, c);
#endif
    	        byte_buf[i] = c;
            }
            else
    	    {
                error("%s: item %d is not a float", objName, i);
                return;
            }
        }
        length = i;
        if (length > 0)
        {
            for (bp = byte_buf, sent = 0; sent < length;)
            {
                timebefore = sys_getrealtime();
                result = send(sockfd, byte_buf, length-sent, 0);
                timeafter = sys_getrealtime();
                late = (timeafter - timebefore > 0.005);
                if (late || pleasewarn)
                {
                    if (timeafter > lastwarntime + 2)
                    {
                        post("%s: send blocked %d msec", objName,
                            (int)(1000 * ((timeafter - timebefore) + pleasewarn)));
                        pleasewarn = 0;
                        lastwarntime = timeafter;
                    }
                    else if (late) pleasewarn += timeafter - timebefore;
                }
                if (result <= 0)
                {
                    sys_sockerror("tcpserver: send");
                    post("%s: could not send data to client %d", objName, client);
                    break;
                }
                else
                {
                    sent += result;
                    bp += result;
    	        }
            }
        }
    }
    else post("%s: not a valid socket number (%d)", objName, sockfd);
}

/* send message to client using socket number */
static void tcpserver_send(t_tcpserver *x, t_symbol *s, int argc, t_atom *argv)
{
    int     i, sockfd;
    int     client = -1;

    if(x->x_nconnections < 0)
    {
        post("%s: no clients connected", objName);
        return;
    }
    if(argc < 2)
    {
        post("%s: nothing to send", objName);
        return;
    }
    /* get socket number of connection (first element in list) */
    if(argv[0].a_type == A_FLOAT)
    {
        sockfd = atom_getfloatarg(0, argc, argv);
        for(i = 0; i < x->x_nconnections; i++)	/* check if connection exists */
        {
            if(x->x_fd[i] == sockfd)
            {
                client = i;	/* the client we're sending to */
                break;
            }
        }
        if(client == -1)
        {
            post("%s: no connection on socket %d", objName, sockfd);
            return;
        }
    }
    else
    {
        post("%s: no socket specified", objName);
        return;
    }
    tcp_server_send_bytes(client, x, argc-1, &argv[1]);
}

/* send message to client using client number 
   note that the client numbers might change in case a client disconnects! */
/* clients start at 1 but our index starts at 0 */
static void tcpserver_client_send(t_tcpserver *x, t_symbol *s, int argc, t_atom *argv)
{
    int     sockfd, client;

    if(x->x_nconnections < 0)
    {
        post("%s: no clients connected", objName);
        return;
    }
    if(argc < 2)
    {
        post("%s: nothing to send", objName);
        return;
    }
    /* get number of client (first element in list) */
    if(argv[0].a_type == A_FLOAT)
        client = atom_getfloatarg(0, argc, argv);
    else
    {
        post("%s: no client specified", objName);
        return;
    }
    if (!((client > 0) && (client < MAX_CONNECT)))
    {
        post("%s: client %d out of range [1..%d]", objName, client, MAX_CONNECT);
        return;
    }
    --client;/* zero based index*/
    tcp_server_send_bytes(client, x, argc-1, &argv[1]);
}

/* broadcasts a message to all connected clients */
static void tcpserver_broadcast(t_tcpserver *x, t_symbol *s, int argc, t_atom *argv)
{
    int     client;

    /* enumerate through the clients and send each the message */
    for(client = 0; client < x->x_nconnections; client++)	/* check if connection exists */
    {
        if(x->x_fd[client] >= 0)
        { /* socket exists for this client */
            tcp_server_send_bytes(client, x, argc, argv);
            break;
        }
    }
}

/* ---------------- main tcpserver (receive) stuff --------------------- */

static void tcpserver_notify(t_tcpserver *x)
{
    int     i, k;

    /* remove connection from list */
    for(i = 0; i < x->x_nconnections; i++)
    {
        if(x->x_fd[i] == x->x_sock_fd)
        {
            x->x_nconnections--;
            post("%s: \"%s\" removed from list of clients", objName, x->x_host[i]->s_name);
            x->x_host[i] = NULL;	/* delete entry */
            x->x_fd[i] = -1;
            /* rearrange list now: move entries to close the gap */
            for(k = i; k < x->x_nconnections; k++)
            {
                x->x_host[k] = x->x_host[k + 1];
                x->x_fd[k] = x->x_fd[k + 1];
            }
        }
    }
    outlet_float(x->x_connectout, x->x_nconnections);
}

static void tcpserver_connectpoll(t_tcpserver *x)
{
    struct sockaddr_in  incomer_address;
    int                 sockaddrl = (int) sizeof( struct sockaddr );
    int                 fd = accept(x->x_connectsocket, (struct sockaddr*)&incomer_address, &sockaddrl);
    int                 i;

    if (fd < 0) post("%s: accept failed", objName);
    else
    {
        t_tcpserver_socketreceiver *y = tcpserver_socketreceiver_new((void *)x, 
            (t_tcpserver_socketnotifier)tcpserver_notify, NULL);/* MP tcpserver_doit isn't used I think...*/
        if (!y)
        {
#ifdef MSW
            closesocket(fd);
#else
            close(fd);
#endif
            return;
        }
        sys_addpollfn(fd, (t_fdpollfn)tcpserver_socketreceiver_read, y);
        x->x_nconnections++;
        i = x->x_nconnections - 1;
        x->x_host[i] = gensym(inet_ntoa(incomer_address.sin_addr));
        x->x_fd[i] = fd;
        post("%s: accepted connection from %s on socket %d", 
            objName, x->x_host[i]->s_name, x->x_fd[i]);
        outlet_float(x->x_connectout, x->x_nconnections);
        outlet_float(x->x_sockout, x->x_fd[i]);	/* the socket number */
        x->x_addr[i] = ntohl(incomer_address.sin_addr.s_addr);
        x->x_addrbytes[0].a_w.w_float = (x->x_addr[i] & 0xFF000000)>>24;
        x->x_addrbytes[1].a_w.w_float = (x->x_addr[i] & 0x0FF0000)>>16;
        x->x_addrbytes[2].a_w.w_float = (x->x_addr[i] & 0x0FF00)>>8;
        x->x_addrbytes[3].a_w.w_float = (x->x_addr[i] & 0x0FF);
        outlet_list(x->x_addrout, &s_list, 4L, x->x_addrbytes);
    }
}

static void tcpserver_print(t_tcpserver *x)
{
    int     i;

    if(x->x_nconnections > 0)
    {
        post("%s: %d open connections:", objName, x->x_nconnections);
        for(i = 0; i < x->x_nconnections; i++)
        {
            post("        \"%s\" on socket %d", 
                x->x_host[i]->s_name, x->x_fd[i]);
        }
    }
    else post("%s: no open connections", objName);
}

static void *tcpserver_new(t_floatarg fportno)
{
    t_tcpserver         *x;
    int                 i;
    struct sockaddr_in  server;
    int                 sockfd, portno = fportno;

    /* create a socket */
    sockfd = socket(AF_INET, SOCK_STREAM, 0);
#ifdef DEBUG
    post("%s: receive socket %d", objName, sockfd);
#endif
    if (sockfd < 0)
    {
        sys_sockerror("tcpserver: socket");
        return (0);
    }
    server.sin_family = AF_INET;
    server.sin_addr.s_addr = INADDR_ANY;
#ifdef IRIX
    /* this seems to work only in IRIX but is unnecessary in
        Linux.  Not sure what NT needs in place of this. */
    if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, 0, 0) < 0)
        post("setsockopt failed\n");
#endif
    /* assign server port number */
    server.sin_port = htons((u_short)portno);
    /* name the socket */
    if (bind(sockfd, (struct sockaddr *)&server, sizeof(server)) < 0)
    {
        sys_sockerror("tcpserver: bind");
        sys_closesocket(sockfd);
        return (0);
    }
    x = (t_tcpserver *)pd_new(tcpserver_class);
    x->x_msgout = outlet_new(&x->x_obj, &s_anything); /* 1st outlet for received data */
    /* streaming protocol */
    if (listen(sockfd, 5) < 0)
    {
        sys_sockerror("tcpserver: listen");
        sys_closesocket(sockfd);
        sockfd = -1;
    }
    else
    {
        sys_addpollfn(sockfd, (t_fdpollfn)tcpserver_connectpoll, x);
        x->x_connectout = outlet_new(&x->x_obj, &s_float); /* 2nd outlet for number of connected clients */
        x->x_sockout = outlet_new(&x->x_obj, &s_float); /* 3rd outlet for socket number of current client */
        x->x_addrout = outlet_new(&x->x_obj, &s_list); /* 4th outlet for ip address of current client */
        inbinbuf = binbuf_new();
    }
    x->x_connectsocket = sockfd;
    x->x_nconnections = 0;
    for(i = 0; i < MAX_CONNECT; i++) x->x_fd[i] = -1;
	/* prepare to convert the bytes in the buffer to floats in a list */
    for (i = 0; i < MAX_UDP_RECEIVE; ++i)
	{
		x->x_msgoutbuf[i].a_type = A_FLOAT;
		x->x_msgoutbuf[i].a_w.w_float = 0;
	}
    for (i = 0; i < 4; ++i)
    {
        x->x_addrbytes[i].a_type = A_FLOAT;
        x->x_addrbytes[i].a_w.w_float = 0;
    }

    return (x);
}

static void tcpserver_free(t_tcpserver *x)
{
    int     i;

    for(i = 0; i < x->x_nconnections; i++)
    {
        sys_rmpollfn(x->x_fd[i]);
        sys_closesocket(x->x_fd[i]);
    }
    if (x->x_connectsocket >= 0)
    {
        sys_rmpollfn(x->x_connectsocket);
        sys_closesocket(x->x_connectsocket);
    }
    binbuf_free(inbinbuf);
}

#ifdef MSW
__declspec(dllexport)
#endif
void tcpserver_setup(void)
{
    tcpserver_class = class_new(gensym(objName),(t_newmethod)tcpserver_new, (t_method)tcpserver_free,
    	sizeof(t_tcpserver), 0, A_DEFFLOAT, 0);
	class_addmethod(tcpserver_class, (t_method)tcpserver_print, gensym("print"), 0);
	class_addmethod(tcpserver_class, (t_method)tcpserver_send, gensym("send"), A_GIMME, 0);
	class_addmethod(tcpserver_class, (t_method)tcpserver_client_send, gensym("client"), A_GIMME, 0);
	class_addmethod(tcpserver_class, (t_method)tcpserver_broadcast, gensym("broadcast"), A_GIMME, 0);
}

--- NEW FILE: tcpreceive-help.pd ---
#N canvas 713 11 478 294 12;
#X obj 212 117 unpack 0 0 0 0;
#X floatatom 212 140 3 0 0 0 - - -;
#X floatatom 247 140 3 0 0 0 - - -;
#X floatatom 283 140 3 0 0 0 - - -;
#X floatatom 319 140 3 0 0 0 - - -;
#X text 169 139 from;
#X obj 155 185 print message;
#X obj 155 57 tcpreceive 9997;
#X floatatom 270 96 5 0 0 0 - - -;
#X text 316 94 connections;
#X text 32 16 tcpreceive receives bytes over a tcp connection.;
#X text 265 235 Martin Peach 2006/04/21;
#X connect 0 0 1 0;
#X connect 0 1 2 0;
#X connect 0 2 3 0;
#X connect 0 3 4 0;
#X connect 7 0 6 0;
#X connect 7 1 0 0;
#X connect 7 2 8 0;

--- NEW FILE: x_net_tcpreceive.c ---
/* x_net_tcpreceive.c 20060424. Martin Peach did it based on x_net.c. x_net.c header follows: */
/* Copyright (c) 1997-1999 Miller Puckette.
* For information on usage and redistribution, and for a DISCLAIMER OF ALL
* WARRANTIES, see the file, "LICENSE.txt," in this distribution.  */

#include "m_pd.h"
#include "s_stuff.h"

#ifdef MSW
#include <winsock2.h>
#include <ws2tcpip.h> /* for socklen_t */
#else
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <netdb.h>
#include <stdio.h>
#endif


/* ----------------------------- tcpreceive ------------------------- */

static t_class *tcpreceive_class;

#define MAX_UDP_RECEIVE 65536L // longer than data in maximum UDP packet
#define MAX_CONNECTIONS 128 // this is going to cause trouble down the line...:(

typedef struct _tcpconnection
{
    long      addr;
    int       socket;
} t_tcpconnection;

typedef struct _tcpreceive
{
    t_object        x_obj;
    t_outlet        *x_msgout;
	t_outlet        *x_addrout;
    t_outlet        *x_connectout;
    int             x_connectsocket;
    int             x_nconnections;
	t_tcpconnection x_connection[MAX_CONNECTIONS];
    t_atom          x_addrbytes[4];
    t_atom          x_msgoutbuf[MAX_UDP_RECEIVE];
    char            x_msginbuf[MAX_UDP_RECEIVE];
} t_tcpreceive;

#ifdef MSW
__declspec(dllexport)
#endif
void tcpreceive_setup(void);
static void tcpreceive_free(t_tcpreceive *x);
static void *tcpreceive_new(t_floatarg fportno);
static void tcpreceive_read(t_tcpreceive *x, int sockfd);
static void tcpreceive_connectpoll(t_tcpreceive *x);
static int tcpreceive_addconnection(t_tcpreceive * x, int fd, long addr);
static int tcpreceive_removeconnection(t_tcpreceive * x, int fd);
static void tcpreceive_closeall(t_tcpreceive *x);
static long tcpreceive_getconnection(t_tcpreceive * x, int fd);

static void tcpreceive_read(t_tcpreceive *x, int sockfd)
{
    int  i, read = 0;
    long addr;

//	read = recvfrom(sockfd, x->x_msginbuf, MAX_UDP_RECEIVE, 0, (struct sockaddr *)&from, &fromlen);
	read = recv(sockfd, x->x_msginbuf, MAX_UDP_RECEIVE, 0);
#ifdef DEBUG
    post("tcpreceive_read: read %lu x->x_connectsocket = %d",
        read, x->x_connectsocket);
#endif
    if (read < 0)
    {
		sys_sockerror("tcpreceive_read: recv");
        sys_rmpollfn(sockfd);
        sys_closesocket(sockfd);
        tcpreceive_removeconnection(x, sockfd);
        outlet_float(x->x_connectout, --x->x_nconnections);
    }
    else if (read == 0)
    {
        post("tcpreceive: EOF on socket %d\n", sockfd);
        sys_rmpollfn(sockfd);
        sys_closesocket(sockfd);
        tcpreceive_removeconnection(x, sockfd);
        outlet_float(x->x_connectout, --x->x_nconnections);
    }
    else if (read > 0)
    {
        for (i = 0; i < read; ++i)
        {
            /* convert the bytes in the buffer to floats in a list */
            x->x_msgoutbuf[i].a_w.w_float = (float)x->x_msginbuf[i];
        }
        /* find sender's ip address and output it */
		addr = tcpreceive_getconnection(x, sockfd);
        x->x_addrbytes[0].a_w.w_float = (addr & 0xFF000000)>>24;
        x->x_addrbytes[1].a_w.w_float = (addr & 0x0FF0000)>>16;
        x->x_addrbytes[2].a_w.w_float = (addr & 0x0FF00)>>8;
        x->x_addrbytes[3].a_w.w_float = (addr & 0x0FF);
        outlet_list(x->x_addrout, &s_list, 4L, x->x_addrbytes);
        /* send the list out the outlet */
        if (read > 1) outlet_list(x->x_msgout, &s_list, read, x->x_msgoutbuf);
        else outlet_float(x->x_msgout, x->x_msgoutbuf[0].a_w.w_float);
    }
}

static void *tcpreceive_new(t_floatarg fportno)
{
    t_tcpreceive       *x;
    struct sockaddr_in server;
    int                sockfd, portno = fportno;
    int                intarg, i;

	/* create a socket */
    sockfd = socket(AF_INET, SOCK_STREAM, 0);
#ifdef DEBUG
    post("tcpreceive_new: socket %d port %d", sockfd, portno);
#endif
    if (sockfd < 0)
    {
        sys_sockerror("tcpreceive: socket");
        return (0);
    }
    server.sin_family = AF_INET;
    server.sin_addr.s_addr = INADDR_ANY;

    /* ask OS to allow another Pd to repoen this port after we close it. */
    intarg = 1;
    if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR,
        (char *)&intarg, sizeof(intarg)) < 0)
        post("tcpreceive: setsockopt (SO_REUSEADDR) failed");
    /* Stream (TCP) sockets are set NODELAY */
    intarg = 1;
    if (setsockopt(sockfd, IPPROTO_TCP, TCP_NODELAY,
        (char *)&intarg, sizeof(intarg)) < 0)
            post("setsockopt (TCP_NODELAY) failed\n");

    /* assign server port number */
    server.sin_port = htons((u_short)portno);

    /* name the socket */
    if (bind(sockfd, (struct sockaddr *)&server, sizeof(server)) < 0)
    {
        sys_sockerror("tcpreceive: bind");
    	sys_closesocket(sockfd);
        return (0);
    }
    x = (t_tcpreceive *)pd_new(tcpreceive_class);
    x->x_msgout = outlet_new(&x->x_obj, &s_anything);
    x->x_addrout = outlet_new(&x->x_obj, &s_list);
    x->x_connectout = outlet_new(&x->x_obj, &s_float);
    /* clear the connection list */
    for (i = 0; i < MAX_CONNECTIONS; ++i)
	{
		x->x_connection[i].socket = -1;
		x->x_connection[i].addr = 0L;
    }
	/* convert the bytes in the buffer to floats in a list */
    for (i = 0; i < MAX_UDP_RECEIVE; ++i)
	{
		x->x_msgoutbuf[i].a_type = A_FLOAT;
		x->x_msgoutbuf[i].a_w.w_float = 0;
	}
    for (i = 0; i < 4; ++i)
    {
        x->x_addrbytes[i].a_type = A_FLOAT;
        x->x_addrbytes[i].a_w.w_float = 0;
    }

    /* streaming protocol */
    if (listen(sockfd, 5) < 0)
    {
        sys_sockerror("tcpreceive: listen");
        sys_closesocket(sockfd);
        sockfd = -1;
    }
    else
    {
        sys_addpollfn(sockfd, (t_fdpollfn)tcpreceive_connectpoll, x);
    }
    x->x_connectsocket = sockfd;
    x->x_nconnections = 0;

//udp version...    sys_addpollfn(x->x_connectsocket, (t_fdpollfn)tcpreceive_read, x);
    return (x);
}

/* tcpreceive_connectpoll checks for incoming connection requests on the original socket */
/* a new socket is assigned  */
static void tcpreceive_connectpoll(t_tcpreceive *x)
{
    struct sockaddr_in  from;
    socklen_t           fromlen = sizeof(from);
	long                addr;
    int                 fd;

    fd = accept(x->x_connectsocket, (struct sockaddr *)&from, &fromlen);
    if (fd < 0) post("tcpreceive: accept failed");
    else
    {
 //       t_socketreceiver *y = socketreceiver_new((void *)x,
   //         (t_socketnotifier)tcpreceive_notify,
     //           0, 0);

        /* get the sender's ip */
        addr = ntohl(from.sin_addr.s_addr);
		if (tcpreceive_addconnection(x, fd, addr))
		{
            sys_addpollfn(fd, (t_fdpollfn)tcpreceive_read, x);
            outlet_float(x->x_connectout, ++x->x_nconnections);
            x->x_addrbytes[0].a_w.w_float = (addr & 0xFF000000)>>24;
            x->x_addrbytes[1].a_w.w_float = (addr & 0x0FF0000)>>16;
            x->x_addrbytes[2].a_w.w_float = (addr & 0x0FF00)>>8;
            x->x_addrbytes[3].a_w.w_float = (addr & 0x0FF);
            outlet_list(x->x_addrout, &s_list, 4L, x->x_addrbytes);
        }
        else
        {
            error ("tcpreceive: Too many connections");
            sys_closesocket(fd);
        }
    }
}

/* tcpreceive_addconnection tries to add the socket fd to the list */
/* returns 1 on success, else 0 */
static int tcpreceive_addconnection(t_tcpreceive *x, int fd, long addr)
{
	int i;
	for (i = 0; i < MAX_CONNECTIONS; ++i)
    {
        if (x->x_connection[i].socket == -1)
        {
            x->x_connection[i].socket = fd;
            x->x_connection[i].addr = addr;
            return 1;
        }
    }
    return 0;
}

/* tcpreceive_closeall closes all open sockets and deletes them from the list */
static void tcpreceive_closeall(t_tcpreceive *x)
{
    int i;

    for (i = 0; ((i < MAX_CONNECTIONS) && (x->x_nconnections > 0)); ++i)
    {
        if (x->x_connection[i].socket != -1)
        {
			post ("tcpreceive: closing socket %d", x->x_connection[i].socket);
            sys_rmpollfn(x->x_connection[i].socket);
            sys_closesocket(x->x_connection[i].socket);
            x->x_connection[i].socket = -1;
            x->x_connection[i].addr = 0L;
            outlet_float(x->x_connectout, --x->x_nconnections);
        }
    }
}

/* tcpreceive_removeconnection tries to delete the socket fd from the list */
/* returns 1 on success, else 0 */
static int tcpreceive_removeconnection(t_tcpreceive *x, int fd)
{
    int i;
    for (i = 0; i < MAX_CONNECTIONS; ++i)
    {
        if (x->x_connection[i].socket == fd)
        {
            x->x_connection[i].socket = -1;
            x->x_connection[i].addr = 0L;
            return 1;
        }
    }
    return 0;
}

/* tcpreceive_getconnection tries to find the socket fd in the list */
/* returns addr on success, else 0 */
static long tcpreceive_getconnection(t_tcpreceive *x, int fd)
{
    int i;
    for (i = 0; i < MAX_CONNECTIONS; ++i)
    {
        if (x->x_connection[i].socket == fd)
            return x->x_connection[i].addr;
    }
    return 0;
}

static void tcpreceive_free(t_tcpreceive *x)
{ /* is this ever called? */
    if (x->x_connectsocket >= 0)
    {
        sys_rmpollfn(x->x_connectsocket);
        sys_closesocket(x->x_connectsocket);
    }
    tcpreceive_closeall(x);
}

#ifdef MSW
__declspec(dllexport)
#endif
void tcpreceive_setup(void)
{
    tcpreceive_class = class_new(gensym("tcpreceive"),
        (t_newmethod)tcpreceive_new, (t_method)tcpreceive_free,
        sizeof(t_tcpreceive), CLASS_NOINLET, A_DEFFLOAT, 0);
}

/* end x_net_tcpreceive.c */


--- NEW FILE: x_net_tcp_client.c ---
/* x_net_tcp_client.c Martin Peach 20060508, working version 20060512 */
/* linux version 20060515 */
/* x_net_tcp_client.c is based on netclient: */
/* --------------------------  netclient  ------------------------------------- */
/*                                                                              */
/* Extended 'netsend', connects to 'netserver'.                                 */
/* Uses child thread to connect to server. Thus needs pd0.35-test17 or later.   */
/* Written by Olaf Matthes (olaf.matthes 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: tcpsend-help.pd ---
#N canvas 0 0 555 316 12;
#X msg 177 158 disconnect;
#X msg 171 96 connect 127.0.0.1 9997;
#X obj 171 207 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0
1;
#X obj 171 184 tcpsend;
#X text 375 97 <--first;
#X msg 67 129 send 0 1 2 3;
#X text 10 38 tcpsend sends bytes over a tcp connection.;
#X text 10 61 Used in conjunction with packOSC will send OSC over tcp
;
#X text 236 259 Martin Peach 2006/04/21;
#X connect 0 0 3 0;
#X connect 1 0 3 0;
#X connect 3 0 2 0;
#X connect 5 0 3 0;

--- NEW FILE: x_net_tcpsend.c ---
/* x_net_tcpsend.c 20060424 Martin Peach did it based on x_net.c. x_net.c header follows: */
/* Copyright (c) 1997-1999 Miller Puckette.
* For information on usage and redistribution, and for a DISCLAIMER OF ALL
* WARRANTIES, see the file, "LICENSE.txt," in this distribution.  */

/* network */

#include "m_pd.h"
#include "s_stuff.h"

#ifdef MSW
#include <winsock2.h>
#else
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <netdb.h>
#include <stdio.h>
#include <string.h>
#endif

static t_class *tcpsend_class;

typedef struct _tcpsend
{
    t_object x_obj;
    int      x_fd;
} t_tcpsend;

#ifdef MSW
__declspec(dllexport)
#endif
void tcpsend_setup(void);
static void tcpsend_free(t_tcpsend *x);
static void tcpsend_send(t_tcpsend *x, t_symbol *s, int argc, t_atom *argv);
static void tcpsend_disconnect(t_tcpsend *x);
static void tcpsend_connect(t_tcpsend *x, t_symbol *hostname, t_floatarg fportno);
static void *tcpsend_new(void);

static void *tcpsend_new(void)
{
    t_tcpsend *x = (t_tcpsend *)pd_new(tcpsend_class);
    outlet_new(&x->x_obj, &s_float);
    x->x_fd = -1;
    return (x);
}

static void tcpsend_connect(t_tcpsend *x, t_symbol *hostname,
    t_floatarg fportno)
{
    struct sockaddr_in  server;
    struct hostent      *hp;
    int                 sockfd;
    int                 portno = fportno;
    int                 intarg;

    if (x->x_fd >= 0)
    {
        error("tcpsend: already connected");
        return;
    }

    /* create a socket */
    sockfd = socket(AF_INET, SOCK_STREAM, 0);
#ifdef DEBUG
    fprintf(stderr, "tcpsend_connect: send socket %d\n", sockfd);
#endif
    if (sockfd < 0)
    {
        sys_sockerror("tcpsend: socket");
        return;
    }
    /* connect socket using hostname provided in command line */
    server.sin_family = AF_INET;
    hp = gethostbyname(hostname->s_name);
    if (hp == 0)
    {
	    post("tcpsend: bad host?\n");
        return;
    }
    /* for stream (TCP) sockets, specify "nodelay" */
    intarg = 1;
    if (setsockopt(sockfd, IPPROTO_TCP, TCP_NODELAY,
        (char *)&intarg, sizeof(intarg)) < 0)
            post("tcpsend: setsockopt (TCP_NODELAY) failed\n");

    memcpy((char *)&server.sin_addr, (char *)hp->h_addr, hp->h_length);

    /* assign client port number */
    server.sin_port = htons((u_short)portno);

    post("tcpsend: connecting to port %d", portno);
    /* try to connect. */
    if (connect(sockfd, (struct sockaddr *) &server, sizeof (server)) < 0)
    {
        sys_sockerror("tcpsend: connecting stream socket");
        sys_closesocket(sockfd);
        return;
    }
    x->x_fd = sockfd;
    outlet_float(x->x_obj.ob_outlet, 1);
}

static void tcpsend_disconnect(t_tcpsend *x)
{
    if (x->x_fd >= 0)
    {
        sys_closesocket(x->x_fd);
        x->x_fd = -1;
        outlet_float(x->x_obj.ob_outlet, 0);
        post("tcpsend: disconnected");
    }
}

static void tcpsend_send(t_tcpsend *x, t_symbol *s, int argc, t_atom *argv)
{
    static char    byte_buf[65536];// arbitrary maximum similar to max IP packet size
    int            i, d;
    char           c;
    float          f, e;
    char           *bp;
    int            length, sent;
    int            result;
    static double  lastwarntime;
    static double  pleasewarn;
    double         timebefore;
    double         timeafter;
    int            late;

#ifdef DEBUG
    post("s: %s", s->s_name);
    post("argc: %d", argc);
#endif
    for (i = 0; i < argc; ++i)
    {
        if (argv[i].a_type == A_FLOAT)
        {
            f = argv[i].a_w.w_float;
            d = (int)f;
            e = f - d;
            if (e != 0)
            {
                error("tcpsend_send: item %d (%f) is not an integer", i, f);
                return;
            }
	        c = (unsigned char)d;
	        if (c != d)
            {
                error("tcpsend_send: item %d (%f) is not between 0 and 255", i, f);
                return;
            }
#ifdef DEBUG
	        post("tcpsend_send: argv[%d]: %d", i, c);
#endif
	        byte_buf[i] = c;
        }
        else
	    {
            error("tcpsend_send: item %d is not a float", i);
            return;
        }
    }

    length = i;
    if ((x->x_fd >= 0) && (length > 0))
    {
        for (bp = byte_buf, sent = 0; sent < length;)
        {
            timebefore = sys_getrealtime();
            result = send(x->x_fd, byte_buf, length-sent, 0);
            timeafter = sys_getrealtime();
            late = (timeafter - timebefore > 0.005);
            if (late || pleasewarn)
            {
                if (timeafter > lastwarntime + 2)
                {
                    post("tcpsend blocked %d msec",
                        (int)(1000 * ((timeafter - timebefore) + pleasewarn)));
                    pleasewarn = 0;
                    lastwarntime = timeafter;
                }
                else if (late) pleasewarn += timeafter - timebefore;
            }
            if (result <= 0)
            {
                sys_sockerror("tcpsend");
                tcpsend_disconnect(x);
                break;
            }
            else
            {
                sent += result;
                bp += result;
	        }
        }
    }
    else error("tcpsend: not connected");
}

static void tcpsend_free(t_tcpsend *x)
{
    tcpsend_disconnect(x);
}

#ifdef MSW
__declspec(dllexport)
#endif
void tcpsend_setup(void)
{
    tcpsend_class = class_new(gensym("tcpsend"), (t_newmethod)tcpsend_new,
        (t_method)tcpsend_free,
        sizeof(t_tcpsend), 0, 0);
    class_addmethod(tcpsend_class, (t_method)tcpsend_connect,
        gensym("connect"), A_SYMBOL, A_FLOAT, 0);
    class_addmethod(tcpsend_class, (t_method)tcpsend_disconnect,
        gensym("disconnect"), 0);
    class_addmethod(tcpsend_class, (t_method)tcpsend_send, gensym("send"),
        A_GIMME, 0);
}

/* end x_net_tcpsend.c*/





More information about the Pd-cvs mailing list