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_Endian.h"
23 #include "SC_HiddenWorld.h"
24 #include "SC_WorldOptions.h"
25 #include "sc_msg_iter.h"
30 #include <sys/types.h>
31 #include "OSC_Packet.h"
34 # include <winsock2.h>
35 typedef int socklen_t
;
36 # define bzero( ptr, count ) memset( ptr, 0, count )
38 #include <netinet/tcp.h>
41 #if defined(__linux__) || defined(__FreeBSD__)
46 #if defined(SC_IPHONE) || defined(__APPLE__)
51 #include "Rendezvous.h"
54 bool ProcessOSCPacket(World
*inWorld
, OSC_Packet
*inPacket
);
58 //////////////////////////////////////////////////////////////////////////////////////////////////////////
67 virtual ReplyFunc
GetReplyFunc()=0;
69 SC_CmdPort(struct World
*inWorld
);
70 virtual ~SC_CmdPort() {}
72 virtual void* Run()=0;
75 //////////////////////////////////////////////////////////////////////////////////////////////////////////
77 class SC_ComPort
: public SC_CmdPort
82 struct sockaddr_in mBindSockAddr
;
85 pthread_t mRendezvousThread
;
89 SC_ComPort(struct World
*inWorld
, int inPortNum
);
90 virtual ~SC_ComPort();
92 int Socket() { return mSocket
; }
94 int PortNum() const { return mPortNum
; }
96 // default implementation does nothing (this is correct for
97 // SC_TcpConnectionPort). Subclasses may override.
98 virtual void PublishToRendezvous() { };
102 //////////////////////////////////////////////////////////////////////////////////////////////////////////
104 const size_t kMaxUDPSize
= 65535;
106 class SC_UdpInPort
: public SC_ComPort
109 struct sockaddr_in mReplySockAddr
;
110 unsigned char mReadBuf
[kMaxUDPSize
];
111 virtual ReplyFunc
GetReplyFunc();
114 SC_UdpInPort(struct World
*inWorld
, int inPortNum
);
117 int PortNum() const { return mPortNum
; }
120 #ifdef USE_RENDEZVOUS
121 virtual void PublishToRendezvous();
126 //////////////////////////////////////////////////////////////////////////////////////////////////////////
128 class SC_TcpInPort
: public SC_ComPort
130 SC_Semaphore mConnectionAvailable
;
134 virtual ReplyFunc
GetReplyFunc();
137 SC_TcpInPort(struct World
*inWorld
, int inPortNum
, int inMaxConnections
, int inBacklog
);
141 void ConnectionTerminated();
142 #ifdef USE_RENDEZVOUS
143 virtual void PublishToRendezvous();
147 //////////////////////////////////////////////////////////////////////////////////////////////////////////
149 class SC_TcpConnectionPort
: public SC_ComPort
151 SC_TcpInPort
*mParent
;
152 unsigned char mReadBuf
[kMaxUDPSize
];
155 virtual ReplyFunc
GetReplyFunc();
158 SC_TcpConnectionPort(struct World
*inWorld
, SC_TcpInPort
*inParent
, int inSocket
);
159 virtual ~SC_TcpConnectionPort();
166 int recvall(int socket
, void *msg
, size_t len
);
167 int sendallto(int socket
, const void *msg
, size_t len
, struct sockaddr
*toaddr
, int addrlen
);
168 int sendall(int socket
, const void *msg
, size_t len
);
170 void dumpOSCmsg(int inSize
, char* inData
)
177 data
= OSCstrskip(inData
);
178 size
= inSize
- (data
- inData
);
179 scprintf("[ \"%s\",", addr
);
183 scprintf("[ %d,", OSCint(inData
));
188 sc_msg_iter
msg(size
, data
);
192 char c
= msg
.nextTag('i');
196 scprintf(" %d", msg
.geti());
199 scprintf(" %g", msg
.getf());
202 scprintf(" %g", msg
.getd());
205 scprintf(" \"%s\"", msg
.gets());
208 scprintf(" DATA[%d]", msg
.getbsize());
220 scprintf(" !unknown tag '%c' 0x%02x !", isprint(c
)?c
:'?', (unsigned char)c
& 255);
223 if (msg
.remain() && (c
!= '[')) scprintf(",");
229 void hexdump(int size
, char* data
)
232 int padsize
= (size
+ 15) & -16;
233 scprintf("size %d\n", size
);
234 for (int i
=0; i
<padsize
; ++i
)
247 scprintf("%02x ", (unsigned char)data
[i
] & 255);
249 if (isprint(data
[i
])) ascii
[i
&15] = data
[i
];
250 else ascii
[i
&15] = '.';
255 scprintf(" |%s|\n", ascii
);
265 void dumpOSC(int mode
, int size
, char* inData
)
269 if (strcmp(inData
, "#bundle") == 0)
271 char* data
= inData
+ 8;
272 scprintf("[ \"#bundle\", %lld, ", OSCtime(data
));
274 char* dataEnd
= inData
+ size
;
275 while (data
< dataEnd
) {
276 int32 msgSize
= OSCint(data
);
277 data
+= sizeof(int32
);
279 dumpOSCmsg(msgSize
, data
);
281 if (data
< dataEnd
) scprintf(",");
287 dumpOSCmsg(size
, inData
);
292 if (mode
& 2) hexdump(size
, inData
);
297 SC_DLLEXPORT_C
bool World_SendPacketWithContext(World
*inWorld
, int inSize
, char *inData
, ReplyFunc inFunc
, void *inContext
)
301 if (inWorld
->mDumpOSC
) dumpOSC(inWorld
->mDumpOSC
, inSize
, inData
);
303 OSC_Packet
* packet
= (OSC_Packet
*)malloc(sizeof(OSC_Packet
));
304 char *data
= (char*)malloc(inSize
);
305 packet
->mReplyAddr
.mSockAddr
.sin_addr
.s_addr
= 0;
306 packet
->mReplyAddr
.mSockAddr
.sin_port
= 0;
307 packet
->mReplyAddr
.mReplyFunc
= inFunc
;
308 packet
->mReplyAddr
.mReplyData
= inContext
;
309 packet
->mSize
= inSize
;
310 packet
->mData
= data
;
311 packet
->mReplyAddr
.mSocket
= 0;
312 memcpy(data
, inData
, inSize
);
314 result
= ProcessOSCPacket(inWorld
, packet
);
319 SC_DLLEXPORT_C
bool World_SendPacket(World
*inWorld
, int inSize
, char *inData
, ReplyFunc inFunc
)
321 return World_SendPacketWithContext(inWorld
, inSize
, inData
, inFunc
, 0);
324 SC_DLLEXPORT_C
int World_OpenUDP(struct World
*inWorld
, int inPort
)
327 new SC_UdpInPort(inWorld
, inPort
);
329 } catch (std::exception
& exc
) {
330 scprintf("Exception in World_OpenUDP: %s\n", exc
.what());
336 SC_DLLEXPORT_C
int World_OpenTCP(struct World
*inWorld
, int inPort
, int inMaxConnections
, int inBacklog
)
339 new SC_TcpInPort(inWorld
, inPort
, inMaxConnections
, inBacklog
);
341 } catch (std::exception
& exc
) {
342 scprintf("Exception in World_OpenTCP: %s\n", exc
.what());
348 void set_real_time_priority(pthread_t thread
)
351 struct sched_param param
;
353 pthread_getschedparam (thread
, &policy
, ¶m
);
356 const char* env
= getenv("SC_SCHED_PRIO");
357 // jack uses a priority of 10 in realtime mode, so this is a good default
358 const int defprio
= 5;
359 const int minprio
= sched_get_priority_min(policy
);
360 const int maxprio
= sched_get_priority_max(policy
);
361 const int prio
= env
? atoi(env
) : defprio
;
362 param
.sched_priority
= sc_clip(prio
, minprio
, maxprio
);
364 policy
= SCHED_RR
; // round-robin, AKA real-time scheduling
365 param
.sched_priority
= 63; // you'll have to play with this to see what it does
367 pthread_setschedparam (thread
, policy
, ¶m
);
372 //////////////////////////////////////////////////////////////////////////////////////////////////////////
376 SC_CmdPort::SC_CmdPort(struct World
*inWorld
) : mWorld(inWorld
)
380 //////////////////////////////////////////////////////////////////////////////////////////////////////////
382 SC_ComPort::SC_ComPort(struct World
*inWorld
, int inPortNum
)
383 : SC_CmdPort(inWorld
), mPortNum(inPortNum
), mSocket(-1)
387 SC_ComPort::~SC_ComPort()
390 if (mSocket
!= -1) closesocket(mSocket
);
392 if (mSocket
!= -1) close(mSocket
);
396 void* com_thread_func(void* arg
);
397 void* com_thread_func(void* arg
)
399 SC_CmdPort
*thread
= (SC_CmdPort
*)arg
;
400 void* result
= thread
->Run();
404 void SC_CmdPort::Start()
406 pthread_create (&mThread
, NULL
, com_thread_func
, (void*)this);
407 set_real_time_priority(mThread
);
410 #ifdef USE_RENDEZVOUS
411 void* rendezvous_thread_func(void* arg
);
412 void* rendezvous_thread_func(void* arg
)
414 SC_ComPort
* port
= reinterpret_cast<SC_ComPort
*>(arg
);
415 port
->PublishToRendezvous();
419 void SC_UdpInPort::PublishToRendezvous()
421 PublishPortToRendezvous(kSCRendezvous_UDP
, htons(mPortNum
));
424 void SC_TcpInPort::PublishToRendezvous()
426 PublishPortToRendezvous(kSCRendezvous_TCP
, htons(mPortNum
));
431 //////////////////////////////////////////////////////////////////////////////////////////////////////////
433 SC_UdpInPort::SC_UdpInPort(struct World
*inWorld
, int inPortNum
)
434 : SC_ComPort(inWorld
, inPortNum
)
436 if ((mSocket
= socket(AF_INET
, SOCK_DGRAM
, 0)) < 0) {
437 throw std::runtime_error("failed to create udp socket\n");
443 setsockopt(mSocket
, SOL_SOCKET
, SO_SNDBUF
, (char*)&bufsize
, sizeof(bufsize
));
445 setsockopt(mSocket
, SOL_SOCKET
, SO_SNDBUF
, &bufsize
, sizeof(bufsize
));
449 //scprintf("@@@ sizeof(ReplyAddress) %d\n", sizeof(ReplyAddress));
451 bzero((char *)&mBindSockAddr
, sizeof(mBindSockAddr
));
452 mBindSockAddr
.sin_family
= AF_INET
;
453 mBindSockAddr
.sin_addr
.s_addr
= htonl(INADDR_ANY
);
454 mBindSockAddr
.sin_port
= htons(mPortNum
);
456 if (bind(mSocket
, (struct sockaddr
*)&mBindSockAddr
, sizeof(mBindSockAddr
)) < 0) {
457 throw std::runtime_error("unable to bind udp socket\n");
462 #ifdef USE_RENDEZVOUS
463 if(inWorld
->mRendezvous
){
464 pthread_create(&mRendezvousThread
,
466 rendezvous_thread_func
,
472 SC_UdpInPort::~SC_UdpInPort()
475 if (mSocket
!= -1) closesocket(mSocket
);
477 if (mSocket
!= -1) close(mSocket
);
484 //////////////////////////////////////////////////////////////////////////////////////////////////////////
486 static void DumpReplyAddress(ReplyAddress
*inReplyAddress
)
488 scprintf("mSockAddrLen %d\n", inReplyAddress
->mSockAddrLen
);
489 scprintf("mSocket %d\n", inReplyAddress
->mSocket
);
491 scprintf("mSockAddr.sin_len %d\n", inReplyAddress
->mSockAddr
.sin_len
);
493 scprintf("mSockAddr.sin_family %d\n", inReplyAddress
->mSockAddr
.sin_family
);
494 scprintf("mSockAddr.sin_port %d\n", inReplyAddress
->mSockAddr
.sin_port
);
495 scprintf("mSockAddr.sin_addr.s_addr %d\n", inReplyAddress
->mSockAddr
.sin_addr
.s_addr
);
496 scprintf("mReplyFunc %p\n", (intptr_t)inReplyAddress
->mReplyFunc
);
500 int32 GetHash(ReplyAddress *inReplyAddress)
502 int32 hash = Hash(inReplyAddress->mSockAddr.sin_addr.s_addr);
504 hash += (inReplyAddress->mSockAddr.sin_len << 24)
505 | (inReplyAddress->mSockAddr.sin_family << 16)
506 | inReplyAddress->mSockAddr.sin_port;
511 ReplyAddress GetKey(ReplyAddress *inReplyAddress)
513 return *inReplyAddress
519 void udp_reply_func(struct ReplyAddress
*addr
, char* msg
, int size
)
521 int total
= sendallto(addr
->mSocket
, msg
, size
, (sockaddr
*)&addr
->mSockAddr
, addr
->mSockAddrLen
);
522 if (total
< size
) DumpReplyAddress(addr
);
525 ReplyFunc
SC_UdpInPort::GetReplyFunc()
527 return udp_reply_func
;
530 void* SC_UdpInPort::Run()
532 OSC_Packet
*packet
= 0;
535 // preallocate packet before we need it.
536 packet
= (OSC_Packet
*)malloc(sizeof(OSC_Packet
));
539 packet
->mReplyAddr
.mSockAddrLen
= sizeof(sockaddr_in
);
541 int size
= recvfrom(mSocket
, (char *)mReadBuf
, kMaxUDPSize
, 0,
543 int size
= recvfrom(mSocket
, mReadBuf
, kMaxUDPSize
, 0,
545 (struct sockaddr
*) &packet
->mReplyAddr
.mSockAddr
, (socklen_t
*)&packet
->mReplyAddr
.mSockAddrLen
);
548 char *data
= (char*)malloc(size
);
549 memcpy(data
, mReadBuf
, size
);
550 if (mWorld
->mDumpOSC
) dumpOSC(mWorld
->mDumpOSC
, size
, data
);
552 packet
->mReplyAddr
.mReplyFunc
= udp_reply_func
;
553 packet
->mReplyAddr
.mReplyData
= 0;
554 packet
->mSize
= size
;
555 packet
->mData
= data
;
556 packet
->mReplyAddr
.mSocket
= mSocket
;
558 if (!ProcessOSCPacket(mWorld
, packet
))
560 scprintf("command FIFO full\n");
571 //////////////////////////////////////////////////////////////////////////////////////////////////////////
573 SC_TcpInPort::SC_TcpInPort(struct World
*inWorld
, int inPortNum
, int inMaxConnections
, int inBacklog
)
574 : SC_ComPort(inWorld
, inPortNum
), mConnectionAvailable(inMaxConnections
),
577 if((mSocket
= socket(AF_INET
, SOCK_STREAM
, 0)) < 0) {
578 throw std::runtime_error("failed to create tcp socket\n");
582 //setsockopt( mSocket, IPPROTO_TCP, TCP_NODELAY, &on, sizeof(on));
584 bzero((char *)&mBindSockAddr
, sizeof(mBindSockAddr
));
585 mBindSockAddr
.sin_family
= AF_INET
;
586 mBindSockAddr
.sin_addr
.s_addr
= htonl(INADDR_ANY
);
587 mBindSockAddr
.sin_port
= htons(mPortNum
);
589 if(bind(mSocket
, (struct sockaddr
*)&mBindSockAddr
, sizeof(mBindSockAddr
)) < 0)
591 throw std::runtime_error("unable to bind tcp socket\n");
594 if(listen(mSocket
, mBacklog
) < 0)
596 throw std::runtime_error("unable to listen tcp socket\n");
600 #ifdef USE_RENDEZVOUS
601 if(inWorld
->mRendezvous
){
602 pthread_create(&mRendezvousThread
,
604 rendezvous_thread_func
,
610 void* SC_TcpInPort::Run()
614 mConnectionAvailable
.Acquire();
615 struct sockaddr_in address
; /* Internet socket address stuct */
616 socklen_t addressSize
=sizeof(struct sockaddr_in
);
617 int socket
= accept(mSocket
,(struct sockaddr
*)&address
,&addressSize
);
619 mConnectionAvailable
.Release();
621 new SC_TcpConnectionPort(mWorld
, this, socket
);
627 void SC_TcpInPort::ConnectionTerminated()
629 mConnectionAvailable
.Release();
632 ReplyFunc
SC_TcpInPort::GetReplyFunc()
634 return null_reply_func
;
637 //////////////////////////////////////////////////////////////////////////////////////////////////////////
639 SC_TcpConnectionPort::SC_TcpConnectionPort(struct World
*inWorld
, SC_TcpInPort
*inParent
, int inSocket
)
640 : SC_ComPort(inWorld
, 0), mParent(inParent
)
646 setsockopt( mSocket
, IPPROTO_TCP
, TCP_NODELAY
, (const char*)&on
, sizeof(on
));
649 setsockopt( mSocket
, IPPROTO_TCP
, TCP_NODELAY
, &on
, sizeof(on
));
655 SC_TcpConnectionPort::~SC_TcpConnectionPort()
658 closesocket(mSocket
);
662 mParent
->ConnectionTerminated();
665 void tcp_reply_func(struct ReplyAddress
*addr
, char* msg
, int size
);
666 void tcp_reply_func(struct ReplyAddress
*addr
, char* msg
, int size
)
669 // Write size as 32bit unsigned network-order integer
672 sendall ( addr
->mSocket
, &u
, 4 ) ;
674 sendall ( addr
->mSocket
, msg
, size
) ;
678 ReplyFunc
SC_TcpConnectionPort::GetReplyFunc()
680 return tcp_reply_func
;
683 void* SC_TcpConnectionPort::Run()
685 const int kMaxPasswordLen
= 32;
686 char buf
[kMaxPasswordLen
];
687 OSC_Packet
*packet
= 0;
688 // wait for login message
692 // first message must be the password. 4 tries.
693 bool validated
= mWorld
->hw
->mPassword
[0] == 0;
694 for (int i
=0; !validated
&& i
<4; ++i
) {
695 size
= recvall(mSocket
, &msglen
, sizeof(int32
) );
696 if (size
< 0) goto leave
;
698 msglen
= ntohl(msglen
);
699 if (msglen
> kMaxPasswordLen
) break;
701 size
= recvall(mSocket
, buf
, msglen
);
702 if (size
< 0) goto leave
;
704 validated
= strcmp(buf
, mWorld
->hw
->mPassword
) == 0;
706 if (!validated
) Sleep(i
+1); // thwart cracking.
708 if (!validated
) sleep(i
+1); // thwart cracking.
715 packet
= (OSC_Packet
*)malloc(sizeof(OSC_Packet
));
717 size
= recvall(mSocket
, &msglen
, sizeof(int32
));
718 if (size
!= sizeof(int32
)) goto leave
;
720 // sk: msglen is in network byte order
721 msglen
= ntohl(msglen
);
723 char *data
= (char*)malloc(msglen
);
724 size
= recvall(mSocket
, data
, msglen
);
725 if (size
< msglen
) goto leave
;
727 if (mWorld
->mDumpOSC
) dumpOSC(mWorld
->mDumpOSC
, size
, data
);
729 packet
->mReplyAddr
.mReplyFunc
= tcp_reply_func
;
730 packet
->mReplyAddr
.mReplyData
= 0;
731 packet
->mSize
= msglen
;
732 packet
->mData
= data
;
733 packet
->mReplyAddr
.mSocket
= mSocket
;
734 if (!ProcessOSCPacket(mWorld
, packet
)) {
735 scprintf("command FIFO full\n");
743 delete this; // ohh this could cause a crash if a reply tries to access it..
747 //////////////////////////////////////////////////////////////////////////////////////////////////////////
749 int recvall(int socket
, void *msg
, size_t len
)
752 while (total
< (int)len
)
755 int numbytes
= recv(socket
, (char*)msg
, len
- total
, 0);
757 int numbytes
= recv(socket
, msg
, len
- total
, 0);
759 if (numbytes
<= 0) return total
;
761 msg
= (void*)((char*)msg
+ numbytes
);
766 int sendallto(int socket
, const void *msg
, size_t len
, struct sockaddr
*toaddr
, int addrlen
)
769 while (total
< (int)len
)
772 int numbytes
= sendto(socket
, (char*)msg
, len
- total
, 0, toaddr
, addrlen
);
774 int numbytes
= sendto(socket
, msg
, len
- total
, 0, toaddr
, addrlen
);
777 scprintf("sendallto errno %d %s\n", errno
, strerror(errno
));
781 msg
= (void*)((char*)msg
+ numbytes
);
786 int sendall(int socket
, const void *msg
, size_t len
)
789 while (total
< (int)len
)
792 int numbytes
= send(socket
, (const char*)msg
, len
- total
, 0);
794 int numbytes
= send(socket
, msg
, len
- total
, 0);
796 if (numbytes
< 0) return total
;
798 msg
= (void*)((char*)msg
+ numbytes
);