Merge branch 'master' into windows
[ardour.git] / libs / midi++2 / ipmidi_port.cc
1 /*
2     Copyright (C) 2012 Paul Davis
3
4     Using code from Rui Nuno Capela's qmidinet as inspiration.
5     
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.
10
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.
15
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., 675 Mass Ave, Cambridge, MA 02139, USA.
19
20     $Id: port.cc 12065 2012-04-23 16:23:48Z paul $
21 */
22 #include <iostream>
23 #include <cstdio>
24 #include <fcntl.h>
25 #include <errno.h>
26 #include <stdlib.h>
27 #include <string.h>
28 #ifdef   COMPILER_MSVC
29 #undef   O_NONBLOCK
30 #define  O_NONBLOCK 0
31 #endif
32 #if defined(PLATFORM_WINDOWS)
33 #include <winsock2.h>
34 #else
35 #include <netdb.h>
36 #endif
37
38 #if defined(PLATFORM_WINDOWS)
39 static WSADATA g_wsaData;
40 typedef int socklen_t;
41 #else
42 #include <unistd.h>
43 #include <sys/ioctl.h>
44 inline void closesocket(int s) { ::close(s); }
45 #endif
46
47 #include <jack/jack.h>
48 #include <jack/midiport.h>
49
50 #include "pbd/xml++.h"
51 #include "pbd/error.h"
52 #include "pbd/failed_constructor.h"
53 #include "pbd/convert.h"
54 #include "pbd/compose.h"
55
56 #include "midi++/types.h"
57 #include "midi++/ipmidi_port.h"
58 #include "midi++/channel.h"
59
60 using namespace MIDI;
61 using namespace std;
62 using namespace PBD;
63
64 IPMIDIPort::IPMIDIPort (int base_port, const string& iface)
65         : Port (string_compose ("IPmidi@%1", base_port), Port::Flags (Port::IsInput|Port::IsOutput))
66         , sockin (-1)
67         , sockout (-1)
68 {
69         if (!open_sockets (base_port, iface)) {
70                 throw (failed_constructor ());
71         }
72 }
73
74 IPMIDIPort::IPMIDIPort (const XMLNode& node)
75         : Port (node)
76 {
77         /* base class does not class set_state() */
78         set_state (node);
79 }
80
81 IPMIDIPort::~IPMIDIPort ()
82 {
83         close_sockets ();
84 }
85
86 int
87 IPMIDIPort::selectable () const
88
89         return sockin; 
90 }
91
92 XMLNode&
93 IPMIDIPort::get_state () const
94 {
95         return Port::get_state ();
96 }
97
98 void
99 IPMIDIPort::set_state (const XMLNode& node)
100 {
101         Port::set_state (node);
102 }
103
104 void
105 IPMIDIPort::close_sockets ()
106 {
107         if (sockin >= 0) {
108                 ::closesocket (sockin);
109                 sockin = -1;
110         }
111         
112         if (sockout >= 0) {
113                 ::closesocket (sockout);
114                 sockout = -1;
115         }
116 }
117
118 static bool 
119 get_address (int sock, struct in_addr *inaddr, const string& ifname )
120 {
121         // Get interface address from supplied name.
122
123 #if !defined(PLATFORM_WINDOWS)
124         struct ifreq ifr;
125         ::strncpy(ifr.ifr_name, ifname.c_str(), sizeof(ifr.ifr_name));
126
127         if (::ioctl(sock, SIOCGIFFLAGS, (char *) &ifr)) {
128                 ::perror("ioctl(SIOCGIFFLAGS)");
129                 return false;
130         }
131
132         if ((ifr.ifr_flags & IFF_UP) == 0) {
133                 error << string_compose ("interface %1 is down", ifname) << endmsg;
134                 return false;
135         }
136
137         if (::ioctl(sock, SIOCGIFADDR, (char *) &ifr)) {
138                 ::perror("ioctl(SIOCGIFADDR)");
139                 return false;
140         }
141
142         struct sockaddr_in sa;
143         ::memcpy(&sa, &ifr.ifr_addr, sizeof(struct sockaddr_in));
144         inaddr->s_addr = sa.sin_addr.s_addr;
145
146         return true;
147
148 #else
149
150         return false;
151
152 #endif  // !PLATFORM_WINDOWS'
153 }
154
155 bool
156 IPMIDIPort::open_sockets (int base_port, const string& ifname)
157 {
158 #if !defined(PLATFORM_WINDOWS)
159         int protonum = 0;
160         struct protoent *proto = ::getprotobyname("IP");
161
162         if (proto) {
163                 protonum = proto->p_proto;
164         }
165
166         sockin = ::socket (PF_INET, SOCK_DGRAM, protonum);
167         if (sockin < 0) {
168                 ::perror("socket(in)");
169                 return false;
170         }
171
172         struct sockaddr_in addrin;
173         ::memset(&addrin, 0, sizeof(addrin));
174         addrin.sin_family = AF_INET;
175         addrin.sin_addr.s_addr = htonl(INADDR_ANY);
176         addrin.sin_port = htons(base_port);
177         
178         if (::bind(sockin, (struct sockaddr *) (&addrin), sizeof(addrin)) < 0) {
179                 ::perror("bind");
180                 return false;
181         }
182         
183         // Will Hall, 2007
184         // INADDR_ANY will bind to default interface,
185         // specify alternate interface nameon which to bind...
186         struct in_addr if_addr_in;
187         if (!ifname.empty()) {
188                 if (!get_address(sockin, &if_addr_in, ifname)) {
189                         error << string_compose ("socket(in): could not find interface address for %1", ifname) << endmsg;
190                         return false;
191                 }
192                 if (::setsockopt(sockin, IPPROTO_IP, IP_MULTICAST_IF,
193                                  (char *) &if_addr_in, sizeof(if_addr_in))) {
194                         ::perror("setsockopt(IP_MULTICAST_IF)");
195                         return false;
196                 }
197         } else {
198                 if_addr_in.s_addr = htonl (INADDR_ANY);
199         }
200         
201         struct ip_mreq mreq;
202         mreq.imr_multiaddr.s_addr = ::inet_addr("225.0.0.37");
203         mreq.imr_interface.s_addr = if_addr_in.s_addr;
204         if(::setsockopt (sockin, IPPROTO_IP, IP_ADD_MEMBERSHIP, (char *) &mreq, sizeof(mreq)) < 0) {
205                 ::perror("setsockopt(IP_ADD_MEMBERSHIP)");
206                 fprintf(stderr, "socket(in): your kernel is probably missing multicast support.\n");
207                 return false;
208         }
209
210         // Output socket...
211
212         sockout = ::socket (AF_INET, SOCK_DGRAM, protonum);
213
214         if (sockout < 0) {
215                 ::perror("socket(out)");
216                 return false;
217         }
218         
219         // Will Hall, Oct 2007
220         if (!ifname.empty()) {
221                 struct in_addr if_addr_out;
222                 if (!get_address(sockout, &if_addr_out, ifname)) {
223                         error << string_compose ("socket(out): could not find interface address for %1", ifname) << endmsg;
224                         return false;
225                 }
226                 if (::setsockopt(sockout, IPPROTO_IP, IP_MULTICAST_IF, (char *) &if_addr_out, sizeof(if_addr_out))) {
227                         ::perror("setsockopt(IP_MULTICAST_IF)");
228                         return false;
229                 }
230         }
231         
232         ::memset(&addrout, 0, sizeof(struct sockaddr_in));
233         addrout.sin_family = AF_INET;
234         addrout.sin_addr.s_addr = ::inet_addr("225.0.0.37");
235         addrout.sin_port = htons (base_port);
236         
237         // Turn off loopback...
238         int loop = 0;
239         if (::setsockopt(sockout, IPPROTO_IP, IP_MULTICAST_LOOP, (char *) &loop, sizeof (loop)) < 0) {
240                 ::perror("setsockopt(IP_MULTICAST_LOOP)");
241                 return false;
242         }
243
244         if (fcntl (sockin, F_SETFL, O_NONBLOCK)) {
245                 error << "cannot set non-blocking mode for IP MIDI input socket (" << ::strerror (errno) << ')' << endmsg;
246                 return false;
247         }
248
249         if (fcntl (sockout, F_SETFL, O_NONBLOCK)) {
250                 error << "cannot set non-blocking mode for IP MIDI output socket (" << ::strerror (errno) << ')' << endmsg;
251                 return false;
252         }
253         
254         return true;
255 #else
256         return false;
257 #endif  // !PLATFORM_WINDOWS'
258 }
259
260 int
261 IPMIDIPort::write (const MIDI::byte* msg, size_t msglen, timestamp_t /* ignored */) {
262
263         if (sockout) {
264                 Glib::Threads::Mutex::Lock lm (write_lock);
265                 if (::sendto (sockout, (const char *) msg, msglen, 0, (struct sockaddr *) &addrout, sizeof(struct sockaddr_in)) < 0) {
266                         ::perror("sendto");
267                         return -1;
268                 }
269                 return msglen;
270         }
271         return 0;
272 }
273
274 int
275 IPMIDIPort::read (MIDI::byte* /*buf*/, size_t /*bufsize*/)
276 {
277         /* nothing to do here - all handled by parse() */
278         return 0;
279 }
280
281 void
282 IPMIDIPort::parse (framecnt_t timestamp)
283 {
284         /* input was detected on the socket, so go get it and hand it to the
285          * parser. This will emit appropriate signals that will be handled
286          * by anyone who cares.
287          */
288         
289         unsigned char buf[1024];
290         struct sockaddr_in sender;
291         socklen_t slen = sizeof(sender);
292         int r = ::recvfrom (sockin, (char *) buf, sizeof(buf), 0, (struct sockaddr *) &sender, &slen);
293
294         if (r >= 0) {
295
296                 _parser->set_timestamp (timestamp);
297                 
298                 for (int i = 0; i < r; ++i) {
299                         _parser->scanner (buf[i]);
300                 }
301         } else {
302                 ::perror ("failed to recv from socket");
303         }
304 }
305