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. */
7 #include "../../pdbox.h"
16 #include <sys/types.h>
19 #include <sys/socket.h>
20 #include <netinet/in.h>
21 #include <netinet/tcp.h>
24 #define SOCKET_ERROR -1
30 static t_class
*netsend_class
;
32 typedef struct _netsend
39 static void *netsend_new(t_floatarg udpflag
)
45 t_netsend
*x
= (t_netsend
*)pd_new(netsend_class
);
46 outlet_new(&x
->x_obj
, &s_float
);
49 x
->x_protocol
= (udpflag
!= 0 ? SOCK_DGRAM
: SOCK_STREAM
);
54 static void netsend_connect(t_netsend
*x
, t_symbol
*hostname
,
62 struct sockaddr_in server
;
69 error("netsend_connect: already connected");
74 sockfd
= socket(AF_INET
, x
->x_protocol
, 0);
76 fprintf(stderr
, "send socket %d\n", sockfd
);
80 sys_sockerror("socket");
83 /* connect socket using hostname provided in command line */
84 server
.sin_family
= AF_INET
;
85 hp
= gethostbyname(hostname
->s_name
);
93 if (setsockopt(sockfd
, SOL_SOCKET
, SO_SNDBUF
,
94 &intarg
, sizeof(intarg
)) < 0)
95 post("setsockopt (SO_RCVBUF) failed\n");
97 /* for stream (TCP) sockets, specify "nodelay" */
98 if (x
->x_protocol
== SOCK_STREAM
)
101 if (setsockopt(sockfd
, IPPROTO_TCP
, TCP_NODELAY
,
102 &intarg
, sizeof(intarg
)) < 0)
103 post("setsockopt (TCP_NODELAY) failed\n");
105 memcpy((char *)&server
.sin_addr
, (char *)hp
->h_addr
, hp
->h_length
);
107 /* assign client port number */
108 server
.sin_port
= htons((u_short
)portno
);
110 post("connecting to port %d", portno
);
111 /* try to connect. LATER make a separate thread to do this
112 because it might block */
113 if (connect(sockfd
, (struct sockaddr
*) &server
, sizeof (server
)) < 0)
115 sys_sockerror("connecting stream socket");
116 sys_closesocket(sockfd
);
120 outlet_float(x
->x_obj
.ob_outlet
, 1);
124 static void netsend_disconnect(t_netsend
*x
)
129 sys_closesocket(x
->x_fd
);
132 outlet_float(x
->x_obj
.ob_outlet
, 0);
136 static void netsend_send(t_netsend
*x
, t_symbol
*s
, int argc
, t_atom
*argv
)
146 t_binbuf
*b
= binbuf_new();
150 binbuf_add(b
, argc
, argv
);
152 binbuf_add(b
, 1, &at
);
153 binbuf_gettext(b
, &buf
, &length
);
154 for (bp
= buf
, sent
= 0; sent
< length
;)
156 static double lastwarntime
;
157 static double pleasewarn
;
158 double timebefore
= sys_getrealtime();
159 int res
= send(x
->x_fd
, buf
, length
-sent
, 0);
160 double timeafter
= sys_getrealtime();
161 int late
= (timeafter
- timebefore
> 0.005);
162 if (late
|| pleasewarn
)
164 if (timeafter
> lastwarntime
+ 2)
166 post("netsend blocked %d msec",
167 (int)(1000 * ((timeafter
- timebefore
) + pleasewarn
)));
169 lastwarntime
= timeafter
;
171 else if (late
) pleasewarn
+= timeafter
- timebefore
;
175 sys_sockerror("netsend");
176 netsend_disconnect(x
);
185 t_freebytes(buf
, length
);
188 else error("netsend: not connected");
192 static void netsend_free(t_netsend
*x
)
197 netsend_disconnect(x
);
201 static void netsend_setup(void)
203 netsend_class
= class_new(gensym("netsend"), (t_newmethod
)netsend_new
,
204 (t_method
)netsend_free
,
205 sizeof(t_netsend
), 0, A_DEFFLOAT
, 0);
206 class_addmethod(netsend_class
, (t_method
)netsend_connect
,
207 gensym("connect"), A_SYMBOL
, A_FLOAT
, 0);
208 class_addmethod(netsend_class
, (t_method
)netsend_disconnect
,
209 gensym("disconnect"), 0);
210 class_addmethod(netsend_class
, (t_method
)netsend_send
, gensym("send"),
214 /* ----------------------------- netreceive ------------------------- */
216 static t_class
*netreceive_class
;
218 typedef struct _netreceive
222 t_outlet
*x_connectout
;
229 static t_netreceive
* receiver
;
230 static int receiver_port
;
234 static void netreceive_notify(t_netreceive
*x
)
236 outlet_float(x
->x_connectout
, --x
->x_nconnections
);
240 static void netreceive_doit(void *z
, t_binbuf
*b
)
243 t_atom messbuf
[1024];
245 t_netreceive
*x
= (t_netreceive
*)z
;
246 int msg
, natom
= binbuf_getnatom(b
);
247 t_atom
*at
= binbuf_getvec(b
);
248 for (msg
= 0; msg
< natom
;)
251 for (emsg
= msg
; emsg
< natom
&& at
[emsg
].a_type
!= A_COMMA
252 && at
[emsg
].a_type
!= A_SEMI
; emsg
++)
257 for (i
= msg
; i
< emsg
; i
++)
258 if (at
[i
].a_type
== A_DOLLAR
|| at
[i
].a_type
== A_DOLLSYM
)
260 pd_error(x
, "netreceive: got dollar sign in message");
263 if (at
[msg
].a_type
== A_FLOAT
)
266 outlet_list(x
->x_msgout
, 0, emsg
-msg
, at
+ msg
);
267 else outlet_float(x
->x_msgout
, at
[msg
].a_w
.w_float
);
269 else if (at
[msg
].a_type
== A_SYMBOL
)
270 outlet_anything(x
->x_msgout
, at
[msg
].a_w
.w_symbol
,
271 emsg
-msg
-1, at
+ msg
+ 1);
279 static void netreceive_connectpoll(t_netreceive
*x
)
281 int fd
= accept(x
->x_connectsocket
, 0, 0);
282 if (fd
< 0) post("netreceive: accept failed");
285 t_socketreceiver
*y
= socketreceiver_new((void *)x
,
286 (t_socketnotifier
)netreceive_notify
,
287 (x
->x_msgout
? netreceive_doit
: 0), 0);
288 sys_addpollfn(fd
, (t_fdpollfn
)socketreceiver_read
, y
);
289 outlet_float(x
->x_connectout
, ++x
->x_nconnections
);
294 static void *netreceive_new(t_symbol
*compatflag
,
295 t_floatarg fportno
, t_floatarg udpflag
)
300 int portno
= fportno
, udp
= (udpflag
!= 0);
304 /* Look whether callback is already taken. */
307 post("Receiver callback already taken!\n");
311 /* Look whether TCP sockets are thought to exist. */
314 post("Trying to create TCP socket!\n");
318 x
= (t_netreceive
*) pd_new(netreceive_class
);
319 x
->x_msgout
= outlet_new(&x
->x_obj
, &s_anything
);
321 x
->x_nconnections
= 0;
325 receiver_port
= portno
;
328 struct sockaddr_in server
;
329 int sockfd
, portno
= fportno
, udp
= (udpflag
!= 0);
330 int old
= !strcmp(compatflag
->s_name
, "old");
332 /* create a socket */
333 sockfd
= socket(AF_INET
, (udp
? SOCK_DGRAM
: SOCK_STREAM
), 0);
335 fprintf(stderr
, "receive socket %d\n", sockfd
);
339 sys_sockerror("socket");
342 server
.sin_family
= AF_INET
;
343 server
.sin_addr
.s_addr
= INADDR_ANY
;
346 /* ask OS to allow another Pd to repoen this port after we close it. */
348 if (setsockopt(sockfd
, SOL_SOCKET
, SO_REUSEADDR
,
349 &intarg
, sizeof(intarg
)) < 0)
350 post("setsockopt (SO_REUSEADDR) failed\n");
354 if (setsockopt(sockfd
, SOL_SOCKET
, SO_RCVBUF
,
355 &intarg
, sizeof(intarg
)) < 0)
356 post("setsockopt (SO_RCVBUF) failed\n");
358 /* Stream (TCP) sockets are set NODELAY */
362 if (setsockopt(sockfd
, IPPROTO_TCP
, TCP_NODELAY
,
363 &intarg
, sizeof(intarg
)) < 0)
364 post("setsockopt (TCP_NODELAY) failed\n");
366 /* assign server port number */
367 server
.sin_port
= htons((u_short
)portno
);
369 /* name the socket */
370 if (bind(sockfd
, (struct sockaddr
*)&server
, sizeof(server
)) < 0)
372 sys_sockerror("bind");
373 sys_closesocket(sockfd
);
376 x
= (t_netreceive
*)pd_new(netreceive_class
);
379 /* old style, nonsecure version */
382 else x
->x_msgout
= outlet_new(&x
->x_obj
, &s_anything
);
384 if (udp
) /* datagram protocol */
386 t_socketreceiver
*y
= socketreceiver_new((void *)x
,
387 (t_socketnotifier
)netreceive_notify
,
388 (x
->x_msgout
? netreceive_doit
: 0), 1);
389 sys_addpollfn(sockfd
, (t_fdpollfn
)socketreceiver_read
, y
);
392 else /* streaming protocol */
394 if (listen(sockfd
, 5) < 0)
396 sys_sockerror("listen");
397 sys_closesocket(sockfd
);
402 sys_addpollfn(sockfd
, (t_fdpollfn
)netreceive_connectpoll
, x
);
403 x
->x_connectout
= outlet_new(&x
->x_obj
, &s_float
);
406 x
->x_connectsocket
= sockfd
;
407 x
->x_nconnections
= 0;
414 static void netreceive_free(t_netreceive
*x
)
417 if(receiver
&& receiver
== x
)
420 /* LATER make me clean up open connections */
421 if (x
->x_connectsocket
>= 0)
423 sys_rmpollfn(x
->x_connectsocket
);
424 sys_closesocket(x
->x_connectsocket
);
430 /* Basically a reimplementation of socketreceiver_getudp()
432 extern t_binbuf
* inbinbuf
;
433 extern void outlet_setstacklim(void);
435 void rockbox_receive_callback(struct datagram
* dg
)
437 /* Check whether there is a receiver. */
442 dg
->data
[dg
->size
] = '\0';
444 /* If complete line... */
445 if(dg
->data
[dg
->size
-1] == '\n')
447 char* semi
= strchr(dg
->data
, ';');
453 /* Create binary buffer. */
454 binbuf_text(inbinbuf
, dg
->data
, strlen(dg
->data
));
456 /* Limit outlet stack. */
457 outlet_setstacklim();
459 /* Execute receive function. */
460 netreceive_doit(receiver
, inbinbuf
);
465 static void netreceive_setup(void)
467 netreceive_class
= class_new(gensym("netreceive"),
468 (t_newmethod
)netreceive_new
, (t_method
)netreceive_free
,
469 sizeof(t_netreceive
), CLASS_NOINLET
, A_DEFFLOAT
, A_DEFFLOAT
,
473 void x_net_setup(void)