diff options
Diffstat (limited to 'apps/plugins/pdbox/PDa/src/x_net.c')
-rw-r--r-- | apps/plugins/pdbox/PDa/src/x_net.c | 726 |
1 files changed, 726 insertions, 0 deletions
diff --git a/apps/plugins/pdbox/PDa/src/x_net.c b/apps/plugins/pdbox/PDa/src/x_net.c new file mode 100644 index 0000000000..5094661214 --- /dev/null +++ b/apps/plugins/pdbox/PDa/src/x_net.c | |||
@@ -0,0 +1,726 @@ | |||
1 | /* Copyright (c) 1997-1999 Miller Puckette. | ||
2 | * For information on usage and redistribution, and for a DISCLAIMER OF ALL | ||
3 | * WARRANTIES, see the file, "LICENSE.txt," in this distribution. */ | ||
4 | |||
5 | /* network */ | ||
6 | |||
7 | #include "m_pd.h" | ||
8 | #include "s_stuff.h" | ||
9 | |||
10 | #include <sys/types.h> | ||
11 | #include <string.h> | ||
12 | #ifdef UNIX | ||
13 | #include <sys/socket.h> | ||
14 | #include <netinet/in.h> | ||
15 | #include <netinet/tcp.h> | ||
16 | #include <netdb.h> | ||
17 | #include <stdio.h> | ||
18 | #define SOCKET_ERROR -1 | ||
19 | #else | ||
20 | #include <winsock.h> | ||
21 | #endif | ||
22 | |||
23 | static t_class *netsend_class; | ||
24 | |||
25 | typedef struct _netsend | ||
26 | { | ||
27 | t_object x_obj; | ||
28 | int x_fd; | ||
29 | int x_protocol; | ||
30 | } t_netsend; | ||
31 | |||
32 | static void *netsend_new(t_floatarg udpflag) | ||
33 | { | ||
34 | t_netsend *x = (t_netsend *)pd_new(netsend_class); | ||
35 | outlet_new(&x->x_obj, &s_float); | ||
36 | x->x_fd = -1; | ||
37 | x->x_protocol = (udpflag != 0 ? SOCK_DGRAM : SOCK_STREAM); | ||
38 | return (x); | ||
39 | } | ||
40 | |||
41 | static void netsend_connect(t_netsend *x, t_symbol *hostname, | ||
42 | t_floatarg fportno) | ||
43 | { | ||
44 | struct sockaddr_in server; | ||
45 | struct hostent *hp; | ||
46 | int sockfd; | ||
47 | int portno = fportno; | ||
48 | int intarg; | ||
49 | if (x->x_fd >= 0) | ||
50 | { | ||
51 | error("netsend_connect: already connected"); | ||
52 | return; | ||
53 | } | ||
54 | |||
55 | /* create a socket */ | ||
56 | sockfd = socket(AF_INET, x->x_protocol, 0); | ||
57 | #if 0 | ||
58 | fprintf(stderr, "send socket %d\n", sockfd); | ||
59 | #endif | ||
60 | if (sockfd < 0) | ||
61 | { | ||
62 | sys_sockerror("socket"); | ||
63 | return; | ||
64 | } | ||
65 | /* connect socket using hostname provided in command line */ | ||
66 | server.sin_family = AF_INET; | ||
67 | hp = gethostbyname(hostname->s_name); | ||
68 | if (hp == 0) | ||
69 | { | ||
70 | post("bad host?\n"); | ||
71 | return; | ||
72 | } | ||
73 | #if 0 | ||
74 | intarg = 0; | ||
75 | if (setsockopt(sockfd, SOL_SOCKET, SO_SNDBUF, | ||
76 | &intarg, sizeof(intarg)) < 0) | ||
77 | post("setsockopt (SO_RCVBUF) failed\n"); | ||
78 | #endif | ||
79 | /* for stream (TCP) sockets, specify "nodelay" */ | ||
80 | if (x->x_protocol == SOCK_STREAM) | ||
81 | { | ||
82 | intarg = 1; | ||
83 | if (setsockopt(sockfd, IPPROTO_TCP, TCP_NODELAY, | ||
84 | &intarg, sizeof(intarg)) < 0) | ||
85 | post("setsockopt (TCP_NODELAY) failed\n"); | ||
86 | } | ||
87 | memcpy((char *)&server.sin_addr, (char *)hp->h_addr, hp->h_length); | ||
88 | |||
89 | /* assign client port number */ | ||
90 | server.sin_port = htons((u_short)portno); | ||
91 | |||
92 | post("connecting to port %d", portno); | ||
93 | /* try to connect. LATER make a separate thread to do this | ||
94 | because it might block */ | ||
95 | if (connect(sockfd, (struct sockaddr *) &server, sizeof (server)) < 0) | ||
96 | { | ||
97 | sys_sockerror("connecting stream socket"); | ||
98 | sys_closesocket(sockfd); | ||
99 | return; | ||
100 | } | ||
101 | x->x_fd = sockfd; | ||
102 | outlet_float(x->x_obj.ob_outlet, 1); | ||
103 | } | ||
104 | |||
105 | static void netsend_disconnect(t_netsend *x) | ||
106 | { | ||
107 | if (x->x_fd >= 0) | ||
108 | { | ||
109 | sys_closesocket(x->x_fd); | ||
110 | x->x_fd = -1; | ||
111 | outlet_float(x->x_obj.ob_outlet, 0); | ||
112 | } | ||
113 | } | ||
114 | |||
115 | static void netsend_send(t_netsend *x, t_symbol *s, int argc, t_atom *argv) | ||
116 | { | ||
117 | if (x->x_fd >= 0) | ||
118 | { | ||
119 | t_binbuf *b = binbuf_new(); | ||
120 | char *buf, *bp; | ||
121 | int length, sent; | ||
122 | t_atom at; | ||
123 | binbuf_add(b, argc, argv); | ||
124 | SETSEMI(&at); | ||
125 | binbuf_add(b, 1, &at); | ||
126 | binbuf_gettext(b, &buf, &length); | ||
127 | for (bp = buf, sent = 0; sent < length;) | ||
128 | { | ||
129 | static double lastwarntime; | ||
130 | static double pleasewarn; | ||
131 | double timebefore = sys_getrealtime(); | ||
132 | int res = send(x->x_fd, buf, length-sent, 0); | ||
133 | double timeafter = sys_getrealtime(); | ||
134 | int late = (timeafter - timebefore > 0.005); | ||
135 | if (late || pleasewarn) | ||
136 | { | ||
137 | if (timeafter > lastwarntime + 2) | ||
138 | { | ||
139 | post("netsend blocked %d msec", | ||
140 | (int)(1000 * ((timeafter - timebefore) + pleasewarn))); | ||
141 | pleasewarn = 0; | ||
142 | lastwarntime = timeafter; | ||
143 | } | ||
144 | else if (late) pleasewarn += timeafter - timebefore; | ||
145 | } | ||
146 | if (res <= 0) | ||
147 | { | ||
148 | sys_sockerror("netsend"); | ||
149 | netsend_disconnect(x); | ||
150 | break; | ||
151 | } | ||
152 | else | ||
153 | { | ||
154 | sent += res; | ||
155 | bp += res; | ||
156 | } | ||
157 | } | ||
158 | t_freebytes(buf, length); | ||
159 | binbuf_free(b); | ||
160 | } | ||
161 | else error("netsend: not connected"); | ||
162 | } | ||
163 | |||
164 | static void netsend_free(t_netsend *x) | ||
165 | { | ||
166 | netsend_disconnect(x); | ||
167 | } | ||
168 | |||
169 | static void netsend_setup(void) | ||
170 | { | ||
171 | netsend_class = class_new(gensym("netsend"), (t_newmethod)netsend_new, | ||
172 | (t_method)netsend_free, | ||
173 | sizeof(t_netsend), 0, A_DEFFLOAT, 0); | ||
174 | class_addmethod(netsend_class, (t_method)netsend_connect, | ||
175 | gensym("connect"), A_SYMBOL, A_FLOAT, 0); | ||
176 | class_addmethod(netsend_class, (t_method)netsend_disconnect, | ||
177 | gensym("disconnect"), 0); | ||
178 | class_addmethod(netsend_class, (t_method)netsend_send, gensym("send"), | ||
179 | A_GIMME, 0); | ||
180 | } | ||
181 | |||
182 | /* ----------------------------- netreceive ------------------------- */ | ||
183 | |||
184 | static t_class *netreceive_class; | ||
185 | |||
186 | typedef struct _netreceive | ||
187 | { | ||
188 | t_object x_obj; | ||
189 | t_outlet *x_msgout; | ||
190 | t_outlet *x_connectout; | ||
191 | int x_connectsocket; | ||
192 | int x_nconnections; | ||
193 | int x_udp; | ||
194 | } t_netreceive; | ||
195 | |||
196 | static void netreceive_notify(t_netreceive *x) | ||
197 | { | ||
198 | outlet_float(x->x_connectout, --x->x_nconnections); | ||
199 | } | ||
200 | |||
201 | static void netreceive_doit(void *z, t_binbuf *b) | ||
202 | { | ||
203 | t_atom messbuf[1024]; | ||
204 | t_netreceive *x = (t_netreceive *)z; | ||
205 | int msg, natom = binbuf_getnatom(b); | ||
206 | t_atom *at = binbuf_getvec(b); | ||
207 | for (msg = 0; msg < natom;) | ||
208 | { | ||
209 | int emsg; | ||
210 | for (emsg = msg; emsg < natom && at[emsg].a_type != A_COMMA | ||
211 | && at[emsg].a_type != A_SEMI; emsg++) | ||
212 | ; | ||
213 | if (emsg > msg) | ||
214 | { | ||
215 | int i; | ||
216 | for (i = msg; i < emsg; i++) | ||
217 | if (at[i].a_type == A_DOLLAR || at[i].a_type == A_DOLLSYM) | ||
218 | { | ||
219 | pd_error(x, "netreceive: got dollar sign in message"); | ||
220 | goto nodice; | ||
221 | } | ||
222 | if (at[msg].a_type == A_FLOAT) | ||
223 | { | ||
224 | if (emsg > msg + 1) | ||
225 | outlet_list(x->x_msgout, 0, emsg-msg, at + msg); | ||
226 | else outlet_float(x->x_msgout, at[msg].a_w.w_float); | ||
227 | } | ||
228 | else if (at[msg].a_type == A_SYMBOL) | ||
229 | outlet_anything(x->x_msgout, at[msg].a_w.w_symbol, | ||
230 | emsg-msg-1, at + msg + 1); | ||
231 | } | ||
232 | nodice: | ||
233 | msg = emsg + 1; | ||
234 | } | ||
235 | } | ||
236 | |||
237 | static void netreceive_connectpoll(t_netreceive *x) | ||
238 | { | ||
239 | int fd = accept(x->x_connectsocket, 0, 0); | ||
240 | if (fd < 0) post("netreceive: accept failed"); | ||
241 | else | ||
242 | { | ||
243 | t_socketreceiver *y = socketreceiver_new((void *)x, | ||
244 | (t_socketnotifier)netreceive_notify, | ||
245 | (x->x_msgout ? netreceive_doit : 0), 0); | ||
246 | sys_addpollfn(fd, (t_fdpollfn)socketreceiver_read, y); | ||
247 | outlet_float(x->x_connectout, ++x->x_nconnections); | ||
248 | } | ||
249 | } | ||
250 | |||
251 | static void *netreceive_new(t_symbol *compatflag, | ||
252 | t_floatarg fportno, t_floatarg udpflag) | ||
253 | { | ||
254 | t_netreceive *x; | ||
255 | struct sockaddr_in server; | ||
256 | int sockfd, portno = fportno, udp = (udpflag != 0); | ||
257 | int old = !strcmp(compatflag->s_name , "old"); | ||
258 | int intarg; | ||
259 | /* create a socket */ | ||
260 | sockfd = socket(AF_INET, (udp ? SOCK_DGRAM : SOCK_STREAM), 0); | ||
261 | #if 0 | ||
262 | fprintf(stderr, "receive socket %d\n", sockfd); | ||
263 | #endif | ||
264 | if (sockfd < 0) | ||
265 | { | ||
266 | sys_sockerror("socket"); | ||
267 | return (0); | ||
268 | } | ||
269 | server.sin_family = AF_INET; | ||
270 | server.sin_addr.s_addr = INADDR_ANY; | ||
271 | |||
272 | #if 1 | ||
273 | /* ask OS to allow another Pd to repoen this port after we close it. */ | ||
274 | intarg = 1; | ||
275 | if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, | ||
276 | &intarg, sizeof(intarg)) < 0) | ||
277 | post("setsockopt (SO_REUSEADDR) failed\n"); | ||
278 | #endif | ||
279 | #if 0 | ||
280 | intarg = 0; | ||
281 | if (setsockopt(sockfd, SOL_SOCKET, SO_RCVBUF, | ||
282 | &intarg, sizeof(intarg)) < 0) | ||
283 | post("setsockopt (SO_RCVBUF) failed\n"); | ||
284 | #endif | ||
285 | /* Stream (TCP) sockets are set NODELAY */ | ||
286 | if (!udp) | ||
287 | { | ||
288 | intarg = 1; | ||
289 | if (setsockopt(sockfd, IPPROTO_TCP, TCP_NODELAY, | ||
290 | &intarg, sizeof(intarg)) < 0) | ||
291 | post("setsockopt (TCP_NODELAY) failed\n"); | ||
292 | } | ||
293 | /* assign server port number */ | ||
294 | server.sin_port = htons((u_short)portno); | ||
295 | |||
296 | /* name the socket */ | ||
297 | if (bind(sockfd, (struct sockaddr *)&server, sizeof(server)) < 0) | ||
298 | { | ||
299 | sys_sockerror("bind"); | ||
300 | sys_closesocket(sockfd); | ||
301 | return (0); | ||
302 | } | ||
303 | x = (t_netreceive *)pd_new(netreceive_class); | ||
304 | if (old) | ||
305 | { | ||
306 | /* old style, nonsecure version */ | ||
307 | x->x_msgout = 0; | ||
308 | } | ||
309 | else x->x_msgout = outlet_new(&x->x_obj, &s_anything); | ||
310 | |||
311 | if (udp) /* datagram protocol */ | ||
312 | { | ||
313 | t_socketreceiver *y = socketreceiver_new((void *)x, | ||
314 | (t_socketnotifier)netreceive_notify, | ||
315 | (x->x_msgout ? netreceive_doit : 0), 1); | ||
316 | sys_addpollfn(sockfd, (t_fdpollfn)socketreceiver_read, y); | ||
317 | x->x_connectout = 0; | ||
318 | } | ||
319 | else /* streaming protocol */ | ||
320 | { | ||
321 | if (listen(sockfd, 5) < 0) | ||
322 | { | ||
323 | sys_sockerror("listen"); | ||
324 | sys_closesocket(sockfd); | ||
325 | sockfd = -1; | ||
326 | } | ||
327 | else | ||
328 | { | ||
329 | sys_addpollfn(sockfd, (t_fdpollfn)netreceive_connectpoll, x); | ||
330 | x->x_connectout = outlet_new(&x->x_obj, &s_float); | ||
331 | } | ||
332 | } | ||
333 | x->x_connectsocket = sockfd; | ||
334 | x->x_nconnections = 0; | ||
335 | x->x_udp = udp; | ||
336 | |||
337 | return (x); | ||
338 | } | ||
339 | |||
340 | static void netreceive_free(t_netreceive *x) | ||
341 | { | ||
342 | /* LATER make me clean up open connections */ | ||
343 | if (x->x_connectsocket >= 0) | ||
344 | { | ||
345 | sys_rmpollfn(x->x_connectsocket); | ||
346 | sys_closesocket(x->x_connectsocket); | ||
347 | } | ||
348 | } | ||
349 | |||
350 | static void netreceive_setup(void) | ||
351 | { | ||
352 | netreceive_class = class_new(gensym("netreceive"), | ||
353 | (t_newmethod)netreceive_new, (t_method)netreceive_free, | ||
354 | sizeof(t_netreceive), CLASS_NOINLET, A_DEFFLOAT, A_DEFFLOAT, | ||
355 | A_DEFSYM, 0); | ||
356 | } | ||
357 | |||
358 | void x_net_setup(void) | ||
359 | { | ||
360 | netsend_setup(); | ||
361 | netreceive_setup(); | ||
362 | } | ||
363 | |||
364 | /* Copyright (c) 1997-1999 Miller Puckette. | ||
365 | * For information on usage and redistribution, and for a DISCLAIMER OF ALL | ||
366 | * WARRANTIES, see the file, "LICENSE.txt," in this distribution. */ | ||
367 | |||
368 | /* network */ | ||
369 | |||
370 | #include "m_pd.h" | ||
371 | #include "s_stuff.h" | ||
372 | |||
373 | #include <sys/types.h> | ||
374 | #include <string.h> | ||
375 | #ifdef UNIX | ||
376 | #include <sys/socket.h> | ||
377 | #include <netinet/in.h> | ||
378 | #include <netinet/tcp.h> | ||
379 | #include <netdb.h> | ||
380 | #include <stdio.h> | ||
381 | #define SOCKET_ERROR -1 | ||
382 | #else | ||
383 | #include <winsock.h> | ||
384 | #endif | ||
385 | |||
386 | static t_class *netsend_class; | ||
387 | |||
388 | typedef struct _netsend | ||
389 | { | ||
390 | t_object x_obj; | ||
391 | int x_fd; | ||
392 | int x_protocol; | ||
393 | } t_netsend; | ||
394 | |||
395 | static void *netsend_new(t_floatarg udpflag) | ||
396 | { | ||
397 | t_netsend *x = (t_netsend *)pd_new(netsend_class); | ||
398 | outlet_new(&x->x_obj, &s_float); | ||
399 | x->x_fd = -1; | ||
400 | x->x_protocol = (udpflag != 0 ? SOCK_DGRAM : SOCK_STREAM); | ||
401 | return (x); | ||
402 | } | ||
403 | |||
404 | static void netsend_connect(t_netsend *x, t_symbol *hostname, | ||
405 | t_floatarg fportno) | ||
406 | { | ||
407 | struct sockaddr_in server; | ||
408 | struct hostent *hp; | ||
409 | int sockfd; | ||
410 | int portno = fportno; | ||
411 | int intarg; | ||
412 | if (x->x_fd >= 0) | ||
413 | { | ||
414 | error("netsend_connect: already connected"); | ||
415 | return; | ||
416 | } | ||
417 | |||
418 | /* create a socket */ | ||
419 | sockfd = socket(AF_INET, x->x_protocol, 0); | ||
420 | #if 0 | ||
421 | fprintf(stderr, "send socket %d\n", sockfd); | ||
422 | #endif | ||
423 | if (sockfd < 0) | ||
424 | { | ||
425 | sys_sockerror("socket"); | ||
426 | return; | ||
427 | } | ||
428 | /* connect socket using hostname provided in command line */ | ||
429 | server.sin_family = AF_INET; | ||
430 | hp = gethostbyname(hostname->s_name); | ||
431 | if (hp == 0) | ||
432 | { | ||
433 | post("bad host?\n"); | ||
434 | return; | ||
435 | } | ||
436 | #if 0 | ||
437 | intarg = 0; | ||
438 | if (setsockopt(sockfd, SOL_SOCKET, SO_SNDBUF, | ||
439 | &intarg, sizeof(intarg)) < 0) | ||
440 | post("setsockopt (SO_RCVBUF) failed\n"); | ||
441 | #endif | ||
442 | /* for stream (TCP) sockets, specify "nodelay" */ | ||
443 | if (x->x_protocol == SOCK_STREAM) | ||
444 | { | ||
445 | intarg = 1; | ||
446 | if (setsockopt(sockfd, IPPROTO_TCP, TCP_NODELAY, | ||
447 | &intarg, sizeof(intarg)) < 0) | ||
448 | post("setsockopt (TCP_NODELAY) failed\n"); | ||
449 | } | ||
450 | memcpy((char *)&server.sin_addr, (char *)hp->h_addr, hp->h_length); | ||
451 | |||
452 | /* assign client port number */ | ||
453 | server.sin_port = htons((u_short)portno); | ||
454 | |||
455 | post("connecting to port %d", portno); | ||
456 | /* try to connect. LATER make a separate thread to do this | ||
457 | because it might block */ | ||
458 | if (connect(sockfd, (struct sockaddr *) &server, sizeof (server)) < 0) | ||
459 | { | ||
460 | sys_sockerror("connecting stream socket"); | ||
461 | sys_closesocket(sockfd); | ||
462 | return; | ||
463 | } | ||
464 | x->x_fd = sockfd; | ||
465 | outlet_float(x->x_obj.ob_outlet, 1); | ||
466 | } | ||
467 | |||
468 | static void netsend_disconnect(t_netsend *x) | ||
469 | { | ||
470 | if (x->x_fd >= 0) | ||
471 | { | ||
472 | sys_closesocket(x->x_fd); | ||
473 | x->x_fd = -1; | ||
474 | outlet_float(x->x_obj.ob_outlet, 0); | ||
475 | } | ||
476 | } | ||
477 | |||
478 | static void netsend_send(t_netsend *x, t_symbol *s, int argc, t_atom *argv) | ||
479 | { | ||
480 | if (x->x_fd >= 0) | ||
481 | { | ||
482 | t_binbuf *b = binbuf_new(); | ||
483 | char *buf, *bp; | ||
484 | int length, sent; | ||
485 | t_atom at; | ||
486 | binbuf_add(b, argc, argv); | ||
487 | SETSEMI(&at); | ||
488 | binbuf_add(b, 1, &at); | ||
489 | binbuf_gettext(b, &buf, &length); | ||
490 | for (bp = buf, sent = 0; sent < length;) | ||
491 | { | ||
492 | static double lastwarntime; | ||
493 | static double pleasewarn; | ||
494 | double timebefore = sys_getrealtime(); | ||
495 | int res = send(x->x_fd, buf, length-sent, 0); | ||
496 | double timeafter = sys_getrealtime(); | ||
497 | int late = (timeafter - timebefore > 0.005); | ||
498 | if (late || pleasewarn) | ||
499 | { | ||
500 | if (timeafter > lastwarntime + 2) | ||
501 | { | ||
502 | post("netsend blocked %d msec", | ||
503 | (int)(1000 * ((timeafter - timebefore) + pleasewarn))); | ||
504 | pleasewarn = 0; | ||
505 | lastwarntime = timeafter; | ||
506 | } | ||
507 | else if (late) pleasewarn += timeafter - timebefore; | ||
508 | } | ||
509 | if (res <= 0) | ||
510 | { | ||
511 | sys_sockerror("netsend"); | ||
512 | netsend_disconnect(x); | ||
513 | break; | ||
514 | } | ||
515 | else | ||
516 | { | ||
517 | sent += res; | ||
518 | bp += res; | ||
519 | } | ||
520 | } | ||
521 | t_freebytes(buf, length); | ||
522 | binbuf_free(b); | ||
523 | } | ||
524 | else error("netsend: not connected"); | ||
525 | } | ||
526 | |||
527 | static void netsend_free(t_netsend *x) | ||
528 | { | ||
529 | netsend_disconnect(x); | ||
530 | } | ||
531 | |||
532 | static void netsend_setup(void) | ||
533 | { | ||
534 | netsend_class = class_new(gensym("netsend"), (t_newmethod)netsend_new, | ||
535 | (t_method)netsend_free, | ||
536 | sizeof(t_netsend), 0, A_DEFFLOAT, 0); | ||
537 | class_addmethod(netsend_class, (t_method)netsend_connect, | ||
538 | gensym("connect"), A_SYMBOL, A_FLOAT, 0); | ||
539 | class_addmethod(netsend_class, (t_method)netsend_disconnect, | ||
540 | gensym("disconnect"), 0); | ||
541 | class_addmethod(netsend_class, (t_method)netsend_send, gensym("send"), | ||
542 | A_GIMME, 0); | ||
543 | } | ||
544 | |||
545 | /* ----------------------------- netreceive ------------------------- */ | ||
546 | |||
547 | static t_class *netreceive_class; | ||
548 | |||
549 | typedef struct _netreceive | ||
550 | { | ||
551 | t_object x_obj; | ||
552 | t_outlet *x_msgout; | ||
553 | t_outlet *x_connectout; | ||
554 | int x_connectsocket; | ||
555 | int x_nconnections; | ||
556 | int x_udp; | ||
557 | } t_netreceive; | ||
558 | |||
559 | static void netreceive_notify(t_netreceive *x) | ||
560 | { | ||
561 | outlet_float(x->x_connectout, --x->x_nconnections); | ||
562 | } | ||
563 | |||
564 | static void netreceive_doit(void *z, t_binbuf *b) | ||
565 | { | ||
566 | t_atom messbuf[1024]; | ||
567 | t_netreceive *x = (t_netreceive *)z; | ||
568 | int msg, natom = binbuf_getnatom(b); | ||
569 | t_atom *at = binbuf_getvec(b); | ||
570 | for (msg = 0; msg < natom;) | ||
571 | { | ||
572 | int emsg; | ||
573 | for (emsg = msg; emsg < natom && at[emsg].a_type != A_COMMA | ||
574 | && at[emsg].a_type != A_SEMI; emsg++) | ||
575 | ; | ||
576 | if (emsg > msg) | ||
577 | { | ||
578 | int i; | ||
579 | for (i = msg; i < emsg; i++) | ||
580 | if (at[i].a_type == A_DOLLAR || at[i].a_type == A_DOLLSYM) | ||
581 | { | ||
582 | pd_error(x, "netreceive: got dollar sign in message"); | ||
583 | goto nodice; | ||
584 | } | ||
585 | if (at[msg].a_type == A_FLOAT) | ||
586 | { | ||
587 | if (emsg > msg + 1) | ||
588 | outlet_list(x->x_msgout, 0, emsg-msg, at + msg); | ||
589 | else outlet_float(x->x_msgout, at[msg].a_w.w_float); | ||
590 | } | ||
591 | else if (at[msg].a_type == A_SYMBOL) | ||
592 | outlet_anything(x->x_msgout, at[msg].a_w.w_symbol, | ||
593 | emsg-msg-1, at + msg + 1); | ||
594 | } | ||
595 | nodice: | ||
596 | msg = emsg + 1; | ||
597 | } | ||
598 | } | ||
599 | |||
600 | static void netreceive_connectpoll(t_netreceive *x) | ||
601 | { | ||
602 | int fd = accept(x->x_connectsocket, 0, 0); | ||
603 | if (fd < 0) post("netreceive: accept failed"); | ||
604 | else | ||
605 | { | ||
606 | t_socketreceiver *y = socketreceiver_new((void *)x, | ||
607 | (t_socketnotifier)netreceive_notify, | ||
608 | (x->x_msgout ? netreceive_doit : 0), 0); | ||
609 | sys_addpollfn(fd, (t_fdpollfn)socketreceiver_read, y); | ||
610 | outlet_float(x->x_connectout, ++x->x_nconnections); | ||
611 | } | ||
612 | } | ||
613 | |||
614 | static void *netreceive_new(t_symbol *compatflag, | ||
615 | t_floatarg fportno, t_floatarg udpflag) | ||
616 | { | ||
617 | t_netreceive *x; | ||
618 | struct sockaddr_in server; | ||
619 | int sockfd, portno = fportno, udp = (udpflag != 0); | ||
620 | int old = !strcmp(compatflag->s_name , "old"); | ||
621 | int intarg; | ||
622 | /* create a socket */ | ||
623 | sockfd = socket(AF_INET, (udp ? SOCK_DGRAM : SOCK_STREAM), 0); | ||
624 | #if 0 | ||
625 | fprintf(stderr, "receive socket %d\n", sockfd); | ||
626 | #endif | ||
627 | if (sockfd < 0) | ||
628 | { | ||
629 | sys_sockerror("socket"); | ||
630 | return (0); | ||
631 | } | ||
632 | server.sin_family = AF_INET; | ||
633 | server.sin_addr.s_addr = INADDR_ANY; | ||
634 | |||
635 | #if 1 | ||
636 | /* ask OS to allow another Pd to repoen this port after we close it. */ | ||
637 | intarg = 1; | ||
638 | if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, | ||
639 | &intarg, sizeof(intarg)) < 0) | ||
640 | post("setsockopt (SO_REUSEADDR) failed\n"); | ||
641 | #endif | ||
642 | #if 0 | ||
643 | intarg = 0; | ||
644 | if (setsockopt(sockfd, SOL_SOCKET, SO_RCVBUF, | ||
645 | &intarg, sizeof(intarg)) < 0) | ||
646 | post("setsockopt (SO_RCVBUF) failed\n"); | ||
647 | #endif | ||
648 | /* Stream (TCP) sockets are set NODELAY */ | ||
649 | if (!udp) | ||
650 | { | ||
651 | intarg = 1; | ||
652 | if (setsockopt(sockfd, IPPROTO_TCP, TCP_NODELAY, | ||
653 | &intarg, sizeof(intarg)) < 0) | ||
654 | post("setsockopt (TCP_NODELAY) failed\n"); | ||
655 | } | ||
656 | /* assign server port number */ | ||
657 | server.sin_port = htons((u_short)portno); | ||
658 | |||
659 | /* name the socket */ | ||
660 | if (bind(sockfd, (struct sockaddr *)&server, sizeof(server)) < 0) | ||
661 | { | ||
662 | sys_sockerror("bind"); | ||
663 | sys_closesocket(sockfd); | ||
664 | return (0); | ||
665 | } | ||
666 | x = (t_netreceive *)pd_new(netreceive_class); | ||
667 | if (old) | ||
668 | { | ||
669 | /* old style, nonsecure version */ | ||
670 | x->x_msgout = 0; | ||
671 | } | ||
672 | else x->x_msgout = outlet_new(&x->x_obj, &s_anything); | ||
673 | |||
674 | if (udp) /* datagram protocol */ | ||
675 | { | ||
676 | t_socketreceiver *y = socketreceiver_new((void *)x, | ||
677 | (t_socketnotifier)netreceive_notify, | ||
678 | (x->x_msgout ? netreceive_doit : 0), 1); | ||
679 | sys_addpollfn(sockfd, (t_fdpollfn)socketreceiver_read, y); | ||
680 | x->x_connectout = 0; | ||
681 | } | ||
682 | else /* streaming protocol */ | ||
683 | { | ||
684 | if (listen(sockfd, 5) < 0) | ||
685 | { | ||
686 | sys_sockerror("listen"); | ||
687 | sys_closesocket(sockfd); | ||
688 | sockfd = -1; | ||
689 | } | ||
690 | else | ||
691 | { | ||
692 | sys_addpollfn(sockfd, (t_fdpollfn)netreceive_connectpoll, x); | ||
693 | x->x_connectout = outlet_new(&x->x_obj, &s_float); | ||
694 | } | ||
695 | } | ||
696 | x->x_connectsocket = sockfd; | ||
697 | x->x_nconnections = 0; | ||
698 | x->x_udp = udp; | ||
699 | |||
700 | return (x); | ||
701 | } | ||
702 | |||
703 | static void netreceive_free(t_netreceive *x) | ||
704 | { | ||
705 | /* LATER make me clean up open connections */ | ||
706 | if (x->x_connectsocket >= 0) | ||
707 | { | ||
708 | sys_rmpollfn(x->x_connectsocket); | ||
709 | sys_closesocket(x->x_connectsocket); | ||
710 | } | ||
711 | } | ||
712 | |||
713 | static void netreceive_setup(void) | ||
714 | { | ||
715 | netreceive_class = class_new(gensym("netreceive"), | ||
716 | (t_newmethod)netreceive_new, (t_method)netreceive_free, | ||
717 | sizeof(t_netreceive), CLASS_NOINLET, A_DEFFLOAT, A_DEFFLOAT, | ||
718 | A_DEFSYM, 0); | ||
719 | } | ||
720 | |||
721 | void x_net_setup(void) | ||
722 | { | ||
723 | netsend_setup(); | ||
724 | netreceive_setup(); | ||
725 | } | ||
726 | |||