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