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 # : sepcify 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);