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
22 # include "SC_ComPort.h"
24 # include "../../include/server/SC_ComPort.h"
27 #include "SC_Endian.h"
29 #include "SC_HiddenWorld.h"
30 #include "SC_WorldOptions.h"
31 #include "sc_msg_iter.h"
37 # include <winsock2.h>
38 typedef int socklen_t
;
39 # define bzero( ptr, count ) memset( ptr, 0, count )
41 #include <netinet/tcp.h>
44 #if defined(__linux__) || defined(__FreeBSD__)
49 #if defined(SC_IPHONE) || defined(__APPLE__)
54 #include "Rendezvous.h"
57 int recvall(int socket
, void *msg
, size_t len
);
58 int sendallto(int socket
, const void *msg
, size_t len
, struct sockaddr
*toaddr
, int addrlen
);
59 int sendall(int socket
, const void *msg
, size_t len
);
61 bool ProcessOSCPacket(World
*inWorld
, OSC_Packet
*inPacket
);
63 void dumpOSCmsg(int inSize
, char* inData
)
70 data
= OSCstrskip(inData
);
71 size
= inSize
- (data
- inData
);
72 scprintf("[ \"%s\",", addr
);
76 scprintf("[ %d,", OSCint(inData
));
81 sc_msg_iter
msg(size
, data
);
85 char c
= msg
.nextTag('i');
89 scprintf(" %d", msg
.geti());
92 scprintf(" %g", msg
.getf());
95 scprintf(" %g", msg
.getd());
98 scprintf(" \"%s\"", msg
.gets());
101 scprintf(" DATA[%d]", msg
.getbsize());
113 scprintf(" !unknown tag '%c' 0x%02x !", isprint(c
)?c
:'?', (unsigned char)c
& 255);
116 if (msg
.remain() && (c
!= '[')) scprintf(",");
122 void hexdump(int size
, char* data
)
125 int padsize
= (size
+ 15) & -16;
126 scprintf("size %d\n", size
);
127 for (int i
=0; i
<padsize
; ++i
)
140 scprintf("%02x ", (unsigned char)data
[i
] & 255);
142 if (isprint(data
[i
])) ascii
[i
&15] = data
[i
];
143 else ascii
[i
&15] = '.';
148 scprintf(" |%s|\n", ascii
);
158 void dumpOSC(int mode
, int size
, char* inData
)
162 if (strcmp(inData
, "#bundle") == 0)
164 char* data
= inData
+ 8;
165 scprintf("[ \"#bundle\", %lld, ", OSCtime(data
));
167 char* dataEnd
= inData
+ size
;
168 while (data
< dataEnd
) {
169 int32 msgSize
= OSCint(data
);
170 data
+= sizeof(int32
);
172 dumpOSCmsg(msgSize
, data
);
174 if (data
< dataEnd
) scprintf(",");
180 dumpOSCmsg(size
, inData
);
185 if (mode
& 2) hexdump(size
, inData
);
188 SC_DLLEXPORT_C
bool World_SendPacketWithContext(World
*inWorld
, int inSize
, char *inData
, ReplyFunc inFunc
, void *inContext
)
192 if (inWorld
->mDumpOSC
) dumpOSC(inWorld
->mDumpOSC
, inSize
, inData
);
194 OSC_Packet
* packet
= (OSC_Packet
*)malloc(sizeof(OSC_Packet
));
195 char *data
= (char*)malloc(inSize
);
196 packet
->mReplyAddr
.mSockAddr
.sin_addr
.s_addr
= 0;
197 packet
->mReplyAddr
.mSockAddr
.sin_port
= 0;
198 packet
->mReplyAddr
.mReplyFunc
= inFunc
;
199 packet
->mReplyAddr
.mReplyData
= inContext
;
200 packet
->mSize
= inSize
;
201 packet
->mData
= data
;
202 packet
->mReplyAddr
.mSocket
= 0;
203 memcpy(data
, inData
, inSize
);
205 result
= ProcessOSCPacket(inWorld
, packet
);
210 SC_DLLEXPORT_C
bool World_SendPacket(World
*inWorld
, int inSize
, char *inData
, ReplyFunc inFunc
)
212 return World_SendPacketWithContext(inWorld
, inSize
, inData
, inFunc
, 0);
215 //////////////////////////////////////////////////////////////////////////////////////////////////////////
217 SC_CmdPort::SC_CmdPort(struct World
*inWorld
) : mWorld(inWorld
)
221 //////////////////////////////////////////////////////////////////////////////////////////////////////////
223 SC_ComPort::SC_ComPort(struct World
*inWorld
, int inPortNum
)
224 : SC_CmdPort(inWorld
), mPortNum(inPortNum
), mSocket(-1)
228 SC_ComPort::~SC_ComPort()
231 if (mSocket
!= -1) closesocket(mSocket
);
233 if (mSocket
!= -1) close(mSocket
);
237 void* com_thread_func(void* arg
);
238 void* com_thread_func(void* arg
)
240 SC_CmdPort
*thread
= (SC_CmdPort
*)arg
;
241 void* result
= thread
->Run();
245 void set_real_time_priority(pthread_t thread
);
246 void set_real_time_priority(pthread_t thread
)
249 struct sched_param param
;
251 pthread_getschedparam (thread
, &policy
, ¶m
);
254 const char* env
= getenv("SC_SCHED_PRIO");
255 // jack uses a priority of 10 in realtime mode, so this is a good default
256 const int defprio
= 5;
257 const int minprio
= sched_get_priority_min(policy
);
258 const int maxprio
= sched_get_priority_max(policy
);
259 const int prio
= env
? atoi(env
) : defprio
;
260 param
.sched_priority
= sc_clip(prio
, minprio
, maxprio
);
262 policy
= SCHED_RR
; // round-robin, AKA real-time scheduling
263 param
.sched_priority
= 63; // you'll have to play with this to see what it does
265 pthread_setschedparam (thread
, policy
, ¶m
);
268 void SC_CmdPort::Start()
270 pthread_create (&mThread
, NULL
, com_thread_func
, (void*)this);
271 set_real_time_priority(mThread
);
274 #ifdef USE_RENDEZVOUS
275 void* rendezvous_thread_func(void* arg
);
276 void* rendezvous_thread_func(void* arg
)
278 SC_ComPort
* port
= reinterpret_cast<SC_ComPort
*>(arg
);
279 port
->PublishToRendezvous();
283 void SC_UdpInPort::PublishToRendezvous()
285 PublishPortToRendezvous(kSCRendezvous_UDP
, htons(mPortNum
));
288 void SC_TcpInPort::PublishToRendezvous()
290 PublishPortToRendezvous(kSCRendezvous_TCP
, htons(mPortNum
));
295 //////////////////////////////////////////////////////////////////////////////////////////////////////////
297 SC_UdpInPort::SC_UdpInPort(struct World
*inWorld
, int inPortNum
)
298 : SC_ComPort(inWorld
, inPortNum
)
300 if ((mSocket
= socket(AF_INET
, SOCK_DGRAM
, 0)) < 0) {
301 throw std::runtime_error("failed to create udp socket\n");
307 setsockopt(mSocket
, SOL_SOCKET
, SO_SNDBUF
, (char*)&bufsize
, sizeof(bufsize
));
309 setsockopt(mSocket
, SOL_SOCKET
, SO_SNDBUF
, &bufsize
, sizeof(bufsize
));
313 //scprintf("@@@ sizeof(ReplyAddress) %d\n", sizeof(ReplyAddress));
315 bzero((char *)&mBindSockAddr
, sizeof(mBindSockAddr
));
316 mBindSockAddr
.sin_family
= AF_INET
;
317 mBindSockAddr
.sin_addr
.s_addr
= htonl(INADDR_ANY
);
318 mBindSockAddr
.sin_port
= htons(mPortNum
);
320 if (bind(mSocket
, (struct sockaddr
*)&mBindSockAddr
, sizeof(mBindSockAddr
)) < 0) {
321 throw std::runtime_error("unable to bind udp socket\n");
326 #ifdef USE_RENDEZVOUS
327 if(inWorld
->mRendezvous
){
328 pthread_create(&mRendezvousThread
,
330 rendezvous_thread_func
,
336 SC_UdpInPort::~SC_UdpInPort()
339 if (mSocket
!= -1) closesocket(mSocket
);
341 if (mSocket
!= -1) close(mSocket
);
345 //////////////////////////////////////////////////////////////////////////////////////////////////////////
347 void DumpReplyAddress(ReplyAddress
*inReplyAddress
)
349 scprintf("mSockAddrLen %d\n", inReplyAddress
->mSockAddrLen
);
350 scprintf("mSocket %d\n", inReplyAddress
->mSocket
);
352 scprintf("mSockAddr.sin_len %d\n", inReplyAddress
->mSockAddr
.sin_len
);
354 scprintf("mSockAddr.sin_family %d\n", inReplyAddress
->mSockAddr
.sin_family
);
355 scprintf("mSockAddr.sin_port %d\n", inReplyAddress
->mSockAddr
.sin_port
);
356 scprintf("mSockAddr.sin_addr.s_addr %d\n", inReplyAddress
->mSockAddr
.sin_addr
.s_addr
);
357 scprintf("mReplyFunc %p\n", (intptr_t)inReplyAddress
->mReplyFunc
);
361 int32 GetHash(ReplyAddress *inReplyAddress)
363 int32 hash = Hash(inReplyAddress->mSockAddr.sin_addr.s_addr);
365 hash += (inReplyAddress->mSockAddr.sin_len << 24)
366 | (inReplyAddress->mSockAddr.sin_family << 16)
367 | inReplyAddress->mSockAddr.sin_port;
372 ReplyAddress GetKey(ReplyAddress *inReplyAddress)
374 return *inReplyAddress
378 bool operator==(const ReplyAddress
& a
, const ReplyAddress
& b
)
380 return a
.mSockAddr
.sin_addr
.s_addr
== b
.mSockAddr
.sin_addr
.s_addr
381 && a
.mSockAddr
.sin_family
== b
.mSockAddr
.sin_family
382 && a
.mSockAddr
.sin_port
== b
.mSockAddr
.sin_port
384 && a
.mSockAddr
.sin_len
== b
.mSockAddr
.sin_len
386 && a
.mSocket
== b
.mSocket
;
389 void udp_reply_func(struct ReplyAddress
*addr
, char* msg
, int size
);
390 void udp_reply_func(struct ReplyAddress
*addr
, char* msg
, int size
)
392 int total
= sendallto(addr
->mSocket
, msg
, size
, (sockaddr
*)&addr
->mSockAddr
, addr
->mSockAddrLen
);
393 if (total
< size
) DumpReplyAddress(addr
);
396 ReplyFunc
SC_UdpInPort::GetReplyFunc()
398 return udp_reply_func
;
401 void* SC_UdpInPort::Run()
403 OSC_Packet
*packet
= 0;
406 // preallocate packet before we need it.
407 packet
= (OSC_Packet
*)malloc(sizeof(OSC_Packet
));
410 packet
->mReplyAddr
.mSockAddrLen
= sizeof(sockaddr_in
);
412 int size
= recvfrom(mSocket
, (char *)mReadBuf
, kMaxUDPSize
, 0,
414 int size
= recvfrom(mSocket
, mReadBuf
, kMaxUDPSize
, 0,
416 (struct sockaddr
*) &packet
->mReplyAddr
.mSockAddr
, (socklen_t
*)&packet
->mReplyAddr
.mSockAddrLen
);
419 char *data
= (char*)malloc(size
);
420 memcpy(data
, mReadBuf
, size
);
421 if (mWorld
->mDumpOSC
) dumpOSC(mWorld
->mDumpOSC
, size
, data
);
423 packet
->mReplyAddr
.mReplyFunc
= udp_reply_func
;
424 packet
->mReplyAddr
.mReplyData
= 0;
425 packet
->mSize
= size
;
426 packet
->mData
= data
;
427 packet
->mReplyAddr
.mSocket
= mSocket
;
429 if (!ProcessOSCPacket(mWorld
, packet
))
431 scprintf("command FIFO full\n");
442 //////////////////////////////////////////////////////////////////////////////////////////////////////////
444 SC_TcpInPort::SC_TcpInPort(struct World
*inWorld
, int inPortNum
, int inMaxConnections
, int inBacklog
)
445 : SC_ComPort(inWorld
, inPortNum
), mConnectionAvailable(inMaxConnections
),
448 if((mSocket
= socket(AF_INET
, SOCK_STREAM
, 0)) < 0) {
449 throw std::runtime_error("failed to create tcp socket\n");
453 //setsockopt( mSocket, IPPROTO_TCP, TCP_NODELAY, &on, sizeof(on));
455 bzero((char *)&mBindSockAddr
, sizeof(mBindSockAddr
));
456 mBindSockAddr
.sin_family
= AF_INET
;
457 mBindSockAddr
.sin_addr
.s_addr
= htonl(INADDR_ANY
);
458 mBindSockAddr
.sin_port
= htons(mPortNum
);
460 if(bind(mSocket
, (struct sockaddr
*)&mBindSockAddr
, sizeof(mBindSockAddr
)) < 0)
462 throw std::runtime_error("unable to bind tcp socket\n");
465 if(listen(mSocket
, mBacklog
) < 0)
467 throw std::runtime_error("unable to listen tcp socket\n");
471 #ifdef USE_RENDEZVOUS
472 if(inWorld
->mRendezvous
){
473 pthread_create(&mRendezvousThread
,
475 rendezvous_thread_func
,
481 void* SC_TcpInPort::Run()
485 mConnectionAvailable
.Acquire();
486 struct sockaddr_in address
; /* Internet socket address stuct */
487 socklen_t addressSize
=sizeof(struct sockaddr_in
);
488 int socket
= accept(mSocket
,(struct sockaddr
*)&address
,&addressSize
);
490 mConnectionAvailable
.Release();
492 new SC_TcpConnectionPort(mWorld
, this, socket
);
498 void SC_TcpInPort::ConnectionTerminated()
500 mConnectionAvailable
.Release();
503 void null_reply_func(struct ReplyAddress
* /*addr*/, char* /*msg*/, int /*size*/)
507 ReplyFunc
SC_TcpInPort::GetReplyFunc()
509 return null_reply_func
;
512 //////////////////////////////////////////////////////////////////////////////////////////////////////////
514 SC_TcpConnectionPort::SC_TcpConnectionPort(struct World
*inWorld
, SC_TcpInPort
*inParent
, int inSocket
)
515 : SC_ComPort(inWorld
, 0), mParent(inParent
)
521 setsockopt( mSocket
, IPPROTO_TCP
, TCP_NODELAY
, (const char*)&on
, sizeof(on
));
524 setsockopt( mSocket
, IPPROTO_TCP
, TCP_NODELAY
, &on
, sizeof(on
));
530 SC_TcpConnectionPort::~SC_TcpConnectionPort()
533 closesocket(mSocket
);
537 mParent
->ConnectionTerminated();
540 void tcp_reply_func(struct ReplyAddress
*addr
, char* msg
, int size
);
541 void tcp_reply_func(struct ReplyAddress
*addr
, char* msg
, int size
)
544 // Write size as 32bit unsigned network-order integer
547 sendall ( addr
->mSocket
, &u
, 4 ) ;
549 sendall ( addr
->mSocket
, msg
, size
) ;
553 ReplyFunc
SC_TcpConnectionPort::GetReplyFunc()
555 return tcp_reply_func
;
558 void* SC_TcpConnectionPort::Run()
560 const int kMaxPasswordLen
= 32;
561 char buf
[kMaxPasswordLen
];
562 OSC_Packet
*packet
= 0;
563 // wait for login message
567 // first message must be the password. 4 tries.
568 bool validated
= mWorld
->hw
->mPassword
[0] == 0;
569 for (int i
=0; !validated
&& i
<4; ++i
) {
570 size
= recvall(mSocket
, &msglen
, sizeof(int32
) );
571 if (size
< 0) goto leave
;
573 msglen
= ntohl(msglen
);
574 if (msglen
> kMaxPasswordLen
) break;
576 size
= recvall(mSocket
, buf
, msglen
);
577 if (size
< 0) goto leave
;
579 validated
= strcmp(buf
, mWorld
->hw
->mPassword
) == 0;
581 if (!validated
) Sleep(i
+1); // thwart cracking.
583 if (!validated
) sleep(i
+1); // thwart cracking.
590 packet
= (OSC_Packet
*)malloc(sizeof(OSC_Packet
));
592 size
= recvall(mSocket
, &msglen
, sizeof(int32
));
593 if (size
!= sizeof(int32
)) goto leave
;
595 // sk: msglen is in network byte order
596 msglen
= ntohl(msglen
);
598 char *data
= (char*)malloc(msglen
);
599 size
= recvall(mSocket
, data
, msglen
);
600 if (size
< msglen
) goto leave
;
602 if (mWorld
->mDumpOSC
) dumpOSC(mWorld
->mDumpOSC
, size
, data
);
604 packet
->mReplyAddr
.mReplyFunc
= tcp_reply_func
;
605 packet
->mReplyAddr
.mReplyData
= 0;
606 packet
->mSize
= msglen
;
607 packet
->mData
= data
;
608 packet
->mReplyAddr
.mSocket
= mSocket
;
609 if (!ProcessOSCPacket(mWorld
, packet
)) {
610 scprintf("command FIFO full\n");
618 delete this; // ohh this could cause a crash if a reply tries to access it..
622 //////////////////////////////////////////////////////////////////////////////////////////////////////////
624 int recvall(int socket
, void *msg
, size_t len
)
627 while (total
< (int)len
)
630 int numbytes
= recv(socket
, (char*)msg
, len
- total
, 0);
632 int numbytes
= recv(socket
, msg
, len
- total
, 0);
634 if (numbytes
<= 0) return total
;
636 msg
= (void*)((char*)msg
+ numbytes
);
641 int sendallto(int socket
, const void *msg
, size_t len
, struct sockaddr
*toaddr
, int addrlen
)
644 while (total
< (int)len
)
647 int numbytes
= sendto(socket
, (char*)msg
, len
- total
, 0, toaddr
, addrlen
);
649 int numbytes
= sendto(socket
, msg
, len
- total
, 0, toaddr
, addrlen
);
652 scprintf("sendallto errno %d %s\n", errno
, strerror(errno
));
656 msg
= (void*)((char*)msg
+ numbytes
);
661 int sendall(int socket
, const void *msg
, size_t len
)
664 while (total
< (int)len
)
667 int numbytes
= send(socket
, (const char*)msg
, len
- total
, 0);
669 int numbytes
= send(socket
, msg
, len
- total
, 0);
671 if (numbytes
< 0) return total
;
673 msg
= (void*)((char*)msg
+ numbytes
);