tarina

git clone https://git.tarina.org/tarina
Log | Files | Refs | README | LICENSE

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