2 SuperCollider real time audio synthesis system
3 Copyright (c) 2002 James McCartney. All rights reserved.
4 http://www.audiosynth.com
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21 #include "SC_BoundsMacros.h"
22 #include "SC_ComPort.h"
23 #include "SC_Endian.h"
24 //#include "SC_Lock.h"
34 #include "SC_Win32Utils.h"
45 #if defined(SC_DARWIN) || defined(SC_IPHONE)
49 // sk: determine means of blocking SIGPIPE for send(2) (implementation
52 #define HAVE_SO_NOSIGPIPE 0
53 #define HAVE_MSG_NOSIGNAL 0
55 #if defined(SO_NOSIGPIPE)
56 # undef HAVE_SO_NOSIGPIPE
57 # define HAVE_SO_NOSIGPIPE 1
58 #elif defined(MSG_NOSIGNAL)
59 # undef HAVE_MSG_NOSIGNAL
60 # define HAVE_MSG_NOSIGNAL 1
63 int recvall(int socket
, void *msg
, size_t len
);
64 int recvallfrom(int socket
, void *msg
, size_t len
, struct sockaddr
*fromaddr
, int addrlen
);
65 int sendallto(int socket
, const void *msg
, size_t len
, struct sockaddr
*toaddr
, int addrlen
);
66 int sendall(int socket
, const void *msg
, size_t len
);
68 void ProcessOSCPacket(OSC_Packet
*inPacket
, int inPortNum
);
70 void dumpOSCmsg(int inSize
, char* inData
)
77 data
= OSCstrskip(inData
);
78 size
= inSize
- (data
- inData
);
79 printf("[ \"%s\",", addr
);
83 printf("[ %d,", OSCint(inData
));
88 sc_msg_iter
msg(size
, data
);
92 char c
= msg
.nextTag('i');
96 printf(" %d", msg
.geti());
99 printf(" %g", msg
.getf());
102 printf(" %g", msg
.getd());
105 printf(" \"%s\"", msg
.gets());
108 printf(" DATA[%zu]", msg
.getbsize());
112 printf(" !unknown tag '%c' 0x%02x !", isprint(c
)?c
:'?', (unsigned char)c
& 255);
115 if (msg
.remain()) printf(",");
121 void hexdump(int size
, char* data
)
124 int padsize
= (size
+ 15) & -16;
125 printf("size %d\n", size
);
126 for (int i
=0; i
<padsize
; ++i
)
139 printf("%02x ", (unsigned char)data
[i
] & 255);
141 if (isprint(data
[i
])) ascii
[i
&15] = data
[i
];
142 else ascii
[i
&15] = '.';
147 printf(" |%s|\n", ascii
);
157 void dumpOSC(int mode
, int size
, char* inData
)
161 if (strcmp(inData
, "#bundle") == 0)
163 char* data
= inData
+ 8;
164 printf("[ \"#bundle\", %lld, ", OSCtime(data
));
166 char* dataEnd
= inData
+ size
;
167 while (data
< dataEnd
) {
168 int32 msgSize
= OSCint(data
);
169 data
+= sizeof(int32
);
171 dumpOSCmsg(msgSize
, data
);
173 if (data
< dataEnd
) printf(",");
179 dumpOSCmsg(size
, inData
);
184 if (mode
& 2) hexdump(size
, inData
);
187 //////////////////////////////////////////////////////////////////////////////////////////////////////////
189 SC_CmdPort::SC_CmdPort()
193 SC_CmdPort::~SC_CmdPort()
197 //////////////////////////////////////////////////////////////////////////////////////////////////////////
199 SC_ComPort::SC_ComPort(int inPortNum
)
200 : mPortNum(inPortNum
), mSocket(-1)
204 SC_ComPort::~SC_ComPort()
207 if (mSocket
!= -1) closesocket(mSocket
);
209 if (mSocket
!= -1) close(mSocket
);
213 static void* com_thread_func(void* arg
)
215 SC_CmdPort
*thread
= (SC_CmdPort
*)arg
;
216 void* result
= thread
->Run();
220 void SC_CmdPort::Start()
222 pthread_create (&mThread
, NULL
, com_thread_func
, (void*)this);
225 //////////////////////////////////////////////////////////////////////////////////////////////////////////
227 SC_UdpInPort::SC_UdpInPort(int inPortNum
)
228 : SC_ComPort(inPortNum
)
230 if ((mSocket
= socket(AF_INET
, SOCK_DGRAM
, 0)) < 0) {
231 throw std::runtime_error("failed to create udp socket\n");
237 setsockopt(mSocket
, SOL_SOCKET
, SO_SNDBUF
, (char*)&bufsize
, sizeof(bufsize
));
239 setsockopt(mSocket
, SOL_SOCKET
, SO_SNDBUF
, &bufsize
, sizeof(bufsize
));
243 bzero((char *)&mBindSockAddr
, sizeof(mBindSockAddr
));
244 mBindSockAddr
.sin_family
= AF_INET
;
245 mBindSockAddr
.sin_addr
.s_addr
= htonl(INADDR_ANY
);
248 for (int i
=0; i
<10 && !bound
; ++i
) {
249 mPortNum
= mPortNum
+i
;
250 mBindSockAddr
.sin_port
= htons(mPortNum
);
251 if (bind(mSocket
, (struct sockaddr
*)&mBindSockAddr
, sizeof(mBindSockAddr
)) >= 0) {
255 if (!bound
) throw std::runtime_error("unable to bind udp socket\n");
259 SC_UdpInPort::~SC_UdpInPort()
262 if (mSocket
!= -1) closesocket(mSocket
);
264 if (mSocket
!= -1) close(mSocket
);
268 //////////////////////////////////////////////////////////////////////////////////////////////////////////
270 SC_UdpCustomInPort::SC_UdpCustomInPort(int inPortNum
)
271 : SC_ComPort(inPortNum
)
273 if ((mSocket
= socket(AF_INET
, SOCK_DGRAM
, 0)) < 0) {
274 throw std::runtime_error("failed to create udp socket\n");
280 setsockopt(mSocket
, SOL_SOCKET
, SO_SNDBUF
, (char*)&bufsize
, sizeof(bufsize
));
282 setsockopt(mSocket
, SOL_SOCKET
, SO_SNDBUF
, &bufsize
, sizeof(bufsize
));
286 bzero((char *)&mBindSockAddr
, sizeof(mBindSockAddr
));
287 mBindSockAddr
.sin_family
= AF_INET
;
288 mBindSockAddr
.sin_addr
.s_addr
= htonl(INADDR_ANY
);
291 mBindSockAddr
.sin_port
= htons(mPortNum
);
292 if (bind(mSocket
, (struct sockaddr
*)&mBindSockAddr
, sizeof(mBindSockAddr
)) >= 0) {
295 if (!bound
) throw std::runtime_error("unable to bind udp socket\n");
299 SC_UdpCustomInPort::~SC_UdpCustomInPort()
301 mRunning
.store(false);
302 pthread_join(mThread
, NULL
);
304 if (mSocket
!= -1) closesocket(mSocket
);
306 if (mSocket
!= -1) close(mSocket
);
311 //////////////////////////////////////////////////////////////////////////////////////////////////////////
313 void DumpReplyAddress(ReplyAddress
*inReplyAddress
)
315 printf("mSockAddrLen %d\n", inReplyAddress
->mSockAddrLen
);
316 printf("mSocket %d\n", inReplyAddress
->mSocket
);
318 printf("mSockAddr.sin_len %d\n", inReplyAddress
->mSockAddr
.sin_len
);
320 printf("mSockAddr.sin_family %d\n", inReplyAddress
->mSockAddr
.sin_family
);
321 printf("mSockAddr.sin_port %d\n", inReplyAddress
->mSockAddr
.sin_port
);
322 printf("mSockAddr.sin_addr.s_addr %d\n", inReplyAddress
->mSockAddr
.sin_addr
.s_addr
);
323 printf("mReplyFunc %p\n", inReplyAddress
->mReplyFunc
);
327 int32 Hash(ReplyAddress *inReplyAddress)
330 int32 *word = (int32*)&inReplyAddress->mSockAddr;
331 hash = Hash(inReplyAddress->mSockAddr.sin_addr.s_addr);
333 hash += inReplyAddress->mSockAddr.sin_len << 24
334 | inReplyAddress->mSockAddr.sin_family << 16
335 | inReplyAddress->mSockAddr.sin_port;
342 void udp_reply_func(struct ReplyAddress
*addr
, char* msg
, int size
);
343 void udp_reply_func(struct ReplyAddress
*addr
, char* msg
, int size
)
345 printf("->udp_reply_func\n");
346 int total
= sendallto(addr
->mSocket
, msg
, size
, (sockaddr
*)&addr
->mSockAddr
, addr
->mSockAddrLen
);
347 printf("<-udp_reply_func %d of %d\n", total
, size
);
348 if (total
< size
) DumpReplyAddress(addr
);
351 ReplyFunc
SC_UdpInPort::GetReplyFunc()
353 return udp_reply_func
;
356 void* SC_UdpInPort::Run()
358 OSC_Packet
*packet
= 0;
360 //printf("SC_UdpInPort::Run\n"); fflush(stdout);
364 packet
= (OSC_Packet
*)malloc(sizeof(OSC_Packet
));
366 packet
->mReplyAddr
.mSockAddrLen
= sizeof(sockaddr_in
);
367 int size
= recvfrom(mSocket
, buf
, kTextBufSize
, 0,
368 (struct sockaddr
*) &packet
->mReplyAddr
.mSockAddr
, (socklen_t
*)&packet
->mReplyAddr
.mSockAddrLen
);
371 //dumpOSC(3, size, buf);
374 char *data
= (char*)malloc(size
);
375 packet
->mReplyAddr
.mReplyFunc
= udp_reply_func
;
376 packet
->mSize
= size
;
377 packet
->mData
= data
;
378 packet
->mReplyAddr
.mSocket
= mSocket
;
379 memcpy(data
, buf
, size
);
380 ProcessOSCPacket(packet
, mPortNum
);
387 ReplyFunc
SC_UdpCustomInPort::GetReplyFunc()
389 return udp_reply_func
;
392 void* SC_UdpCustomInPort::Run()
394 OSC_Packet
*packet
= 0;
396 const int fd
= mSocket
;
397 const int max_fd
= fd
+1;
399 mRunning
.store(true);
400 while (mRunning
.load(boost::memory_order_consume
)) {
406 struct timeval timeout
;
408 timeout
.tv_usec
= 500000;
410 int n
= select(max_fd
, &rfds
, 0, 0, &timeout
);
411 if ((n
> 0) && FD_ISSET(fd
, &rfds
)) {
413 packet
= (OSC_Packet
*)malloc(sizeof(OSC_Packet
));
415 packet
->mReplyAddr
.mSockAddrLen
= sizeof(sockaddr_in
);
416 int size
= recvfrom(mSocket
, buf
, kTextBufSize
, 0,
417 (struct sockaddr
*) &packet
->mReplyAddr
.mSockAddr
, (socklen_t
*)&packet
->mReplyAddr
.mSockAddrLen
);
419 if (size
> 0 && mRunning
.load(boost::memory_order_consume
)) {
420 //dumpOSC(3, size, buf);
423 char *data
= (char*)malloc(size
);
424 packet
->mReplyAddr
.mReplyFunc
= udp_reply_func
;
425 packet
->mSize
= size
;
426 packet
->mData
= data
;
427 packet
->mReplyAddr
.mSocket
= mSocket
;
428 memcpy(data
, buf
, size
);
429 ProcessOSCPacket(packet
, mPortNum
);
434 FreeOSCPacket(packet
); // just in case
438 //////////////////////////////////////////////////////////////////////////////////////////////////////////
440 SC_TcpInPort::SC_TcpInPort(int inPortNum
, int inMaxConnections
, int inBacklog
)
441 : SC_ComPort(inPortNum
), mConnectionAvailable(inMaxConnections
),
445 if((mSocket
= socket(AF_INET
, SOCK_STREAM
, 0)) < 0) {
446 throw std::runtime_error("failed to create tcp socket\n");
448 //setsockopt(mSocket, SOL_SOCKET, TCP_NODELAY);
450 bzero((char *)&mBindSockAddr
, sizeof(mBindSockAddr
));
451 mBindSockAddr
.sin_family
= AF_INET
;
452 mBindSockAddr
.sin_addr
.s_addr
= htonl(INADDR_ANY
);
453 mBindSockAddr
.sin_port
= htons(mPortNum
);
455 if(bind(mSocket
, (struct sockaddr
*)&mBindSockAddr
, sizeof(mBindSockAddr
)) < 0)
457 throw std::runtime_error("unable to bind tcp socket\n");
459 if(listen(mSocket
, mBacklog
) < 0)
461 throw std::runtime_error("unable to listen tcp socket\n");
467 void* SC_TcpInPort::Run()
471 mConnectionAvailable
.Acquire();
472 struct sockaddr_in address
; /* Internet socket address stuct */
473 int addressSize
=sizeof(struct sockaddr_in
);
474 int socket
= accept(mSocket
,(struct sockaddr
*)&address
,(socklen_t
*)&addressSize
);
476 mConnectionAvailable
.Release();
478 new SC_TcpConnectionPort(this, socket
);
484 void SC_TcpInPort::ConnectionTerminated()
486 mConnectionAvailable
.Release();
489 void null_reply_func(struct ReplyAddress
*addr
, char* msg
, int size
);
490 void null_reply_func(struct ReplyAddress
*addr
, char* msg
, int size
)
494 ReplyFunc
SC_TcpInPort::GetReplyFunc()
496 return null_reply_func
;
499 //////////////////////////////////////////////////////////////////////////////////////////////////////////
501 SC_TcpConnectionPort::SC_TcpConnectionPort(SC_TcpInPort
*inParent
, int inSocket
)
502 : SC_ComPort(0), mParent(inParent
)
508 SC_TcpConnectionPort::~SC_TcpConnectionPort()
511 closesocket(mSocket
);
515 mParent
->ConnectionTerminated();
518 void tcp_reply_func(struct ReplyAddress
*addr
, char* msg
, int size
);
519 void tcp_reply_func(struct ReplyAddress
*addr
, char* msg
, int size
)
521 sendall(addr
->mSocket
, msg
, size
);
524 ReplyFunc
SC_TcpConnectionPort::GetReplyFunc()
526 return tcp_reply_func
;
529 extern const char* gPassword
;
531 void* SC_TcpConnectionPort::Run()
533 OSC_Packet
*packet
= 0;
534 // wait for login message
540 packet
= (OSC_Packet
*)malloc(sizeof(OSC_Packet
));
542 size
= recvall(mSocket
, &msglen
, sizeof(int32
));
543 if (size
< 0) goto leave
;
545 // sk: msglen is in network byte order
546 msglen
= ntohl(msglen
);
548 char *data
= (char*)malloc(msglen
);
549 size
= recvall(mSocket
, data
, msglen
);
550 if (size
< msglen
) goto leave
;
552 packet
->mReplyAddr
.mReplyFunc
= tcp_reply_func
;
553 packet
->mSize
= msglen
;
554 packet
->mData
= data
;
555 packet
->mReplyAddr
.mSocket
= mSocket
;
556 ProcessOSCPacket(packet
, mPortNum
);
560 delete this; // ohh this could cause a crash if a reply tries to access it..
564 //////////////////////////////////////////////////////////////////////////////////////////////////////////
567 # include <sys/select.h>
571 SC_TcpClientPort::SC_TcpClientPort(int inSocket
, ClientNotifyFunc notifyFunc
, void *clientData
)
573 mClientNotifyFunc(notifyFunc
),
574 mClientData(clientData
)
577 socklen_t sockAddrLen
= sizeof(mReplySockAddr
);
579 if (getpeername(mSocket
, (struct sockaddr
*)&mReplySockAddr
, &sockAddrLen
) == -1) {
580 memset(&mReplySockAddr
, 0, sizeof(mReplySockAddr
));
581 mReplySockAddr
.sin_family
= AF_INET
;
582 mReplySockAddr
.sin_addr
.s_addr
= htonl(INADDR_NONE
);
583 mReplySockAddr
.sin_port
= htons(0);
586 #if HAVE_SO_NOSIGPIPE
588 setsockopt(mSocket
, SOL_SOCKET
, SO_NOSIGPIPE
, &sockopt
, sizeof(sockopt
));
589 #endif // HAVE_SO_NOSIGPIPE
591 if (pipe(mCmdFifo
) == -1) {
592 mCmdFifo
[0] = mCmdFifo
[1] = -1;
598 SC_TcpClientPort::~SC_TcpClientPort()
601 closesocket(mCmdFifo
[0]);
602 closesocket(mCmdFifo
[1]);
603 closesocket(mSocket
);
611 void* SC_TcpClientPort::Run()
613 OSC_Packet
*packet
= 0;
617 int cmdfd
= mCmdFifo
[0];
618 int sockfd
= mSocket
;
619 int nfds
= sc_max(cmdfd
, sockfd
) + 1;
621 bool cmdClose
= false;
623 pthread_detach(mThread
);
628 FD_SET(cmdfd
, &rfds
);
629 FD_SET(sockfd
, &rfds
);
631 if ((select(nfds
, &rfds
, 0, 0, 0) == -1) || (cmdClose
= FD_ISSET(cmdfd
, &rfds
)))
634 if (!FD_ISSET(sockfd
, &rfds
))
637 packet
= (OSC_Packet
*)malloc(sizeof(OSC_Packet
));
638 if (!packet
) goto leave
;
642 size
= recvall(sockfd
, &msglen
, sizeof(int32
));
643 if (size
< (int32
)sizeof(int32
)) goto leave
;
645 // msglen is in network byte order
646 msglen
= ntohl(msglen
);
648 packet
->mData
= (char*)malloc(msglen
);
649 if (!packet
->mData
) goto leave
;
651 size
= recvall(sockfd
, packet
->mData
, msglen
);
652 if (size
< msglen
) goto leave
;
654 memcpy(&packet
->mReplyAddr
.mSockAddr
, &mReplySockAddr
, sizeof(mReplySockAddr
));
655 packet
->mReplyAddr
.mSockAddrLen
= sizeof(mReplySockAddr
);
656 packet
->mReplyAddr
.mSocket
= sockfd
;
657 packet
->mReplyAddr
.mReplyFunc
= tcp_reply_func
;
658 packet
->mSize
= msglen
;
659 ProcessOSCPacket(packet
, mPortNum
);
669 // Only call notify function when not closed explicitly
670 if (!cmdClose
&& mClientNotifyFunc
) {
671 (*mClientNotifyFunc
)(mClientData
);
677 void SC_TcpClientPort::Close()
681 win32_pipewrite(mCmdFifo
[1], &cmd
, sizeof(cmd
));
683 size_t written
= write(mCmdFifo
[1], &cmd
, sizeof(cmd
));
684 if (written
!= sizeof(cmd
))
685 post("warning: invalid write in SC_TcpClientPort::Close");
689 ReplyFunc
SC_TcpClientPort::GetReplyFunc()
691 return tcp_reply_func
;
694 //////////////////////////////////////////////////////////////////////////////////////////////////////////
696 int recvall(int socket
, void *msg
, size_t len
)
702 int numbytes
= recv(socket
, reinterpret_cast<char*>(msg
), len
- total
, 0);
704 int numbytes
= recv(socket
, msg
, len
- total
, 0);
706 if (numbytes
<= 0) return total
;
708 msg
= (void*)((char*)msg
+ numbytes
);
713 int recvallfrom(int socket
, void *msg
, size_t len
, struct sockaddr
*fromaddr
, int addrlen
)
718 socklen_t addrlen2
= addrlen
;
720 int numbytes
= recvfrom(socket
, reinterpret_cast<char*>(msg
), len
- total
, 0, fromaddr
, &addrlen2
);
722 int numbytes
= recvfrom(socket
, msg
, len
- total
, 0, fromaddr
, &addrlen2
);
724 if (numbytes
< 0) return total
;
726 msg
= (void*)((char*)msg
+ numbytes
);
731 int sendallto(int socket
, const void *msg
, size_t len
, struct sockaddr
*toaddr
, int addrlen
)
737 int numbytes
= sendto(socket
, reinterpret_cast<const char*>(msg
), len
- total
, 0, toaddr
, addrlen
);
739 int numbytes
= sendto(socket
, msg
, len
- total
, 0, toaddr
, addrlen
);
741 //printf("numbytes %d total %d len %d\n", numbytes, total, len);
743 printf("******* errno %d %s\n", errno
, strerror(errno
));
747 msg
= (void*)((char*)msg
+ numbytes
);
752 int sendall(int socket
, const void *msg
, size_t len
)
757 #if HAVE_MSG_NOSIGNAL
758 int flags
= MSG_NOSIGNAL
;
761 #endif // HAVE_MSG_NOSIGNAL
763 int numbytes
= send(socket
, reinterpret_cast<const char*>(msg
), len
- total
, flags
);
765 int numbytes
= send(socket
, msg
, len
- total
, flags
);
767 if (numbytes
< 0) return total
;
769 msg
= (void*)((char*)msg
+ numbytes
);
774 //////////////////////////////////////////////////////////////////////////////////////////////////////////