2 * network server/client for ALSA sequencer
5 * Copyright (C) 1999-2000 Takashi Iwai
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.
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.
22 #include <netinet/in.h>
23 #include <sys/socket.h>
26 #include <alsa/asoundlib.h>
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);
50 * default TCP port number
52 #define DEFAULT_PORT 40002
59 static char *writebuf;
60 static int cur_wrlen, max_wrlen;
62 #define MAX_BUF_EVENTS 200
63 #define MAX_CONNECTION 10
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;
77 static int server_mode;
78 static int verbose = 0;
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'},
96 int main(int argc, char **argv)
99 int port = DEFAULT_PORT;
100 char *source = NULL, *dest = NULL;
103 setlocale(LC_ALL, "");
107 while ((c = getopt_long(argc, argv, "p:s:d:vi", long_option, NULL)) != -1) {
110 if (isdigit(*optarg))
113 port = get_port(optarg);
133 signal(SIGINT, sigterm_exit);
134 signal(SIGTERM, sigterm_exit);
137 init_seq(source, dest);
139 if (optind >= argc) {
141 max_connection = MAX_CONNECTION;
148 init_client(argv[optind], port);
162 static void usage(void)
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"));
179 * allocate and initialize buffers
181 static void init_buf(void)
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"));
191 memset(writebuf, 0, max_wrlen);
192 memset(readbuf, 0, max_rdlen);
197 * allocate and initialize poll array
199 static void init_pollfds(void)
201 pollfds_count = seqifds_count + seqofds_count + 1 + max_connection;
202 pollfds = (struct pollfd *)calloc(pollfds_count, sizeof(struct pollfd));
209 static void close_files(void)
213 fprintf(stderr, _("closing files..\n"));
214 for (i = 0; i < max_connection; i++) {
224 * initialize sequencer
226 static void init_seq(char *source, char *dest)
229 int err, counti, counto;
231 if (snd_seq_open(&handle, "default", SND_SEQ_OPEN_DUPLEX, 0) < 0) {
232 perror("snd_seq_open");
239 counti = seqifds_count = snd_seq_poll_descriptors_count(handle, POLLIN);
241 counto = seqofds_count = snd_seq_poll_descriptors_count(handle, POLLOUT);
243 seqifds = (struct pollfd *)calloc(counti, sizeof(struct pollfd));
245 seqofds = (struct pollfd *)calloc(counto, sizeof(struct pollfd));
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);
252 snd_seq_nonblock(handle, 1);
254 /* set client info */
256 snd_seq_set_client_name(handle, "Net Server");
258 snd_seq_set_client_name(handle, "Net Client");
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);
268 perror("create seq port");
272 fprintf(stderr, _("sequencer opened: %d:%d\n"),
273 snd_seq_client_id(handle), seq_port);
275 /* explicit subscriptions */
277 /* read subscription */
278 if (snd_seq_parse_address(handle, &addr, source) < 0) {
279 fprintf(stderr, _("invalid source address %s\n"), source);
282 if (snd_seq_connect_from(handle, seq_port, addr.client, addr.port)) {
283 perror("read subscription");
288 /* write subscription */
289 if (snd_seq_parse_address(handle, &addr, dest) < 0) {
290 fprintf(stderr, _("invalid destination address %s\n"), dest);
293 if (snd_seq_connect_to(handle, seq_port, addr.client, addr.port)) {
294 perror("write subscription");
302 * convert from string to TCP port number
304 static int get_port(char *service)
308 if ((sp = getservbyname(service, "tcp")) == NULL){
309 fprintf(stderr, _("service '%s' is not found in /etc/services\n"), service);
318 static void sigterm_exit(int sig)
326 * initialize network server
328 static void init_server(int port)
332 struct sockaddr_in addr;
334 memset(&addr, 0, sizeof(addr));
336 addr.sin_family = AF_INET;
337 addr.sin_addr.s_addr = INADDR_ANY;
338 addr.sin_port = htons(port);
340 sockfd = socket(AF_INET, SOCK_STREAM, 0);
342 perror("create socket");
345 setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &curstate, sizeof(curstate));
346 /* the return value is ignored.. */
348 if (bind(sockfd, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
349 perror("can't bind");
353 if (listen(sockfd, 5) < 0) {
354 perror("can't listen");
359 for (i = 0; i < max_connection; i++)
364 * start connection on server
366 static void start_connection(void)
368 struct sockaddr_in addr;
372 for (i = 0; i < max_connection; i++) {
376 if (i >= max_connection) {
377 fprintf(stderr, _("too many connections!\n"));
380 memset(&addr, 0, sizeof(addr));
381 addr_len = sizeof(addr);
382 netfd[i] = accept(sockfd, (struct sockaddr *)&addr, &addr_len);
388 fprintf(stderr, _("accepted[%d]\n"), netfd[i]);
393 * initialize network client
395 static void init_client(char *server, int port)
397 struct sockaddr_in addr;
398 struct hostent *host;
402 if ((fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0){
403 perror("create socket");
406 if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &curstate, sizeof(curstate)) < 0) {
407 perror("setsockopt");
410 if ((host = gethostbyname(server)) == NULL){
411 fprintf(stderr, _("can't get address %s\n"), server);
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) {
422 fprintf(stderr, _("ok.. connected\n"));
430 static void do_loop(void)
433 int seqifd_ptr, sockfd_ptr = -1, netfd_ptr;
436 memset(pollfds, 0, pollfds_count * sizeof(struct pollfd));
438 memcpy(pollfds, seqifds, sizeof(*seqifds)*(width = seqifds_count));
441 pollfds[width].fd = sockfd;
442 pollfds[width].events = POLLIN;
446 for (i = 0; i < max_connection; i++) {
448 pollfds[width].fd = netfd[i];
449 pollfds[width].events = POLLIN;
454 rc = poll(pollfds, width, -1);
455 } while (rc <= 0 && errno == EINTR);
461 if (pollfds[sockfd_ptr].revents & (POLLIN|POLLOUT))
464 for (i = 0; i < seqifds_count; i++)
465 if (pollfds[seqifd_ptr + i].revents & (POLLIN|POLLOUT)) {
466 if (copy_local_to_remote())
470 for (i = 0; i < max_connection; i++) {
473 if (pollfds[netfd_ptr + i].revents & (POLLIN|POLLOUT)) {
474 if (copy_remote_to_local(netfd[i])) {
477 if (cur_connected <= 0)
487 * flush write buffer - send data to the socket
489 static void flush_writebuf(void)
493 for (i = 0; i < max_connection; i++) {
495 write(netfd[i], writebuf, cur_wrlen);
502 * get space from write buffer
504 static char *get_writebuf(int len)
507 if (cur_wrlen + len >= max_wrlen)
509 buf = writebuf + cur_wrlen;
514 static void print_event(snd_seq_event_t *ev)
517 case SND_SEQ_EVENT_CONTROLLER:
518 printf(_("Channel %2d: Control event : %5d\n"),
519 ev->data.control.channel, ev->data.control.value);
521 case SND_SEQ_EVENT_PITCHBEND:
522 printf(_("Channel %2d: Pitchbender : %5d\n"),
523 ev->data.control.channel, ev->data.control.value);
525 case SND_SEQ_EVENT_NOTEON:
526 printf(_("Channel %2d: Note On event : %5d\n"),
527 ev->data.control.channel, ev->data.note.note);
529 case SND_SEQ_EVENT_NOTEOFF:
530 printf(_("Channel %2d: Note Off event: %5d\n"),
531 ev->data.control.channel, ev->data.note.note);
536 #define EVENT_PACKET_SIZE 32
539 * copy events from sequencer to port(s)
541 static int copy_local_to_remote(void)
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);
553 if (snd_seq_ev_is_variable(ev)) {
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);
560 buf = get_writebuf(EVENT_PACKET_SIZE);
561 memcpy(buf, ev, EVENT_PACKET_SIZE);
565 snd_seq_free_event(ev);
572 * copy events from a port to sequencer
574 static int copy_remote_to_local(int fd)
580 count = read(fd, readbuf, MAX_BUF_EVENTS * sizeof(snd_seq_event_t));
585 fprintf(stderr, _("disconnected\n"));
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;
598 snd_seq_ev_set_direct(ev);
599 snd_seq_ev_set_source(ev, seq_port);
600 snd_seq_ev_set_subs(ev);
603 snd_seq_event_output(handle, ev);
606 snd_seq_drain_output(handle);