1 /*
2  * Copyright (C) 2012-2017 Paul Davis <paul@linuxaudiosystems.com>
3  * Copyright (C) 2013 John Emmas <john@creativepost.co.uk>
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 2 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License along
16  * with this program; if not, write to the Free Software Foundation, Inc.,
17  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18  */
19 #include <iostream>
20 #include <cstdio>
21 #include <fcntl.h>
22 #include <errno.h>
23 #include <stdlib.h>
24 #include <string.h>
25 #ifdef   COMPILER_MSVC
26 #undef   O_NONBLOCK
27 #define  O_NONBLOCK 0
28 #endif
29 #if defined(PLATFORM_WINDOWS)
30 #include <winsock2.h>
31 #include <ws2tcpip.h>
32 #else
33 #include <netdb.h>
34 #endif
35 
36 #if defined(PLATFORM_WINDOWS)
37 typedef int socklen_t;
38 #else
39 #include <unistd.h>
40 #include <sys/ioctl.h>
closesocket(int s)41 inline void closesocket(int s) { ::close(s); }
42 #endif
43 
44 #include "pbd/xml++.h"
45 #include "pbd/error.h"
46 #include "pbd/failed_constructor.h"
47 #include "pbd/convert.h"
48 #include "pbd/compose.h"
49 
50 #include "midi++/types.h"
51 #include "midi++/ipmidi_port.h"
52 #include "midi++/channel.h"
53 
54 using namespace MIDI;
55 using namespace std;
56 using namespace PBD;
57 
IPMIDIPort(int base_port,const string & iface)58 IPMIDIPort::IPMIDIPort (int base_port, const string& iface)
59 	: Port (string_compose ("IPmidi@%1", base_port), Port::Flags (Port::IsInput|Port::IsOutput))
60 	, sockin (-1)
61 	, sockout (-1)
62 {
63 	if (!open_sockets (base_port, iface)) {
64 		throw (failed_constructor ());
65 	}
66 }
67 
IPMIDIPort(const XMLNode & node)68 IPMIDIPort::IPMIDIPort (const XMLNode& node)
69 	: Port (node)
70 {
71 	/* base class does not class set_state() */
72 	set_state (node);
73 }
74 
~IPMIDIPort()75 IPMIDIPort::~IPMIDIPort ()
76 {
77 	close_sockets ();
78 }
79 
80 int
selectable() const81 IPMIDIPort::selectable () const
82 {
83 	return sockin;
84 }
85 
86 XMLNode&
get_state() const87 IPMIDIPort::get_state () const
88 {
89 	return Port::get_state ();
90 }
91 
92 void
set_state(const XMLNode & node)93 IPMIDIPort::set_state (const XMLNode& node)
94 {
95 	Port::set_state (node);
96 }
97 
98 void
close_sockets()99 IPMIDIPort::close_sockets ()
100 {
101 	if (sockin >= 0) {
102 		::closesocket (sockin);
103 		sockin = -1;
104 	}
105 
106 	if (sockout >= 0) {
107 		::closesocket (sockout);
108 		sockout = -1;
109 	}
110 }
111 
112 #ifndef PLATFORM_WINDOWS
113 static bool
get_address(int sock,struct in_addr * inaddr,const string & ifname)114 get_address (int sock, struct in_addr *inaddr, const string& ifname )
115 {
116 	// Get interface address from supplied name.
117 
118 	struct ifreq ifr;
119 	::strncpy(ifr.ifr_name, ifname.c_str(), sizeof(ifr.ifr_name));
120 
121 	if (::ioctl(sock, SIOCGIFFLAGS, (char *) &ifr)) {
122 		::perror("ioctl(SIOCGIFFLAGS)");
123 		return false;
124 	}
125 
126 	if ((ifr.ifr_flags & IFF_UP) == 0) {
127 		error << string_compose ("interface %1 is down", ifname) << endmsg;
128 		return false;
129 	}
130 
131 	if (::ioctl(sock, SIOCGIFADDR, (char *) &ifr)) {
132 		::perror("ioctl(SIOCGIFADDR)");
133 		return false;
134 	}
135 
136 	struct sockaddr_in sa;
137 	::memcpy(&sa, &ifr.ifr_addr, sizeof(struct sockaddr_in));
138 	inaddr->s_addr = sa.sin_addr.s_addr;
139 
140 	return true;
141 }
142 #endif
143 
144 bool
open_sockets(int base_port,const string & ifname)145 IPMIDIPort::open_sockets (int base_port, const string& ifname)
146 {
147 	int protonum = 0;
148 	struct protoent *proto = ::getprotobyname("IP");
149 
150 	if (proto) {
151 		protonum = proto->p_proto;
152 	}
153 
154 	sockin = ::socket (PF_INET, SOCK_DGRAM, protonum);
155 	if (sockin < 0) {
156 		::perror("socket(in)");
157 		return false;
158 	}
159 
160 	struct sockaddr_in addrin;
161 	::memset(&addrin, 0, sizeof(addrin));
162 	addrin.sin_family = AF_INET;
163 	addrin.sin_addr.s_addr = htonl(INADDR_ANY);
164 	addrin.sin_port = htons(base_port);
165 
166 	if (::bind(sockin, (struct sockaddr *) (&addrin), sizeof(addrin)) < 0) {
167 		::perror("bind");
168 		return false;
169 	}
170 
171 	// Will Hall, 2007
172 	// INADDR_ANY will bind to default interface,
173 	// specify alternate interface nameon which to bind...
174 	struct in_addr if_addr_in;
175 #ifndef PLATFORM_WINDOWS
176 	if (!ifname.empty()) {
177 		if (!get_address(sockin, &if_addr_in, ifname)) {
178 			error << string_compose ("socket(in): could not find interface address for %1", ifname) << endmsg;
179 			return false;
180 		}
181 		if (::setsockopt(sockin, IPPROTO_IP, IP_MULTICAST_IF,
182 				 (char *) &if_addr_in, sizeof(if_addr_in))) {
183 			::perror("setsockopt(IP_MULTICAST_IF)");
184 			return false;
185 		}
186 	} else {
187 		if_addr_in.s_addr = htonl (INADDR_ANY);
188 	}
189 #else
190 	if_addr_in.s_addr = htonl (INADDR_ANY);
191 #endif
192 
193 	struct ip_mreq mreq;
194 	mreq.imr_multiaddr.s_addr = ::inet_addr("225.0.0.37"); /* ipMIDI group multicast address */
195 	mreq.imr_interface.s_addr = if_addr_in.s_addr;
196 	if(::setsockopt (sockin, IPPROTO_IP, IP_ADD_MEMBERSHIP, (char *) &mreq, sizeof(mreq)) < 0) {
197 		::perror("setsockopt(IP_ADD_MEMBERSHIP)");
198 		fprintf(stderr, "socket(in): your kernel is probably missing multicast support.\n");
199 		return false;
200 	}
201 
202 	// Output socket...
203 
204 	sockout = ::socket (AF_INET, SOCK_DGRAM, protonum);
205 
206 	if (sockout < 0) {
207 		::perror("socket(out)");
208 		return false;
209 	}
210 
211 	// Will Hall, Oct 2007
212 #ifndef PLATFORM_WINDOWS
213 	if (!ifname.empty()) {
214 		struct in_addr if_addr_out;
215 		if (!get_address(sockout, &if_addr_out, ifname)) {
216 			error << string_compose ("socket(out): could not find interface address for %1", ifname) << endmsg;
217 			return false;
218 		}
219 		if (::setsockopt(sockout, IPPROTO_IP, IP_MULTICAST_IF, (char *) &if_addr_out, sizeof(if_addr_out))) {
220 			::perror("setsockopt(IP_MULTICAST_IF)");
221 			return false;
222 		}
223 	}
224 #endif
225 
226 	::memset(&addrout, 0, sizeof(struct sockaddr_in));
227 	addrout.sin_family = AF_INET;
228 	addrout.sin_addr.s_addr = ::inet_addr("225.0.0.37");
229 	addrout.sin_port = htons (base_port);
230 
231 	// Turn off loopback...
232 	int loop = 0;
233 
234 #ifdef PLATFORM_WINDOWS
235 
236 	/* https://msdn.microsoft.com/en-us/library/windows/desktop/ms739161%28v=vs.85%29.aspx
237 	 *
238 	 * ------------------------------------------------------------------------------
239 	 * Note The Winsock version of the IP_MULTICAST_LOOP option is
240 	 * semantically different than the UNIX version of the
241 	 * IP_MULTICAST_LOOP option:
242 	 *
243 	 * In Winsock, the IP_MULTICAST_LOOP option applies only to the receive path.
244 	 * In the UNIX version, the IP_MULTICAST_LOOP option applies to the send path.
245 	 *
246 	 * For example, applications ON and OFF (which are easier to track than
247 	 * X and Y) join the same group on the same interface; application ON
248 	 * sets the IP_MULTICAST_LOOP option on, application OFF sets the
249 	 * IP_MULTICAST_LOOP option off. If ON and OFF are Winsock
250 	 * applications, OFF can send to ON, but ON cannot sent to OFF. In
251 	 * contrast, if ON and OFF are UNIX applications, ON can send to OFF,
252 	 * but OFF cannot send to ON.
253 	 * ------------------------------------------------------------------------------
254 	 *
255 	 * Alles klar? Gut!
256 	 */
257 
258 	const int target_sock = sockin;
259 #else
260 	const int target_sock = sockout;
261 #endif
262 
263 	if (::setsockopt (target_sock, IPPROTO_IP, IP_MULTICAST_LOOP, (char *) &loop, sizeof (loop)) < 0) {
264 		::perror("setsockopt(IP_MULTICAST_LOOP)");
265 		return false;
266 	}
267 
268 #ifndef PLATFORM_WINDOWS
269 
270 	if (fcntl (sockin, F_SETFL, O_NONBLOCK)) {
271 		error << "cannot set non-blocking mode for IP MIDI input socket (" << ::strerror (errno) << ')' << endmsg;
272 		return false;
273 	}
274 
275 	if (fcntl (sockout, F_SETFL, O_NONBLOCK)) {
276 		error << "cannot set non-blocking mode for IP MIDI output socket (" << ::strerror (errno) << ')' << endmsg;
277 		return false;
278 	}
279 
280 #else
281 	// If imode !=0, non-blocking mode is enabled.
282 	u_long mode=1;
283 	if (ioctlsocket(sockin,FIONBIO,&mode)) {
284 		error << "cannot set non-blocking mode for IP MIDI input socket (" << ::strerror (errno) << ')' << endmsg;
285 		return false;
286 	}
287 	mode = 1; /* just in case it was modified in the previous call */
288 	if (ioctlsocket(sockout,FIONBIO,&mode)) {
289 		error << "cannot set non-blocking mode for IP MIDI output socket (" << ::strerror (errno) << ')' << endmsg;
290 		return false;
291 	}
292 #endif
293 
294 	return true;
295 }
296 
297 int
write(const MIDI::byte * msg,size_t msglen,timestamp_t)298 IPMIDIPort::write (const MIDI::byte* msg, size_t msglen, timestamp_t /* ignored */) {
299 
300 	if (sockout) {
301 		Glib::Threads::Mutex::Lock lm (write_lock);
302 		if (::sendto (sockout, (const char *) msg, msglen, 0, (struct sockaddr *) &addrout, sizeof(struct sockaddr_in)) < 0) {
303 			::perror("sendto");
304 			return -1;
305 		}
306 		return msglen;
307 	}
308 	return 0;
309 }
310 
311 int
read(MIDI::byte *,size_t)312 IPMIDIPort::read (MIDI::byte* /*buf*/, size_t /*bufsize*/)
313 {
314 	/* nothing to do here - all handled by parse() */
315 	return 0;
316 }
317 
318 void
parse(samplecnt_t timestamp)319 IPMIDIPort::parse (samplecnt_t timestamp)
320 {
321 	/* input was detected on the socket, so go get it and hand it to the
322 	 * parser. This will emit appropriate signals that will be handled
323 	 * by anyone who cares.
324 	 */
325 
326 	unsigned char buf[1024];
327 	struct sockaddr_in sender;
328 	socklen_t slen = sizeof(sender);
329 	int r = ::recvfrom (sockin, (char *) buf, sizeof(buf), 0, (struct sockaddr *) &sender, &slen);
330 
331 	if (r >= 0) {
332 
333 		_parser->set_timestamp (timestamp);
334 
335 		for (int i = 0; i < r; ++i) {
336 			_parser->scanner (buf[i]);
337 		}
338 	} else {
339 		::perror ("failed to recv from socket");
340 	}
341 }
342