Fix scvim regsitry file for updated filename (thanks Carlo Capocasa)
[supercollider.git] / server / scsynth / SC_ComPort.cpp
blob8f94294060d3232fd92c3e61f67b3cbcc52bc3cc
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 #include "SC_Endian.h"
22 #include "SC_Lock.h"
23 #include "SC_HiddenWorld.h"
24 #include "SC_WorldOptions.h"
25 #include "sc_msg_iter.h"
26 #include <ctype.h>
27 #include <stdexcept>
28 #include <stdarg.h>
30 #include <sys/types.h>
31 #include "OSC_Packet.h"
33 #ifdef _WIN32
34 # include <winsock2.h>
35 typedef int socklen_t;
36 # define bzero( ptr, count ) memset( ptr, 0, count )
37 #else
38 #include <netinet/tcp.h>
39 #endif
41 #if defined(__linux__) || defined(__FreeBSD__)
42 #include <errno.h>
43 #include <unistd.h>
44 #endif
46 #if defined(SC_IPHONE) || defined(__APPLE__)
47 #include <errno.h>
48 #endif
50 #ifdef USE_RENDEZVOUS
51 #include "Rendezvous.h"
52 #endif
54 bool ProcessOSCPacket(World *inWorld, OSC_Packet *inPacket);
56 namespace {
58 //////////////////////////////////////////////////////////////////////////////////////////////////////////
60 class SC_CmdPort
62 protected:
63 pthread_t mThread;
64 struct World *mWorld;
66 void Start();
67 virtual ReplyFunc GetReplyFunc()=0;
68 public:
69 SC_CmdPort(struct World *inWorld);
70 virtual ~SC_CmdPort() {}
72 virtual void* Run()=0;
75 //////////////////////////////////////////////////////////////////////////////////////////////////////////
77 class SC_ComPort : public SC_CmdPort
79 protected:
80 int mPortNum;
81 int mSocket;
82 struct sockaddr_in mBindSockAddr;
84 #ifdef USE_RENDEZVOUS
85 pthread_t mRendezvousThread;
86 #endif
88 public:
89 SC_ComPort(struct World *inWorld, int inPortNum);
90 virtual ~SC_ComPort();
92 int Socket() { return mSocket; }
94 int PortNum() const { return mPortNum; }
95 #ifdef USE_RENDEZVOUS
96 // default implementation does nothing (this is correct for
97 // SC_TcpConnectionPort). Subclasses may override.
98 virtual void PublishToRendezvous() { };
99 #endif
102 //////////////////////////////////////////////////////////////////////////////////////////////////////////
104 const size_t kMaxUDPSize = 65535;
106 class SC_UdpInPort : public SC_ComPort
108 protected:
109 struct sockaddr_in mReplySockAddr;
110 unsigned char mReadBuf[kMaxUDPSize];
111 virtual ReplyFunc GetReplyFunc();
113 public:
114 SC_UdpInPort(struct World *inWorld, int inPortNum);
115 ~SC_UdpInPort();
117 int PortNum() const { return mPortNum; }
119 void* Run();
120 #ifdef USE_RENDEZVOUS
121 virtual void PublishToRendezvous();
122 #endif
126 //////////////////////////////////////////////////////////////////////////////////////////////////////////
128 class SC_TcpInPort : public SC_ComPort
130 SC_Semaphore mConnectionAvailable;
131 int mBacklog;
133 protected:
134 virtual ReplyFunc GetReplyFunc();
136 public:
137 SC_TcpInPort(struct World *inWorld, int inPortNum, int inMaxConnections, int inBacklog);
139 virtual void* Run();
141 void ConnectionTerminated();
142 #ifdef USE_RENDEZVOUS
143 virtual void PublishToRendezvous();
144 #endif
147 //////////////////////////////////////////////////////////////////////////////////////////////////////////
149 class SC_TcpConnectionPort : public SC_ComPort
151 SC_TcpInPort *mParent;
152 unsigned char mReadBuf[kMaxUDPSize];
154 protected:
155 virtual ReplyFunc GetReplyFunc();
157 public:
158 SC_TcpConnectionPort(struct World *inWorld, SC_TcpInPort *inParent, int inSocket);
159 virtual ~SC_TcpConnectionPort();
161 virtual void* Run();
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)
172 int size;
173 const char *data;
175 if (inData[0]) {
176 char *addr = inData;
177 data = OSCstrskip(inData);
178 size = inSize - (data - inData);
179 scprintf("[ \"%s\",", addr);
181 else
183 scprintf("[ %d,", OSCint(inData));
184 data = inData + 4;
185 size = inSize - 4;
188 sc_msg_iter msg(size, data);
190 while (msg.remain())
192 char c = msg.nextTag('i');
193 switch(c)
195 case 'i' :
196 scprintf(" %d", msg.geti());
197 break;
198 case 'f' :
199 scprintf(" %g", msg.getf());
200 break;
201 case 'd' :
202 scprintf(" %g", msg.getd());
203 break;
204 case 's' :
205 scprintf(" \"%s\"", msg.gets());
206 break;
207 case 'b' :
208 scprintf(" DATA[%d]", msg.getbsize());
209 msg.skipb();
210 break;
211 case '[' :
212 scprintf("[");
213 msg.count++;
214 break;
215 case ']' :
216 scprintf("]");
217 msg.count++;
218 break;
219 default :
220 scprintf(" !unknown tag '%c' 0x%02x !", isprint(c)?c:'?', (unsigned char)c & 255);
221 goto leave;
223 if (msg.remain() && (c!= '[')) scprintf(",");
225 leave:
226 scprintf(" ]");
229 void hexdump(int size, char* data)
231 char ascii[20];
232 int padsize = (size + 15) & -16;
233 scprintf("size %d\n", size);
234 for (int i=0; i<padsize; ++i)
236 if ((i&15)==0)
238 scprintf("%4d ", i);
240 if (i >= size)
242 scprintf(" ");
243 ascii[i&15] = 0;
245 else
247 scprintf("%02x ", (unsigned char)data[i] & 255);
249 if (isprint(data[i])) ascii[i&15] = data[i];
250 else ascii[i&15] = '.';
252 if ((i&15)==15)
254 ascii[16] = 0;
255 scprintf(" |%s|\n", ascii);
257 else if ((i&3)==3)
259 scprintf(" ");
262 scprintf("\n");
265 void dumpOSC(int mode, int size, char* inData)
267 if (mode & 1)
269 if (strcmp(inData, "#bundle") == 0)
271 char* data = inData + 8;
272 scprintf("[ \"#bundle\", %lld, ", OSCtime(data));
273 data += 8;
274 char* dataEnd = inData + size;
275 while (data < dataEnd) {
276 int32 msgSize = OSCint(data);
277 data += sizeof(int32);
278 scprintf("\n ");
279 dumpOSCmsg(msgSize, data);
280 data += msgSize;
281 if (data < dataEnd) scprintf(",");
283 scprintf("\n]\n");
285 else
287 dumpOSCmsg(size, inData);
288 scprintf("\n");
292 if (mode & 2) hexdump(size, inData);
297 SC_DLLEXPORT_C bool World_SendPacketWithContext(World *inWorld, int inSize, char *inData, ReplyFunc inFunc, void *inContext)
299 bool result = false;
300 if (inSize > 0) {
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);
316 return result;
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)
326 try {
327 new SC_UdpInPort(inWorld, inPort);
328 return true;
329 } catch (std::exception& exc) {
330 scprintf("Exception in World_OpenUDP: %s\n", exc.what());
331 } catch (...) {
333 return false;
336 SC_DLLEXPORT_C int World_OpenTCP(struct World *inWorld, int inPort, int inMaxConnections, int inBacklog)
338 try {
339 new SC_TcpInPort(inWorld, inPort, inMaxConnections, inBacklog);
340 return true;
341 } catch (std::exception& exc) {
342 scprintf("Exception in World_OpenTCP: %s\n", exc.what());
343 } catch (...) {
345 return false;
348 void set_real_time_priority(pthread_t thread)
350 int policy;
351 struct sched_param param;
353 pthread_getschedparam (thread, &policy, &param);
354 #ifdef __linux__
355 policy = SCHED_FIFO;
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);
363 #else
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
366 #endif
367 pthread_setschedparam (thread, policy, &param);
372 //////////////////////////////////////////////////////////////////////////////////////////////////////////
374 namespace {
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()
389 #ifdef _WIN32
390 if (mSocket != -1) closesocket(mSocket);
391 #else
392 if (mSocket != -1) close(mSocket);
393 #endif
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();
401 return result;
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();
416 return NULL;
419 void SC_UdpInPort::PublishToRendezvous()
421 PublishPortToRendezvous(kSCRendezvous_UDP, htons(mPortNum));
424 void SC_TcpInPort::PublishToRendezvous()
426 PublishPortToRendezvous(kSCRendezvous_TCP, htons(mPortNum));
429 #endif
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");
441 int bufsize = 65536;
442 #ifdef _WIN32
443 setsockopt(mSocket, SOL_SOCKET, SO_SNDBUF, (char*)&bufsize, sizeof(bufsize));
444 #else
445 setsockopt(mSocket, SOL_SOCKET, SO_SNDBUF, &bufsize, sizeof(bufsize));
446 #endif
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");
460 Start();
462 #ifdef USE_RENDEZVOUS
463 if(inWorld->mRendezvous){
464 pthread_create(&mRendezvousThread,
465 NULL,
466 rendezvous_thread_func,
467 (void*)this);
469 #endif
472 SC_UdpInPort::~SC_UdpInPort()
474 #ifdef _WIN32
475 if (mSocket != -1) closesocket(mSocket);
476 #else
477 if (mSocket != -1) close(mSocket);
478 #endif
484 //////////////////////////////////////////////////////////////////////////////////////////////////////////
486 static void DumpReplyAddress(ReplyAddress *inReplyAddress)
488 scprintf("mSockAddrLen %d\n", inReplyAddress->mSockAddrLen);
489 scprintf("mSocket %d\n", inReplyAddress->mSocket);
490 #ifdef __APPLE__
491 scprintf("mSockAddr.sin_len %d\n", inReplyAddress->mSockAddr.sin_len);
492 #endif
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;
508 return Hash(hash);
511 ReplyAddress GetKey(ReplyAddress *inReplyAddress)
513 return *inReplyAddress
517 namespace {
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;
533 while (true) {
534 if (!packet) {
535 // preallocate packet before we need it.
536 packet = (OSC_Packet*)malloc(sizeof(OSC_Packet));
539 packet->mReplyAddr.mSockAddrLen = sizeof(sockaddr_in);
540 #ifdef _WIN32
541 int size = recvfrom(mSocket, (char *)mReadBuf, kMaxUDPSize , 0,
542 #else
543 int size = recvfrom(mSocket, mReadBuf, kMaxUDPSize , 0,
544 #endif
545 (struct sockaddr *) &packet->mReplyAddr.mSockAddr, (socklen_t*)&packet->mReplyAddr.mSockAddrLen);
547 if (size > 0) {
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");
561 free(data);
562 free(packet);
564 packet = 0;
565 data = 0;
568 return 0;
571 //////////////////////////////////////////////////////////////////////////////////////////////////////////
573 SC_TcpInPort::SC_TcpInPort(struct World *inWorld, int inPortNum, int inMaxConnections, int inBacklog)
574 : SC_ComPort(inWorld, inPortNum), mConnectionAvailable(inMaxConnections),
575 mBacklog(inBacklog)
577 if((mSocket = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
578 throw std::runtime_error("failed to create tcp socket\n");
581 //const int on = 1;
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");
599 Start();
600 #ifdef USE_RENDEZVOUS
601 if(inWorld->mRendezvous){
602 pthread_create(&mRendezvousThread,
603 NULL,
604 rendezvous_thread_func,
605 (void*)this);
607 #endif
610 void* SC_TcpInPort::Run()
612 while (true)
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);
618 if (socket < 0) {
619 mConnectionAvailable.Release();
620 } else {
621 new SC_TcpConnectionPort(mWorld, this, socket);
624 return 0;
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)
642 mSocket = inSocket;
644 #ifdef _WIN32
645 const char on = 1;
646 setsockopt( mSocket, IPPROTO_TCP, TCP_NODELAY, (const char*)&on, sizeof(on));
647 #else
648 const int on = 1;
649 setsockopt( mSocket, IPPROTO_TCP, TCP_NODELAY, &on, sizeof(on));
650 #endif
652 Start();
655 SC_TcpConnectionPort::~SC_TcpConnectionPort()
657 #ifdef _WIN32
658 closesocket(mSocket);
659 #else
660 close(mSocket);
661 #endif
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)
668 uint32 u ;
669 // Write size as 32bit unsigned network-order integer
670 u = size;
671 u = htonl ( u ) ;
672 sendall ( addr->mSocket , &u , 4 ) ;
673 // Write message.
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
689 int32 size;
690 int32 msglen;
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;
705 #ifdef _WIN32
706 if (!validated) Sleep(i+1); // thwart cracking.
707 #else
708 if (!validated) sleep(i+1); // thwart cracking.
709 #endif
712 if (validated) {
713 while (true) {
714 if (!packet) {
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");
736 free(data);
737 free(packet);
739 packet = 0;
742 leave:
743 delete this; // ohh this could cause a crash if a reply tries to access it..
744 return 0;
747 //////////////////////////////////////////////////////////////////////////////////////////////////////////
749 int recvall(int socket, void *msg, size_t len)
751 int total = 0;
752 while (total < (int)len)
754 #ifdef _WIN32
755 int numbytes = recv(socket, (char*)msg, len - total, 0);
756 #else
757 int numbytes = recv(socket, msg, len - total, 0);
758 #endif
759 if (numbytes <= 0) return total;
760 total += numbytes;
761 msg = (void*)((char*)msg + numbytes);
763 return total;
766 int sendallto(int socket, const void *msg, size_t len, struct sockaddr *toaddr, int addrlen)
768 int total = 0;
769 while (total < (int)len)
771 #ifdef _WIN32
772 int numbytes = sendto(socket, (char*)msg, len - total, 0, toaddr, addrlen);
773 #else
774 int numbytes = sendto(socket, msg, len - total, 0, toaddr, addrlen);
775 #endif
776 if (numbytes < 0) {
777 scprintf("sendallto errno %d %s\n", errno, strerror(errno));
778 return total;
780 total += numbytes;
781 msg = (void*)((char*)msg + numbytes);
783 return total;
786 int sendall(int socket, const void *msg, size_t len)
788 int total = 0;
789 while (total < (int)len)
791 #ifdef _WIN32
792 int numbytes = send(socket, (const char*)msg, len - total, 0);
793 #else
794 int numbytes = send(socket, msg, len - total, 0);
795 #endif
796 if (numbytes < 0) return total;
797 total += numbytes;
798 msg = (void*)((char*)msg + numbytes);
800 return total;