class library: SynthDef - lazy implementation of removeUGen
[supercollider.git] / lang / LangPrimSource / SC_ComPort.cpp
blob68f4dfde411dddf00d9b0402b2801776da5b8fa9
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 "SC_Lock.h"
25 #include <ctype.h>
26 #include <stdexcept>
27 #include <stdarg.h>
28 #include "SCBase.h"
29 #include <fcntl.h>
31 #ifndef SC_WIN32
32 # include <unistd.h>
33 #else
34 #include "SC_Win32Utils.h"
35 #endif
37 #ifdef SC_LINUX
38 # include <errno.h>
39 #endif
41 #ifdef __FreeBSD__
42 # include <errno.h>
43 #endif
45 #if defined(SC_DARWIN) || defined(SC_IPHONE)
46 #include <errno.h>
47 #endif
49 // sk: determine means of blocking SIGPIPE for send(2) (implementation
50 // dependent)
52 #define HAVE_SO_NOSIGPIPE 0
53 #define HAVE_MSG_NOSIGNAL 0
55 #if defined(SO_NOSIGPIPE)
56 # undef HAVE_SO_NOSIGPIPE
57 # define HAVE_SO_NOSIGPIPE 1
58 #elif defined(MSG_NOSIGNAL)
59 # undef HAVE_MSG_NOSIGNAL
60 # define HAVE_MSG_NOSIGNAL 1
61 #endif
63 int recvall(int socket, void *msg, size_t len);
64 int recvallfrom(int socket, void *msg, size_t len, struct sockaddr *fromaddr, int addrlen);
65 int sendallto(int socket, const void *msg, size_t len, struct sockaddr *toaddr, int addrlen);
66 int sendall(int socket, const void *msg, size_t len);
68 void ProcessOSCPacket(OSC_Packet *inPacket, int inPortNum);
70 void dumpOSCmsg(int inSize, char* inData)
72 int size;
73 const char *data;
75 if (inData[0]) {
76 char *addr = inData;
77 data = OSCstrskip(inData);
78 size = inSize - (data - inData);
79 printf("[ \"%s\",", addr);
81 else
83 printf("[ %d,", OSCint(inData));
84 data = inData + 4;
85 size = inSize - 4;
88 sc_msg_iter msg(size, data);
90 while (msg.remain())
92 char c = msg.nextTag('i');
93 switch(c)
95 case 'i' :
96 printf(" %d", msg.geti());
97 break;
98 case 'f' :
99 printf(" %g", msg.getf());
100 break;
101 case 'd' :
102 printf(" %g", msg.getd());
103 break;
104 case 's' :
105 printf(" \"%s\"", msg.gets());
106 break;
107 case 'b' :
108 printf(" DATA[%zu]", msg.getbsize());
109 msg.skipb();
110 break;
111 default :
112 printf(" !unknown tag '%c' 0x%02x !", isprint(c)?c:'?', (unsigned char)c & 255);
113 goto leave;
115 if (msg.remain()) printf(",");
117 leave:
118 printf(" ]");
121 void hexdump(int size, char* data)
123 char ascii[20];
124 int padsize = (size + 15) & -16;
125 printf("size %d\n", size);
126 for (int i=0; i<padsize; ++i)
128 if ((i&15)==0)
130 printf("%4d ", i);
132 if (i >= size)
134 printf(" ");
135 ascii[i&15] = 0;
137 else
139 printf("%02x ", (unsigned char)data[i] & 255);
141 if (isprint(data[i])) ascii[i&15] = data[i];
142 else ascii[i&15] = '.';
144 if ((i&15)==15)
146 ascii[16] = 0;
147 printf(" |%s|\n", ascii);
149 else if ((i&3)==3)
151 printf(" ");
154 printf("\n");
157 void dumpOSC(int mode, int size, char* inData)
159 if (mode & 1)
161 if (strcmp(inData, "#bundle") == 0)
163 char* data = inData + 8;
164 printf("[ \"#bundle\", %lld, ", OSCtime(data));
165 data += 8;
166 char* dataEnd = inData + size;
167 while (data < dataEnd) {
168 int32 msgSize = OSCint(data);
169 data += sizeof(int32);
170 printf("\n ");
171 dumpOSCmsg(msgSize, data);
172 data += msgSize;
173 if (data < dataEnd) printf(",");
175 printf("\n]\n");
177 else
179 dumpOSCmsg(size, inData);
180 printf("\n");
184 if (mode & 2) hexdump(size, inData);
187 //////////////////////////////////////////////////////////////////////////////////////////////////////////
189 SC_CmdPort::SC_CmdPort()
193 SC_CmdPort::~SC_CmdPort()
197 //////////////////////////////////////////////////////////////////////////////////////////////////////////
199 SC_ComPort::SC_ComPort(int inPortNum)
200 : mPortNum(inPortNum), mSocket(-1)
204 SC_ComPort::~SC_ComPort()
206 #ifdef SC_WIN32
207 if (mSocket != -1) closesocket(mSocket);
208 #else
209 if (mSocket != -1) close(mSocket);
210 #endif
213 void* com_thread_func(void* arg);
214 void* com_thread_func(void* arg)
216 SC_CmdPort *thread = (SC_CmdPort*)arg;
217 void* result = thread->Run();
218 return result;
221 void SC_CmdPort::Start()
223 pthread_create (&mThread, NULL, com_thread_func, (void*)this);
226 //////////////////////////////////////////////////////////////////////////////////////////////////////////
228 SC_UdpInPort::SC_UdpInPort(int inPortNum)
229 : SC_ComPort(inPortNum)
231 if ((mSocket = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
232 throw std::runtime_error("failed to create udp socket\n");
236 int bufsize = 65536;
237 #ifdef SC_WIN32
238 setsockopt(mSocket, SOL_SOCKET, SO_SNDBUF, (char*)&bufsize, sizeof(bufsize));
239 #else
240 setsockopt(mSocket, SOL_SOCKET, SO_SNDBUF, &bufsize, sizeof(bufsize));
241 #endif
244 bzero((char *)&mBindSockAddr, sizeof(mBindSockAddr));
245 mBindSockAddr.sin_family = AF_INET;
246 mBindSockAddr.sin_addr.s_addr = htonl(INADDR_ANY);
248 bool bound = false;
249 for (int i=0; i<10 && !bound; ++i) {
250 mPortNum = mPortNum+i;
251 mBindSockAddr.sin_port = htons(mPortNum);
252 if (bind(mSocket, (struct sockaddr *)&mBindSockAddr, sizeof(mBindSockAddr)) >= 0) {
253 bound = true;
256 if (!bound) throw std::runtime_error("unable to bind udp socket\n");
257 Start();
260 SC_UdpInPort::~SC_UdpInPort()
262 #ifdef SC_WIN32
263 if (mSocket != -1) closesocket(mSocket);
264 #else
265 if (mSocket != -1) close(mSocket);
266 #endif
269 //////////////////////////////////////////////////////////////////////////////////////////////////////////
271 SC_UdpCustomInPort::SC_UdpCustomInPort(int inPortNum)
272 : SC_ComPort(inPortNum)
274 if ((mSocket = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
275 throw std::runtime_error("failed to create udp socket\n");
279 int bufsize = 65536;
280 #ifdef SC_WIN32
281 setsockopt(mSocket, SOL_SOCKET, SO_SNDBUF, (char*)&bufsize, sizeof(bufsize));
282 #else
283 setsockopt(mSocket, SOL_SOCKET, SO_SNDBUF, &bufsize, sizeof(bufsize));
284 #endif
287 bzero((char *)&mBindSockAddr, sizeof(mBindSockAddr));
288 mBindSockAddr.sin_family = AF_INET;
289 mBindSockAddr.sin_addr.s_addr = htonl(INADDR_ANY);
291 bool bound = false;
292 mBindSockAddr.sin_port = htons(mPortNum);
293 if (bind(mSocket, (struct sockaddr *)&mBindSockAddr, sizeof(mBindSockAddr)) >= 0) {
294 bound = true;
296 if (!bound) throw std::runtime_error("unable to bind udp socket\n");
297 Start();
300 SC_UdpCustomInPort::~SC_UdpCustomInPort()
302 mRunning.store(false);
303 pthread_join(mThread, NULL);
304 #ifdef SC_WIN32
305 if (mSocket != -1) closesocket(mSocket);
306 #else
307 if (mSocket != -1) close(mSocket);
308 #endif
312 //////////////////////////////////////////////////////////////////////////////////////////////////////////
314 void DumpReplyAddress(ReplyAddress *inReplyAddress)
316 printf("mSockAddrLen %d\n", inReplyAddress->mSockAddrLen);
317 printf("mSocket %d\n", inReplyAddress->mSocket);
318 #ifdef SC_DARWIN
319 printf("mSockAddr.sin_len %d\n", inReplyAddress->mSockAddr.sin_len);
320 #endif
321 printf("mSockAddr.sin_family %d\n", inReplyAddress->mSockAddr.sin_family);
322 printf("mSockAddr.sin_port %d\n", inReplyAddress->mSockAddr.sin_port);
323 printf("mSockAddr.sin_addr.s_addr %d\n", inReplyAddress->mSockAddr.sin_addr.s_addr);
324 printf("mReplyFunc %p\n", inReplyAddress->mReplyFunc);
328 int32 Hash(ReplyAddress *inReplyAddress)
330 int32 hash;
331 int32 *word = (int32*)&inReplyAddress->mSockAddr;
332 hash = Hash(inReplyAddress->mSockAddr.sin_addr.s_addr);
334 hash += inReplyAddress->mSockAddr.sin_len << 24
335 | inReplyAddress->mSockAddr.sin_family << 16
336 | inReplyAddress->mSockAddr.sin_port;
338 hash = Hash(hash);
339 return hash;
343 void udp_reply_func(struct ReplyAddress *addr, char* msg, int size);
344 void udp_reply_func(struct ReplyAddress *addr, char* msg, int size)
346 printf("->udp_reply_func\n");
347 int total = sendallto(addr->mSocket, msg, size, (sockaddr*)&addr->mSockAddr, addr->mSockAddrLen);
348 printf("<-udp_reply_func %d of %d\n", total, size);
349 if (total < size) DumpReplyAddress(addr);
352 ReplyFunc SC_UdpInPort::GetReplyFunc()
354 return udp_reply_func;
357 void* SC_UdpInPort::Run()
359 char buf[kTextBufSize];
360 OSC_Packet *packet = 0;
362 //printf("SC_UdpInPort::Run\n"); fflush(stdout);
364 while (true) {
365 if (!packet) {
366 packet = (OSC_Packet*)malloc(sizeof(OSC_Packet));
368 packet->mReplyAddr.mSockAddrLen = sizeof(sockaddr_in);
369 int size = recvfrom(mSocket, buf, kTextBufSize , 0,
370 (struct sockaddr *) &packet->mReplyAddr.mSockAddr, (socklen_t*)&packet->mReplyAddr.mSockAddrLen);
372 if (size > 0) {
373 //dumpOSC(3, size, buf);
374 //fflush(stdout);
376 char *data = (char*)malloc(size);
377 packet->mReplyAddr.mReplyFunc = udp_reply_func;
378 packet->mSize = size;
379 packet->mData = data;
380 packet->mReplyAddr.mSocket = mSocket;
381 memcpy(data, buf, size);
382 ProcessOSCPacket(packet, mPortNum);
383 packet = 0;
386 return 0;
389 ReplyFunc SC_UdpCustomInPort::GetReplyFunc()
391 return udp_reply_func;
394 void* SC_UdpCustomInPort::Run()
396 char buf[kTextBufSize];
397 OSC_Packet *packet = 0;
399 const int fd = mSocket;
400 const int max_fd = fd+1;
402 mRunning.store(true);
403 while (mRunning.load(boost::memory_order_consume)) {
404 fd_set rfds;
406 FD_ZERO( &rfds);
407 FD_SET(fd, &rfds);
409 struct timeval timeout;
410 timeout.tv_sec = 0;
411 timeout.tv_usec = 500000;
413 int n = select(max_fd, &rfds, 0, 0, &timeout);
414 if ((n > 0) && FD_ISSET(fd, &rfds)) {
415 if (!packet) {
416 packet = (OSC_Packet*)malloc(sizeof(OSC_Packet));
418 packet->mReplyAddr.mSockAddrLen = sizeof(sockaddr_in);
419 int size = recvfrom(mSocket, buf, kTextBufSize , 0,
420 (struct sockaddr *) &packet->mReplyAddr.mSockAddr, (socklen_t*)&packet->mReplyAddr.mSockAddrLen);
422 if (size > 0 && mRunning.load(boost::memory_order_consume)) {
423 //dumpOSC(3, size, buf);
424 //fflush(stdout);
426 char *data = (char*)malloc(size);
427 packet->mReplyAddr.mReplyFunc = udp_reply_func;
428 packet->mSize = size;
429 packet->mData = data;
430 packet->mReplyAddr.mSocket = mSocket;
431 memcpy(data, buf, size);
432 ProcessOSCPacket(packet, mPortNum);
433 packet = 0;
437 FreeOSCPacket(packet); // just in case
438 return 0;
441 //////////////////////////////////////////////////////////////////////////////////////////////////////////
443 SC_TcpInPort::SC_TcpInPort(int inPortNum, int inMaxConnections, int inBacklog)
444 : SC_ComPort(inPortNum), mConnectionAvailable(inMaxConnections),
445 mBacklog(inBacklog)
448 if((mSocket = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
449 throw std::runtime_error("failed to create tcp socket\n");
451 //setsockopt(mSocket, SOL_SOCKET, TCP_NODELAY);
453 bzero((char *)&mBindSockAddr, sizeof(mBindSockAddr));
454 mBindSockAddr.sin_family = AF_INET;
455 mBindSockAddr.sin_addr.s_addr = htonl(INADDR_ANY);
456 mBindSockAddr.sin_port = htons(mPortNum);
458 if(bind(mSocket, (struct sockaddr *)&mBindSockAddr, sizeof(mBindSockAddr)) < 0)
460 throw std::runtime_error("unable to bind tcp socket\n");
462 if(listen(mSocket, mBacklog) < 0)
464 throw std::runtime_error("unable to listen tcp socket\n");
467 Start();
470 void* SC_TcpInPort::Run()
472 while (true)
474 mConnectionAvailable.Acquire();
475 struct sockaddr_in address; /* Internet socket address stuct */
476 int addressSize=sizeof(struct sockaddr_in);
477 int socket = accept(mSocket,(struct sockaddr*)&address,(socklen_t*)&addressSize);
478 if (socket < 0) {
479 mConnectionAvailable.Release();
480 } else {
481 new SC_TcpConnectionPort(this, socket);
484 return 0;
487 void SC_TcpInPort::ConnectionTerminated()
489 mConnectionAvailable.Release();
492 void null_reply_func(struct ReplyAddress *addr, char* msg, int size);
493 void null_reply_func(struct ReplyAddress *addr, char* msg, int size)
497 ReplyFunc SC_TcpInPort::GetReplyFunc()
499 return null_reply_func;
502 //////////////////////////////////////////////////////////////////////////////////////////////////////////
504 SC_TcpConnectionPort::SC_TcpConnectionPort(SC_TcpInPort *inParent, int inSocket)
505 : SC_ComPort(0), mParent(inParent)
507 mSocket = inSocket;
508 Start();
511 SC_TcpConnectionPort::~SC_TcpConnectionPort()
513 #ifdef SC_WIN32
514 closesocket(mSocket);
515 #else
516 close(mSocket);
517 #endif
518 mParent->ConnectionTerminated();
521 void tcp_reply_func(struct ReplyAddress *addr, char* msg, int size);
522 void tcp_reply_func(struct ReplyAddress *addr, char* msg, int size)
524 sendall(addr->mSocket, msg, size);
527 ReplyFunc SC_TcpConnectionPort::GetReplyFunc()
529 return tcp_reply_func;
532 extern const char* gPassword;
534 void* SC_TcpConnectionPort::Run()
536 OSC_Packet *packet = 0;
537 // wait for login message
538 int32 size;
539 int32 msglen;
541 while (true) {
542 if (!packet) {
543 packet = (OSC_Packet*)malloc(sizeof(OSC_Packet));
545 size = recvall(mSocket, &msglen, sizeof(int32));
546 if (size < 0) goto leave;
548 // sk: msglen is in network byte order
549 msglen = ntohl(msglen);
551 char *data = (char*)malloc(msglen);
552 size = recvall(mSocket, data, msglen);
553 if (size < msglen) goto leave;
555 packet->mReplyAddr.mReplyFunc = tcp_reply_func;
556 packet->mSize = msglen;
557 packet->mData = data;
558 packet->mReplyAddr.mSocket = mSocket;
559 ProcessOSCPacket(packet, mPortNum);
560 packet = 0;
562 leave:
563 delete this; // ohh this could cause a crash if a reply tries to access it..
564 return 0;
567 //////////////////////////////////////////////////////////////////////////////////////////////////////////
569 #ifndef SC_WIN32
570 # include <sys/select.h>
571 #endif
572 //SC_WIN32
574 SC_TcpClientPort::SC_TcpClientPort(int inSocket, ClientNotifyFunc notifyFunc, void *clientData)
575 : SC_ComPort(0),
576 mClientNotifyFunc(notifyFunc),
577 mClientData(clientData)
579 mSocket = inSocket;
580 socklen_t sockAddrLen = sizeof(mReplySockAddr);
582 if (getpeername(mSocket, (struct sockaddr*)&mReplySockAddr, &sockAddrLen) == -1) {
583 memset(&mReplySockAddr, 0, sizeof(mReplySockAddr));
584 mReplySockAddr.sin_family = AF_INET;
585 mReplySockAddr.sin_addr.s_addr = htonl(INADDR_NONE);
586 mReplySockAddr.sin_port = htons(0);
589 #if HAVE_SO_NOSIGPIPE
590 int sockopt = 1;
591 setsockopt(mSocket, SOL_SOCKET, SO_NOSIGPIPE, &sockopt, sizeof(sockopt));
592 #endif // HAVE_SO_NOSIGPIPE
594 if (pipe(mCmdFifo) == -1) {
595 mCmdFifo[0] = mCmdFifo[1] = -1;
598 Start();
601 SC_TcpClientPort::~SC_TcpClientPort()
603 #ifdef SC_WIN32
604 closesocket(mCmdFifo[0]);
605 closesocket(mCmdFifo[1]);
606 closesocket(mSocket);
607 #else
608 close(mCmdFifo[0]);
609 close(mCmdFifo[1]);
610 close(mSocket);
611 #endif
614 void* SC_TcpClientPort::Run()
616 OSC_Packet *packet = 0;
617 int32 size;
618 int32 msglen;
620 int cmdfd = mCmdFifo[0];
621 int sockfd = mSocket;
622 int nfds = sc_max(cmdfd, sockfd) + 1;
624 bool cmdClose = false;
626 pthread_detach(mThread);
628 while (true) {
629 fd_set rfds;
630 FD_ZERO(&rfds);
631 FD_SET(cmdfd, &rfds);
632 FD_SET(sockfd, &rfds);
634 if ((select(nfds, &rfds, 0, 0, 0) == -1) || (cmdClose = FD_ISSET(cmdfd, &rfds)))
635 goto leave;
637 if (!FD_ISSET(sockfd, &rfds))
638 continue;
640 packet = (OSC_Packet*)malloc(sizeof(OSC_Packet));
641 if (!packet) goto leave;
643 packet->mData = 0;
645 size = recvall(sockfd, &msglen, sizeof(int32));
646 if (size < (int32)sizeof(int32)) goto leave;
648 // msglen is in network byte order
649 msglen = ntohl(msglen);
651 packet->mData = (char*)malloc(msglen);
652 if (!packet->mData) goto leave;
654 size = recvall(sockfd, packet->mData, msglen);
655 if (size < msglen) goto leave;
657 memcpy(&packet->mReplyAddr.mSockAddr, &mReplySockAddr, sizeof(mReplySockAddr));
658 packet->mReplyAddr.mSockAddrLen = sizeof(mReplySockAddr);
659 packet->mReplyAddr.mSocket = sockfd;
660 packet->mReplyAddr.mReplyFunc = tcp_reply_func;
661 packet->mSize = msglen;
662 ProcessOSCPacket(packet, mPortNum);
664 packet = 0;
667 leave:
668 if (packet) {
669 free(packet->mData);
670 free(packet);
672 // Only call notify function when not closed explicitly
673 if (!cmdClose && mClientNotifyFunc) {
674 (*mClientNotifyFunc)(mClientData);
676 delete this;
677 return 0;
680 void SC_TcpClientPort::Close()
682 char cmd = 0;
683 #ifdef SC_WIN32
684 win32_pipewrite(mCmdFifo[1], &cmd, sizeof(cmd));
685 #else
686 size_t written = write(mCmdFifo[1], &cmd, sizeof(cmd));
687 if (written != sizeof(cmd))
688 post("warning: invalid write in SC_TcpClientPort::Close");
689 #endif
692 ReplyFunc SC_TcpClientPort::GetReplyFunc()
694 return tcp_reply_func;
697 //////////////////////////////////////////////////////////////////////////////////////////////////////////
699 int recvall(int socket, void *msg, size_t len)
701 size_t total = 0;
702 while (total < len)
704 #ifdef SC_WIN32
705 int numbytes = recv(socket, reinterpret_cast<char*>(msg), len - total, 0);
706 #else
707 int numbytes = recv(socket, msg, len - total, 0);
708 #endif
709 if (numbytes <= 0) return total;
710 total += numbytes;
711 msg = (void*)((char*)msg + numbytes);
713 return total;
716 int recvallfrom(int socket, void *msg, size_t len, struct sockaddr *fromaddr, int addrlen)
718 size_t total = 0;
719 while (total < len)
721 socklen_t addrlen2 = addrlen;
722 #ifdef SC_WIN32
723 int numbytes = recvfrom(socket, reinterpret_cast<char*>(msg), len - total, 0, fromaddr, &addrlen2);
724 #else
725 int numbytes = recvfrom(socket, msg, len - total, 0, fromaddr, &addrlen2);
726 #endif
727 if (numbytes < 0) return total;
728 total += numbytes;
729 msg = (void*)((char*)msg + numbytes);
731 return total;
734 int sendallto(int socket, const void *msg, size_t len, struct sockaddr *toaddr, int addrlen)
736 size_t total = 0;
737 while (total < len)
739 #ifdef SC_WIN32
740 int numbytes = sendto(socket, reinterpret_cast<const char*>(msg), len - total, 0, toaddr, addrlen);
741 #else
742 int numbytes = sendto(socket, msg, len - total, 0, toaddr, addrlen);
743 #endif
744 //printf("numbytes %d total %d len %d\n", numbytes, total, len);
745 if (numbytes < 0) {
746 printf("******* errno %d %s\n", errno, strerror(errno));
747 return total;
749 total += numbytes;
750 msg = (void*)((char*)msg + numbytes);
752 return total;
755 int sendall(int socket, const void *msg, size_t len)
757 size_t total = 0;
758 while (total < len)
760 #if HAVE_MSG_NOSIGNAL
761 int flags = MSG_NOSIGNAL;
762 #else
763 int flags = 0;
764 #endif // HAVE_MSG_NOSIGNAL
765 #ifdef SC_WIN32
766 int numbytes = send(socket, reinterpret_cast<const char*>(msg), len - total, flags);
767 #else
768 int numbytes = send(socket, msg, len - total, flags);
769 #endif
770 if (numbytes < 0) return total;
771 total += numbytes;
772 msg = (void*)((char*)msg + numbytes);
774 return total;
777 //////////////////////////////////////////////////////////////////////////////////////////////////////////