Merge pull request #506 from andrewcsmith/patch-2
[supercollider.git] / lang / LangPrimSource / SC_ComPort.cpp
blobc5a935724ac6af0d9768477e7b2edc315211a044
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_BoundsMacros.h"
22 #include "SC_ComPort.h"
23 #include "SC_Endian.h"
24 #include <ctype.h>
25 #include <stdexcept>
26 #include <stdarg.h>
27 #include "SCBase.h"
28 #include <fcntl.h>
30 #ifndef SC_WIN32
31 # include <unistd.h>
32 #else
33 #include "SC_Win32Utils.h"
34 #endif
36 #ifdef __linux__
37 # include <errno.h>
38 #endif
40 #ifdef __FreeBSD__
41 # include <errno.h>
42 #endif
44 #if defined(SC_DARWIN) || defined(SC_IPHONE)
45 #include <errno.h>
46 #endif
48 // sk: determine means of blocking SIGPIPE for send(2) (implementation
49 // dependent)
51 #define HAVE_SO_NOSIGPIPE 0
52 #define HAVE_MSG_NOSIGNAL 0
54 #if defined(SO_NOSIGPIPE)
55 # undef HAVE_SO_NOSIGPIPE
56 # define HAVE_SO_NOSIGPIPE 1
57 #elif defined(MSG_NOSIGNAL)
58 # undef HAVE_MSG_NOSIGNAL
59 # define HAVE_MSG_NOSIGNAL 1
60 #endif
62 int recvall(int socket, void *msg, size_t len);
63 int recvallfrom(int socket, void *msg, size_t len, struct sockaddr *fromaddr, int addrlen);
64 int sendallto(int socket, const void *msg, size_t len, struct sockaddr *toaddr, int addrlen);
65 int sendall(int socket, const void *msg, size_t len);
67 void ProcessOSCPacket(OSC_Packet *inPacket, int inPortNum);
69 static void dumpOSCmsg(int inSize, char* inData)
71 int size;
72 const char *data;
74 if (inData[0]) {
75 char *addr = inData;
76 data = OSCstrskip(inData);
77 size = inSize - (data - inData);
78 printf("[ \"%s\",", addr);
80 else
82 printf("[ %d,", OSCint(inData));
83 data = inData + 4;
84 size = inSize - 4;
87 sc_msg_iter msg(size, data);
89 while (msg.remain())
91 char c = msg.nextTag('i');
92 switch(c)
94 case 'i' :
95 printf(" %d", msg.geti());
96 break;
97 case 'f' :
98 printf(" %g", msg.getf());
99 break;
100 case 'd' :
101 printf(" %g", msg.getd());
102 break;
103 case 's' :
104 printf(" \"%s\"", msg.gets());
105 break;
106 case 'b' :
107 printf(" DATA[%zu]", msg.getbsize());
108 msg.skipb();
109 break;
110 default :
111 printf(" !unknown tag '%c' 0x%02x !", isprint(c)?c:'?', (unsigned char)c & 255);
112 goto leave;
114 if (msg.remain()) printf(",");
116 leave:
117 printf(" ]");
120 static void hexdump(int size, char* data)
122 char ascii[20];
123 int padsize = (size + 15) & -16;
124 printf("size %d\n", size);
125 for (int i=0; i<padsize; ++i)
127 if ((i&15)==0)
129 printf("%4d ", i);
131 if (i >= size)
133 printf(" ");
134 ascii[i&15] = 0;
136 else
138 printf("%02x ", (unsigned char)data[i] & 255);
140 if (isprint(data[i])) ascii[i&15] = data[i];
141 else ascii[i&15] = '.';
143 if ((i&15)==15)
145 ascii[16] = 0;
146 printf(" |%s|\n", ascii);
148 else if ((i&3)==3)
150 printf(" ");
153 printf("\n");
156 void dumpOSC(int mode, int size, char* inData)
158 if (mode & 1)
160 if (strcmp(inData, "#bundle") == 0)
162 char* data = inData + 8;
163 printf("[ \"#bundle\", %lld, ", OSCtime(data));
164 data += 8;
165 char* dataEnd = inData + size;
166 while (data < dataEnd) {
167 int32 msgSize = OSCint(data);
168 data += sizeof(int32);
169 printf("\n ");
170 dumpOSCmsg(msgSize, data);
171 data += msgSize;
172 if (data < dataEnd) printf(",");
174 printf("\n]\n");
176 else
178 dumpOSCmsg(size, inData);
179 printf("\n");
183 if (mode & 2) hexdump(size, inData);
186 //////////////////////////////////////////////////////////////////////////////////////////////////////////
188 SC_CmdPort::SC_CmdPort()
192 SC_CmdPort::~SC_CmdPort()
196 //////////////////////////////////////////////////////////////////////////////////////////////////////////
198 SC_ComPort::SC_ComPort(int inPortNum)
199 : mPortNum(inPortNum), mSocket(-1)
203 SC_ComPort::~SC_ComPort()
205 #ifdef SC_WIN32
206 if (mSocket != -1) closesocket(mSocket);
207 #else
208 if (mSocket != -1) close(mSocket);
209 #endif
212 static void* com_thread_func(void* arg)
214 SC_CmdPort *thread = (SC_CmdPort*)arg;
215 void* result = thread->Run();
216 return result;
219 void SC_CmdPort::Start()
221 pthread_create (&mThread, NULL, com_thread_func, (void*)this);
224 //////////////////////////////////////////////////////////////////////////////////////////////////////////
226 SC_UdpInPort::SC_UdpInPort(int inPortNum)
227 : SC_ComPort(inPortNum)
229 if ((mSocket = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
230 throw std::runtime_error("failed to create udp socket\n");
234 int bufsize = 65536;
235 #ifdef SC_WIN32
236 setsockopt(mSocket, SOL_SOCKET, SO_SNDBUF, (char*)&bufsize, sizeof(bufsize));
237 #else
238 setsockopt(mSocket, SOL_SOCKET, SO_SNDBUF, &bufsize, sizeof(bufsize));
239 #endif
242 bzero((char *)&mBindSockAddr, sizeof(mBindSockAddr));
243 mBindSockAddr.sin_family = AF_INET;
244 mBindSockAddr.sin_addr.s_addr = htonl(INADDR_ANY);
246 bool bound = false;
247 for (int i=0; i<10 && !bound; ++i) {
248 mPortNum = mPortNum+i;
249 mBindSockAddr.sin_port = htons(mPortNum);
250 if (bind(mSocket, (struct sockaddr *)&mBindSockAddr, sizeof(mBindSockAddr)) >= 0) {
251 bound = true;
254 if (!bound) throw std::runtime_error("unable to bind udp socket\n");
255 Start();
258 SC_UdpInPort::~SC_UdpInPort()
260 #ifdef SC_WIN32
261 if (mSocket != -1) closesocket(mSocket);
262 #else
263 if (mSocket != -1) close(mSocket);
264 #endif
267 //////////////////////////////////////////////////////////////////////////////////////////////////////////
269 SC_UdpCustomInPort::SC_UdpCustomInPort(int inPortNum)
270 : SC_ComPort(inPortNum)
272 if ((mSocket = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
273 throw std::runtime_error("failed to create udp socket\n");
277 int bufsize = 65536;
278 #ifdef SC_WIN32
279 setsockopt(mSocket, SOL_SOCKET, SO_SNDBUF, (char*)&bufsize, sizeof(bufsize));
280 #else
281 setsockopt(mSocket, SOL_SOCKET, SO_SNDBUF, &bufsize, sizeof(bufsize));
282 #endif
285 bzero((char *)&mBindSockAddr, sizeof(mBindSockAddr));
286 mBindSockAddr.sin_family = AF_INET;
287 mBindSockAddr.sin_addr.s_addr = htonl(INADDR_ANY);
289 bool bound = false;
290 mBindSockAddr.sin_port = htons(mPortNum);
291 if (bind(mSocket, (struct sockaddr *)&mBindSockAddr, sizeof(mBindSockAddr)) >= 0) {
292 bound = true;
294 if (!bound) throw std::runtime_error("unable to bind udp socket\n");
295 Start();
298 SC_UdpCustomInPort::~SC_UdpCustomInPort()
300 mRunning.store(false);
301 pthread_join(mThread, NULL);
302 #ifdef SC_WIN32
303 if (mSocket != -1) closesocket(mSocket);
304 #else
305 if (mSocket != -1) close(mSocket);
306 #endif
310 //////////////////////////////////////////////////////////////////////////////////////////////////////////
312 static void DumpReplyAddress(ReplyAddress *inReplyAddress)
314 printf("mSockAddrLen %d\n", inReplyAddress->mSockAddrLen);
315 printf("mSocket %d\n", inReplyAddress->mSocket);
316 #ifdef SC_DARWIN
317 printf("mSockAddr.sin_len %d\n", inReplyAddress->mSockAddr.sin_len);
318 #endif
319 printf("mSockAddr.sin_family %d\n", inReplyAddress->mSockAddr.sin_family);
320 printf("mSockAddr.sin_port %d\n", inReplyAddress->mSockAddr.sin_port);
321 printf("mSockAddr.sin_addr.s_addr %d\n", inReplyAddress->mSockAddr.sin_addr.s_addr);
322 printf("mReplyFunc %p\n", inReplyAddress->mReplyFunc);
326 int32 Hash(ReplyAddress *inReplyAddress)
328 int32 hash;
329 int32 *word = (int32*)&inReplyAddress->mSockAddr;
330 hash = Hash(inReplyAddress->mSockAddr.sin_addr.s_addr);
332 hash += inReplyAddress->mSockAddr.sin_len << 24
333 | inReplyAddress->mSockAddr.sin_family << 16
334 | inReplyAddress->mSockAddr.sin_port;
336 hash = Hash(hash);
337 return hash;
341 void udp_reply_func(struct ReplyAddress *addr, char* msg, int size);
342 void udp_reply_func(struct ReplyAddress *addr, char* msg, int size)
344 printf("->udp_reply_func\n");
345 int total = sendallto(addr->mSocket, msg, size, (sockaddr*)&addr->mSockAddr, addr->mSockAddrLen);
346 printf("<-udp_reply_func %d of %d\n", total, size);
347 if (total < size) DumpReplyAddress(addr);
350 ReplyFunc SC_UdpInPort::GetReplyFunc()
352 return udp_reply_func;
355 void* SC_UdpInPort::Run()
357 OSC_Packet *packet = 0;
359 //printf("SC_UdpInPort::Run\n"); fflush(stdout);
361 while (true) {
362 if (!packet) {
363 packet = (OSC_Packet*)malloc(sizeof(OSC_Packet));
365 packet->mReplyAddr.mSockAddrLen = sizeof(sockaddr_in);
366 int size = recvfrom(mSocket, buf, kTextBufSize , 0,
367 (struct sockaddr *) &packet->mReplyAddr.mSockAddr, (socklen_t*)&packet->mReplyAddr.mSockAddrLen);
369 if (size > 0) {
370 //dumpOSC(3, size, buf);
371 //fflush(stdout);
373 char *data = (char*)malloc(size);
374 packet->mReplyAddr.mReplyFunc = udp_reply_func;
375 packet->mSize = size;
376 packet->mData = data;
377 packet->mReplyAddr.mSocket = mSocket;
378 memcpy(data, buf, size);
379 ProcessOSCPacket(packet, mPortNum);
380 packet = 0;
383 return 0;
386 ReplyFunc SC_UdpCustomInPort::GetReplyFunc()
388 return udp_reply_func;
391 void* SC_UdpCustomInPort::Run()
393 OSC_Packet *packet = 0;
395 const int fd = mSocket;
396 const int max_fd = fd+1;
398 mRunning.store(true);
399 while (mRunning.load(boost::memory_order_consume)) {
400 fd_set rfds;
402 FD_ZERO( &rfds);
403 FD_SET(fd, &rfds);
405 struct timeval timeout;
406 timeout.tv_sec = 0;
407 timeout.tv_usec = 500000;
409 int n = select(max_fd, &rfds, 0, 0, &timeout);
410 if ((n > 0) && FD_ISSET(fd, &rfds)) {
411 if (!packet) {
412 packet = (OSC_Packet*)malloc(sizeof(OSC_Packet));
414 packet->mReplyAddr.mSockAddrLen = sizeof(sockaddr_in);
415 int size = recvfrom(mSocket, buf, kTextBufSize , 0,
416 (struct sockaddr *) &packet->mReplyAddr.mSockAddr, (socklen_t*)&packet->mReplyAddr.mSockAddrLen);
418 if (size > 0 && mRunning.load(boost::memory_order_consume)) {
419 //dumpOSC(3, size, buf);
420 //fflush(stdout);
422 char *data = (char*)malloc(size);
423 packet->mReplyAddr.mReplyFunc = udp_reply_func;
424 packet->mSize = size;
425 packet->mData = data;
426 packet->mReplyAddr.mSocket = mSocket;
427 memcpy(data, buf, size);
428 ProcessOSCPacket(packet, mPortNum);
429 packet = 0;
433 FreeOSCPacket(packet); // just in case
434 return 0;
437 //////////////////////////////////////////////////////////////////////////////////////////////////////////
439 SC_TcpInPort::SC_TcpInPort(int inPortNum, int inMaxConnections, int inBacklog)
440 : SC_ComPort(inPortNum), mConnectionAvailable(inMaxConnections),
441 mBacklog(inBacklog)
444 if((mSocket = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
445 throw std::runtime_error("failed to create tcp socket\n");
447 //setsockopt(mSocket, SOL_SOCKET, TCP_NODELAY);
449 bzero((char *)&mBindSockAddr, sizeof(mBindSockAddr));
450 mBindSockAddr.sin_family = AF_INET;
451 mBindSockAddr.sin_addr.s_addr = htonl(INADDR_ANY);
452 mBindSockAddr.sin_port = htons(mPortNum);
454 if(bind(mSocket, (struct sockaddr *)&mBindSockAddr, sizeof(mBindSockAddr)) < 0)
456 throw std::runtime_error("unable to bind tcp socket\n");
458 if(listen(mSocket, mBacklog) < 0)
460 throw std::runtime_error("unable to listen tcp socket\n");
463 Start();
466 void* SC_TcpInPort::Run()
468 while (true)
470 mConnectionAvailable.Acquire();
471 struct sockaddr_in address; /* Internet socket address stuct */
472 int addressSize=sizeof(struct sockaddr_in);
473 int socket = accept(mSocket,(struct sockaddr*)&address,(socklen_t*)&addressSize);
474 if (socket < 0) {
475 mConnectionAvailable.Release();
476 } else {
477 new SC_TcpConnectionPort(this, socket);
480 return 0;
483 void SC_TcpInPort::ConnectionTerminated()
485 mConnectionAvailable.Release();
488 ReplyFunc SC_TcpInPort::GetReplyFunc()
490 return null_reply_func;
493 //////////////////////////////////////////////////////////////////////////////////////////////////////////
495 SC_TcpConnectionPort::SC_TcpConnectionPort(SC_TcpInPort *inParent, int inSocket)
496 : SC_ComPort(0), mParent(inParent)
498 mSocket = inSocket;
499 Start();
502 SC_TcpConnectionPort::~SC_TcpConnectionPort()
504 #ifdef SC_WIN32
505 closesocket(mSocket);
506 #else
507 close(mSocket);
508 #endif
509 mParent->ConnectionTerminated();
512 void tcp_reply_func(struct ReplyAddress *addr, char* msg, int size);
513 void tcp_reply_func(struct ReplyAddress *addr, char* msg, int size)
515 sendall(addr->mSocket, msg, size);
518 ReplyFunc SC_TcpConnectionPort::GetReplyFunc()
520 return tcp_reply_func;
523 extern const char* gPassword;
525 void* SC_TcpConnectionPort::Run()
527 OSC_Packet *packet = 0;
528 // wait for login message
529 int32 size;
530 int32 msglen;
532 while (true) {
533 if (!packet) {
534 packet = (OSC_Packet*)malloc(sizeof(OSC_Packet));
536 size = recvall(mSocket, &msglen, sizeof(int32));
537 if (size < 0) goto leave;
539 // sk: msglen is in network byte order
540 msglen = ntohl(msglen);
542 char *data = (char*)malloc(msglen);
543 size = recvall(mSocket, data, msglen);
544 if (size < msglen) goto leave;
546 packet->mReplyAddr.mReplyFunc = tcp_reply_func;
547 packet->mSize = msglen;
548 packet->mData = data;
549 packet->mReplyAddr.mSocket = mSocket;
550 ProcessOSCPacket(packet, mPortNum);
551 packet = 0;
553 leave:
554 delete this; // ohh this could cause a crash if a reply tries to access it..
555 return 0;
558 //////////////////////////////////////////////////////////////////////////////////////////////////////////
560 #ifndef SC_WIN32
561 # include <sys/select.h>
562 #endif
563 //SC_WIN32
565 SC_TcpClientPort::SC_TcpClientPort(int inSocket, ClientNotifyFunc notifyFunc, void *clientData)
566 : SC_ComPort(0),
567 mClientNotifyFunc(notifyFunc),
568 mClientData(clientData)
570 mSocket = inSocket;
571 socklen_t sockAddrLen = sizeof(mReplySockAddr);
573 if (getpeername(mSocket, (struct sockaddr*)&mReplySockAddr, &sockAddrLen) == -1) {
574 memset(&mReplySockAddr, 0, sizeof(mReplySockAddr));
575 mReplySockAddr.sin_family = AF_INET;
576 mReplySockAddr.sin_addr.s_addr = htonl(INADDR_NONE);
577 mReplySockAddr.sin_port = htons(0);
580 #if HAVE_SO_NOSIGPIPE
581 int sockopt = 1;
582 setsockopt(mSocket, SOL_SOCKET, SO_NOSIGPIPE, &sockopt, sizeof(sockopt));
583 #endif // HAVE_SO_NOSIGPIPE
585 if (pipe(mCmdFifo) == -1) {
586 mCmdFifo[0] = mCmdFifo[1] = -1;
589 Start();
592 SC_TcpClientPort::~SC_TcpClientPort()
594 #ifdef SC_WIN32
595 closesocket(mCmdFifo[0]);
596 closesocket(mCmdFifo[1]);
597 closesocket(mSocket);
598 #else
599 close(mCmdFifo[0]);
600 close(mCmdFifo[1]);
601 close(mSocket);
602 #endif
605 void* SC_TcpClientPort::Run()
607 OSC_Packet *packet = 0;
608 int32 size;
609 int32 msglen;
611 int cmdfd = mCmdFifo[0];
612 int sockfd = mSocket;
613 int nfds = sc_max(cmdfd, sockfd) + 1;
615 bool cmdClose = false;
617 pthread_detach(mThread);
619 while (true) {
620 fd_set rfds;
621 FD_ZERO(&rfds);
622 FD_SET(cmdfd, &rfds);
623 FD_SET(sockfd, &rfds);
625 if ((select(nfds, &rfds, 0, 0, 0) == -1) || (cmdClose = FD_ISSET(cmdfd, &rfds)))
626 goto leave;
628 if (!FD_ISSET(sockfd, &rfds))
629 continue;
631 packet = (OSC_Packet*)malloc(sizeof(OSC_Packet));
632 if (!packet) goto leave;
634 packet->mData = 0;
636 size = recvall(sockfd, &msglen, sizeof(int32));
637 if (size < (int32)sizeof(int32)) goto leave;
639 // msglen is in network byte order
640 msglen = ntohl(msglen);
642 packet->mData = (char*)malloc(msglen);
643 if (!packet->mData) goto leave;
645 size = recvall(sockfd, packet->mData, msglen);
646 if (size < msglen) goto leave;
648 memcpy(&packet->mReplyAddr.mSockAddr, &mReplySockAddr, sizeof(mReplySockAddr));
649 packet->mReplyAddr.mSockAddrLen = sizeof(mReplySockAddr);
650 packet->mReplyAddr.mSocket = sockfd;
651 packet->mReplyAddr.mReplyFunc = tcp_reply_func;
652 packet->mSize = msglen;
653 ProcessOSCPacket(packet, mPortNum);
655 packet = 0;
658 leave:
659 if (packet) {
660 free(packet->mData);
661 free(packet);
663 // Only call notify function when not closed explicitly
664 if (!cmdClose && mClientNotifyFunc) {
665 (*mClientNotifyFunc)(mClientData);
667 delete this;
668 return 0;
671 void SC_TcpClientPort::Close()
673 char cmd = 0;
674 #ifdef SC_WIN32
675 win32_pipewrite(mCmdFifo[1], &cmd, sizeof(cmd));
676 #else
677 size_t written = write(mCmdFifo[1], &cmd, sizeof(cmd));
678 if (written != sizeof(cmd))
679 post("warning: invalid write in SC_TcpClientPort::Close");
680 #endif
683 ReplyFunc SC_TcpClientPort::GetReplyFunc()
685 return tcp_reply_func;
688 //////////////////////////////////////////////////////////////////////////////////////////////////////////
690 int recvall(int socket, void *msg, size_t len)
692 size_t total = 0;
693 while (total < len)
695 #ifdef SC_WIN32
696 int numbytes = recv(socket, reinterpret_cast<char*>(msg), len - total, 0);
697 #else
698 int numbytes = recv(socket, msg, len - total, 0);
699 #endif
700 if (numbytes <= 0) return total;
701 total += numbytes;
702 msg = (void*)((char*)msg + numbytes);
704 return total;
707 int recvallfrom(int socket, void *msg, size_t len, struct sockaddr *fromaddr, int addrlen)
709 size_t total = 0;
710 while (total < len)
712 socklen_t addrlen2 = addrlen;
713 #ifdef SC_WIN32
714 int numbytes = recvfrom(socket, reinterpret_cast<char*>(msg), len - total, 0, fromaddr, &addrlen2);
715 #else
716 int numbytes = recvfrom(socket, msg, len - total, 0, fromaddr, &addrlen2);
717 #endif
718 if (numbytes < 0) return total;
719 total += numbytes;
720 msg = (void*)((char*)msg + numbytes);
722 return total;
725 int sendallto(int socket, const void *msg, size_t len, struct sockaddr *toaddr, int addrlen)
727 size_t total = 0;
728 while (total < len)
730 #ifdef SC_WIN32
731 int numbytes = sendto(socket, reinterpret_cast<const char*>(msg), len - total, 0, toaddr, addrlen);
732 #else
733 int numbytes = sendto(socket, msg, len - total, 0, toaddr, addrlen);
734 #endif
735 //printf("numbytes %d total %d len %d\n", numbytes, total, len);
736 if (numbytes < 0) {
737 printf("******* errno %d %s\n", errno, strerror(errno));
738 return total;
740 total += numbytes;
741 msg = (void*)((char*)msg + numbytes);
743 return total;
746 int sendall(int socket, const void *msg, size_t len)
748 size_t total = 0;
749 while (total < len)
751 #if HAVE_MSG_NOSIGNAL
752 int flags = MSG_NOSIGNAL;
753 #else
754 int flags = 0;
755 #endif // HAVE_MSG_NOSIGNAL
756 #ifdef SC_WIN32
757 int numbytes = send(socket, reinterpret_cast<const char*>(msg), len - total, flags);
758 #else
759 int numbytes = send(socket, msg, len - total, flags);
760 #endif
761 if (numbytes < 0) return total;
762 total += numbytes;
763 msg = (void*)((char*)msg + numbytes);
765 return total;
768 //////////////////////////////////////////////////////////////////////////////////////////////////////////