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 
main(int argc,char ** argv)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  */
usage(void)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  */
init_buf(void)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  */
init_pollfds(void)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  */
close_files(void)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  */
init_seq(char * source,char * dest)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  */
get_port(char * service)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  */
sigterm_exit(int sig)318 static void sigterm_exit(int sig)
319 {
320 	close_files();
321 	exit(1);
322 }
323 
324 
325 /*
326  * initialize network server
327  */
init_server(int port)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  */
start_connection(void)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  */
init_client(char * server,int port)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  */
do_loop(void)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  */
flush_writebuf(void)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  */
get_writebuf(int len)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 
print_event(snd_seq_event_t * ev)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  */
copy_local_to_remote(void)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  */
copy_remote_to_local(int fd)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 
610