bumping version to 3.5-rc1
[supercollider.git] / server / scsynth / SC_ComPort.cpp
blob61684c732597972dd2eff091985586cd13c93bd5
1 /*
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 #ifndef _WIN32
22 # include "SC_ComPort.h"
23 #else
24 # include "../../include/server/SC_ComPort.h"
25 #endif
27 #include "SC_Endian.h"
28 #include "SC_Lock.h"
29 #include "SC_HiddenWorld.h"
30 #include "SC_WorldOptions.h"
31 #include "sc_msg_iter.h"
32 #include <ctype.h>
33 #include <stdexcept>
34 #include <stdarg.h>
36 #ifdef _WIN32
37 # include <winsock2.h>
38 typedef int socklen_t;
39 # define bzero( ptr, count ) memset( ptr, 0, count )
40 #else
41 #include <netinet/tcp.h>
42 #endif
44 #if defined(__linux__) || defined(__FreeBSD__)
45 #include <errno.h>
46 #include <unistd.h>
47 #endif
49 #if defined(SC_IPHONE) || defined(__APPLE__)
50 #include <errno.h>
51 #endif
53 #ifdef USE_RENDEZVOUS
54 #include "Rendezvous.h"
55 #endif
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)
65 int size;
66 const char *data;
68 if (inData[0]) {
69 char *addr = inData;
70 data = OSCstrskip(inData);
71 size = inSize - (data - inData);
72 scprintf("[ \"%s\",", addr);
74 else
76 scprintf("[ %d,", OSCint(inData));
77 data = inData + 4;
78 size = inSize - 4;
81 sc_msg_iter msg(size, data);
83 while (msg.remain())
85 char c = msg.nextTag('i');
86 switch(c)
88 case 'i' :
89 scprintf(" %d", msg.geti());
90 break;
91 case 'f' :
92 scprintf(" %g", msg.getf());
93 break;
94 case 'd' :
95 scprintf(" %g", msg.getd());
96 break;
97 case 's' :
98 scprintf(" \"%s\"", msg.gets());
99 break;
100 case 'b' :
101 scprintf(" DATA[%d]", msg.getbsize());
102 msg.skipb();
103 break;
104 case '[' :
105 scprintf("[");
106 msg.count++;
107 break;
108 case ']' :
109 scprintf("]");
110 msg.count++;
111 break;
112 default :
113 scprintf(" !unknown tag '%c' 0x%02x !", isprint(c)?c:'?', (unsigned char)c & 255);
114 goto leave;
116 if (msg.remain() && (c!= '[')) scprintf(",");
118 leave:
119 scprintf(" ]");
122 void hexdump(int size, char* data)
124 char ascii[20];
125 int padsize = (size + 15) & -16;
126 scprintf("size %d\n", size);
127 for (int i=0; i<padsize; ++i)
129 if ((i&15)==0)
131 scprintf("%4d ", i);
133 if (i >= size)
135 scprintf(" ");
136 ascii[i&15] = 0;
138 else
140 scprintf("%02x ", (unsigned char)data[i] & 255);
142 if (isprint(data[i])) ascii[i&15] = data[i];
143 else ascii[i&15] = '.';
145 if ((i&15)==15)
147 ascii[16] = 0;
148 scprintf(" |%s|\n", ascii);
150 else if ((i&3)==3)
152 scprintf(" ");
155 scprintf("\n");
158 void dumpOSC(int mode, int size, char* inData)
160 if (mode & 1)
162 if (strcmp(inData, "#bundle") == 0)
164 char* data = inData + 8;
165 scprintf("[ \"#bundle\", %lld, ", OSCtime(data));
166 data += 8;
167 char* dataEnd = inData + size;
168 while (data < dataEnd) {
169 int32 msgSize = OSCint(data);
170 data += sizeof(int32);
171 scprintf("\n ");
172 dumpOSCmsg(msgSize, data);
173 data += msgSize;
174 if (data < dataEnd) scprintf(",");
176 scprintf("\n]\n");
178 else
180 dumpOSCmsg(size, inData);
181 scprintf("\n");
185 if (mode & 2) hexdump(size, inData);
188 SC_DLLEXPORT_C bool World_SendPacketWithContext(World *inWorld, int inSize, char *inData, ReplyFunc inFunc, void *inContext)
190 bool result = false;
191 if (inSize > 0) {
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);
207 return result;
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()
230 #ifdef _WIN32
231 if (mSocket != -1) closesocket(mSocket);
232 #else
233 if (mSocket != -1) close(mSocket);
234 #endif
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();
242 return result;
245 void set_real_time_priority(pthread_t thread);
246 void set_real_time_priority(pthread_t thread)
248 int policy;
249 struct sched_param param;
251 pthread_getschedparam (thread, &policy, &param);
252 #ifdef __linux__
253 policy = SCHED_FIFO;
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);
261 #else
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
264 #endif
265 pthread_setschedparam (thread, policy, &param);
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();
280 return NULL;
283 void SC_UdpInPort::PublishToRendezvous()
285 PublishPortToRendezvous(kSCRendezvous_UDP, htons(mPortNum));
288 void SC_TcpInPort::PublishToRendezvous()
290 PublishPortToRendezvous(kSCRendezvous_TCP, htons(mPortNum));
293 #endif
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");
305 int bufsize = 65536;
306 #ifdef _WIN32
307 setsockopt(mSocket, SOL_SOCKET, SO_SNDBUF, (char*)&bufsize, sizeof(bufsize));
308 #else
309 setsockopt(mSocket, SOL_SOCKET, SO_SNDBUF, &bufsize, sizeof(bufsize));
310 #endif
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");
324 Start();
326 #ifdef USE_RENDEZVOUS
327 if(inWorld->mRendezvous){
328 pthread_create(&mRendezvousThread,
329 NULL,
330 rendezvous_thread_func,
331 (void*)this);
333 #endif
336 SC_UdpInPort::~SC_UdpInPort()
338 #ifdef _WIN32
339 if (mSocket != -1) closesocket(mSocket);
340 #else
341 if (mSocket != -1) close(mSocket);
342 #endif
345 //////////////////////////////////////////////////////////////////////////////////////////////////////////
347 void DumpReplyAddress(ReplyAddress *inReplyAddress)
349 scprintf("mSockAddrLen %d\n", inReplyAddress->mSockAddrLen);
350 scprintf("mSocket %d\n", inReplyAddress->mSocket);
351 #ifdef __APPLE__
352 scprintf("mSockAddr.sin_len %d\n", inReplyAddress->mSockAddr.sin_len);
353 #endif
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;
369 return Hash(hash);
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
383 #ifdef __APPLE__
384 && a.mSockAddr.sin_len == b.mSockAddr.sin_len
385 #endif
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;
404 while (true) {
405 if (!packet) {
406 // preallocate packet before we need it.
407 packet = (OSC_Packet*)malloc(sizeof(OSC_Packet));
410 packet->mReplyAddr.mSockAddrLen = sizeof(sockaddr_in);
411 #ifdef _WIN32
412 int size = recvfrom(mSocket, (char *)mReadBuf, kMaxUDPSize , 0,
413 #else
414 int size = recvfrom(mSocket, mReadBuf, kMaxUDPSize , 0,
415 #endif
416 (struct sockaddr *) &packet->mReplyAddr.mSockAddr, (socklen_t*)&packet->mReplyAddr.mSockAddrLen);
418 if (size > 0) {
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");
432 free(data);
433 free(packet);
435 packet = 0;
436 data = 0;
439 return 0;
442 //////////////////////////////////////////////////////////////////////////////////////////////////////////
444 SC_TcpInPort::SC_TcpInPort(struct World *inWorld, int inPortNum, int inMaxConnections, int inBacklog)
445 : SC_ComPort(inWorld, inPortNum), mConnectionAvailable(inMaxConnections),
446 mBacklog(inBacklog)
448 if((mSocket = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
449 throw std::runtime_error("failed to create tcp socket\n");
452 //const int on = 1;
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");
470 Start();
471 #ifdef USE_RENDEZVOUS
472 if(inWorld->mRendezvous){
473 pthread_create(&mRendezvousThread,
474 NULL,
475 rendezvous_thread_func,
476 (void*)this);
478 #endif
481 void* SC_TcpInPort::Run()
483 while (true)
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);
489 if (socket < 0) {
490 mConnectionAvailable.Release();
491 } else {
492 new SC_TcpConnectionPort(mWorld, this, socket);
495 return 0;
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)
517 mSocket = inSocket;
519 #ifdef _WIN32
520 const char on = 1;
521 setsockopt( mSocket, IPPROTO_TCP, TCP_NODELAY, (const char*)&on, sizeof(on));
522 #else
523 const int on = 1;
524 setsockopt( mSocket, IPPROTO_TCP, TCP_NODELAY, &on, sizeof(on));
525 #endif
527 Start();
530 SC_TcpConnectionPort::~SC_TcpConnectionPort()
532 #ifdef _WIN32
533 closesocket(mSocket);
534 #else
535 close(mSocket);
536 #endif
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)
543 uint32 u ;
544 // Write size as 32bit unsigned network-order integer
545 u = size;
546 u = htonl ( u ) ;
547 sendall ( addr->mSocket , &u , 4 ) ;
548 // Write message.
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
564 int32 size;
565 int32 msglen;
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;
580 #ifdef _WIN32
581 if (!validated) Sleep(i+1); // thwart cracking.
582 #else
583 if (!validated) sleep(i+1); // thwart cracking.
584 #endif
587 if (validated) {
588 while (true) {
589 if (!packet) {
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");
611 free(data);
612 free(packet);
614 packet = 0;
617 leave:
618 delete this; // ohh this could cause a crash if a reply tries to access it..
619 return 0;
622 //////////////////////////////////////////////////////////////////////////////////////////////////////////
624 int recvall(int socket, void *msg, size_t len)
626 int total = 0;
627 while (total < (int)len)
629 #ifdef _WIN32
630 int numbytes = recv(socket, (char*)msg, len - total, 0);
631 #else
632 int numbytes = recv(socket, msg, len - total, 0);
633 #endif
634 if (numbytes <= 0) return total;
635 total += numbytes;
636 msg = (void*)((char*)msg + numbytes);
638 return total;
641 int sendallto(int socket, const void *msg, size_t len, struct sockaddr *toaddr, int addrlen)
643 int total = 0;
644 while (total < (int)len)
646 #ifdef _WIN32
647 int numbytes = sendto(socket, (char*)msg, len - total, 0, toaddr, addrlen);
648 #else
649 int numbytes = sendto(socket, msg, len - total, 0, toaddr, addrlen);
650 #endif
651 if (numbytes < 0) {
652 scprintf("sendallto errno %d %s\n", errno, strerror(errno));
653 return total;
655 total += numbytes;
656 msg = (void*)((char*)msg + numbytes);
658 return total;
661 int sendall(int socket, const void *msg, size_t len)
663 int total = 0;
664 while (total < (int)len)
666 #ifdef _WIN32
667 int numbytes = send(socket, (const char*)msg, len - total, 0);
668 #else
669 int numbytes = send(socket, msg, len - total, 0);
670 #endif
671 if (numbytes < 0) return total;
672 total += numbytes;
673 msg = (void*)((char*)msg + numbytes);
675 return total;