1 /*
2 oscpack -- Open Sound Control (OSC) packet manipulation library
3 http://www.rossbencina.com/code/oscpack
4
5 Copyright (c) 2004-2013 Ross Bencina <rossb@audiomulch.com>
6
7 Permission is hereby granted, free of charge, to any person obtaining
8 a copy of this software and associated documentation files
9 (the "Software"), to deal in the Software without restriction,
10 including without limitation the rights to use, copy, modify, merge,
11 publish, distribute, sublicense, and/or sell copies of the Software,
12 and to permit persons to whom the Software is furnished to do so,
13 subject to the following conditions:
14
15 The above copyright notice and this permission notice shall be
16 included in all copies or substantial portions of the Software.
17
18 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
19 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
21 IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
22 ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
23 CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
24 WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25 */
26
27 /*
28 The text above constitutes the entire oscpack license; however,
29 the oscpack developer(s) also make the following non-binding requests:
30
31 Any person wishing to distribute modifications to the Software is
32 requested to send the modifications to the original developer so that
33 they can be incorporated into the canonical version. It is also
34 requested that these non-binding requests be included whenever the
35 above license is reproduced.
36 */
37
38 #include "UdpSocket.h"
39
40 #include <errno.h>
41 #include <math.h>
42 #include <netdb.h>
43 #include <netinet/in.h> // for sockaddr_in
44 #include <pthread.h>
45 #include <signal.h>
46 #include <stdio.h>
47 #include <stdlib.h>
48 #include <string.h>
49 #include <sys/socket.h>
50 #include <sys/time.h>
51 #include <sys/types.h>
52 #include <unistd.h>
53
54 #include <algorithm>
55 #include <cassert>
56 #include <cstring> // for memset
57 #include <stdexcept>
58 #include <vector>
59
60 #include "PacketListener.h"
61 #include "TimerListener.h"
62
63 #if defined(__APPLE__) && !defined(_SOCKLEN_T)
64 // pre system 10.3 didn't have socklen_t
65 typedef ssize_t socklen_t;
66 #endif
67
SockaddrFromIpEndpointName(struct sockaddr_in & sockAddr,const IpEndpointName & endpoint)68 static void SockaddrFromIpEndpointName(struct sockaddr_in &sockAddr,
69 const IpEndpointName &endpoint)
70 {
71 std::memset((char *)&sockAddr, 0, sizeof(sockAddr));
72 sockAddr.sin_family = AF_INET;
73
74 sockAddr.sin_addr.s_addr = (endpoint.address == IpEndpointName::ANY_ADDRESS)
75 ? INADDR_ANY
76 : htonl(endpoint.address);
77
78 sockAddr.sin_port =
79 (endpoint.port == IpEndpointName::ANY_PORT) ? 0 : htons(endpoint.port);
80 }
81
IpEndpointNameFromSockaddr(const struct sockaddr_in & sockAddr)82 static IpEndpointName IpEndpointNameFromSockaddr(
83 const struct sockaddr_in &sockAddr)
84 {
85 return IpEndpointName((sockAddr.sin_addr.s_addr == INADDR_ANY)
86 ? IpEndpointName::ANY_ADDRESS
87 : ntohl(sockAddr.sin_addr.s_addr),
88 (sockAddr.sin_port == 0) ? IpEndpointName::ANY_PORT
89 : ntohs(sockAddr.sin_port));
90 }
91
92 class UdpSocket::Implementation
93 {
94 bool isBound_;
95 bool isConnected_;
96
97 int socket_;
98 struct sockaddr_in connectedAddr_;
99 struct sockaddr_in sendToAddr_;
100
101 public:
Implementation()102 Implementation() : isBound_(false), isConnected_(false), socket_(-1)
103 {
104 if ((socket_ = socket(AF_INET, SOCK_DGRAM, 0)) == -1)
105 {
106 throw std::runtime_error("unable to create udp socket\n");
107 }
108
109 std::memset(&sendToAddr_, 0, sizeof(sendToAddr_));
110 sendToAddr_.sin_family = AF_INET;
111 }
112
~Implementation()113 ~Implementation()
114 {
115 if (socket_ != -1) close(socket_);
116 }
117
SetEnableBroadcast(bool enableBroadcast)118 void SetEnableBroadcast(bool enableBroadcast)
119 {
120 int broadcast = (enableBroadcast) ? 1 : 0; // int on posix
121 setsockopt(socket_, SOL_SOCKET, SO_BROADCAST, &broadcast,
122 sizeof(broadcast));
123 }
124
SetAllowReuse(bool allowReuse)125 void SetAllowReuse(bool allowReuse)
126 {
127 int reuseAddr = (allowReuse) ? 1 : 0; // int on posix
128 setsockopt(socket_, SOL_SOCKET, SO_REUSEADDR, &reuseAddr,
129 sizeof(reuseAddr));
130
131 #ifdef __APPLE__
132 // needed also for OS X - enable multiple listeners for a single port on
133 // same network interface
134 int reusePort = (allowReuse) ? 1 : 0; // int on posix
135 setsockopt(socket_, SOL_SOCKET, SO_REUSEPORT, &reusePort,
136 sizeof(reusePort));
137 #endif
138 }
139
LocalEndpointFor(const IpEndpointName & remoteEndpoint) const140 IpEndpointName LocalEndpointFor(const IpEndpointName &remoteEndpoint) const
141 {
142 assert(isBound_);
143
144 // first connect the socket to the remote server
145
146 struct sockaddr_in connectSockAddr;
147 SockaddrFromIpEndpointName(connectSockAddr, remoteEndpoint);
148
149 if (connect(socket_, (struct sockaddr *)&connectSockAddr,
150 sizeof(connectSockAddr)) < 0)
151 {
152 throw std::runtime_error("unable to connect udp socket\n");
153 }
154
155 // get the address
156
157 struct sockaddr_in sockAddr;
158 std::memset((char *)&sockAddr, 0, sizeof(sockAddr));
159 socklen_t length = sizeof(sockAddr);
160 if (getsockname(socket_, (struct sockaddr *)&sockAddr, &length) < 0)
161 {
162 throw std::runtime_error("unable to getsockname\n");
163 }
164
165 if (isConnected_)
166 {
167 // reconnect to the connected address
168
169 if (connect(socket_, (struct sockaddr *)&connectedAddr_,
170 sizeof(connectedAddr_)) < 0)
171 {
172 throw std::runtime_error("unable to connect udp socket\n");
173 }
174 }
175 else
176 {
177 // unconnect from the remote address
178
179 struct sockaddr_in unconnectSockAddr;
180 std::memset((char *)&unconnectSockAddr, 0, sizeof(unconnectSockAddr));
181 unconnectSockAddr.sin_family = AF_UNSPEC;
182 // address fields are zero
183 int connectResult =
184 connect(socket_, (struct sockaddr *)&unconnectSockAddr,
185 sizeof(unconnectSockAddr));
186 if (connectResult < 0 && errno != EAFNOSUPPORT)
187 {
188 throw std::runtime_error("unable to un-connect udp socket\n");
189 }
190 }
191
192 return IpEndpointNameFromSockaddr(sockAddr);
193 }
194
Connect(const IpEndpointName & remoteEndpoint)195 void Connect(const IpEndpointName &remoteEndpoint)
196 {
197 SockaddrFromIpEndpointName(connectedAddr_, remoteEndpoint);
198
199 if (connect(socket_, (struct sockaddr *)&connectedAddr_,
200 sizeof(connectedAddr_)) < 0)
201 {
202 throw std::runtime_error("unable to connect udp socket\n");
203 }
204
205 isConnected_ = true;
206 }
207
Send(const char * data,std::size_t size)208 void Send(const char *data, std::size_t size)
209 {
210 assert(isConnected_);
211
212 send(socket_, data, size, 0);
213 }
214
SendTo(const IpEndpointName & remoteEndpoint,const char * data,std::size_t size)215 void SendTo(const IpEndpointName &remoteEndpoint, const char *data,
216 std::size_t size)
217 {
218 sendToAddr_.sin_addr.s_addr = htonl(remoteEndpoint.address);
219 sendToAddr_.sin_port = htons(remoteEndpoint.port);
220
221 sendto(socket_, data, size, 0, (sockaddr *)&sendToAddr_,
222 sizeof(sendToAddr_));
223 }
224
Bind(const IpEndpointName & localEndpoint)225 void Bind(const IpEndpointName &localEndpoint)
226 {
227 struct sockaddr_in bindSockAddr;
228 SockaddrFromIpEndpointName(bindSockAddr, localEndpoint);
229
230 if (bind(socket_, (struct sockaddr *)&bindSockAddr, sizeof(bindSockAddr)) <
231 0)
232 {
233 throw std::runtime_error("unable to bind udp socket\n");
234 }
235
236 isBound_ = true;
237 }
238
IsBound() const239 bool IsBound() const { return isBound_; }
240
ReceiveFrom(IpEndpointName & remoteEndpoint,char * data,std::size_t size)241 std::size_t ReceiveFrom(IpEndpointName &remoteEndpoint, char *data,
242 std::size_t size)
243 {
244 assert(isBound_);
245
246 struct sockaddr_in fromAddr;
247 socklen_t fromAddrLen = sizeof(fromAddr);
248
249 ssize_t result =
250 recvfrom(socket_, data, size, 0, (struct sockaddr *)&fromAddr,
251 (socklen_t *)&fromAddrLen);
252 if (result < 0) return 0;
253
254 remoteEndpoint.address = ntohl(fromAddr.sin_addr.s_addr);
255 remoteEndpoint.port = ntohs(fromAddr.sin_port);
256
257 return (std::size_t)result;
258 }
259
Socket()260 int Socket() { return socket_; }
261 };
262
UdpSocket()263 UdpSocket::UdpSocket() { impl_ = new Implementation(); }
264
~UdpSocket()265 UdpSocket::~UdpSocket() { delete impl_; }
266
SetEnableBroadcast(bool enableBroadcast)267 void UdpSocket::SetEnableBroadcast(bool enableBroadcast)
268 {
269 impl_->SetEnableBroadcast(enableBroadcast);
270 }
271
SetAllowReuse(bool allowReuse)272 void UdpSocket::SetAllowReuse(bool allowReuse)
273 {
274 impl_->SetAllowReuse(allowReuse);
275 }
276
LocalEndpointFor(const IpEndpointName & remoteEndpoint) const277 IpEndpointName UdpSocket::LocalEndpointFor(
278 const IpEndpointName &remoteEndpoint) const
279 {
280 return impl_->LocalEndpointFor(remoteEndpoint);
281 }
282
Connect(const IpEndpointName & remoteEndpoint)283 void UdpSocket::Connect(const IpEndpointName &remoteEndpoint)
284 {
285 impl_->Connect(remoteEndpoint);
286 }
287
Send(const char * data,std::size_t size)288 void UdpSocket::Send(const char *data, std::size_t size)
289 {
290 impl_->Send(data, size);
291 }
292
SendTo(const IpEndpointName & remoteEndpoint,const char * data,std::size_t size)293 void UdpSocket::SendTo(const IpEndpointName &remoteEndpoint, const char *data,
294 std::size_t size)
295 {
296 impl_->SendTo(remoteEndpoint, data, size);
297 }
298
Bind(const IpEndpointName & localEndpoint)299 void UdpSocket::Bind(const IpEndpointName &localEndpoint)
300 {
301 impl_->Bind(localEndpoint);
302 }
303
IsBound() const304 bool UdpSocket::IsBound() const { return impl_->IsBound(); }
305
ReceiveFrom(IpEndpointName & remoteEndpoint,char * data,std::size_t size)306 std::size_t UdpSocket::ReceiveFrom(IpEndpointName &remoteEndpoint, char *data,
307 std::size_t size)
308 {
309 return impl_->ReceiveFrom(remoteEndpoint, data, size);
310 }
311
312 struct AttachedTimerListener
313 {
AttachedTimerListenerAttachedTimerListener314 AttachedTimerListener(int id, int p, TimerListener *tl)
315 : initialDelayMs(id), periodMs(p), listener(tl)
316 {
317 }
318 int initialDelayMs;
319 int periodMs;
320 TimerListener *listener;
321 };
322
CompareScheduledTimerCalls(const std::pair<double,AttachedTimerListener> & lhs,const std::pair<double,AttachedTimerListener> & rhs)323 static bool CompareScheduledTimerCalls(
324 const std::pair<double, AttachedTimerListener> &lhs,
325 const std::pair<double, AttachedTimerListener> &rhs)
326 {
327 return lhs.first < rhs.first;
328 }
329
330 SocketReceiveMultiplexer *multiplexerInstanceToAbortWithSigInt_ = 0;
331
332 extern "C" /*static*/ void InterruptSignalHandler(int);
InterruptSignalHandler(int)333 /*static*/ void InterruptSignalHandler(int)
334 {
335 multiplexerInstanceToAbortWithSigInt_->AsynchronousBreak();
336 signal(SIGINT, SIG_DFL);
337 }
338
339 class SocketReceiveMultiplexer::Implementation
340 {
341 std::vector<std::pair<PacketListener *, UdpSocket *> > socketListeners_;
342 std::vector<AttachedTimerListener> timerListeners_;
343
344 volatile bool break_;
345 int breakPipe_[2]; // [0] is the reader descriptor and [1] the writer
346
GetCurrentTimeMs() const347 double GetCurrentTimeMs() const
348 {
349 struct timeval t;
350
351 gettimeofday(&t, 0);
352
353 return ((double)t.tv_sec * 1000.) + ((double)t.tv_usec / 1000.);
354 }
355
356 public:
Implementation()357 Implementation()
358 {
359 if (pipe(breakPipe_) != 0)
360 throw std::runtime_error("creation of asynchronous break pipes failed\n");
361 }
362
~Implementation()363 ~Implementation()
364 {
365 close(breakPipe_[0]);
366 close(breakPipe_[1]);
367 }
368
AttachSocketListener(UdpSocket * socket,PacketListener * listener)369 void AttachSocketListener(UdpSocket *socket, PacketListener *listener)
370 {
371 assert(std::find(socketListeners_.begin(), socketListeners_.end(),
372 std::make_pair(listener, socket)) ==
373 socketListeners_.end());
374 // we don't check that the same socket has been added multiple times, even
375 // though this is an error
376 socketListeners_.push_back(std::make_pair(listener, socket));
377 }
378
DetachSocketListener(UdpSocket * socket,PacketListener * listener)379 void DetachSocketListener(UdpSocket *socket, PacketListener *listener)
380 {
381 std::vector<std::pair<PacketListener *, UdpSocket *> >::iterator i =
382 std::find(socketListeners_.begin(), socketListeners_.end(),
383 std::make_pair(listener, socket));
384 assert(i != socketListeners_.end());
385
386 socketListeners_.erase(i);
387 }
388
AttachPeriodicTimerListener(int periodMilliseconds,TimerListener * listener)389 void AttachPeriodicTimerListener(int periodMilliseconds,
390 TimerListener *listener)
391 {
392 timerListeners_.push_back(AttachedTimerListener(
393 periodMilliseconds, periodMilliseconds, listener));
394 }
395
AttachPeriodicTimerListener(int initialDelayMilliseconds,int periodMilliseconds,TimerListener * listener)396 void AttachPeriodicTimerListener(int initialDelayMilliseconds,
397 int periodMilliseconds,
398 TimerListener *listener)
399 {
400 timerListeners_.push_back(AttachedTimerListener(
401 initialDelayMilliseconds, periodMilliseconds, listener));
402 }
403
DetachPeriodicTimerListener(TimerListener * listener)404 void DetachPeriodicTimerListener(TimerListener *listener)
405 {
406 std::vector<AttachedTimerListener>::iterator i = timerListeners_.begin();
407 while (i != timerListeners_.end())
408 {
409 if (i->listener == listener) break;
410 ++i;
411 }
412
413 assert(i != timerListeners_.end());
414
415 timerListeners_.erase(i);
416 }
417
Run()418 void Run()
419 {
420 break_ = false;
421 char *data = 0;
422
423 try
424 {
425 // configure the master fd_set for select()
426
427 fd_set masterfds, tempfds;
428 FD_ZERO(&masterfds);
429 FD_ZERO(&tempfds);
430
431 // in addition to listening to the inbound sockets we
432 // also listen to the asynchronous break pipe, so that AsynchronousBreak()
433 // can break us out of select() from another thread.
434 FD_SET(breakPipe_[0], &masterfds);
435 int fdmax = breakPipe_[0];
436
437 for (std::vector<std::pair<PacketListener *, UdpSocket *> >::iterator i =
438 socketListeners_.begin();
439 i != socketListeners_.end(); ++i)
440 {
441 if (fdmax < i->second->impl_->Socket())
442 fdmax = i->second->impl_->Socket();
443 FD_SET(i->second->impl_->Socket(), &masterfds);
444 }
445
446 // configure the timer queue
447 double currentTimeMs = GetCurrentTimeMs();
448
449 // expiry time ms, listener
450 std::vector<std::pair<double, AttachedTimerListener> > timerQueue_;
451 for (std::vector<AttachedTimerListener>::iterator i =
452 timerListeners_.begin();
453 i != timerListeners_.end(); ++i)
454 timerQueue_.push_back(
455 std::make_pair(currentTimeMs + i->initialDelayMs, *i));
456 std::sort(timerQueue_.begin(), timerQueue_.end(),
457 CompareScheduledTimerCalls);
458
459 const int MAX_BUFFER_SIZE = 4098;
460 data = new char[MAX_BUFFER_SIZE];
461 IpEndpointName remoteEndpoint;
462
463 struct timeval timeout;
464
465 while (!break_)
466 {
467 tempfds = masterfds;
468
469 struct timeval *timeoutPtr = 0;
470 if (!timerQueue_.empty())
471 {
472 double timeoutMs = timerQueue_.front().first - GetCurrentTimeMs();
473 if (timeoutMs < 0) timeoutMs = 0;
474
475 long timoutSecondsPart = (long)(timeoutMs * .001);
476 timeout.tv_sec = (time_t)timoutSecondsPart;
477 // 1000000 microseconds in a second
478 timeout.tv_usec =
479 (suseconds_t)((timeoutMs - (timoutSecondsPart * 1000)) * 1000);
480 timeoutPtr = &timeout;
481 }
482
483 if (select(fdmax + 1, &tempfds, 0, 0, timeoutPtr) < 0)
484 {
485 if (break_)
486 {
487 break;
488 }
489 else if (errno == EINTR)
490 {
491 // on returning an error, select() doesn't clear tempfds.
492 // so tempfds would remain all set, which would cause read(
493 // breakPipe_[0]... below to block indefinitely. therefore if select
494 // returns EINTR we restart the while() loop instead of continuing
495 // on to below.
496 continue;
497 }
498 else
499 {
500 throw std::runtime_error("select failed\n");
501 }
502 }
503
504 if (FD_ISSET(breakPipe_[0], &tempfds))
505 {
506 // clear pending data from the asynchronous break pipe
507 char c;
508 read(breakPipe_[0], &c, 1);
509 }
510
511 if (break_) break;
512
513 for (std::vector<std::pair<PacketListener *, UdpSocket *> >::iterator
514 i = socketListeners_.begin();
515 i != socketListeners_.end(); ++i)
516 {
517 if (FD_ISSET(i->second->impl_->Socket(), &tempfds))
518 {
519 std::size_t size =
520 i->second->ReceiveFrom(remoteEndpoint, data, MAX_BUFFER_SIZE);
521 if (size > 0)
522 {
523 i->first->ProcessPacket(data, (int)size, remoteEndpoint);
524 if (break_) break;
525 }
526 }
527 }
528
529 // execute any expired timers
530 currentTimeMs = GetCurrentTimeMs();
531 bool resort = false;
532 for (std::vector<std::pair<double, AttachedTimerListener> >::iterator
533 i = timerQueue_.begin();
534 i != timerQueue_.end() && i->first <= currentTimeMs; ++i)
535 {
536 i->second.listener->TimerExpired();
537 if (break_) break;
538
539 i->first += i->second.periodMs;
540 resort = true;
541 }
542 if (resort)
543 std::sort(timerQueue_.begin(), timerQueue_.end(),
544 CompareScheduledTimerCalls);
545 }
546
547 delete[] data;
548 }
549 catch (...)
550 {
551 if (data) delete[] data;
552 throw;
553 }
554 }
555
Break()556 void Break() { break_ = true; }
557
AsynchronousBreak()558 void AsynchronousBreak()
559 {
560 break_ = true;
561
562 // Send a termination message to the asynchronous break pipe, so select()
563 // will return
564 write(breakPipe_[1], "!", 1);
565 }
566 };
567
SocketReceiveMultiplexer()568 SocketReceiveMultiplexer::SocketReceiveMultiplexer()
569 {
570 impl_ = new Implementation();
571 }
572
~SocketReceiveMultiplexer()573 SocketReceiveMultiplexer::~SocketReceiveMultiplexer() { delete impl_; }
574
AttachSocketListener(UdpSocket * socket,PacketListener * listener)575 void SocketReceiveMultiplexer::AttachSocketListener(UdpSocket *socket,
576 PacketListener *listener)
577 {
578 impl_->AttachSocketListener(socket, listener);
579 }
580
DetachSocketListener(UdpSocket * socket,PacketListener * listener)581 void SocketReceiveMultiplexer::DetachSocketListener(UdpSocket *socket,
582 PacketListener *listener)
583 {
584 impl_->DetachSocketListener(socket, listener);
585 }
586
AttachPeriodicTimerListener(int periodMilliseconds,TimerListener * listener)587 void SocketReceiveMultiplexer::AttachPeriodicTimerListener(
588 int periodMilliseconds, TimerListener *listener)
589 {
590 impl_->AttachPeriodicTimerListener(periodMilliseconds, listener);
591 }
592
AttachPeriodicTimerListener(int initialDelayMilliseconds,int periodMilliseconds,TimerListener * listener)593 void SocketReceiveMultiplexer::AttachPeriodicTimerListener(
594 int initialDelayMilliseconds, int periodMilliseconds,
595 TimerListener *listener)
596 {
597 impl_->AttachPeriodicTimerListener(initialDelayMilliseconds,
598 periodMilliseconds, listener);
599 }
600
DetachPeriodicTimerListener(TimerListener * listener)601 void SocketReceiveMultiplexer::DetachPeriodicTimerListener(
602 TimerListener *listener)
603 {
604 impl_->DetachPeriodicTimerListener(listener);
605 }
606
Run()607 void SocketReceiveMultiplexer::Run() { impl_->Run(); }
608
RunUntilSigInt()609 void SocketReceiveMultiplexer::RunUntilSigInt()
610 {
611 assert(multiplexerInstanceToAbortWithSigInt_ ==
612 0); /* at present we support only one multiplexer instance running
613 until sig int */
614 multiplexerInstanceToAbortWithSigInt_ = this;
615 signal(SIGINT, InterruptSignalHandler);
616 impl_->Run();
617 signal(SIGINT, SIG_DFL);
618 multiplexerInstanceToAbortWithSigInt_ = 0;
619 }
620
Break()621 void SocketReceiveMultiplexer::Break() { impl_->Break(); }
622
AsynchronousBreak()623 void SocketReceiveMultiplexer::AsynchronousBreak()
624 {
625 impl_->AsynchronousBreak();
626 }
627