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