From 29f2b2b9168fd2d45ec5a2699dab2e5ab44ad10b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?IOhannes=20m=20zm=C3=B6lnig?= Date: Thu, 25 Mar 2010 08:28:36 +0000 Subject: most of the tcp-objects seem to work now; performance increase as measured until now is great :-) svn path=/trunk/externals/iem/iemnet/; revision=13265 --- iemnet.c | 26 ++-- tcpclient.c | 13 -- tcpreceive.c | 481 +++++++++++++++++++++++++++-------------------------------- tcpsend.c | 318 ++++++++++++++------------------------- tcpserver.c | 39 ++--- 5 files changed, 368 insertions(+), 509 deletions(-) diff --git a/iemnet.c b/iemnet.c index 5c739c7..7586c7a 100644 --- a/iemnet.c +++ b/iemnet.c @@ -4,8 +4,6 @@ #include "iemnet.h" -#include "s_stuff.h" - #include #include #include @@ -488,7 +486,7 @@ int iemnet__sender_setsockopt(t_iemnet_sender*s, int level, int optname, const v struct _iemnet_receiver { pthread_t thread; int sockfd; /* owned outside; you must call iemnet__receiver_destroy() before freeing socket yourself */ - void*owner; + void*userdata; t_iemnet_chunk*data; t_iemnet_receivecallback callback; t_queue*queue; @@ -542,20 +540,20 @@ static void iemnet__receiver_tick(t_iemnet_receiver *x) t_iemnet_chunk*c=queue_pop_noblock(x->queue); while(NULL!=c) { x->flist = iemnet__chunk2list(c, x->flist); - (x->callback)(x->owner, x->sockfd, x->flist->argc, x->flist->argv); + (x->callback)(x->userdata, x->flist->argc, x->flist->argv); iemnet__chunk_destroy(c); c=queue_pop_noblock(x->queue); } if(!x->running) { // read terminated - x->callback(x->owner, x->sockfd, 0, NULL); + x->callback(x->userdata, 0, NULL); } } -t_iemnet_receiver*iemnet__receiver_create(int sock, void*owner, t_iemnet_receivecallback callback) { +t_iemnet_receiver*iemnet__receiver_create(int sock, void*userdata, t_iemnet_receivecallback callback) { t_iemnet_receiver*rec=(t_iemnet_receiver*)getbytes(sizeof(t_iemnet_receiver)); - //fprintf(stderr, "new receiver for %d\t%x\t%x\n", sock, owner, callback); + //fprintf(stderr, "new receiver for %d\t%x\t%x\n", sock, userdata, callback); if(rec) { t_iemnet_chunk*data=iemnet__chunk_create_empty(INBUFSIZE); int res=0; @@ -564,7 +562,7 @@ t_iemnet_receiver*iemnet__receiver_create(int sock, void*owner, t_iemnet_receive return NULL; } rec->sockfd=sock; - rec->owner=owner; + rec->userdata=userdata; rec->data=data; rec->callback=callback; rec->flist=iemnet__floatlist_create(1024); @@ -590,7 +588,7 @@ void iemnet__receiver_destroy(t_iemnet_receiver*rec) { rec->sockfd=0; pthread_join(rec->thread, NULL); - rec->owner=NULL; + rec->userdata=NULL; rec->data=NULL; rec->callback=NULL; rec->clock=NULL; @@ -609,15 +607,17 @@ void iemnet__receiver_destroy(t_iemnet_receiver*rec) { #ifdef _MSC_VER - void tcpclient_setup(void); - void tcpserver_setup(void); +void tcpclient_setup(void); +void tcpserver_setup(void); +void tcpsend_setup(void); #endif IEMNET_EXTERN void iemnet_setup(void) { #ifdef _MSC_VER - tcpclient_setup(); - tcpserver_setup(); + tcpclient_setup(); + tcpserver_setup(); + tcpserver_setup(); #endif } diff --git a/tcpclient.c b/tcpclient.c index c0c89ef..c7bffe2 100644 --- a/tcpclient.c +++ b/tcpclient.c @@ -25,21 +25,8 @@ /* ---------------------------------------------------------------------------- */ #include "iemnet.h" - -#include "s_stuff.h" - -#ifdef _WIN32 -#else -# include /* gethostbyname, htons... */ -#endif - #include - - //#include - //#include - - #include diff --git a/tcpreceive.c b/tcpreceive.c index 418e77b..502cbf7 100644 --- a/tcpreceive.c +++ b/tcpreceive.c @@ -1,332 +1,297 @@ -/* 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 _WIN32 -#include -#include /* for socklen_t */ -#else -#include -#include -#include -#include -#include -#include -#endif +/* tcpreceive.c + * copyright (c) 2010 IOhannes m zmölnig, IEM + * copyright (c) 2006-2010 Martin Peach + * copyright (c) Miller Puckette + */ + +/* */ +/* A client for unidirectional communication from within Pd. */ +/* */ +/* 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. */ +/* */ + +#include "iemnet.h" +#ifndef _WIN32 +# include +#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; - unsigned short port; - int socket; + long addr; + unsigned short port; + int socket; + struct _tcpreceive*owner; + t_iemnet_receiver*receiver; } 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[5]; - t_atom x_msgoutbuf[MAX_UDP_RECEIVE]; - char x_msginbuf[MAX_UDP_RECEIVE]; + 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[5]; } t_tcpreceive; -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, unsigned short port); -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 unsigned short tcpreceive_getconnectionport(t_tcpreceive * x, int fd); - -static void tcpreceive_read(t_tcpreceive *x, int sockfd) -{ - int i, read = 0; - long addr; - unsigned short port; -// 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); - port = tcpreceive_getconnectionport(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); - x->x_addrbytes[4].a_w.w_float = port; - outlet_list(x->x_addrout, &s_list, 5L, 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 int tcpreceive_find_socket(t_tcpreceive *x, int fd) { + int i; + for (i = 0; i < MAX_CONNECTIONS; ++i) + if (x->x_connection[i].socket == fd)return i; + + return -1; } -static void *tcpreceive_new(t_floatarg fportno) +static int tcpreceive_disconnect(t_tcpreceive *x, int id); + +static void tcpreceive_read_callback(t_tcpconnection *y, int argc, t_atom*argv) { - t_tcpreceive *x; - struct sockaddr_in server; - int sockfd, portno = fportno; - int intarg, i; + t_tcpreceive*x=NULL; + if(NULL==y || NULL==(x=y->owner))return; + int index=tcpreceive_find_socket(x, y->socket); + if(index>=0) { - /* 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; - x->x_connection[i].port = 0; - } - /* 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 < 5; ++i) - { - x->x_addrbytes[i].a_type = A_FLOAT; - x->x_addrbytes[i].a_w.w_float = 0; + if(argc) { + // outlet info about connection + outlet_list(x->x_msgout, gensym("list"), argc, argv); + } else { + // disconnected + int sockfd=y->socket; + tcpreceive_disconnect(x, index); } + } - /* streaming protocol */ - if (listen(sockfd, 5) < 0) - { - sys_sockerror("tcpreceive: listen"); - sys_closesocket(sockfd); - sockfd = -1; - } - else +} + + +/* 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, unsigned short port) +{ + int i; + for (i = 0; i < MAX_CONNECTIONS; ++i) { - sys_addpollfn(sockfd, (t_fdpollfn)tcpreceive_connectpoll, x); + if (x->x_connection[i].socket == -1) + { + x->x_connection[i].socket = fd; + x->x_connection[i].addr = addr; + x->x_connection[i].port = port; + x->x_connection[i].owner = x; + x->x_connection[i].receiver= + iemnet__receiver_create(fd, + x->x_connection+i, + (t_iemnet_receivecallback)tcpreceive_read_callback); + + return 1; + } } - x->x_connectsocket = sockfd; - x->x_nconnections = 0; - -//udp version... sys_addpollfn(x->x_connectsocket, (t_fdpollfn)tcpreceive_read, x); - return (x); + return 0; } + /* 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; - unsigned short port; - int fd; - - fd = accept(x->x_connectsocket, (struct sockaddr *)&from, &fromlen); - if (fd < 0) post("tcpreceive: accept failed"); - else + struct sockaddr_in from; + socklen_t fromlen = sizeof(from); + long addr; + unsigned short port; + 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); - port = ntohs(from.sin_port); - if (tcpreceive_addconnection(x, fd, addr, port)) - { - 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); - x->x_addrbytes[4].a_w.w_float = port; - outlet_list(x->x_addrout, &s_list, 5L, x->x_addrbytes); + // 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); + port = ntohs(from.sin_port); + if (tcpreceive_addconnection(x, fd, addr, port)) + { + 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); + x->x_addrbytes[4].a_w.w_float = port; + outlet_list(x->x_addrout, &s_list, 5L, x->x_addrbytes); } - else + else { - error ("tcpreceive: Too many connections"); - sys_closesocket(fd); + 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, unsigned short port) + +static int tcpreceive_disconnect(t_tcpreceive *x, int id) { - 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; - x->x_connection[i].port = port; - return 1; - } - } - return 0; + if(id>=0 && id < MAX_CONNECTIONS && x->x_connection[id].port>0) { + iemnet__receiver_destroy(x->x_connection[id].receiver); + x->x_connection[id].receiver=NULL; + + sys_closesocket(x->x_connection[id].socket); + x->x_connection[id].socket = -1; + + x->x_connection[id].addr = 0L; + x->x_connection[id].port = 0; + x->x_nconnections--; + outlet_float(x->x_connectout, x->x_nconnections); + return 1; + } + + return 0; } /* tcpreceive_closeall closes all open sockets and deletes them from the list */ -static void tcpreceive_closeall(t_tcpreceive *x) +static void tcpreceive_disconnect_all(t_tcpreceive *x) { - int i; + int i; - for (i = 0; ((i < MAX_CONNECTIONS) && (x->x_nconnections > 0)); ++i) + for (i = 0; i < MAX_CONNECTIONS; 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; - x->x_connection[i].port = 0; - outlet_float(x->x_connectout, --x->x_nconnections); - } + tcpreceive_disconnect(x, i); } } + + + /* 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) +static int tcpreceive_disconnect_socket(t_tcpreceive *x, int fd) { - int i; - for (i = 0; i < MAX_CONNECTIONS; ++i) + int i; + for (i = 0; i < MAX_CONNECTIONS; ++i) { - if (x->x_connection[i].socket == fd) + if (x->x_connection[i].socket == fd) { - x->x_connection[i].socket = -1; - x->x_connection[i].addr = 0L; - x->x_connection[i].port = 0; - return 1; + return tcpreceive_disconnect(x, i); } } - return 0; + return 0; } -/* tcpreceive_getconnectionport tries to find the socket fd in the list */ -/* returns port on success, else 0 */ -static u_short tcpreceive_getconnectionport(t_tcpreceive *x, int fd) -{ - int i; - for (i = 0; i < MAX_CONNECTIONS; ++i) +static void tcpreceive_free(t_tcpreceive *x) +{ /* is this ever called? */ + if (x->x_connectsocket >= 0) { - if (x->x_connection[i].socket == fd) - return x->x_connection[i].port; + sys_rmpollfn(x->x_connectsocket); + sys_closesocket(x->x_connectsocket); } - return 0; + tcpreceive_disconnect_all(x); } -/* 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) +static void *tcpreceive_new(t_floatarg fportno) { - int i; - for (i = 0; i < MAX_CONNECTIONS; ++i) + 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) { - if (x->x_connection[i].socket == fd) - return x->x_connection[i].addr; + sys_sockerror("tcpreceive: socket"); + return (0); } - return 0; -} + server.sin_family = AF_INET; + server.sin_addr.s_addr = INADDR_ANY; -static void tcpreceive_free(t_tcpreceive *x) -{ /* is this ever called? */ - if (x->x_connectsocket >= 0) + /* 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_rmpollfn(x->x_connectsocket); - sys_closesocket(x->x_connectsocket); + sys_sockerror("tcpreceive: bind"); + sys_closesocket(sockfd); + return (0); } - tcpreceive_closeall(x); + 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; + x->x_connection[i].port = 0; + } + for (i = 0; i < 5; ++i) + { + SETFLOAT(x->x_addrbytes+i, 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; + + return (x); } + 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); + tcpreceive_class = class_new(gensym("tcpreceive"), + (t_newmethod)tcpreceive_new, (t_method)tcpreceive_free, + sizeof(t_tcpreceive), CLASS_NOINLET, A_DEFFLOAT, 0); } /* end x_net_tcpreceive.c */ diff --git a/tcpsend.c b/tcpsend.c index b576eae..98ac620 100644 --- a/tcpsend.c +++ b/tcpsend.c @@ -1,254 +1,156 @@ -/* 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" -#include +/* tcpsend.c + * copyright (c) 2010 IOhannes m zmölnig, IEM + * copyright (c) 2006-2010 Martin Peach + * copyright (c) Miller Puckette + */ + +/* */ +/* A client for unidirectional communication from within Pd. */ +/* */ +/* 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. */ +/* */ + + +#include "iemnet.h" #include -#ifdef _WIN32 -#include -#else -#include -#include -#include -#include -#include +#ifndef _WIN32 +# include #endif + static t_class *tcpsend_class; typedef struct _tcpsend { - t_object x_obj; - int x_fd; + t_object x_obj; + int x_fd; + t_iemnet_sender*x_sender; } t_tcpsend; -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) +static void tcpsend_disconnect(t_tcpsend *x) { - t_tcpsend *x = (t_tcpsend *)pd_new(tcpsend_class); - outlet_new(&x->x_obj, &s_float); - x->x_fd = -1; - return (x); + if (x->x_fd >= 0) + { + if(x->x_sender)iemnet__sender_destroy(x->x_sender); x->x_sender=NULL; + sys_closesocket(x->x_fd); + x->x_fd = -1; + outlet_float(x->x_obj.ob_outlet, 0); + post("tcpsend: disconnected"); + } } + + static void tcpsend_connect(t_tcpsend *x, t_symbol *hostname, - t_floatarg fportno) + t_floatarg fportno) { - struct sockaddr_in server; - struct hostent *hp; - int sockfd; - int portno = fportno; - int intarg; + struct sockaddr_in server; + struct hostent *hp; + int sockfd; + int portno = fportno; + int intarg; - if (x->x_fd >= 0) + if (x->x_fd >= 0) { - error("tcpsend: already connected"); - return; + error("tcpsend: already connected"); + return; } - /* create a socket */ - sockfd = socket(AF_INET, SOCK_STREAM, 0); + /* create a socket */ + sockfd = socket(AF_INET, SOCK_STREAM, 0); #ifdef DEBUG - fprintf(stderr, "tcpsend_connect: send socket %d\n", sockfd); + fprintf(stderr, "tcpsend_connect: send socket %d\n", sockfd); #endif - if (sockfd < 0) + if (sockfd < 0) { - sys_sockerror("tcpsend: socket"); - return; + 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) + /* 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; + 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"); + /* 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); + memcpy((char *)&server.sin_addr, (char *)hp->h_addr, hp->h_length); - /* assign client port number */ - server.sin_port = htons((u_short)portno); + /* 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) + 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; + sys_sockerror("tcpsend: connecting stream socket"); + sys_closesocket(sockfd); + return; } - x->x_fd = sockfd; - outlet_float(x->x_obj.ob_outlet, 1); -} + x->x_fd = sockfd; -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"); - } + x->x_sender=iemnet__sender_create(sockfd); + + outlet_float(x->x_obj.ob_outlet, 1); } static void tcpsend_send(t_tcpsend *x, t_symbol *s, int argc, t_atom *argv) { -#define BYTE_BUF_LEN 65536 // arbitrary maximum similar to max IP packet size - static char byte_buf[BYTE_BUF_LEN]; - int i, j; - unsigned int 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; - char fpath[FILENAME_MAX]; - FILE *fptr; - -#ifdef DEBUG - post("s: %s", s->s_name); - post("argc: %d", argc); -#endif - for (i = j = 0; i < argc; ++i) - { - if (argv[i].a_type == A_FLOAT) - { - f = argv[i].a_w.w_float; - d = (unsigned 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[j++] = c; - } - else if (argv[i].a_type == A_SYMBOL) - { - - atom_string(&argv[i], fpath, FILENAME_MAX); -#ifdef DEBUG - post ("tcpsend fname: %s", fpath); -#endif - fptr = fopen(fpath, "rb"); - if (fptr == NULL) - { - post("tcpsend: unable to open \"%s\"", fpath); - return; - } - rewind(fptr); -#ifdef DEBUG - post("tcpsend: d is %d", d); -#endif - while ((d = fgetc(fptr)) != EOF) - { - byte_buf[j++] = (char)(d & 0x0FF); -#ifdef DEBUG - post("tcpsend: byte_buf[%d] = %d", j-1, byte_buf[j-1]); -#endif - if (j >= BYTE_BUF_LEN) - { - post ("tcpsend: file too long, truncating at %lu", BYTE_BUF_LEN); - break; - } - } - fclose(fptr); - fptr = NULL; - post("tcpsend: read \"%s\" length %d byte%s", fpath, j, ((d==1)?"":"s")); - } - else - { - error("tcpsend_send: item %d is not a float or a file name", i); - return; - } - } - - length = j; - if ((x->x_fd >= 0) && (length > 0)) - { - for (bp = byte_buf, sent = 0; sent < length;) - { - timebefore = sys_getrealtime(); - result = send(x->x_fd, byte_buf, length-sent, 0); - timeafter = sys_getrealtime(); - late = (timeafter - timebefore > 0.005); - if (late || pleasewarn) - { - if (timeafter > lastwarntime + 2) - { - post("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"); + int size=0; + t_iemnet_sender*sender=x->x_sender; + t_iemnet_chunk*chunk=iemnet__chunk_create_list(argc, argv); + if(sender && chunk) { + size=iemnet__sender_send(sender, chunk); + } + iemnet__chunk_destroy(chunk); } static void tcpsend_free(t_tcpsend *x) { - tcpsend_disconnect(x); + tcpsend_disconnect(x); +} + +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); } 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); - class_addlist(tcpsend_class, (t_method)tcpsend_send); + 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); + class_addlist(tcpsend_class, (t_method)tcpsend_send); } /* end tcpsend.c */ diff --git a/tcpserver.c b/tcpserver.c index e84eb10..8e99eb7 100644 --- a/tcpserver.c +++ b/tcpserver.c @@ -27,12 +27,8 @@ //#define DEBUG #include "iemnet.h" -#include "s_stuff.h" - -#if defined(UNIX) || defined(unix) +#ifndef _WIN32 # include -#else -# include #endif @@ -45,6 +41,8 @@ static char objName[] = "tcpserver"; typedef struct _tcpserver_socketreceiver { + struct _tcpserver *sr_owner; + t_symbol *sr_host; t_int sr_fd; t_iemnet_sender*sr_sender; @@ -66,20 +64,22 @@ typedef struct _tcpserver t_atom x_addrbytes[4]; } t_tcpserver; -static void tcpserver_receive_callback(t_tcpserver *x, int sockfd, int argc, t_atom*argv); +static void tcpserver_receive_callback(t_tcpserver_socketreceiver*x, int argc, t_atom*argv); -static t_tcpserver_socketreceiver *tcpserver_socketreceiver_new(void *owner, int sockfd, t_symbol*host) +static t_tcpserver_socketreceiver *tcpserver_socketreceiver_new(t_tcpserver *owner, int sockfd, t_symbol*host) { t_tcpserver_socketreceiver *x = (t_tcpserver_socketreceiver *)getbytes(sizeof(*x)); if(NULL==x) { error("%s_socketreceiver: unable to allocate %d bytes", objName, sizeof(*x)); return NULL; } else { - x->sr_host=host; - x->sr_fd=sockfd; + x->sr_owner=owner; + + x->sr_host=host; + x->sr_fd=sockfd; - x->sr_sender=iemnet__sender_create(sockfd); - x->sr_receiver=iemnet__receiver_create(sockfd, owner, (t_iemnet_receivecallback)tcpserver_receive_callback); + x->sr_sender=iemnet__sender_create(sockfd); + x->sr_receiver=iemnet__receiver_create(sockfd, x, (t_iemnet_receivecallback)tcpserver_receive_callback); } return (x); } @@ -93,6 +93,11 @@ static void tcpserver_socketreceiver_free(t_tcpserver_socketreceiver *x) sys_closesocket(x->sr_fd); + x->sr_owner=NULL; + x->sr_sender=NULL; + x->sr_receiver=NULL; + x->sr_fd=-1; + freebytes(x, sizeof(*x)); } } @@ -294,16 +299,16 @@ static void tcpserver_disconnect_all(t_tcpserver *x) } } - - - - /* ---------------- main tcpserver (receive) stuff --------------------- */ -static void tcpserver_receive_callback(t_tcpserver *x, int sockfd, int argc, t_atom*argv) { - if(argc) { +static void tcpserver_receive_callback(t_tcpserver_socketreceiver *y, int argc, t_atom*argv) { + t_tcpserver*x=NULL; + if(NULL==y || NULL==(x=y->sr_owner))return; + + if(argc) { outlet_list(x->x_msgout, gensym("list"), argc, argv); } else { // disconnected + int sockfd=y->sr_fd; tcpserver_disconnect_socket(x, sockfd); } -- cgit v1.2.1