1 /*
2  * Schism Tracker - a cross-platform Impulse Tracker clone
3  * copyright (c) 2003-2005 Storlek <storlek@rigelseven.com>
4  * copyright (c) 2005-2008 Mrs. Brisby <mrs.brisby@nimh.org>
5  * copyright (c) 2009 Storlek & Mrs. Brisby
6  * copyright (c) 2010-2012 Storlek
7  * URL: http://schismtracker.org/
8  *
9  * This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software
21  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
22  */
23 #include "headers.h"
24 #include "midi.h"
25 
26 #include "it.h"
27 #include "util.h"
28 #include "sdlmain.h"
29 #include "event.h"
30 
31 #ifdef USE_NETWORK
32 
33 #ifdef WIN32
34 #include <windows.h>
35 #include <ws2tcpip.h>
36 #else
37 #include <sys/types.h>
38 #include <sys/socket.h>
39 #include <netinet/in.h>
40 #include <sys/select.h>
41 #include <fcntl.h>
42 #endif
43 
44 #include <errno.h>
45 
46 #define DEFAULT_IP_PORT_COUNT   5
47 #define MIDI_IP_BASE    21928
48 #define MAX_DGRAM_SIZE  1280
49 
50 #ifndef WIN32
51 static int wakeup[2];
52 #endif
53 static int real_num_ports = 0;
54 static int num_ports = 0;
55 static int out_fd = -1;
56 static int *port_fd = NULL;
57 static int *state = NULL;
58 static SDL_mutex *blocker = NULL;
59 
60 static void do_wake_main(void)
61 {
62 	/* send at end */
63 	SDL_Event e;
64 	e.user.type = SCHISM_EVENT_UPDATE_IPMIDI;
65 	e.user.code = 0;
66 	e.user.data1 = NULL;
67 	e.user.data2 = NULL;
68 	SDL_PushEvent(&e);
69 }
70 static void do_wake_midi(void)
71 {
72 #ifdef WIN32
73 	/* anyone want to suggest how this is done? XXX */
74 #else
75 	if (write(wakeup[1], "\x1", 1) == 1) {
76 		/* fortify is stupid */
77 	}
78 #endif
79 }
80 
81 static int _get_fd(int pb, int isout)
82 {
83 	struct ip_mreq mreq = {};
__construct(array $p_data)84 	struct sockaddr_in asin = {};
85 	unsigned char *ipcopy;
86 	int fd, opt;
87 
88 #if !defined(PF_INET) && defined(AF_INET)
89 #define PF_INET AF_INET
90 #endif
validate()91 	fd = socket(PF_INET, SOCK_DGRAM, 0);
92 	if (fd == -1) return -1;
93 
94 	opt = 1; setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (void*)&opt, sizeof(int));
95 
96 	/* don't loop back what we generate */
97 	opt = !isout;
98 	if (setsockopt(fd, IPPROTO_IP, IP_MULTICAST_LOOP, (void*)&opt, sizeof(opt)) < 0) {
99 #ifdef WIN32
100 		closesocket(fd);
101 #else
102 		close(fd);
103 #endif
104 		return -1;
105 	}
106 
107 	opt = 31;
108 	if (setsockopt(fd, IPPROTO_IP, IP_MULTICAST_TTL, (void*)&opt, sizeof(opt)) < 0) {
109 #ifdef WIN32
110 		closesocket(fd);
111 #else
112 		close(fd);
113 #endif
114 		return -1;
115 	}
116 
117 	ipcopy = (unsigned char *)&mreq.imr_multiaddr;
118 	ipcopy[0] = 225; ipcopy[1] = ipcopy[2] = 0; ipcopy[3] = 37;
119 	if (setsockopt(fd, IPPROTO_IP, IP_ADD_MEMBERSHIP, (void*)&mreq, sizeof(mreq)) < 0) {
120 #ifdef WIN32
121 		closesocket(fd);
122 #else
123 		close(fd);
124 #endif
125 		return -1;
126 	}
127 
128 	opt = 1;
129 	if (setsockopt(fd, SOL_SOCKET, SO_BROADCAST, (void*)&opt, sizeof(opt)) < 0) {
130 #ifdef WIN32
131 		closesocket(fd);
132 #else
133 		close(fd);
134 #endif
135 		return -1;
136 	}
137 
138 	asin.sin_family = AF_INET;
139 	ipcopy = (unsigned char *)&asin.sin_addr;
140 	if (!isout) {
141 		/* all 0s is inaddr_any; but this is for listening */
142 #ifdef WIN32
143 		//JosepMa:On my machine, using the 225.0.0.37 address caused bind to fail.
process()144 		//Didn't look too much to find why.
145 		ipcopy[0] = ipcopy[1] = ipcopy[2] = ipcopy[3] = 0;
146 #else
147 		ipcopy[0] = 225; ipcopy[1] = ipcopy[2] = 0; ipcopy[3] = 37;
148 #endif
149 		asin.sin_port = htons(MIDI_IP_BASE+pb);
150 	}
151 	if (bind(fd, (struct sockaddr *)&asin, sizeof(asin)) < 0) {
152 #ifdef WIN32
153 
154 		int asdf = WSAGetLastError();
155 		perror("binderror");
156 		switch(asdf) {
157 			case WSANOTINITIALISED: perror("WSANOTINITIALISED");break;
158 			case WSAENETDOWN: perror("WSAENETDOWN");break;
159 			case WSAEFAULT: perror("WSAEFAULT");break;
160 			case WSAEINVAL: perror("WSAEINVAL");break;
161 			case WSAEINPROGRESS: perror("WSAEINPROGRESS");break;
162 			case WSAENOTSOCK: perror("WSAENOTSOCK");break;
parseFiles()163 			case WSAEACCES: perror("WSAEACCES");break;
164 			case WSAEADDRINUSE: perror("WSAEADDRINUSE");break;
165 			case WSAEADDRNOTAVAIL: perror("WSAEADDRNOTAVAIL");break;
166 			case WSAENOBUFS: perror("WSAENOBUFS");break;
167 			default: perror("default");break;
168 		}
169 		closesocket(fd);
170 #else
171 		close(fd);
172 #endif
173 		return -1;
174 	}
175 
176 	return fd;
177 }
178 void ip_midi_setports(int n)
179 {
180 	if (out_fd == -1) return;
181 	if (status.flags & NO_NETWORK) return;
182 
183 	SDL_mutexP(blocker);
184 	num_ports = n;
185 	SDL_mutexV(blocker);
186 	do_wake_midi();
187 }
188 static void _readin(struct midi_provider *p, int en, int fd)
189 {
190 	struct midi_port *ptr, *src;
191 	static unsigned char buffer[65536];
192 	static struct sockaddr_in asin;
193 	unsigned slen = sizeof(asin);
194 	int r;
195 
196 	r = recvfrom(fd, buffer, sizeof(buffer), 0,
197 		(struct sockaddr *)&asin, &slen);
198 	if (r > 0) {
199 		ptr = src = NULL;
200 		while (midi_port_foreach(p, &ptr)) {
201 			int n = INT_SHAPED_PTR(ptr->userdata);
202 			if (n == en) src = ptr;
203 		}
204 		midi_received_cb(src, buffer, r);
205 	}
206 }
207 static int _ip_thread(struct midi_provider *p)
208 {
209 #ifdef WIN32
210 	struct timeval tv;
211 #else
212 	static unsigned char buffer[4096];
213 #endif
214 	fd_set rfds;
215 	int *tmp2, *tmp;
216 	int i, m;
217 
218 	for (;;) {
219 		SDL_mutexP(blocker);
220 		m = (volatile int)num_ports;
221 		//If no ports, wait and try again
222 		if (m > real_num_ports) {
223 			/* need more ports */
224 			tmp = malloc(2 * (m * sizeof(int)));
225 			if (tmp) {
226 				tmp2 = tmp + m;
227 				for (i = 0; i < real_num_ports; i++) {
228 					tmp[i] = port_fd[i];
229 					tmp2[i] = state[i];
230 				}
231 				free(port_fd);
232 
233 				port_fd = tmp;
234 				state = tmp2;
235 
236 				for (i = real_num_ports; i < m; i++) {
237 					state[i] = 0;
238 					if ((port_fd[i] = _get_fd(i,0)) == -1) {
239 						m = i+1;
240 						break;
241 					}
242 				}
243 				real_num_ports = num_ports = m;
244 			}
245 			SDL_mutexV(blocker);
246 			do_wake_main();
247 
248 		} else if (m < real_num_ports) {
249 			for (i = m; i < real_num_ports; i++) {
250 #ifdef WIN32
251 				closesocket(port_fd[i]);
252 #else
253 				close(port_fd[i]);
254 #endif
255 				port_fd[i] = -1;
256 			}
257 			real_num_ports = num_ports = m;
258 
259 			SDL_mutexV(blocker);
260 			do_wake_main();
261 		} else {
262 			SDL_mutexV(blocker);
263 			if (!real_num_ports) {
264 				//Since the thread is not finished in this case (maybe it should),
265 				//we put a delay to prevent the thread using all the cpu.
266 				SDL_Delay(1000);
267 			}
268 		}
269 
270 		FD_ZERO(&rfds);
271 		m = 0;
272 		for (i = 0; i < real_num_ports; i++) {
273 			FD_SET(port_fd[i], &rfds);
274 			if (port_fd[i] > m) m = port_fd[i];
275 		}
276 
277 #ifdef WIN32
278 		tv.tv_sec = 1;
279 		tv.tv_usec = 0;
280 #else
281 		FD_SET(wakeup[0], &rfds);
282 		if (wakeup[0] > m) m = wakeup[0];
283 #endif
284 		do {
285 			i = select(m+1, &rfds, NULL, NULL,
286 #ifdef WIN32
287 				&tv
288 #else
289 				NULL
290 #endif
291 				);
292 #ifdef WIN32
293 			if (i == SOCKET_ERROR ) {
294 				perror("selectError:");
295 				int asdf = WSAGetLastError();
296 				switch(asdf) {
297 					case WSANOTINITIALISED: perror("WSANOTINITIALISED");break;
298 					case WSAEFAULT: perror("WSAEFAULT");break;
299 					case WSAENETDOWN: perror("WSAENETDOWN");break;
300 					case WSAEINVAL: perror("WSAEINVAL");break;
301 					case WSAEINTR: perror("WSAEINTR");break;
302 					case WSAEINPROGRESS: perror("WSAEINPROGRESS");break;
303 					case WSAENOTSOCK: perror("WSAENOTSOCK");break;
304 					default: perror("default");break;
305 				}
306 			}
307 #endif
308 		} while (i == -1 && errno == EINTR);
309 
310 #ifndef WIN32
311 		if (FD_ISSET(wakeup[0], &rfds)) {
312 			if (read(wakeup[0], buffer, sizeof(buffer)) == -1) {
313 				/* fortify is stupid */
314 			}
315 		}
316 #endif
317 		for (i = 0; i < real_num_ports; i++) {
318 			if (FD_ISSET(port_fd[i], &rfds)) {
319 				if (state[i] & 1) _readin(p, i, port_fd[i]);
320 			}
321 		}
322 	}
323 	return 0;
324 }
325 
326 static int _ip_start(struct midi_port *p)
327 {
328 	int n = INT_SHAPED_PTR(p->userdata);
329 	SDL_mutexP(blocker);
330 	if (p->io & MIDI_INPUT)
331 		state[n] |= 1;
332 	if (p->io & MIDI_OUTPUT)
333 		state[n] |= 2;
334 	SDL_mutexV(blocker);
335 	do_wake_midi();
336 	return 1;
337 }
338 static int _ip_stop(struct midi_port *p)
339 {
340 	int n = INT_SHAPED_PTR(p->userdata);
341 	SDL_mutexP(blocker);
342 	if (p->io & MIDI_INPUT)
343 		state[n] &= (~1);
344 	if (p->io & MIDI_OUTPUT)
345 		state[n] &= (~2);
346 	SDL_mutexV(blocker);
347 	do_wake_midi();
348 	return 1;
349 }
350 
351 static void _ip_send(struct midi_port *p, const unsigned char *data, unsigned int len,
352 				UNUSED unsigned int delay)
353 {
354 	struct sockaddr_in asin = {};
355 	unsigned char *ipcopy;
356 	int n = INT_SHAPED_PTR(p->userdata);
357 	int ss;
358 
359 	if (len == 0) return;
360 	if (!(state[n] & 2)) return; /* blah... */
361 
362 	asin.sin_family = AF_INET;
363 	ipcopy = (unsigned char *)&asin.sin_addr.s_addr;
364 	ipcopy[0] = 225; ipcopy[1] = ipcopy[2] = 0; ipcopy[3] = 37;
365 	asin.sin_port = htons(MIDI_IP_BASE+n);
366 
367 	while (len) {
368 		ss = (len > MAX_DGRAM_SIZE) ?  MAX_DGRAM_SIZE : len;
369 		if (sendto(out_fd, data, ss, 0,
370 				(struct sockaddr *)&asin,sizeof(asin)) < 0) {
371 			state[n] &= (~2); /* turn off output */
372 			break;
373 		}
374 		len -= ss;
375 		data += ss;
376 	}
377 }
378 static void _ip_poll(struct midi_provider *p)
379 {
380 	static int last_buildout = 0;
381 	struct midi_port *ptr;
382 	char *buffer;
383 	long i = 0;
384 	long m;
385 
386 	SDL_mutexP(blocker);
387 	m = (volatile int)real_num_ports;
388 	if (m < last_buildout) {
389 		ptr = NULL;
390 		while (midi_port_foreach(p, &ptr)) {
391 			i = INT_SHAPED_PTR(ptr->userdata);
392 			if (i >= m) {
393 				midi_port_unregister(ptr->num);
394 				//port_top[i] (the address where ptr points to) is freed in midi_port_unregister.
395 				//So clear it to avoid midi_port_foreach crashing on next round
396 				ptr = NULL;
397 			}
398 		}
399 		last_buildout = m;
400 	} else if (m > last_buildout) {
401 		for (i = last_buildout; i < m; i++) {
402 			buffer = NULL;
403 			if (asprintf(&buffer, " Multicast/IP MIDI %lu", i+1) == -1) {
404 				perror("asprintf");
405 				exit(255);
406 			}
407 			if (!buffer) {
408 				perror("asprintf");
409 				exit(255);
410 			}
411 			midi_port_register(p, MIDI_INPUT | MIDI_OUTPUT, buffer,
412 					PTR_SHAPED_INT((intptr_t)i), 0);
413 		}
414 		last_buildout = m;
415 	}
416 	SDL_mutexV(blocker);
417 }
418 
419 int ip_midi_setup(void)
420 {
421 	static struct midi_driver driver;
422 
423 	if (status.flags & NO_NETWORK) return 0;
424 
425 	blocker = SDL_CreateMutex();
426 	if (!blocker) {
427 		return 0;
428 	}
429 
430 #ifndef WIN32
431 	if (pipe(wakeup) == -1) {
432 		return 0;
433 	}
434 	fcntl(wakeup[0], F_SETFL, fcntl(wakeup[0], F_GETFL, 0) | O_NONBLOCK);
435 	fcntl(wakeup[1], F_SETFL, fcntl(wakeup[1], F_GETFL, 0) | O_NONBLOCK);
436 #endif
437 
438 	if (out_fd == -1) {
439 		out_fd = _get_fd(-1, 1);
440 		if (out_fd == -1) return 0;
441 	}
442 
443 	driver.flags = 0;
444 	driver.poll = _ip_poll;
445 	driver.thread = _ip_thread;
446 	driver.send = _ip_send;
447 	driver.enable = _ip_start;
448 	driver.disable = _ip_stop;
449 	//TODO: Save number of MIDI-IP ports
450 	ip_midi_setports(DEFAULT_IP_PORT_COUNT);
451 
452 	if (!midi_provider_register("IP", &driver)) return 0;
453 	return 1;
454 }
455 
456 int ip_midi_getports(void)
457 {
458 	int tmp;
459 
460 	if (out_fd == -1) return 0;
461 	if (status.flags & NO_NETWORK) return 0;
462 
463 	SDL_mutexP(blocker);
464 	tmp = (volatile int)real_num_ports;
465 	SDL_mutexV(blocker);
466 	return tmp;
467 }
468 
469 #else
470 
471 int ip_midi_getports(void)
472 {
473 	return 0;
474 }
475 
476 void ip_midi_setports(UNUSED int n)
477 {
478 }
479 
480 #endif
481 
482