/* -------------------------- flashserver ----------------------------------- */ /* */ /* A server for bidirectional communication between Flash and Pd. */ /* Use XMLsocket() functions in Macromedia Flash 5.0 to connect to it. */ /* Written by Olaf Matthes */ /* Get source at http://www.akustische-kunst.org/puredata/flash/ */ /* */ /* 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. */ /* Inspired by work done by Eric Skogen (http://www.cyburrs.com/eskogen/). */ /* */ /* ---------------------------------------------------------------------------- */ #include "m_pd.h" #include "s_stuff.h" /* for socket / networking stuff borought from Pd */ #include "m_imp.h" /* we need more than just m_pd.h */ #include #include #include #include #include #include #include #include /* needs pthread library on win! */ #ifdef UNIX #include #include #include #include #include #include #include #include #include #include #include #include #define SOCKET_ERROR -1 #else #include #include #include #endif #define MAX_CONNECT 256 /* maximum number of connected Flash clients */ #define INBUFSIZE 4096 /* size of receiving data buffer */ #define DEFSTRSIZE 256 /* default size for strings */ static char *version = "flashserver v0.2h :: bidirectional communication between Flash and Pd\n" " written by Olaf Matthes "; /* ----------------------------- flashserver ------------------------- */ static t_class *flashserver_class; static t_binbuf *b; /* a binbuf used to parse output data */ static char databuf[INBUFSIZE]; /* the string we received from Flash client */ typedef void (*t_flashserver_socketnotifier)(void *x); typedef void (*t_flashserver_socketreceivefn)(void *x, char *buf); typedef struct _flashserver { t_object x_obj; t_outlet *x_msgout; /* output for the received message */ t_outlet *x_connectout; /* output for number of connections (0 - MAX_CONNECT) */ t_outlet *x_clientno; /* output for client number (0 - MAX_CONNECT) */ t_outlet *x_clientsock; /* output for socket number */ t_outlet *x_connectionip; /* outlet for the IP we just got data from */ t_canvas *x_canvas; /* needed to get current directory */ t_symbol *x_host[MAX_CONNECT]; /* list of all hostnames */ t_int x_fd[MAX_CONNECT]; /* list of all socket numbers */ t_int x_client[MAX_CONNECT]; /* the client number assigned to each client */ t_int x_clientlist[MAX_CONNECT]; /* list of client numbers already in use */ t_int x_sock_fd; /* the socket number we just got data from */ t_int x_connectsocket; /* number of socket we are listening on */ t_int x_nconnections; /* total number of open connections */ t_int x_maxconnect; /* user setable maximum number of connections */ t_int x_prepend; /* prepend client number to output data */ t_int x_verbose; } t_flashserver; typedef struct _flashserver_socketreceiver { char *sr_inbuf; /* data we got from clients, a plain character string */ int sr_inhead; /* writing position in above receive buffer */ int sr_intail; /* reading position in above receive buffer */ void *sr_owner; /* we'll put the correcponding t_flashserver in here */ t_flashserver_socketnotifier sr_notifier; t_flashserver_socketreceivefn sr_socketreceivefn; } t_flashserver_socketreceiver; /* some prototypes (as needed) */ static void flashserver_notify(t_flashserver *x); /* notify us in case a client disconnected */ static void flashserver_client_remove(t_flashserver *x, int sockfd);/* remove client from list */ static int flashserver_get_client(t_flashserver *x, int sockno); /* find client number */ static int flashserver_get_socket(t_flashserver *x, int client); /* find socket */ static int flashserver_get_entry(t_flashserver *x, int sockno); /* find number of entry */ /* ----------- socket utility functions ----------- */ /* set SO_KEEPALIVE option for socket */ static int flashserver_socket_set_keepalive(int sockfd) { int keepalive = 1; return setsockopt(sockfd, SOL_SOCKET, SO_KEEPALIVE, (void *)&keepalive, sizeof(int)); } /* set SO_SNDBUF to 0 -> disable send buffer */ static int flashserver_socket_disable_buffer(int sockfd) { int zero = 0; /* the buffer size */ return setsockopt(sockfd, SOL_SOCKET, SO_SNDBUF, (char *)&zero, sizeof(zero)); } /* ----------- socket receiver funtions ----------- */ static t_flashserver_socketreceiver *flashserver_socketreceiver_new(void *owner, t_flashserver_socketnotifier notifier, t_flashserver_socketreceivefn socketreceivefn) { t_flashserver_socketreceiver *x = (t_flashserver_socketreceiver *)getbytes(sizeof(*x)); 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))) bug("t_flashserver_socketreceiver"); 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 flashserver_socketreceiver_doread(t_flashserver_socketreceiver *x) { char messbuf[INBUFSIZE], *bp = messbuf; int indx; int inhead = x->sr_inhead; int intail = x->sr_intail; char *inbuf = x->sr_inbuf; if (intail == inhead) return (0); for (indx = intail; indx != inhead; indx = (indx+1)&(INBUFSIZE-1)) { char c = *bp++ = inbuf[indx]; /* we split the buffer at terminating null character */ if (((c == '\0' || c == '\n') && (!indx || inbuf[indx-1] != '\\'))) { intail = (indx+1)&(INBUFSIZE-1); /* copy data into buffer we pass on to flashserver_doit */ strncpy(databuf, messbuf, bp - messbuf); x->sr_inhead = inhead; x->sr_intail = intail; return (1); } } return (0); } static void flashserver_socketreceiver_read(t_flashserver_socketreceiver *x, int fd) { char *semi; int readto = (x->sr_inhead >= x->sr_intail ? INBUFSIZE : x->sr_intail-1); int ret; t_flashserver *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("flashserver: dropped message"); 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("recv"); if (x->sr_notifier) (*x->sr_notifier)(x->sr_owner); sys_rmpollfn(fd); sys_closesocket(fd); } else if (ret == 0) { post("flashserver: connection closed on socket %d", fd); if (x->sr_notifier) (*x->sr_notifier)(x->sr_owner); sys_rmpollfn(fd); sys_closesocket(fd); } else { x->sr_inhead += ret; if (x->sr_inhead >= INBUFSIZE) x->sr_inhead = 0; while (flashserver_socketreceiver_doread(x)) { outlet_setstacklim(); if (x->sr_socketreceivefn) (*x->sr_socketreceivefn)(x->sr_owner, databuf); // else binbuf_eval(inbinbuf, 0, 0, 0); } } } } static void flashserver_socketreceiver_free(t_flashserver_socketreceiver *x) { free(x->sr_inbuf); freebytes(x, sizeof(*x)); } /* ------------------ main flashserver send stuff ----------------------- */ /* flashserver_send_doit() - send data to client, might return an error in case client disconnected LATER put this into a seperate thread because send might block, e.g. in case a client disconnects during send or crashes... */ static int flashserver_send_doit(t_flashserver *x, int sockfd, char *buf, int length, int client) { int sent; for (sent = 0; sent < length;) { static double lastwarntime; static double pleasewarn; double timebefore = clock_getlogicaltime(); #ifndef __linux__ int res = send(sockfd, buf+sent, length-sent, 0); #else int res = send(sockfd, buf+sent, length-sent, MSG_DONTWAIT|MSG_NOSIGNAL); #endif double timeafter = clock_getlogicaltime(); int late = (timeafter - timebefore > 0.005); if (late || pleasewarn) { if (timeafter > lastwarntime + 2) { post("flashserver blocked %d msec", (int)(1000 * ((timeafter - timebefore) + pleasewarn))); pleasewarn = 0; lastwarntime = timeafter; } else if (late) pleasewarn += timeafter - timebefore; } if (res <= 0) { sys_sockerror("flashserver"); post("flashserver: could not send data to cient #%d, disconnecting", client+1); flashserver_client_remove(x, sockfd); sys_rmpollfn(sockfd); sys_closesocket(sockfd); return -1; } else { sent += res; } } return sent; } /* send XML message consisting of a symbol and a float to client using socket number, messages are terminated with a null character */ static void flashserver_sendXML(t_flashserver *x, t_symbol *s, int argc, t_atom *argv) { int sockfd, client = -1, i; char XMLmsg[DEFSTRSIZE]; if(x->x_nconnections < 0) { post("flashserver: no Flash clients connected"); return; } if(argc < 2) { post("flashserver: nothing to send"); return; } /* get socket number of connection (first element in list) */ if(argv[0].a_type == A_FLOAT) { sockfd = atom_getfloatarg(0, argc, argv); client = flashserver_get_client(x, sockfd); if(client == -1) /* no Flash client found ? */ { post("flashserver: no Flash client on socket %d", sockfd); return; } } else { post("flashserver: no socket specified"); return; } /* process & send data */ if(sockfd > 0) { t_symbol *XMLsym; t_float XMLvalue; int length; /* get symbol and value from input */ if(argv[1].a_type == A_SYMBOL) { XMLsym = atom_getsymbolarg(1, argc, argv); if(argv[2].a_type == A_FLOAT) { XMLvalue = atom_getfloatarg(2, argc, argv); } else { post("flashserver: no value specified"); return; } } else { post("flashserver: no symbol specified"); return; } /* build up XML message */ sprintf(XMLmsg, "", XMLsym->s_name, XMLvalue); if(x->x_verbose)post("flashserver: sending data to client #%d on socket %d", client + 1, sockfd); length = strlen(XMLmsg) + 1; /* lenght of string including terminating null character ! */ if(x->x_verbose)post("flashserver: sending XML: \n%s", XMLmsg); flashserver_send_doit(x, sockfd, XMLmsg, length, client); } else post("flashserver: not a valid socket number (%d)", sockfd); } /* send message to client using socket number, messages are terminated with a null character, not with A_SEMMI as it would be needed for Pd ! */ static void flashserver_send(t_flashserver *x, t_symbol *s, int argc, t_atom *argv) { int sockfd, client = -1, i; if(x->x_nconnections < 0) { post("flashserver: no Flash clients connected"); return; } if(argc < 2) { post("flashserver: nothing to send"); 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 = x->x_client[i]; /* the client we're sending to */ break; } } if(client == -1) /* still no Flash client found ? */ { post("flashserver: no client on socket %d", sockfd); return; } } else { post("flashserver: no socket specified"); return; } /* process & send data */ if(sockfd > 0) { t_binbuf *bb = binbuf_new(); char *buf; int length, sent; if(x->x_verbose)post("flashserver: sending data to client #%d on socket %d", client+1, sockfd); binbuf_add(bb, argc - 1, argv + 1); /* skip first element which is the socket no. */ binbuf_gettext(bb, &buf, &length); /* convert binbuf into string */ buf[length] = '\0'; /* append null termination '\0' */ strcat(buf, ";"); /* add A_SEMI at end of binbuf */ length = strlen(buf) + 1; /* we send one character more because we must include the '\0' for Flash ! */ if(x->x_verbose)post("flashserver: sending \"%s\"", buf); // flashserver_check_socket(x, sockfd); flashserver_send_doit(x, sockfd, buf, length, client); t_freebytes(buf, length); binbuf_free(bb); } else post("flashserver: not a valid socket number (%d)", sockfd); } /* send XML message to client using client number */ static void flashserver_client_sendXML(t_flashserver *x, t_symbol *s, int argc, t_atom *argv) { int sock = -1, client, i; if(x->x_nconnections < 0) { post("flashserver: no clients connected"); return; } if(argc < 2) { post("flashserver: nothing to send"); return; } /* get number of client (first element in list) */ if(argv[0].a_type == A_FLOAT) client = atom_getfloatarg(0, argc, argv); else { post("flashserver: no client specified"); return; } if((sock = flashserver_get_socket(x, client-1)) < 0) { post("flashserver: client #%d does not exist", client); return; } argv[0].a_w.w_float = sock; /* replace client # with socket number */ flashserver_sendXML(x, NULL, argc, argv); /* call send routine with socket number */ } /* send message to client using client number */ static void flashserver_client_send(t_flashserver *x, t_symbol *s, int argc, t_atom *argv) { int sock = -1, client, i; if(x->x_nconnections < 0) { post("flashserver: no clients connected"); return; } if(argc < 2) { post("flashserver: nothing to send"); return; } /* get number of client (first element in list) */ if(argv[0].a_type == A_FLOAT) client = atom_getfloatarg(0, argc, argv); else { post("flashserver: no client specified"); return; } if((sock = flashserver_get_socket(x, client-1)) < 0) { post("flashserver: client #%d does not exist", client); return; } argv[0].a_w.w_float = sock; /* replace client # with socket number */ flashserver_send(x, NULL, argc, argv); /* call send routine with socket number */ } /* broadcasts a XML message to all connected Flash clients */ static void flashserver_broadcastXML(t_flashserver *x, t_symbol *s, int argc, t_atom *argv) { int i, c = x->x_nconnections; t_atom at[MAX_CONNECT]; if(x->x_nconnections == 0) return; /* check if there are any clients connected */ for(i = 0; i < argc; i++) { at[i + 1] = argv[i]; } argc++; /* enumerate through the clients and send each socket the message */ while(c--) { SETFLOAT(at, x->x_fd[c]); /* prepend number of client */ flashserver_sendXML(x, s, argc, at); } } /* broadcasts a message to all connected Flash clients */ static void flashserver_broadcast(t_flashserver *x, t_symbol *s, int argc, t_atom *argv) { int i, c = x->x_nconnections; t_atom at[MAX_CONNECT]; if(x->x_nconnections == 0) return; /* check if there are any clients connected */ for(i = 0; i < argc; i++) { at[i + 1] = argv[i]; } argc++; /* enumerate through the clients and send each socket the message */ while(c--) { SETFLOAT(at, x->x_fd[c]); /* prepend number of client */ flashserver_send(x, s, argc, at); } } /* ---------------- main flashserver receive stuff --------------------- */ static void flashserver_client_remove(t_flashserver *x, int sockfd) { int i, k; /* remove connection from list */ for(i = 0; i < x->x_nconnections; i++) { if(x->x_fd[i] == sockfd) { x->x_nconnections--; post("flashserver: client #%d (\"%s\") removed from list of clients", x->x_client[i] + 1, x->x_host[i]->s_name); x->x_host[i] = NULL; /* delete entry */ x->x_fd[i] = -1; x->x_clientlist[x->x_client[i]] = -1; /* free client number in list */ /* 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]; x->x_client[k] = x->x_client[k + 1]; } } } outlet_float(x->x_connectout, x->x_nconnections); } /* gets called whenever a client disconnects and removes this client from the list of clients and reports new number of clients */ static void flashserver_notify(t_flashserver *x) { flashserver_client_remove(x, x->x_sock_fd); } /* find the entry number for a given socket */ static int flashserver_get_entry(t_flashserver *x, int sockno) { int i; /* look at all clients... */ for(i = 0; i < x->x_nconnections; i++) { if(x->x_fd[i] == sockno) { return i; } } return -1; /* return an error in case there is no match */ } /* find the client for a given socket number */ static int flashserver_get_client(t_flashserver *x, int sockno) { int i; /* look at all clients... */ for(i = 0; i < x->x_nconnections; i++) /* search for specified socket number */ { if(x->x_fd[i] == sockno) { return i; /* return the result */ } } return -1; /* return an error in case there is no match */ } /* find the socket for a given client */ static int flashserver_get_socket(t_flashserver *x, int client) { int i; /* look at all entries... */ for(i = 0; i < x->x_nconnections; i++) /* search for specified client number */ { if(x->x_client[i] == client) { return x->x_fd[i]; /* return the socket */ } } return -1; /* return an error in case there is no match */ } /* kick client number f */ static void flashserver_client_kick(t_flashserver *x, t_floatarg f) { int client = (int)f; int sockfd = flashserver_get_socket(x, client-1); /* find socket */ int i = flashserver_get_entry(x, sockfd); /* find the entry */ if(sockfd == -1) { post("flashserver: client #%d does not exist", client); return; } post("flashserver: kicking client #%d (\"%s\") on socket %d", client, x->x_host[i]->s_name, sockfd); flashserver_client_remove(x, sockfd); sys_rmpollfn(sockfd); sys_closesocket(sockfd); } /* send out socket number and client allocation number */ static void flashserver_identify(t_flashserver *x) { int i = flashserver_get_client(x, x->x_sock_fd); if(i == -1) { post("flashserver: internal error"); return; } outlet_symbol(x->x_connectionip, x->x_host[i]); /* client's IP address */ outlet_float(x->x_clientsock, x->x_sock_fd); /* the socket number */ outlet_float(x->x_clientno, x->x_client[i] + 1); /* the client's allocation number */ } static void flashserver_doit(void *z, char *buf) { t_atom messbuf[1024]; t_flashserver *x = (t_flashserver *)z; int msg, natom; t_atom *at; int i, length; /* check for valid data in this string */ if(strstr(buf, "GET / HTTP/1.0")) /* oops, got a HTTP request */ { post("flashserver: HTTP requests not supported"); return; } else if(strstr(buf, " */ if(t = strstr(buf, "symbol=\"")) { stringlength = strcspn(t+8, "\""); s = getbytes(stringlength + 1); strncpy(s, t+8, stringlength); /* copy up to next 'inverted commas' */ XMLsym = gensym(s); if(t = strstr(t+8, "value=\"")) { XMLvalue = atof(t+7); /* prepare list for output */ if(x->x_prepend)SETFLOAT(list, x->x_client[flashserver_get_client(x, x->x_sock_fd)] + 1); SETSYMBOL(list+x->x_prepend, XMLsym); SETFLOAT(list+x->x_prepend+1, XMLvalue); outlet_list(x->x_msgout, 0, 2+x->x_prepend, list); } else post("flashserver: got corrupted XML data"); freebytes(s, stringlength + 1); } else post("flashserver: got corrupted XML data"); } else if(strstr(buf, ";\0")) /* (probably) got Pd conform data */ { /* with semi and null termination at the end */ /* prepend client number if user chose to do so */ if(x->x_prepend) { char buf2[DEFSTRSIZE]; strcpy(buf2, buf); sprintf(buf, "%d ", x->x_client[flashserver_get_client(x, x->x_sock_fd)] + 1); strcat(buf, buf2); } /* convert the string buffer we received into a binbuf */ binbuf_text(b, buf, strlen(buf)); /* get content out of binbuf */ natom = binbuf_getnatom(b); at = binbuf_getvec(b); /* check again for valid data */ if(natom < 2) /* need at least 2 atoms: something (float, symbol...) and the semi */ return; flashserver_identify(x); /* output client info */ /* process data */ for (msg = 0; msg < natom;) { int emsg; for (emsg = msg; emsg < natom && at[emsg].a_type != A_COMMA && at[emsg].a_type != A_SEMI; emsg++); if (emsg > msg) { int ii; for (ii = msg; ii < emsg; ii++) if (at[ii].a_type == A_DOLLAR || at[ii].a_type == A_DOLLSYM) { pd_error(x, "flashserver: got dollar sign in message"); goto nodice; } if (at[msg].a_type == A_FLOAT) { if (emsg > msg + 1) outlet_list(x->x_msgout, 0, emsg-msg, at + msg); else outlet_float(x->x_msgout, at[msg].a_w.w_float); } else if (at[msg].a_type == A_SYMBOL) outlet_anything(x->x_msgout, at[msg].a_w.w_symbol, emsg-msg-1, at + msg + 1); } nodice: msg = emsg + 1; } } /* endif Pd conform data */ } static void flashserver_connectpoll(t_flashserver *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) /* f...ed up socket number */ { post("flashserver: accept failed"); return; } else if(x->x_nconnections == x->x_maxconnect) /* too many clients connected */ { post("flashserver: refused connection from %s on socket %d, too many clients", inet_ntoa(incomer_address.sin_addr), fd); sys_closesocket(fd); return; } else /* everything looks fine, go on... */ { t_flashserver_socketreceiver *y = flashserver_socketreceiver_new((void *)x, (t_flashserver_socketnotifier)flashserver_notify, (x->x_msgout ? flashserver_doit : 0)); if(flashserver_socket_set_keepalive(fd)) /* set socket to SO_KEEPALIVE */ error("flashserver: flashserver_socket_set_keepalive() failed"); // if(flashserver_socket_disable_buffer(fd)) /* disable send buffer */ // error("flashserver: flashserver_socket_disable_buffer() failed"); sys_addpollfn(fd, (t_fdpollfn)flashserver_socketreceiver_read, y); /* add poll-function */ x->x_nconnections++; x->x_host[x->x_nconnections - 1] = gensym(inet_ntoa(incomer_address.sin_addr)); x->x_fd[x->x_nconnections - 1] = fd; /* search for free client allocation number */ for(i = 0; i < x->x_maxconnect; i++) { if(x->x_clientlist[i] == -1) /* this is the first unused number ! */ { x->x_client[x->x_nconnections - 1] = i; x->x_clientlist[i] = 1; /* mark number as 'used' */ break; } } post("flashserver: accepted connection from %s on socket %d", x->x_host[x->x_nconnections - 1]->s_name, x->x_fd[x->x_nconnections - 1]); outlet_float(x->x_connectout, x->x_nconnections); } } /* open the Flash projektor file, code in parts stolen from Joseph A. Sarlo's GriPD */ static void flashserver_open(t_flashserver *x, t_symbol *sym, int argc, t_atom *argv) { char flashExec[DEFSTRSIZE], filename[DEFSTRSIZE], dirbuf[DEFSTRSIZE], *nameptr; #ifdef NT STARTUPINFO si; PROCESS_INFORMATION pi; int i; #else /* not NT */ int i, pid; #endif /* get the filename from message box */ if (argc > 0) { strcpy(filename, argv[0].a_w.w_symbol->s_name); } else { post("flashserver: no filename specified"); return; } /* now search for the correct path */ i = open_via_path(canvas_getdir(x->x_canvas)->s_name, filename, "", dirbuf, &nameptr, DEFSTRSIZE, 0); if(i != -1) { close(i); /* open_via_path() has opened the file, we don't want that, so we close it */ strcpy(flashExec, filename); if(!strstr(filename, "/") && !strstr(filename, "\\")) /* refabricate the pathname if needed */ sprintf(filename, "%s/%s", dirbuf, flashExec); sys_bashfilename(filename, filename); /* convert filename into system conform spelling */ post("flashserver: going to open \"%s\"", filename); } else { post("flashserver: \"%s\" not found", filename); return; } #ifdef NT ZeroMemory(&si, sizeof(si)); si.cb = sizeof(si); ZeroMemory(&pi, sizeof(pi)); if(strstr(filename, ".swf")) /* is it a .swf file ? */ sprintf(flashExec, "\"FlashPla.exe %s\"", filename); /* use FlashPlayer -> does not work */ else sprintf(flashExec, "\"%s\"", filename); /* add quotation marks */ if(!CreateProcess(NULL, flashExec, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi) != 0) { post("flashserver: failed to execute %s", flashExec); } #else pid = fork(); if (pid == 0) { struct sched_param par; int p1; /* Lose setuid priveliges */ seteuid(getuid()); /* set lowest priority, SCHED_OTHER policy, unlock mem*/ #if (_POSIX_PRIORITY_SCHEDULING - 0) >= 200112L p1 = sched_get_priority_min(SCHED_OTHER); par.sched_priority = p1; if (sched_setscheduler(0,SCHED_OTHER, &par) == -1) post("flashserver: unable to set priority %d scheduling.", p1); #endif #ifdef _POSIX_MEMLOCK if((munlockall() == -1) && (!getuid())) post("flashserver: unable to unlock memory."); #endif if((execlp(flashExec, flashExec, filename, 0, 0, (char *)0)) == -1) { post("flashserver: error launching \"%s\"", flashExec); exit(1); } } #endif } /* set prepend mode (prepend client allocation number to data) */ static void flashserver_prepend(t_flashserver *x, t_floatarg f) { if(f) { if(!x->x_prepend)post("flashserver~: switching to prepend mode"); x->x_prepend = 1; } else { if(x->x_prepend)post("flashserver~: turning off prepend mode"); x->x_prepend = 0; } } static void flashserver_print(t_flashserver *x) { int i; if(x->x_nconnections > 0) { post("flashserver: %d open connections:", x->x_nconnections); for(i = 0; i < x->x_nconnections; i++) { post(" client #%d: \"%s\" on socket %d", x->x_client[i] + 1, x->x_host[i]->s_name, x->x_fd[i]); } } else post("flashserver: no open connections"); } static void *flashserver_new(t_floatarg fportno, t_floatarg fclients, t_floatarg fprep, t_floatarg fverbose) { t_flashserver *x; int i, keepalive = 1; struct sockaddr_in server; int sockfd, portno = (int)fportno; #ifdef UNIX_SIGPIPE struct sigaction sa; /* add our own sigpipe handler to avoid calling Pd's handler */ sa.sa_handler = SIG_IGN; /* sa.sa_mask = 0; sa.sa_flags = 0; */ sigaction(SIGPIPE, &sa, (struct sigaction *)NULL); #endif /* create a socket */ sockfd = socket(AF_INET, SOCK_STREAM, 0); #if 0 post("flashserver: receive socket %d", sockfd); #endif if (sockfd < 0) { sys_sockerror("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("bind"); sys_closesocket(sockfd); return (0); } x = (t_flashserver *)pd_new(flashserver_class); x->x_msgout = outlet_new(&x->x_obj, &s_anything); /* streaming protocol */ if (listen(sockfd, 5) < 0) { sys_sockerror("listen"); sys_closesocket(sockfd); sockfd = -1; } else { sys_addpollfn(sockfd, (t_fdpollfn)flashserver_connectpoll, x); x->x_connectout = outlet_new(&x->x_obj, &s_float); x->x_clientno = outlet_new(&x->x_obj, &s_float); x->x_clientsock = outlet_new(&x->x_obj, &s_float); x->x_connectionip = outlet_new(&x->x_obj, &s_symbol); b = binbuf_new(); } x->x_connectsocket = sockfd; x->x_nconnections = 0; x->x_verbose = 0; x->x_canvas = canvas_getcurrent(); if(fclients) { x->x_maxconnect = (t_int)fclients; if(x->x_maxconnect > MAX_CONNECT) x->x_maxconnect = MAX_CONNECT; post("flashserver: set maximum number of clients to %d", x->x_maxconnect); } else x->x_maxconnect = MAX_CONNECT; for(i = 0; i < x->x_maxconnect; i++) { x->x_fd[i] = -1; x->x_client[i] = -1; x->x_clientlist[i] = -1; } if(fprep) { x->x_prepend = 1; post("flashserver: setting \"prepend mode\""); } else x->x_prepend = 0; if(fverbose) { x->x_verbose = 1; post("flashserver: debugging mode"); } return (x); } static void flashserver_free(t_flashserver *x) { int i; post("flashserver: closing open connections...."); 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); } post("flashserver: ...done"); binbuf_free(b); } void flashserver_setup(void) { flashserver_class = class_new(gensym("flashserver"),(t_newmethod)flashserver_new, (t_method)flashserver_free, sizeof(t_flashserver), 0, A_DEFFLOAT, A_DEFFLOAT, A_DEFFLOAT, A_DEFFLOAT, 0); class_addmethod(flashserver_class, (t_method)flashserver_print, gensym("print"), 0); class_addmethod(flashserver_class, (t_method)flashserver_send, gensym("send"), A_GIMME, 0); class_addmethod(flashserver_class, (t_method)flashserver_sendXML, gensym("sendXML"), A_GIMME, 0); class_addmethod(flashserver_class, (t_method)flashserver_client_send, gensym("client"), A_GIMME, 0); class_addmethod(flashserver_class, (t_method)flashserver_client_sendXML, gensym("clientXML"), A_GIMME, 0); class_addmethod(flashserver_class, (t_method)flashserver_broadcast, gensym("broadcast"), A_GIMME, 0); class_addmethod(flashserver_class, (t_method)flashserver_broadcastXML, gensym("broadcastXML"), A_GIMME, 0); class_addmethod(flashserver_class, (t_method)flashserver_open, gensym("open"), A_GIMME, 0); class_addmethod(flashserver_class, (t_method)flashserver_prepend, gensym("prepend"), A_FLOAT, 0); class_addmethod(flashserver_class, (t_method)flashserver_client_kick, gensym("kick"), A_FLOAT, 0); class_sethelpsymbol(flashserver_class, gensym("help-flashserver.pd")); post(version); }