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 void* com_thread_func(void* arg
);
214 void* com_thread_func(void* arg
)
216 SC_CmdPort
*thread
= (SC_CmdPort
*)arg
;
217 void* result
= thread
->Run();
221 void SC_CmdPort::Start()
223 pthread_create (&mThread
, NULL
, com_thread_func
, (void*)this);
226 //////////////////////////////////////////////////////////////////////////////////////////////////////////
228 SC_UdpInPort::SC_UdpInPort(int inPortNum
)
229 : SC_ComPort(inPortNum
)
231 if ((mSocket
= socket(AF_INET
, SOCK_DGRAM
, 0)) < 0) {
232 throw std::runtime_error("failed to create udp socket\n");
238 setsockopt(mSocket
, SOL_SOCKET
, SO_SNDBUF
, (char*)&bufsize
, sizeof(bufsize
));
240 setsockopt(mSocket
, SOL_SOCKET
, SO_SNDBUF
, &bufsize
, sizeof(bufsize
));
244 bzero((char *)&mBindSockAddr
, sizeof(mBindSockAddr
));
245 mBindSockAddr
.sin_family
= AF_INET
;
246 mBindSockAddr
.sin_addr
.s_addr
= htonl(INADDR_ANY
);
249 for (int i
=0; i
<10 && !bound
; ++i
) {
250 mPortNum
= mPortNum
+i
;
251 mBindSockAddr
.sin_port
= htons(mPortNum
);
252 if (bind(mSocket
, (struct sockaddr
*)&mBindSockAddr
, sizeof(mBindSockAddr
)) >= 0) {
256 if (!bound
) throw std::runtime_error("unable to bind udp socket\n");
260 SC_UdpInPort::~SC_UdpInPort()
263 if (mSocket
!= -1) closesocket(mSocket
);
265 if (mSocket
!= -1) close(mSocket
);
269 //////////////////////////////////////////////////////////////////////////////////////////////////////////
271 SC_UdpCustomInPort::SC_UdpCustomInPort(int inPortNum
)
272 : SC_ComPort(inPortNum
)
274 if ((mSocket
= socket(AF_INET
, SOCK_DGRAM
, 0)) < 0) {
275 throw std::runtime_error("failed to create udp socket\n");
281 setsockopt(mSocket
, SOL_SOCKET
, SO_SNDBUF
, (char*)&bufsize
, sizeof(bufsize
));
283 setsockopt(mSocket
, SOL_SOCKET
, SO_SNDBUF
, &bufsize
, sizeof(bufsize
));
287 bzero((char *)&mBindSockAddr
, sizeof(mBindSockAddr
));
288 mBindSockAddr
.sin_family
= AF_INET
;
289 mBindSockAddr
.sin_addr
.s_addr
= htonl(INADDR_ANY
);
292 mBindSockAddr
.sin_port
= htons(mPortNum
);
293 if (bind(mSocket
, (struct sockaddr
*)&mBindSockAddr
, sizeof(mBindSockAddr
)) >= 0) {
296 if (!bound
) throw std::runtime_error("unable to bind udp socket\n");
300 SC_UdpCustomInPort::~SC_UdpCustomInPort()
302 mRunning
.store(false);
303 pthread_join(mThread
, NULL
);
305 if (mSocket
!= -1) closesocket(mSocket
);
307 if (mSocket
!= -1) close(mSocket
);
312 //////////////////////////////////////////////////////////////////////////////////////////////////////////
314 void DumpReplyAddress(ReplyAddress
*inReplyAddress
)
316 printf("mSockAddrLen %d\n", inReplyAddress
->mSockAddrLen
);
317 printf("mSocket %d\n", inReplyAddress
->mSocket
);
319 printf("mSockAddr.sin_len %d\n", inReplyAddress
->mSockAddr
.sin_len
);
321 printf("mSockAddr.sin_family %d\n", inReplyAddress
->mSockAddr
.sin_family
);
322 printf("mSockAddr.sin_port %d\n", inReplyAddress
->mSockAddr
.sin_port
);
323 printf("mSockAddr.sin_addr.s_addr %d\n", inReplyAddress
->mSockAddr
.sin_addr
.s_addr
);
324 printf("mReplyFunc %p\n", inReplyAddress
->mReplyFunc
);
328 int32 Hash(ReplyAddress *inReplyAddress)
331 int32 *word = (int32*)&inReplyAddress->mSockAddr;
332 hash = Hash(inReplyAddress->mSockAddr.sin_addr.s_addr);
334 hash += inReplyAddress->mSockAddr.sin_len << 24
335 | inReplyAddress->mSockAddr.sin_family << 16
336 | inReplyAddress->mSockAddr.sin_port;
343 void udp_reply_func(struct ReplyAddress
*addr
, char* msg
, int size
);
344 void udp_reply_func(struct ReplyAddress
*addr
, char* msg
, int size
)
346 printf("->udp_reply_func\n");
347 int total
= sendallto(addr
->mSocket
, msg
, size
, (sockaddr
*)&addr
->mSockAddr
, addr
->mSockAddrLen
);
348 printf("<-udp_reply_func %d of %d\n", total
, size
);
349 if (total
< size
) DumpReplyAddress(addr
);
352 ReplyFunc
SC_UdpInPort::GetReplyFunc()
354 return udp_reply_func
;
357 void* SC_UdpInPort::Run()
359 char buf
[kTextBufSize
];
360 OSC_Packet
*packet
= 0;
362 //printf("SC_UdpInPort::Run\n"); fflush(stdout);
366 packet
= (OSC_Packet
*)malloc(sizeof(OSC_Packet
));
368 packet
->mReplyAddr
.mSockAddrLen
= sizeof(sockaddr_in
);
369 int size
= recvfrom(mSocket
, buf
, kTextBufSize
, 0,
370 (struct sockaddr
*) &packet
->mReplyAddr
.mSockAddr
, (socklen_t
*)&packet
->mReplyAddr
.mSockAddrLen
);
373 //dumpOSC(3, size, buf);
376 char *data
= (char*)malloc(size
);
377 packet
->mReplyAddr
.mReplyFunc
= udp_reply_func
;
378 packet
->mSize
= size
;
379 packet
->mData
= data
;
380 packet
->mReplyAddr
.mSocket
= mSocket
;
381 memcpy(data
, buf
, size
);
382 ProcessOSCPacket(packet
, mPortNum
);
389 ReplyFunc
SC_UdpCustomInPort::GetReplyFunc()
391 return udp_reply_func
;
394 void* SC_UdpCustomInPort::Run()
396 char buf
[kTextBufSize
];
397 OSC_Packet
*packet
= 0;
399 const int fd
= mSocket
;
400 const int max_fd
= fd
+1;
402 mRunning
.store(true);
403 while (mRunning
.load(boost::memory_order_consume
)) {
409 struct timeval timeout
;
411 timeout
.tv_usec
= 500000;
413 int n
= select(max_fd
, &rfds
, 0, 0, &timeout
);
414 if ((n
> 0) && FD_ISSET(fd
, &rfds
)) {
416 packet
= (OSC_Packet
*)malloc(sizeof(OSC_Packet
));
418 packet
->mReplyAddr
.mSockAddrLen
= sizeof(sockaddr_in
);
419 int size
= recvfrom(mSocket
, buf
, kTextBufSize
, 0,
420 (struct sockaddr
*) &packet
->mReplyAddr
.mSockAddr
, (socklen_t
*)&packet
->mReplyAddr
.mSockAddrLen
);
422 if (size
> 0 && mRunning
.load(boost::memory_order_consume
)) {
423 //dumpOSC(3, size, buf);
426 char *data
= (char*)malloc(size
);
427 packet
->mReplyAddr
.mReplyFunc
= udp_reply_func
;
428 packet
->mSize
= size
;
429 packet
->mData
= data
;
430 packet
->mReplyAddr
.mSocket
= mSocket
;
431 memcpy(data
, buf
, size
);
432 ProcessOSCPacket(packet
, mPortNum
);
437 FreeOSCPacket(packet
); // just in case
441 //////////////////////////////////////////////////////////////////////////////////////////////////////////
443 SC_TcpInPort::SC_TcpInPort(int inPortNum
, int inMaxConnections
, int inBacklog
)
444 : SC_ComPort(inPortNum
), mConnectionAvailable(inMaxConnections
),
448 if((mSocket
= socket(AF_INET
, SOCK_STREAM
, 0)) < 0) {
449 throw std::runtime_error("failed to create tcp socket\n");
451 //setsockopt(mSocket, SOL_SOCKET, TCP_NODELAY);
453 bzero((char *)&mBindSockAddr
, sizeof(mBindSockAddr
));
454 mBindSockAddr
.sin_family
= AF_INET
;
455 mBindSockAddr
.sin_addr
.s_addr
= htonl(INADDR_ANY
);
456 mBindSockAddr
.sin_port
= htons(mPortNum
);
458 if(bind(mSocket
, (struct sockaddr
*)&mBindSockAddr
, sizeof(mBindSockAddr
)) < 0)
460 throw std::runtime_error("unable to bind tcp socket\n");
462 if(listen(mSocket
, mBacklog
) < 0)
464 throw std::runtime_error("unable to listen tcp socket\n");
470 void* SC_TcpInPort::Run()
474 mConnectionAvailable
.Acquire();
475 struct sockaddr_in address
; /* Internet socket address stuct */
476 int addressSize
=sizeof(struct sockaddr_in
);
477 int socket
= accept(mSocket
,(struct sockaddr
*)&address
,(socklen_t
*)&addressSize
);
479 mConnectionAvailable
.Release();
481 new SC_TcpConnectionPort(this, socket
);
487 void SC_TcpInPort::ConnectionTerminated()
489 mConnectionAvailable
.Release();
492 void null_reply_func(struct ReplyAddress
*addr
, char* msg
, int size
);
493 void null_reply_func(struct ReplyAddress
*addr
, char* msg
, int size
)
497 ReplyFunc
SC_TcpInPort::GetReplyFunc()
499 return null_reply_func
;
502 //////////////////////////////////////////////////////////////////////////////////////////////////////////
504 SC_TcpConnectionPort::SC_TcpConnectionPort(SC_TcpInPort
*inParent
, int inSocket
)
505 : SC_ComPort(0), mParent(inParent
)
511 SC_TcpConnectionPort::~SC_TcpConnectionPort()
514 closesocket(mSocket
);
518 mParent
->ConnectionTerminated();
521 void tcp_reply_func(struct ReplyAddress
*addr
, char* msg
, int size
);
522 void tcp_reply_func(struct ReplyAddress
*addr
, char* msg
, int size
)
524 sendall(addr
->mSocket
, msg
, size
);
527 ReplyFunc
SC_TcpConnectionPort::GetReplyFunc()
529 return tcp_reply_func
;
532 extern const char* gPassword
;
534 void* SC_TcpConnectionPort::Run()
536 OSC_Packet
*packet
= 0;
537 // wait for login message
543 packet
= (OSC_Packet
*)malloc(sizeof(OSC_Packet
));
545 size
= recvall(mSocket
, &msglen
, sizeof(int32
));
546 if (size
< 0) goto leave
;
548 // sk: msglen is in network byte order
549 msglen
= ntohl(msglen
);
551 char *data
= (char*)malloc(msglen
);
552 size
= recvall(mSocket
, data
, msglen
);
553 if (size
< msglen
) goto leave
;
555 packet
->mReplyAddr
.mReplyFunc
= tcp_reply_func
;
556 packet
->mSize
= msglen
;
557 packet
->mData
= data
;
558 packet
->mReplyAddr
.mSocket
= mSocket
;
559 ProcessOSCPacket(packet
, mPortNum
);
563 delete this; // ohh this could cause a crash if a reply tries to access it..
567 //////////////////////////////////////////////////////////////////////////////////////////////////////////
570 # include <sys/select.h>
574 SC_TcpClientPort::SC_TcpClientPort(int inSocket
, ClientNotifyFunc notifyFunc
, void *clientData
)
576 mClientNotifyFunc(notifyFunc
),
577 mClientData(clientData
)
580 socklen_t sockAddrLen
= sizeof(mReplySockAddr
);
582 if (getpeername(mSocket
, (struct sockaddr
*)&mReplySockAddr
, &sockAddrLen
) == -1) {
583 memset(&mReplySockAddr
, 0, sizeof(mReplySockAddr
));
584 mReplySockAddr
.sin_family
= AF_INET
;
585 mReplySockAddr
.sin_addr
.s_addr
= htonl(INADDR_NONE
);
586 mReplySockAddr
.sin_port
= htons(0);
589 #if HAVE_SO_NOSIGPIPE
591 setsockopt(mSocket
, SOL_SOCKET
, SO_NOSIGPIPE
, &sockopt
, sizeof(sockopt
));
592 #endif // HAVE_SO_NOSIGPIPE
594 if (pipe(mCmdFifo
) == -1) {
595 mCmdFifo
[0] = mCmdFifo
[1] = -1;
601 SC_TcpClientPort::~SC_TcpClientPort()
604 closesocket(mCmdFifo
[0]);
605 closesocket(mCmdFifo
[1]);
606 closesocket(mSocket
);
614 void* SC_TcpClientPort::Run()
616 OSC_Packet
*packet
= 0;
620 int cmdfd
= mCmdFifo
[0];
621 int sockfd
= mSocket
;
622 int nfds
= sc_max(cmdfd
, sockfd
) + 1;
624 bool cmdClose
= false;
626 pthread_detach(mThread
);
631 FD_SET(cmdfd
, &rfds
);
632 FD_SET(sockfd
, &rfds
);
634 if ((select(nfds
, &rfds
, 0, 0, 0) == -1) || (cmdClose
= FD_ISSET(cmdfd
, &rfds
)))
637 if (!FD_ISSET(sockfd
, &rfds
))
640 packet
= (OSC_Packet
*)malloc(sizeof(OSC_Packet
));
641 if (!packet
) goto leave
;
645 size
= recvall(sockfd
, &msglen
, sizeof(int32
));
646 if (size
< (int32
)sizeof(int32
)) goto leave
;
648 // msglen is in network byte order
649 msglen
= ntohl(msglen
);
651 packet
->mData
= (char*)malloc(msglen
);
652 if (!packet
->mData
) goto leave
;
654 size
= recvall(sockfd
, packet
->mData
, msglen
);
655 if (size
< msglen
) goto leave
;
657 memcpy(&packet
->mReplyAddr
.mSockAddr
, &mReplySockAddr
, sizeof(mReplySockAddr
));
658 packet
->mReplyAddr
.mSockAddrLen
= sizeof(mReplySockAddr
);
659 packet
->mReplyAddr
.mSocket
= sockfd
;
660 packet
->mReplyAddr
.mReplyFunc
= tcp_reply_func
;
661 packet
->mSize
= msglen
;
662 ProcessOSCPacket(packet
, mPortNum
);
672 // Only call notify function when not closed explicitly
673 if (!cmdClose
&& mClientNotifyFunc
) {
674 (*mClientNotifyFunc
)(mClientData
);
680 void SC_TcpClientPort::Close()
684 win32_pipewrite(mCmdFifo
[1], &cmd
, sizeof(cmd
));
686 size_t written
= write(mCmdFifo
[1], &cmd
, sizeof(cmd
));
687 if (written
!= sizeof(cmd
))
688 post("warning: invalid write in SC_TcpClientPort::Close");
692 ReplyFunc
SC_TcpClientPort::GetReplyFunc()
694 return tcp_reply_func
;
697 //////////////////////////////////////////////////////////////////////////////////////////////////////////
699 int recvall(int socket
, void *msg
, size_t len
)
705 int numbytes
= recv(socket
, reinterpret_cast<char*>(msg
), len
- total
, 0);
707 int numbytes
= recv(socket
, msg
, len
- total
, 0);
709 if (numbytes
<= 0) return total
;
711 msg
= (void*)((char*)msg
+ numbytes
);
716 int recvallfrom(int socket
, void *msg
, size_t len
, struct sockaddr
*fromaddr
, int addrlen
)
721 socklen_t addrlen2
= addrlen
;
723 int numbytes
= recvfrom(socket
, reinterpret_cast<char*>(msg
), len
- total
, 0, fromaddr
, &addrlen2
);
725 int numbytes
= recvfrom(socket
, msg
, len
- total
, 0, fromaddr
, &addrlen2
);
727 if (numbytes
< 0) return total
;
729 msg
= (void*)((char*)msg
+ numbytes
);
734 int sendallto(int socket
, const void *msg
, size_t len
, struct sockaddr
*toaddr
, int addrlen
)
740 int numbytes
= sendto(socket
, reinterpret_cast<const char*>(msg
), len
- total
, 0, toaddr
, addrlen
);
742 int numbytes
= sendto(socket
, msg
, len
- total
, 0, toaddr
, addrlen
);
744 //printf("numbytes %d total %d len %d\n", numbytes, total, len);
746 printf("******* errno %d %s\n", errno
, strerror(errno
));
750 msg
= (void*)((char*)msg
+ numbytes
);
755 int sendall(int socket
, const void *msg
, size_t len
)
760 #if HAVE_MSG_NOSIGNAL
761 int flags
= MSG_NOSIGNAL
;
764 #endif // HAVE_MSG_NOSIGNAL
766 int numbytes
= send(socket
, reinterpret_cast<const char*>(msg
), len
- total
, flags
);
768 int numbytes
= send(socket
, msg
, len
- total
, flags
);
770 if (numbytes
< 0) return total
;
772 msg
= (void*)((char*)msg
+ numbytes
);
777 //////////////////////////////////////////////////////////////////////////////////////////////////////////