Add FS #10214. Initial commit of the original PDa code for the GSoC Pure Data plugin...
[kugel-rb.git] / apps / plugins / pdbox / PDa / src / u_pdreceive.c
blob3ec097edcc43f30d22703102fbd45d9e36779638
1 /* Copyright (c) 2000 Miller Puckette.
2 * For information on usage and redistribution, and for a DISCLAIMER OF ALL
3 * WARRANTIES, see the file, "LICENSE.txt," in the Pd distribution. */
5 /* the "pdreceive" command. This is a standalone program that receives messages
6 from Pd via the netsend/netreceive ("FUDI") protocol, and copies them to
7 standard output. */
9 #include <sys/types.h>
10 #include <string.h>
11 #include <stdio.h>
12 #include <errno.h>
13 #include <stdlib.h>
14 #ifdef UNIX
15 #include <sys/time.h>
16 #include <unistd.h>
17 #include <sys/socket.h>
18 #include <netinet/in.h>
19 #include <netdb.h>
20 #define SOCKET_ERROR -1
21 #else
22 #include <winsock.h>
23 #endif
25 typedef struct _fdpoll
27 int fdp_fd;
28 char *fdp_inbuf;
29 int fdp_inhead;
30 int fdp_intail;
31 int fdp_udp;
32 } t_fdpoll;
34 static int nfdpoll;
35 static t_fdpoll *fdpoll;
36 static int maxfd;
37 static int sockfd;
38 static int protocol;
40 static void sockerror(char *s);
41 static void x_closesocket(int fd);
42 static void dopoll(void);
43 #define BUFSIZE 4096
45 int main(int argc, char **argv)
47 int portno;
48 struct sockaddr_in server;
49 int nretry = 10;
50 #ifdef MSW
51 short version = MAKEWORD(2, 0);
52 WSADATA nobby;
53 #endif
54 if (argc < 2 || sscanf(argv[1], "%d", &portno) < 1 || portno <= 0)
55 goto usage;
56 if (argc >= 3)
58 if (!strcmp(argv[2], "tcp"))
59 protocol = SOCK_STREAM;
60 else if (!strcmp(argv[2], "udp"))
61 protocol = SOCK_DGRAM;
62 else goto usage;
64 else protocol = SOCK_STREAM;
65 #ifdef MSW
66 if (WSAStartup(version, &nobby)) sockerror("WSAstartup");
67 #endif
68 sockfd = socket(AF_INET, protocol, 0);
69 if (sockfd < 0)
71 sockerror("socket()");
72 exit(1);
74 maxfd = sockfd + 1;
75 server.sin_family = AF_INET;
76 server.sin_addr.s_addr = INADDR_ANY;
78 #ifdef IRIX
79 /* this seems to work only in IRIX but is unnecessary in
80 Linux. Not sure what MSW needs in place of this. */
81 if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, 0, 0) < 0)
82 post("setsockopt failed\n");
83 #endif
85 /* assign client port number */
86 server.sin_port = htons((unsigned short)portno);
88 /* name the socket */
89 if (bind(sockfd, (struct sockaddr *)&server, sizeof(server)) < 0)
91 sockerror("bind");
92 x_closesocket(sockfd);
93 return (0);
95 if (protocol == SOCK_STREAM)
97 if (listen(sockfd, 5) < 0)
99 sockerror("listen");
100 x_closesocket(sockfd);
101 exit(1);
104 /* now loop forever selecting on sockets */
105 while (1)
106 dopoll();
108 usage:
109 fprintf(stderr, "usage: pdreceive <portnumber> [udp|tcp]\n");
110 fprintf(stderr, "(default is tcp)\n");
111 exit(1);
114 static void addport(int fd)
116 int nfd = nfdpoll;
117 t_fdpoll *fp;
118 fdpoll = (t_fdpoll *)realloc(fdpoll,
119 (nfdpoll+1) * sizeof(t_fdpoll));
120 fp = fdpoll + nfdpoll;
121 fp->fdp_fd = fd;
122 nfdpoll++;
123 if (fd >= maxfd) maxfd = fd + 1;
124 fp->fdp_inhead = fp->fdp_intail = 0;
125 if (!(fp->fdp_inbuf = malloc(BUFSIZE)))
127 fprintf(stderr, "out of memory");
128 exit(1);
130 printf("number_connected %d;\n", nfdpoll);
133 static void rmport(t_fdpoll *x)
135 int nfd = nfdpoll;
136 int i, size = nfdpoll * sizeof(t_fdpoll);
137 t_fdpoll *fp;
138 for (i = nfdpoll, fp = fdpoll; i--; fp++)
140 if (fp == x)
142 x_closesocket(fp->fdp_fd);
143 free(fp->fdp_inbuf);
144 while (i--)
146 fp[0] = fp[1];
147 fp++;
149 fdpoll = (t_fdpoll *)realloc(fdpoll,
150 (nfdpoll-1) * sizeof(t_fdpoll));
151 nfdpoll--;
152 printf("number_connected %d;\n", nfdpoll);
153 return;
156 fprintf(stderr, "warning: item removed from poll list but not found");
159 static void doconnect(void)
161 int fd = accept(sockfd, 0, 0);
162 if (fd < 0)
163 perror("accept");
164 else addport(fd);
167 static void udpread(void)
169 char buf[BUFSIZE];
170 int ret = recv(sockfd, buf, BUFSIZE, 0);
171 if (ret < 0)
173 sockerror("recv (udp)");
174 x_closesocket(sockfd);
175 exit(1);
177 else if (ret > 0)
179 #ifdef UNIX
180 if (write(1, buf, ret) < ret)
182 perror("write");
183 exit(1);
185 #else
186 int j;
187 for (j = 0; j < ret; j++)
188 putchar(buf[j]);
189 #endif
193 static int tcpmakeoutput(t_fdpoll *x)
195 char messbuf[BUFSIZE+1], *bp = messbuf;
196 int indx;
197 int inhead = x->fdp_inhead;
198 int intail = x->fdp_intail;
199 char *inbuf = x->fdp_inbuf;
200 if (intail == inhead)
201 return (0);
202 for (indx = intail; indx != inhead; indx = (indx+1)&(BUFSIZE-1))
204 /* search for a semicolon. */
205 char c = *bp++ = inbuf[indx];
206 if (c == ';')
208 intail = (indx+1)&(BUFSIZE-1);
209 if (inbuf[intail] == '\n')
210 intail = (intail+1)&(BUFSIZE-1);
211 *bp++ = '\n';
212 #ifdef UNIX
213 write(1, messbuf, bp - messbuf);
214 #else
216 int j;
217 for (j = 0; j < bp - messbuf; j++)
218 putchar(messbuf[j]);
220 #endif
221 x->fdp_inhead = inhead;
222 x->fdp_intail = intail;
223 return (1);
226 return (0);
229 static void tcpread(t_fdpoll *x)
231 int readto =
232 (x->fdp_inhead >= x->fdp_intail ? BUFSIZE : x->fdp_intail-1);
233 int ret;
235 /* the input buffer might be full. If so, drop the whole thing */
236 if (readto == x->fdp_inhead)
238 fprintf(stderr, "pd: dropped message from gui\n");
239 x->fdp_inhead = x->fdp_intail = 0;
240 readto = BUFSIZE;
242 else
244 ret = recv(x->fdp_fd, x->fdp_inbuf + x->fdp_inhead,
245 readto - x->fdp_inhead, 0);
246 if (ret < 0)
248 sockerror("recv (tcp)");
249 rmport(x);
251 else if (ret == 0)
252 rmport(x);
253 else
255 x->fdp_inhead += ret;
256 if (x->fdp_inhead >= BUFSIZE)
257 x->fdp_inhead = 0;
258 while (tcpmakeoutput(x))
264 static void dopoll(void)
266 int i;
267 t_fdpoll *fp;
268 fd_set readset, writeset, exceptset;
269 FD_ZERO(&writeset);
270 FD_ZERO(&readset);
271 FD_ZERO(&exceptset);
273 FD_SET(sockfd, &readset);
274 if (protocol == SOCK_STREAM)
276 for (fp = fdpoll, i = nfdpoll; i--; fp++)
277 FD_SET(fp->fdp_fd, &readset);
279 if (select(maxfd+1, &readset, &writeset, &exceptset, 0) < 0)
281 perror("select");
282 exit(1);
284 if (protocol == SOCK_STREAM)
286 for (i = 0; i < nfdpoll; i++)
287 if (FD_ISSET(fdpoll[i].fdp_fd, &readset))
288 tcpread(&fdpoll[i]);
289 if (FD_ISSET(sockfd, &readset))
290 doconnect();
292 else
294 if (FD_ISSET(sockfd, &readset))
295 udpread();
300 static void sockerror(char *s)
302 #ifdef MSW
303 int err = WSAGetLastError();
304 if (err == 10054) return;
305 else if (err == 10044)
307 fprintf(stderr,
308 "Warning: you might not have TCP/IP \"networking\" turned on\n");
310 #endif
311 #ifdef UNIX
312 int err = errno;
313 #endif
314 fprintf(stderr, "%s: %s (%d)\n", s, strerror(err), err);
317 static void x_closesocket(int fd)
319 #ifdef UNIX
320 close(fd);
321 #endif
322 #ifdef MSW
323 closesocket(fd);
324 #endif
326 /* Copyright (c) 2000 Miller Puckette.
327 * For information on usage and redistribution, and for a DISCLAIMER OF ALL
328 * WARRANTIES, see the file, "LICENSE.txt," in the Pd distribution. */
330 /* the "pdreceive" command. This is a standalone program that receives messages
331 from Pd via the netsend/netreceive ("FUDI") protocol, and copies them to
332 standard output. */
334 #include <sys/types.h>
335 #include <string.h>
336 #include <stdio.h>
337 #include <errno.h>
338 #include <stdlib.h>
339 #ifdef UNIX
340 #include <sys/time.h>
341 #include <unistd.h>
342 #include <sys/socket.h>
343 #include <netinet/in.h>
344 #include <netdb.h>
345 #define SOCKET_ERROR -1
346 #else
347 #include <winsock.h>
348 #endif
350 typedef struct _fdpoll
352 int fdp_fd;
353 char *fdp_inbuf;
354 int fdp_inhead;
355 int fdp_intail;
356 int fdp_udp;
357 } t_fdpoll;
359 static int nfdpoll;
360 static t_fdpoll *fdpoll;
361 static int maxfd;
362 static int sockfd;
363 static int protocol;
365 static void sockerror(char *s);
366 static void x_closesocket(int fd);
367 static void dopoll(void);
368 #define BUFSIZE 4096
370 int main(int argc, char **argv)
372 int portno;
373 struct sockaddr_in server;
374 int nretry = 10;
375 #ifdef MSW
376 short version = MAKEWORD(2, 0);
377 WSADATA nobby;
378 #endif
379 if (argc < 2 || sscanf(argv[1], "%d", &portno) < 1 || portno <= 0)
380 goto usage;
381 if (argc >= 3)
383 if (!strcmp(argv[2], "tcp"))
384 protocol = SOCK_STREAM;
385 else if (!strcmp(argv[2], "udp"))
386 protocol = SOCK_DGRAM;
387 else goto usage;
389 else protocol = SOCK_STREAM;
390 #ifdef MSW
391 if (WSAStartup(version, &nobby)) sockerror("WSAstartup");
392 #endif
393 sockfd = socket(AF_INET, protocol, 0);
394 if (sockfd < 0)
396 sockerror("socket()");
397 exit(1);
399 maxfd = sockfd + 1;
400 server.sin_family = AF_INET;
401 server.sin_addr.s_addr = INADDR_ANY;
403 #ifdef IRIX
404 /* this seems to work only in IRIX but is unnecessary in
405 Linux. Not sure what MSW needs in place of this. */
406 if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, 0, 0) < 0)
407 post("setsockopt failed\n");
408 #endif
410 /* assign client port number */
411 server.sin_port = htons((unsigned short)portno);
413 /* name the socket */
414 if (bind(sockfd, (struct sockaddr *)&server, sizeof(server)) < 0)
416 sockerror("bind");
417 x_closesocket(sockfd);
418 return (0);
420 if (protocol == SOCK_STREAM)
422 if (listen(sockfd, 5) < 0)
424 sockerror("listen");
425 x_closesocket(sockfd);
426 exit(1);
429 /* now loop forever selecting on sockets */
430 while (1)
431 dopoll();
433 usage:
434 fprintf(stderr, "usage: pdreceive <portnumber> [udp|tcp]\n");
435 fprintf(stderr, "(default is tcp)\n");
436 exit(1);
439 static void addport(int fd)
441 int nfd = nfdpoll;
442 t_fdpoll *fp;
443 fdpoll = (t_fdpoll *)realloc(fdpoll,
444 (nfdpoll+1) * sizeof(t_fdpoll));
445 fp = fdpoll + nfdpoll;
446 fp->fdp_fd = fd;
447 nfdpoll++;
448 if (fd >= maxfd) maxfd = fd + 1;
449 fp->fdp_inhead = fp->fdp_intail = 0;
450 if (!(fp->fdp_inbuf = malloc(BUFSIZE)))
452 fprintf(stderr, "out of memory");
453 exit(1);
455 printf("number_connected %d;\n", nfdpoll);
458 static void rmport(t_fdpoll *x)
460 int nfd = nfdpoll;
461 int i, size = nfdpoll * sizeof(t_fdpoll);
462 t_fdpoll *fp;
463 for (i = nfdpoll, fp = fdpoll; i--; fp++)
465 if (fp == x)
467 x_closesocket(fp->fdp_fd);
468 free(fp->fdp_inbuf);
469 while (i--)
471 fp[0] = fp[1];
472 fp++;
474 fdpoll = (t_fdpoll *)realloc(fdpoll,
475 (nfdpoll-1) * sizeof(t_fdpoll));
476 nfdpoll--;
477 printf("number_connected %d;\n", nfdpoll);
478 return;
481 fprintf(stderr, "warning: item removed from poll list but not found");
484 static void doconnect(void)
486 int fd = accept(sockfd, 0, 0);
487 if (fd < 0)
488 perror("accept");
489 else addport(fd);
492 static void udpread(void)
494 char buf[BUFSIZE];
495 int ret = recv(sockfd, buf, BUFSIZE, 0);
496 if (ret < 0)
498 sockerror("recv (udp)");
499 x_closesocket(sockfd);
500 exit(1);
502 else if (ret > 0)
504 #ifdef UNIX
505 if (write(1, buf, ret) < ret)
507 perror("write");
508 exit(1);
510 #else
511 int j;
512 for (j = 0; j < ret; j++)
513 putchar(buf[j]);
514 #endif
518 static int tcpmakeoutput(t_fdpoll *x)
520 char messbuf[BUFSIZE+1], *bp = messbuf;
521 int indx;
522 int inhead = x->fdp_inhead;
523 int intail = x->fdp_intail;
524 char *inbuf = x->fdp_inbuf;
525 if (intail == inhead)
526 return (0);
527 for (indx = intail; indx != inhead; indx = (indx+1)&(BUFSIZE-1))
529 /* search for a semicolon. */
530 char c = *bp++ = inbuf[indx];
531 if (c == ';')
533 intail = (indx+1)&(BUFSIZE-1);
534 if (inbuf[intail] == '\n')
535 intail = (intail+1)&(BUFSIZE-1);
536 *bp++ = '\n';
537 #ifdef UNIX
538 write(1, messbuf, bp - messbuf);
539 #else
541 int j;
542 for (j = 0; j < bp - messbuf; j++)
543 putchar(messbuf[j]);
545 #endif
546 x->fdp_inhead = inhead;
547 x->fdp_intail = intail;
548 return (1);
551 return (0);
554 static void tcpread(t_fdpoll *x)
556 int readto =
557 (x->fdp_inhead >= x->fdp_intail ? BUFSIZE : x->fdp_intail-1);
558 int ret;
560 /* the input buffer might be full. If so, drop the whole thing */
561 if (readto == x->fdp_inhead)
563 fprintf(stderr, "pd: dropped message from gui\n");
564 x->fdp_inhead = x->fdp_intail = 0;
565 readto = BUFSIZE;
567 else
569 ret = recv(x->fdp_fd, x->fdp_inbuf + x->fdp_inhead,
570 readto - x->fdp_inhead, 0);
571 if (ret < 0)
573 sockerror("recv (tcp)");
574 rmport(x);
576 else if (ret == 0)
577 rmport(x);
578 else
580 x->fdp_inhead += ret;
581 if (x->fdp_inhead >= BUFSIZE)
582 x->fdp_inhead = 0;
583 while (tcpmakeoutput(x))
589 static void dopoll(void)
591 int i;
592 t_fdpoll *fp;
593 fd_set readset, writeset, exceptset;
594 FD_ZERO(&writeset);
595 FD_ZERO(&readset);
596 FD_ZERO(&exceptset);
598 FD_SET(sockfd, &readset);
599 if (protocol == SOCK_STREAM)
601 for (fp = fdpoll, i = nfdpoll; i--; fp++)
602 FD_SET(fp->fdp_fd, &readset);
604 if (select(maxfd+1, &readset, &writeset, &exceptset, 0) < 0)
606 perror("select");
607 exit(1);
609 if (protocol == SOCK_STREAM)
611 for (i = 0; i < nfdpoll; i++)
612 if (FD_ISSET(fdpoll[i].fdp_fd, &readset))
613 tcpread(&fdpoll[i]);
614 if (FD_ISSET(sockfd, &readset))
615 doconnect();
617 else
619 if (FD_ISSET(sockfd, &readset))
620 udpread();
625 static void sockerror(char *s)
627 #ifdef MSW
628 int err = WSAGetLastError();
629 if (err == 10054) return;
630 else if (err == 10044)
632 fprintf(stderr,
633 "Warning: you might not have TCP/IP \"networking\" turned on\n");
635 #endif
636 #ifdef UNIX
637 int err = errno;
638 #endif
639 fprintf(stderr, "%s: %s (%d)\n", s, strerror(err), err);
642 static void x_closesocket(int fd)
644 #ifdef UNIX
645 close(fd);
646 #endif
647 #ifdef MSW
648 closesocket(fd);
649 #endif