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