aseqnet.c (13284B)
1 /* 2 * network server/client for ALSA sequencer 3 * ver.0.1 4 * 5 * Copyright (C) 1999-2000 Takashi Iwai 6 * 7 * This program is free software; you can redistribute it and/or modify 8 * it under the terms of the GNU General Public License version 2 as 9 * published by the Free Software Foundation. 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 */ 17 18 #include <stdio.h> 19 #include <stdlib.h> 20 #include <ctype.h> 21 #include <string.h> 22 #include <netinet/in.h> 23 #include <sys/socket.h> 24 #include <netdb.h> 25 #include <locale.h> 26 #include <alsa/asoundlib.h> 27 #include <getopt.h> 28 #include <signal.h> 29 #include <assert.h> 30 #include "aconfig.h" 31 #include "gettext.h" 32 33 /* 34 * prototypes 35 */ 36 static void usage(void); 37 static void init_buf(void); 38 static void init_pollfds(void); 39 static void close_files(void); 40 static void init_seq(char *source, char *dest); 41 static int get_port(char *service); 42 static void sigterm_exit(int sig); 43 static void init_server(int port); 44 static void init_client(char *server, int port); 45 static void do_loop(void); 46 static int copy_local_to_remote(void); 47 static int copy_remote_to_local(int fd); 48 49 /* 50 * default TCP port number 51 */ 52 #define DEFAULT_PORT 40002 53 54 /* 55 * local input buffer 56 */ 57 static char *readbuf; 58 static int max_rdlen; 59 static char *writebuf; 60 static int cur_wrlen, max_wrlen; 61 62 #define MAX_BUF_EVENTS 200 63 #define MAX_CONNECTION 10 64 65 static snd_seq_t *handle; 66 static struct pollfd *seqifds = NULL; 67 static struct pollfd *seqofds = NULL; 68 static struct pollfd *pollfds = NULL; 69 static int seqifds_count = 0; 70 static int seqofds_count = 0; 71 static int pollfds_count = 0; 72 static int sockfd, netfd[MAX_CONNECTION] = {[0 ... MAX_CONNECTION-1] = -1}; 73 static int max_connection; 74 static int cur_connected; 75 static int seq_port; 76 77 static int server_mode; 78 static int verbose = 0; 79 static int info = 0; 80 81 82 /* 83 * main routine 84 */ 85 86 static const struct option long_option[] = { 87 {"port", 1, NULL, 'p'}, 88 {"source", 1, NULL, 's'}, 89 {"dest", 1, NULL, 'd'}, 90 {"help", 0, NULL, 'h'}, 91 {"verbose", 0, NULL, 'v'}, 92 {"info", 0, NULL, 'i'}, 93 {NULL, 0, NULL, 0}, 94 }; 95 96 int main(int argc, char **argv) 97 { 98 int c; 99 int port = DEFAULT_PORT; 100 char *source = NULL, *dest = NULL; 101 102 #ifdef ENABLE_NLS 103 setlocale(LC_ALL, ""); 104 textdomain(PACKAGE); 105 #endif 106 107 while ((c = getopt_long(argc, argv, "p:s:d:vi", long_option, NULL)) != -1) { 108 switch (c) { 109 case 'p': 110 if (isdigit(*optarg)) 111 port = atoi(optarg); 112 else 113 port = get_port(optarg); 114 break; 115 case 's': 116 source = optarg; 117 break; 118 case 'd': 119 dest = optarg; 120 break; 121 case 'v': 122 verbose++; 123 break; 124 case 'i': 125 info++; 126 break; 127 default: 128 usage(); 129 exit(1); 130 } 131 } 132 133 signal(SIGINT, sigterm_exit); 134 signal(SIGTERM, sigterm_exit); 135 136 init_buf(); 137 init_seq(source, dest); 138 139 if (optind >= argc) { 140 server_mode = 1; 141 max_connection = MAX_CONNECTION; 142 init_pollfds(); 143 init_server(port); 144 } else { 145 server_mode = 0; 146 max_connection = 1; 147 init_pollfds(); 148 init_client(argv[optind], port); 149 } 150 151 do_loop(); 152 153 close_files(); 154 155 return 0; 156 } 157 158 159 /* 160 * print usage 161 */ 162 static void usage(void) 163 { 164 printf(_("aseqnet - network client/server on ALSA sequencer\n")); 165 printf(_(" Copyright (C) 1999 Takashi Iwai\n")); 166 printf(_("usage:\n")); 167 printf(_(" server mode: aseqnet [-options]\n")); 168 printf(_(" client mode: aseqnet [-options] server_host\n")); 169 printf(_("options:\n")); 170 printf(_(" -p,--port # : specify TCP port (digit or service name)\n")); 171 printf(_(" -s,--source addr : read from given addr (client:port)\n")); 172 printf(_(" -d,--dest addr : write to given addr (client:port)\n")); 173 printf(_(" -v, --verbose : print verbose messages\n")); 174 printf(_(" -i, --info : print certain received events\n")); 175 } 176 177 178 /* 179 * allocate and initialize buffers 180 */ 181 static void init_buf(void) 182 { 183 max_wrlen = MAX_BUF_EVENTS * sizeof(snd_seq_event_t); 184 max_rdlen = MAX_BUF_EVENTS * sizeof(snd_seq_event_t); 185 writebuf = malloc(max_wrlen); 186 readbuf = malloc(max_rdlen); 187 if (writebuf == NULL || readbuf == NULL) { 188 fprintf(stderr, _("can't malloc\n")); 189 exit(1); 190 } 191 memset(writebuf, 0, max_wrlen); 192 memset(readbuf, 0, max_rdlen); 193 cur_wrlen = 0; 194 } 195 196 /* 197 * allocate and initialize poll array 198 */ 199 static void init_pollfds(void) 200 { 201 pollfds_count = seqifds_count + seqofds_count + 1 + max_connection; 202 pollfds = (struct pollfd *)calloc(pollfds_count, sizeof(struct pollfd)); 203 assert(pollfds); 204 } 205 206 /* 207 * close all files 208 */ 209 static void close_files(void) 210 { 211 int i; 212 if (verbose) 213 fprintf(stderr, _("closing files..\n")); 214 for (i = 0; i < max_connection; i++) { 215 if (netfd[i] >= 0) 216 close(netfd[i]); 217 } 218 if (sockfd >= 0) 219 close(sockfd); 220 } 221 222 223 /* 224 * initialize sequencer 225 */ 226 static void init_seq(char *source, char *dest) 227 { 228 snd_seq_addr_t addr; 229 int err, counti, counto; 230 231 if (snd_seq_open(&handle, "default", SND_SEQ_OPEN_DUPLEX, 0) < 0) { 232 perror("snd_seq_open"); 233 exit(1); 234 } 235 if (seqifds) 236 free(seqifds); 237 if (seqofds) 238 free(seqofds); 239 counti = seqifds_count = snd_seq_poll_descriptors_count(handle, POLLIN); 240 assert(counti > 0); 241 counto = seqofds_count = snd_seq_poll_descriptors_count(handle, POLLOUT); 242 assert(counto > 0); 243 seqifds = (struct pollfd *)calloc(counti, sizeof(struct pollfd)); 244 assert(seqifds); 245 seqofds = (struct pollfd *)calloc(counto, sizeof(struct pollfd)); 246 assert(seqofds); 247 err = snd_seq_poll_descriptors(handle, seqifds, counti, POLLIN); 248 assert(err == counti); 249 err = snd_seq_poll_descriptors(handle, seqofds, counto, POLLOUT); 250 assert(err == counto); 251 252 snd_seq_nonblock(handle, 1); 253 254 /* set client info */ 255 if (server_mode) 256 snd_seq_set_client_name(handle, "Net Server"); 257 else 258 snd_seq_set_client_name(handle, "Net Client"); 259 260 /* create a port */ 261 seq_port = snd_seq_create_simple_port(handle, "Network", 262 SND_SEQ_PORT_CAP_READ | 263 SND_SEQ_PORT_CAP_WRITE | 264 SND_SEQ_PORT_CAP_SUBS_READ | 265 SND_SEQ_PORT_CAP_SUBS_WRITE, 266 SND_SEQ_PORT_TYPE_MIDI_GENERIC); 267 if (seq_port < 0) { 268 perror("create seq port"); 269 exit(1); 270 } 271 if (verbose) 272 fprintf(stderr, _("sequencer opened: %d:%d\n"), 273 snd_seq_client_id(handle), seq_port); 274 275 /* explicit subscriptions */ 276 if (source) { 277 /* read subscription */ 278 if (snd_seq_parse_address(handle, &addr, source) < 0) { 279 fprintf(stderr, _("invalid source address %s\n"), source); 280 exit(1); 281 } 282 if (snd_seq_connect_from(handle, seq_port, addr.client, addr.port)) { 283 perror("read subscription"); 284 exit(1); 285 } 286 } 287 if (dest) { 288 /* write subscription */ 289 if (snd_seq_parse_address(handle, &addr, dest) < 0) { 290 fprintf(stderr, _("invalid destination address %s\n"), dest); 291 exit(1); 292 } 293 if (snd_seq_connect_to(handle, seq_port, addr.client, addr.port)) { 294 perror("write subscription"); 295 exit(1); 296 } 297 } 298 } 299 300 301 /* 302 * convert from string to TCP port number 303 */ 304 static int get_port(char *service) 305 { 306 struct servent *sp; 307 308 if ((sp = getservbyname(service, "tcp")) == NULL){ 309 fprintf(stderr, _("service '%s' is not found in /etc/services\n"), service); 310 return -1; 311 } 312 return sp->s_port; 313 } 314 315 /* 316 * signal handler 317 */ 318 static void sigterm_exit(int sig) 319 { 320 close_files(); 321 exit(1); 322 } 323 324 325 /* 326 * initialize network server 327 */ 328 static void init_server(int port) 329 { 330 int i; 331 int curstate = 1; 332 struct sockaddr_in addr; 333 334 memset(&addr, 0, sizeof(addr)); 335 336 addr.sin_family = AF_INET; 337 addr.sin_addr.s_addr = INADDR_ANY; 338 addr.sin_port = htons(port); 339 340 sockfd = socket(AF_INET, SOCK_STREAM, 0); 341 if (sockfd < 0) { 342 perror("create socket"); 343 exit(1); 344 } 345 setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &curstate, sizeof(curstate)); 346 /* the return value is ignored.. */ 347 348 if (bind(sockfd, (struct sockaddr *)&addr, sizeof(addr)) < 0) { 349 perror("can't bind"); 350 exit(1); 351 } 352 353 if (listen(sockfd, 5) < 0) { 354 perror("can't listen"); 355 exit(1); 356 } 357 358 cur_connected = 0; 359 for (i = 0; i < max_connection; i++) 360 netfd[i] = -1; 361 } 362 363 /* 364 * start connection on server 365 */ 366 static void start_connection(void) 367 { 368 struct sockaddr_in addr; 369 int i; 370 socklen_t addr_len; 371 372 for (i = 0; i < max_connection; i++) { 373 if (netfd[i] < 0) 374 break; 375 } 376 if (i >= max_connection) { 377 fprintf(stderr, _("too many connections!\n")); 378 exit(1); 379 } 380 memset(&addr, 0, sizeof(addr)); 381 addr_len = sizeof(addr); 382 netfd[i] = accept(sockfd, (struct sockaddr *)&addr, &addr_len); 383 if (netfd[i] < 0) { 384 perror("accept"); 385 exit(1); 386 } 387 if (verbose) 388 fprintf(stderr, _("accepted[%d]\n"), netfd[i]); 389 cur_connected++; 390 } 391 392 /* 393 * initialize network client 394 */ 395 static void init_client(char *server, int port) 396 { 397 struct sockaddr_in addr; 398 struct hostent *host; 399 int curstate = 1; 400 int fd; 401 402 if ((fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0){ 403 perror("create socket"); 404 exit(1); 405 } 406 if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &curstate, sizeof(curstate)) < 0) { 407 perror("setsockopt"); 408 exit(1); 409 } 410 if ((host = gethostbyname(server)) == NULL){ 411 fprintf(stderr, _("can't get address %s\n"), server); 412 exit(1); 413 } 414 addr.sin_port = htons(port); 415 addr.sin_family = AF_INET; 416 memcpy(&addr.sin_addr, host->h_addr, host->h_length); 417 if (connect(fd, (struct sockaddr *)&addr, sizeof(addr)) < 0) { 418 perror("connect"); 419 exit(1); 420 } 421 if (verbose) 422 fprintf(stderr, _("ok.. connected\n")); 423 netfd[0] = fd; 424 cur_connected = 1; 425 } 426 427 /* 428 * event loop 429 */ 430 static void do_loop(void) 431 { 432 int i, rc, width; 433 int seqifd_ptr, sockfd_ptr = -1, netfd_ptr; 434 435 for (;;) { 436 memset(pollfds, 0, pollfds_count * sizeof(struct pollfd)); 437 seqifd_ptr = 0; 438 memcpy(pollfds, seqifds, sizeof(*seqifds)*(width = seqifds_count)); 439 if (server_mode) { 440 sockfd_ptr = width; 441 pollfds[width].fd = sockfd; 442 pollfds[width].events = POLLIN; 443 width++; 444 } 445 netfd_ptr = width; 446 for (i = 0; i < max_connection; i++) { 447 if (netfd[i] >= 0) { 448 pollfds[width].fd = netfd[i]; 449 pollfds[width].events = POLLIN; 450 width++; 451 } 452 } 453 do { 454 rc = poll(pollfds, width, -1); 455 } while (rc <= 0 && errno == EINTR); 456 if (rc <= 0) { 457 perror("poll"); 458 exit(1); 459 } 460 if (server_mode) { 461 if (pollfds[sockfd_ptr].revents & (POLLIN|POLLOUT)) 462 start_connection(); 463 } 464 for (i = 0; i < seqifds_count; i++) 465 if (pollfds[seqifd_ptr + i].revents & (POLLIN|POLLOUT)) { 466 if (copy_local_to_remote()) 467 return; 468 break; 469 } 470 for (i = 0; i < max_connection; i++) { 471 if (netfd[i] < 0) 472 continue; 473 if (pollfds[netfd_ptr + i].revents & (POLLIN|POLLOUT)) { 474 if (copy_remote_to_local(netfd[i])) { 475 netfd[i] = -1; 476 cur_connected--; 477 if (cur_connected <= 0) 478 return; 479 } 480 } 481 } 482 } 483 } 484 485 486 /* 487 * flush write buffer - send data to the socket 488 */ 489 static void flush_writebuf(void) 490 { 491 if (cur_wrlen) { 492 int i; 493 for (i = 0; i < max_connection; i++) { 494 if (netfd[i] >= 0) 495 write(netfd[i], writebuf, cur_wrlen); 496 } 497 cur_wrlen = 0; 498 } 499 } 500 501 /* 502 * get space from write buffer 503 */ 504 static char *get_writebuf(int len) 505 { 506 char *buf; 507 if (cur_wrlen + len >= max_wrlen) 508 flush_writebuf(); 509 buf = writebuf + cur_wrlen; 510 cur_wrlen += len; 511 return buf; 512 } 513 514 static void print_event(snd_seq_event_t *ev) 515 { 516 switch (ev->type) { 517 case SND_SEQ_EVENT_CONTROLLER: 518 printf(_("Channel %2d: Control event : %5d\n"), 519 ev->data.control.channel, ev->data.control.value); 520 break; 521 case SND_SEQ_EVENT_PITCHBEND: 522 printf(_("Channel %2d: Pitchbender : %5d\n"), 523 ev->data.control.channel, ev->data.control.value); 524 break; 525 case SND_SEQ_EVENT_NOTEON: 526 printf(_("Channel %2d: Note On event : %5d\n"), 527 ev->data.control.channel, ev->data.note.note); 528 break; 529 case SND_SEQ_EVENT_NOTEOFF: 530 printf(_("Channel %2d: Note Off event: %5d\n"), 531 ev->data.control.channel, ev->data.note.note); 532 break; 533 } 534 } 535 536 #define EVENT_PACKET_SIZE 32 537 538 /* 539 * copy events from sequencer to port(s) 540 */ 541 static int copy_local_to_remote(void) 542 { 543 int rc; 544 snd_seq_event_t *ev; 545 char *buf; 546 547 while ((rc = snd_seq_event_input(handle, &ev)) >= 0 && ev) { 548 if (ev->type >= SND_SEQ_EVENT_CLIENT_START && 549 ! snd_seq_ev_is_variable_type(ev)) { 550 snd_seq_free_event(ev); 551 continue; 552 } 553 if (snd_seq_ev_is_variable(ev)) { 554 int len; 555 len = EVENT_PACKET_SIZE + ev->data.ext.len; 556 buf = get_writebuf(len); 557 memcpy(buf, ev, sizeof(snd_seq_event_t)); 558 memcpy(buf + EVENT_PACKET_SIZE, ev->data.ext.ptr, ev->data.ext.len); 559 } else { 560 buf = get_writebuf(EVENT_PACKET_SIZE); 561 memcpy(buf, ev, EVENT_PACKET_SIZE); 562 } 563 if (info) 564 print_event(ev); 565 snd_seq_free_event(ev); 566 } 567 flush_writebuf(); 568 return 0; 569 } 570 571 /* 572 * copy events from a port to sequencer 573 */ 574 static int copy_remote_to_local(int fd) 575 { 576 int count; 577 char *buf; 578 snd_seq_event_t *ev; 579 580 count = read(fd, readbuf, MAX_BUF_EVENTS * sizeof(snd_seq_event_t)); 581 buf = readbuf; 582 583 if (count == 0) { 584 if (verbose) 585 fprintf(stderr, _("disconnected\n")); 586 return 1; 587 } 588 589 while (count > 0) { 590 ev = (snd_seq_event_t*)buf; 591 buf += EVENT_PACKET_SIZE; 592 count -= EVENT_PACKET_SIZE; 593 if (snd_seq_ev_is_variable(ev) && ev->data.ext.len > 0) { 594 ev->data.ext.ptr = buf; 595 buf += ev->data.ext.len; 596 count -= ev->data.ext.len; 597 } 598 snd_seq_ev_set_direct(ev); 599 snd_seq_ev_set_source(ev, seq_port); 600 snd_seq_ev_set_subs(ev); 601 if (info) 602 print_event(ev); 603 snd_seq_event_output(handle, ev); 604 } 605 606 snd_seq_drain_output(handle); 607 return 0; 608 } 609