From 6e8398df98237d7cf85fc14e369534f7ffa833a9 Mon Sep 17 00:00:00 2001 From: Martin Peach Date: Mon, 20 May 2013 22:37:36 +0000 Subject: Added a port method to change the listening port. svn path=/trunk/externals/mrpeach/; revision=17143 --- net/tcpserver.c | 97 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 96 insertions(+), 1 deletion(-) (limited to 'net/tcpserver.c') diff --git a/net/tcpserver.c b/net/tcpserver.c index 379a7ec..ca872b4 100644 --- a/net/tcpserver.c +++ b/net/tcpserver.c @@ -112,6 +112,7 @@ typedef struct _tcpserver t_atom x_addrbytes[4]; t_int x_sock_fd; t_int x_connectsocket; + t_int x_port; t_int x_nconnections; t_int x_blocked; t_atom x_msgoutbuf[MAX_UDP_RECEIVE]; @@ -151,6 +152,7 @@ static void tcpserver_connectpoll(t_tcpserver *x); static void tcpserver_print(t_tcpserver *x); static void tcpserver_unblock(t_tcpserver *x); static void *tcpserver_new(t_floatarg fportno); +static void tcpserver_port(t_tcpserver *x, t_floatarg fportno); static void tcpserver_free(t_tcpserver *x); void tcpserver_setup(void); static void tcpserver_dump(t_tcpserver *x, t_float dump); @@ -1142,6 +1144,96 @@ static void tcpserver_unblock(t_tcpserver *x) x->x_blocked = 0; } +static void tcpserver_port(t_tcpserver*x, t_floatarg fportno) +{ + t_atom output_atom; + int portno = fportno; + struct sockaddr_in server; + socklen_t serversize = sizeof(server); + int sockfd = x->x_connectsocket; + int optVal = 1; + int optLen = sizeof(int); + + + if(x->x_port == portno) return; + + if(x->x_nconnections > 0) + { + post ("%s: can't change port (connection count is %d)", objName, x->x_nconnections); + return; + } + + SETFLOAT(&output_atom, -1); + + /* shut down the old socket */ + if (sockfd >= 0) + { + sys_rmpollfn(sockfd); + sys_closesocket(sockfd); + x->x_connectsocket = -1; + x->x_port = -1; + } + + /* create a whole new 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; + } + server.sin_family = AF_INET; + server.sin_addr.s_addr = INADDR_ANY; + /* enable reuse of local address */ +#ifdef _WIN32 + if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, (char*)&optVal, optLen) == SOCKET_ERROR) +#else + if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, (char*)&optVal, optLen) == -1) +#endif + sys_sockerror("tcpserver: setsockopt SO_REUSEADDR"); + + /* assign server port number */ + server.sin_port = htons((u_short)portno); + /* name the socket */ + if (bind(sockfd, (struct sockaddr *)&server, serversize) < 0) + { + sys_sockerror("tcpserver: bind"); + sys_closesocket(sockfd); + outlet_anything(x->x_status_outlet, gensym("port"), 1, &output_atom); + return; + } + + /* streaming protocol */ + if (listen(sockfd, 5) < 0) + { + sys_sockerror("tcpserver: listen"); + sys_closesocket(sockfd); + sockfd = -1; + outlet_anything(x->x_status_outlet, gensym("port"), 1, &output_atom); + return; + } + else + { + sys_addpollfn(sockfd, (t_fdpollfn)tcpserver_connectpoll, x); // wait for new connections + } + + x->x_connectsocket = sockfd; + x->x_nconnections = 0; + x->x_blocked = 0; + + + // find out which port is actually used (useful when assigning "0") + if(!getsockname(sockfd, (struct sockaddr *)&server, &serversize)) + { + x->x_port=ntohs(server.sin_port); + } + + SETFLOAT(&output_atom, x->x_port); + outlet_anything(x->x_status_outlet, gensym("port"), 1, &output_atom); +} + static void *tcpserver_new(t_floatarg fportno) { t_tcpserver *x; @@ -1215,10 +1307,12 @@ static void *tcpserver_new(t_floatarg fportno) x->x_addrbytes[i].a_type = A_FLOAT; x->x_addrbytes[i].a_w.w_float = 0; } - post ("tcpserver listening on port %d", portno); + x->x_port = portno; + post ("tcpserver listening on port %d", x->x_port); return (x); } + static void tcpserver_free(t_tcpserver *x) { int i; @@ -1257,6 +1351,7 @@ void tcpserver_setup(void) class_addmethod(tcpserver_class, (t_method)tcpserver_dump, gensym("dump"), A_FLOAT, 0); class_addmethod(tcpserver_class, (t_method)tcpserver_unblock, gensym("unblock"), 0); class_addmethod(tcpserver_class, (t_method)tcpserver_broadcast, gensym("broadcast"), A_GIMME, 0); + class_addmethod(tcpserver_class, (t_method)tcpserver_port, gensym("port"), A_FLOAT, 0); class_addlist(tcpserver_class, (t_method)tcpserver_send); } -- cgit v1.2.1