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