• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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