From 4413d72a3b1f88919d019c9c16f5c354b4e143fa Mon Sep 17 00:00:00 2001 From: Dave Kelly Date: Mon, 28 Jan 2019 19:35:45 -0800 Subject: [PATCH 01/33] Added option for service discovery --- raveloxmidi/man/raveloxmidi.1.in | 3 + raveloxmidi/src/Makefile.am | 1 + raveloxmidi/src/dns_service_discoverer.c | 180 +++++++++++++++++++++++ raveloxmidi/src/raveloxmidi.c | 8 +- raveloxmidi/src/raveloxmidi_config.c | 9 +- 5 files changed, 198 insertions(+), 3 deletions(-) create mode 100644 raveloxmidi/src/dns_service_discoverer.c diff --git a/raveloxmidi/man/raveloxmidi.1.in b/raveloxmidi/man/raveloxmidi.1.in index 46b0f5d..8f9e58f 100644 --- a/raveloxmidi/man/raveloxmidi.1.in +++ b/raveloxmidi/man/raveloxmidi.1.in @@ -59,6 +59,9 @@ Number of connections that can be made to @PACKAGE@. Maximum is 255. Minimum is .B service.name Label to prepend to mDNS service name "_apple-midi._udp". ( default is raveloxmidi ) .TP +.B client.name +Label to use when making a rtpMIDI connection to a remote service. ( default is raveloxremote ) +.TP .B run_as_daemon Run the binary in the background. Can be yes or no. ( default is yes ). .TP diff --git a/raveloxmidi/src/Makefile.am b/raveloxmidi/src/Makefile.am index f1b900d..8c98bb0 100755 --- a/raveloxmidi/src/Makefile.am +++ b/raveloxmidi/src/Makefile.am @@ -3,6 +3,7 @@ bin_PROGRAMS = raveloxmidi raveloxmidi_SOURCES = \ raveloxmidi.c \ dns_service_publisher.c \ + dns_service_discoverer.c \ cmd_end_handler.c \ cmd_inv_handler.c \ cmd_sync_handler.c \ diff --git a/raveloxmidi/src/dns_service_discoverer.c b/raveloxmidi/src/dns_service_discoverer.c new file mode 100644 index 0000000..118ff99 --- /dev/null +++ b/raveloxmidi/src/dns_service_discoverer.c @@ -0,0 +1,180 @@ +/*** + This file is a modified version of client-browse-services.c + which uses AvahiThreadedPoll + + client-browse-services.c is part of avahi. + + avahi is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) any later version. + avahi is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General + Public License for more details. + You should have received a copy of the GNU Lesser General Public + License along with avahi; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include + +static AvahiThreadedPoll *threaded_poll = NULL; +static AvahiClient *client = NULL; + +static void resolve_callback( + AvahiServiceResolver *r, + AVAHI_GCC_UNUSED AvahiIfIndex interface, + AVAHI_GCC_UNUSED AvahiProtocol protocol, + AvahiResolverEvent event, + const char *name, + const char *type, + const char *domain, + const char *host_name, + const AvahiAddress *address, + uint16_t port, + AvahiStringList *txt, + AvahiLookupResultFlags flags, + AVAHI_GCC_UNUSED void* userdata) { + + assert(r); + + /* Called whenever a service has been resolved successfully or timed out */ + switch (event) { + case AVAHI_RESOLVER_FAILURE: + fprintf(stderr, "(Resolver) Failed to resolve service '%s' of type '%s' in domain '%s': %s\n", name, type, domain, avahi_strerror(avahi_client_errno(avahi_service_resolver_get_client(r)))); + break; + case AVAHI_RESOLVER_FOUND: { + char a[AVAHI_ADDRESS_STR_MAX], *t; + fprintf(stderr, "Service '%s' of type '%s' in domain '%s':\n", name, type, domain); + avahi_address_snprint(a, sizeof(a), address); + t = avahi_string_list_to_string(txt); + fprintf(stderr, + "\t%s:%u (%s)\n" + "\tTXT=%s\n" + "\tcookie is %u\n" + "\tis_local: %i\n" + "\tour_own: %i\n" + "\twide_area: %i\n" + "\tmulticast: %i\n" + "\tcached: %i\n", + host_name, port, a, + t, + avahi_string_list_get_service_cookie(txt), + !!(flags & AVAHI_LOOKUP_RESULT_LOCAL), + !!(flags & AVAHI_LOOKUP_RESULT_OUR_OWN), + !!(flags & AVAHI_LOOKUP_RESULT_WIDE_AREA), + !!(flags & AVAHI_LOOKUP_RESULT_MULTICAST), + !!(flags & AVAHI_LOOKUP_RESULT_CACHED)); + avahi_free(t); + } + } + avahi_service_resolver_free(r); +} + +static void browse_callback( + AvahiServiceBrowser *b, + AvahiIfIndex interface, + AvahiProtocol protocol, + AvahiBrowserEvent event, + const char *name, + const char *type, + const char *domain, + AVAHI_GCC_UNUSED AvahiLookupResultFlags flags, + void* userdata) { + AvahiClient *c = userdata; + + assert(b); + + /* Called whenever a new services becomes available on the LAN or is removed from the LAN */ + switch (event) { + case AVAHI_BROWSER_FAILURE: + fprintf(stderr, "(Browser) %s\n", avahi_strerror(avahi_client_errno(avahi_service_browser_get_client(b)))); + avahi_threaded_poll_quit( threaded_poll ); + return; + case AVAHI_BROWSER_NEW: + fprintf(stderr, "(Browser) NEW: service '%s' of type '%s' in domain '%s'\n", name, type, domain); + /* We ignore the returned resolver object. In the callback + function we free it. If the server is terminated before + the callback function is called the server will free + the resolver for us. */ + if (!(avahi_service_resolver_new(c, interface, protocol, name, type, domain, AVAHI_PROTO_UNSPEC, 0, resolve_callback, c))) + fprintf(stderr, "Failed to resolve service '%s': %s\n", name, avahi_strerror(avahi_client_errno(c))); + break; + case AVAHI_BROWSER_REMOVE: + fprintf(stderr, "(Browser) REMOVE: service '%s' of type '%s' in domain '%s'\n", name, type, domain); + break; + case AVAHI_BROWSER_ALL_FOR_NOW: + case AVAHI_BROWSER_CACHE_EXHAUSTED: + fprintf(stderr, "(Browser) %s\n", event == AVAHI_BROWSER_CACHE_EXHAUSTED ? "CACHE_EXHAUSTED" : "ALL_FOR_NOW"); + break; + } +} + +static void client_callback(AvahiClient *c, AvahiClientState state, AVAHI_GCC_UNUSED void * userdata) { + + assert(c); + + /* Called whenever the client or server state changes */ + if (state == AVAHI_CLIENT_FAILURE) { + fprintf(stderr, "Server connection failure: %s\n", avahi_strerror(avahi_client_errno(c))); + avahi_threaded_poll_quit(threaded_poll); + } +} + +void dns_discover_services( void ) +{ + AvahiServiceBrowser *sb = NULL; + int error; + int ret = 1; + struct timeval timeout; + + if (!(threaded_poll = avahi_threaded_poll_new())) { + fprintf(stderr, "Failed to create threaded poll object.\n"); + goto fail; + } + /* Allocate a new client */ + client = avahi_client_new(avahi_threaded_poll_get(threaded_poll), 0, client_callback, NULL, &error); + + if (!client) { + fprintf(stderr, "Failed to create client: %s\n", avahi_strerror(error)); + goto fail; + } + + if (!(sb = avahi_service_browser_new(client, AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC, "_apple-midi._udp", NULL, 0, browse_callback, client))) { + fprintf(stderr, "Failed to create service browser: %s\n", avahi_strerror(avahi_client_errno(client))); + goto fail; + } + + avahi_threaded_poll_start(threaded_poll); + ret = 0; + timeout.tv_sec = 10; + timeout.tv_usec= 0; + select( 0, NULL, NULL, NULL, &timeout ); + +fail: + if (sb) avahi_service_browser_free(sb); + + if (threaded_poll) avahi_threaded_poll_stop( threaded_poll ); + + if (client) avahi_client_free(client); + + if (threaded_poll) avahi_threaded_poll_free( threaded_poll ); + return ret; +} diff --git a/raveloxmidi/src/raveloxmidi.c b/raveloxmidi/src/raveloxmidi.c index 70b6108..47afdd5 100644 --- a/raveloxmidi/src/raveloxmidi.c +++ b/raveloxmidi/src/raveloxmidi.c @@ -33,6 +33,7 @@ #include "utils.h" #include "dns_service_publisher.h" +#include "dns_service_discoverer.h" #include "raveloxmidi_config.h" #include "daemon.h" @@ -55,6 +56,12 @@ int main(int argc, char *argv[]) logging_init(); logging_printf( LOGGING_INFO, "%s (%s)\n", PACKAGE, VERSION); + if( is_yes( config_string_get("discover.services" ) ) ) + { + dns_discover_services(); + goto daemon_stop; + } + #ifdef HAVE_ALSA raveloxmidi_alsa_init( config_string_get("alsa.input_device") , config_string_get("alsa.output_device") , config_int_get("alsa.input_buffer_size") ); #endif @@ -116,6 +123,5 @@ int main(int argc, char *argv[]) logging_teardown(); - return 0; } diff --git a/raveloxmidi/src/raveloxmidi_config.c b/raveloxmidi/src/raveloxmidi_config.c index e1e4f3a..3971cdb 100644 --- a/raveloxmidi/src/raveloxmidi_config.c +++ b/raveloxmidi/src/raveloxmidi_config.c @@ -53,6 +53,7 @@ static void config_set_defaults( void ) config_add_item("readonly","no"); config_add_item("inbound_midi","/dev/sequencer"); config_add_item("file_mode", "0640"); + config_add_Item("client.name", "raveloxremote"); #ifdef HAVE_ALSA config_add_item("alsa.input_buffer_size", "4096" ); @@ -191,6 +192,9 @@ void config_init( int argc, char *argv[] ) case 'C': dump_config = 1; break; + case 'D': + config_add_item("discover.services", "yes"); + break; } } @@ -329,9 +333,9 @@ void config_dump( void ) void config_usage( void ) { fprintf( stderr, "Usage:\n"); - fprintf( stderr, "\traveloxmidi [-c filename] [-d] [-I] [-R] [-N] [-P filename] [-C] [-h]"); + fprintf( stderr, "\traveloxmidi [-c filename] [-d] [-I] [-R] [-N] [-P filename] [-C] [-D] [-h]"); fprintf( stderr, "\n"); - fprintf( stderr, "\traveloxmidi [--config filename] [--debug] [--info] [--readonly] [--nodaemon] [--pidfile filename] [--dumpconfig] [--help]"); + fprintf( stderr, "\traveloxmidi [--config filename] [--debug] [--info] [--readonly] [--nodaemon] [--pidfile filename] [--dumpconfig] [--discover] [--help]"); fprintf( stderr, "\n"); fprintf( stderr, "\n"); fprintf( stderr, "-c filename\tName of config file to use\n"); @@ -340,6 +344,7 @@ void config_usage( void ) fprintf( stderr, "-N\t\tDo not run in the background\n"); fprintf( stderr, "-P filename\tName of file to write background pid\n"); fprintf( stderr, "-C\t\tDump the current config to stderr\n"); + fprintf( stderr, "-D\t\tDiscover rtpMIDI services\n"); fprintf( stderr, "-h\t\tThis output\n"); fprintf( stderr, "\nThe following configuration file items are default:\n"); config_dump(); From 39aa2ce277403fd37de4a7e2454dd5d05fb9f921 Mon Sep 17 00:00:00 2001 From: Dave Kelly Date: Mon, 28 Jan 2019 19:37:53 -0800 Subject: [PATCH 02/33] Added dns_service_discover header --- raveloxmidi/include/dns_service_discoverer.h | 26 ++++++++++++++++++++ 1 file changed, 26 insertions(+) create mode 100644 raveloxmidi/include/dns_service_discoverer.h diff --git a/raveloxmidi/include/dns_service_discoverer.h b/raveloxmidi/include/dns_service_discoverer.h new file mode 100644 index 0000000..b343c16 --- /dev/null +++ b/raveloxmidi/include/dns_service_discoverer.h @@ -0,0 +1,26 @@ +/* + This file is part of raveloxmidi. + + Copyright (C) 2018 Dave Kelly + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef DNS_SERVICE_DISCOVERER_H +#define DNS_SERVICE_DISCOVERER_H + +void dns_discover_services( void ); + +#endif From 0cc2d5f5c92b2b572481bdd8340d93f72ecf8e61 Mon Sep 17 00:00:00 2001 From: Dave Kelly Date: Mon, 28 Jan 2019 19:39:41 -0800 Subject: [PATCH 03/33] Corrected typo --- raveloxmidi/src/raveloxmidi_config.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/raveloxmidi/src/raveloxmidi_config.c b/raveloxmidi/src/raveloxmidi_config.c index 3971cdb..a38e127 100644 --- a/raveloxmidi/src/raveloxmidi_config.c +++ b/raveloxmidi/src/raveloxmidi_config.c @@ -53,7 +53,7 @@ static void config_set_defaults( void ) config_add_item("readonly","no"); config_add_item("inbound_midi","/dev/sequencer"); config_add_item("file_mode", "0640"); - config_add_Item("client.name", "raveloxremote"); + config_add_item("client.name", "raveloxremote"); #ifdef HAVE_ALSA config_add_item("alsa.input_buffer_size", "4096" ); From c444ef3ccfea872939f7e23cef35197f8c3f52e0 Mon Sep 17 00:00:00 2001 From: Dave Kelly Date: Mon, 28 Jan 2019 19:40:38 -0800 Subject: [PATCH 04/33] Removed unnecessary return value --- raveloxmidi/src/dns_service_discoverer.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/raveloxmidi/src/dns_service_discoverer.c b/raveloxmidi/src/dns_service_discoverer.c index 118ff99..ab7c508 100644 --- a/raveloxmidi/src/dns_service_discoverer.c +++ b/raveloxmidi/src/dns_service_discoverer.c @@ -142,7 +142,6 @@ void dns_discover_services( void ) { AvahiServiceBrowser *sb = NULL; int error; - int ret = 1; struct timeval timeout; if (!(threaded_poll = avahi_threaded_poll_new())) { @@ -176,5 +175,4 @@ void dns_discover_services( void ) if (client) avahi_client_free(client); if (threaded_poll) avahi_threaded_poll_free( threaded_poll ); - return ret; } From 049ba601ce3bcddf7e36c57624cf5acecbd19faa Mon Sep 17 00:00:00 2001 From: Dave Kelly Date: Mon, 28 Jan 2019 19:42:01 -0800 Subject: [PATCH 05/33] Removed unused variable --- raveloxmidi/src/dns_service_discoverer.c | 1 - 1 file changed, 1 deletion(-) diff --git a/raveloxmidi/src/dns_service_discoverer.c b/raveloxmidi/src/dns_service_discoverer.c index ab7c508..4423b5a 100644 --- a/raveloxmidi/src/dns_service_discoverer.c +++ b/raveloxmidi/src/dns_service_discoverer.c @@ -162,7 +162,6 @@ void dns_discover_services( void ) } avahi_threaded_poll_start(threaded_poll); - ret = 0; timeout.tv_sec = 10; timeout.tv_usec= 0; select( 0, NULL, NULL, NULL, &timeout ); From e27b009ffd734431e1ebe19f441834c7dd9c2107 Mon Sep 17 00:00:00 2001 From: Dave Kelly Date: Mon, 28 Jan 2019 19:48:05 -0800 Subject: [PATCH 06/33] Correct startup options and man page --- raveloxmidi/man/raveloxmidi.1.in | 6 ++++-- raveloxmidi/src/raveloxmidi_config.c | 5 +++-- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/raveloxmidi/man/raveloxmidi.1.in b/raveloxmidi/man/raveloxmidi.1.in index 8f9e58f..67bec93 100644 --- a/raveloxmidi/man/raveloxmidi.1.in +++ b/raveloxmidi/man/raveloxmidi.1.in @@ -3,10 +3,10 @@ raveloxmidi - RTP MIDI proxy for NoteOn/NoteOff/ControlChange/ProgramChange events .SH SYNOPSIS .B raveloxmidi -[-c filename] [-d|-I] [-N] [-P filename] [-R] [-h] [-C] +[-c filename] [-d|-I] [-N] [-P filename] [-R] [-h] [-C] [-D] .B raveloxmidi -[--config filename] [--debug|--info] [--nodaemon] [--pidfile filename] [--readonly] [--help] [--dumpconfig] +[--config filename] [--debug|--info] [--nodaemon] [--pidfile filename] [--readonly] [--help] [--dumpconfig] [--discover] .SH DESCRIPTION .BR raveloxmidi provides a RTP MIDI proxy to send MIDI NoteOn, NoteOff, ControlChange and ProgramChange events to a remote MIDI device. @@ -35,6 +35,8 @@ Enable readonly mode. This doesn't write anything to disk. Display help information including default values for some parameters. .B -C Display the current config to stderr +.B -D +Discover available _apple-midi._udp services .SH NOTES The available options for the configuration file are as follows: .TP diff --git a/raveloxmidi/src/raveloxmidi_config.c b/raveloxmidi/src/raveloxmidi_config.c index a38e127..3d84958 100644 --- a/raveloxmidi/src/raveloxmidi_config.c +++ b/raveloxmidi/src/raveloxmidi_config.c @@ -138,6 +138,7 @@ void config_init( int argc, char *argv[] ) {"pidfile", required_argument, NULL, 'P'}, {"readonly", no_argument, NULL, 'R'}, {"dumpconfig", no_argument, NULL, 'C'}, + {"discover", no_argument, NULL, 'D'}, #ifdef HAVE_ALSA {"listinterfaces", no_argument, NULL, 'L'}, #endif @@ -145,9 +146,9 @@ void config_init( int argc, char *argv[] ) {0,0,0,0} }; #ifdef HAVE_ALSA - const char *short_options = "c:dIhNP:RLC"; + const char *short_options = "c:dIhNP:RLCD"; #else - const char *short_options = "c:dIhNP:RC"; + const char *short_options = "c:dIhNP:RCD"; #endif int c; config_items = NULL; From 6a1e92165ae70361cbee4c345e9bbf735d9de12a Mon Sep 17 00:00:00 2001 From: Dave Kelly Date: Wed, 30 Jan 2019 20:59:53 -0800 Subject: [PATCH 07/33] Renamed cmd_inv_handler to applemidi_inv --- .../include/{cmd_inv_handler.h => applemidi_inv.h} | 6 +++--- raveloxmidi/src/Makefile.am | 2 +- .../src/{cmd_inv_handler.c => applemidi_inv.c} | 12 ++++++------ raveloxmidi/src/net_socket.c | 4 ++-- 4 files changed, 12 insertions(+), 12 deletions(-) rename raveloxmidi/include/{cmd_inv_handler.h => applemidi_inv.h} (85%) rename raveloxmidi/src/{cmd_inv_handler.c => applemidi_inv.c} (82%) diff --git a/raveloxmidi/include/cmd_inv_handler.h b/raveloxmidi/include/applemidi_inv.h similarity index 85% rename from raveloxmidi/include/cmd_inv_handler.h rename to raveloxmidi/include/applemidi_inv.h index ec27918..29217d7 100644 --- a/raveloxmidi/include/cmd_inv_handler.h +++ b/raveloxmidi/include/applemidi_inv.h @@ -18,9 +18,9 @@ Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -#ifndef CMD_INV_HANDLER_H -#define CMD_INV_HANDLER_H +#ifndef APPLEMIDI_INV_H +#define APPLEMIDI_INV_H -net_response_t * cmd_inv_handler( char *ip_address, uint16_t port, void *data ); +net_response_t * applemidi_inv_responder( char *ip_address, uint16_t port, void *data ); #endif diff --git a/raveloxmidi/src/Makefile.am b/raveloxmidi/src/Makefile.am index 8c98bb0..308c7ab 100755 --- a/raveloxmidi/src/Makefile.am +++ b/raveloxmidi/src/Makefile.am @@ -5,7 +5,7 @@ raveloxmidi_SOURCES = \ dns_service_publisher.c \ dns_service_discoverer.c \ cmd_end_handler.c \ - cmd_inv_handler.c \ + applemidi_inv.c \ cmd_sync_handler.c \ cmd_feedback_handler.c \ midi_journal.c \ diff --git a/raveloxmidi/src/cmd_inv_handler.c b/raveloxmidi/src/applemidi_inv.c similarity index 82% rename from raveloxmidi/src/cmd_inv_handler.c rename to raveloxmidi/src/applemidi_inv.c index 19f5ecb..30e66e6 100644 --- a/raveloxmidi/src/cmd_inv_handler.c +++ b/raveloxmidi/src/applemidi_inv.c @@ -43,7 +43,7 @@ extern int errno; #include "raveloxmidi_config.h" #include "logging.h" -net_response_t * cmd_inv_handler( char *ip_address, uint16_t port, void *data ) +net_response_t * applemidi_inv_responder( char *ip_address, uint16_t port, void *data ) { net_applemidi_command *cmd = NULL; net_applemidi_inv *inv = NULL; @@ -64,12 +64,12 @@ net_response_t * cmd_inv_handler( char *ip_address, uint16_t port, void *data ) /* We assume that the current port is the control port */ if( ! ctx ) { - logging_printf( LOGGING_DEBUG, "cmd_inv_hander: Registering new connection\n"); + logging_printf( LOGGING_DEBUG, "applemidi_inv_responder: Registering new connection\n"); ctx = net_ctx_register( inv->ssrc, inv->initiator, ip_address, port ); if( ! ctx ) { - logging_printf( LOGGING_ERROR, "cmd_inv_handler: Error registering connection\n"); + logging_printf( LOGGING_ERROR, "applemidi_inv_responder: Error registering connection\n"); } /* Otherwise, we assume that the current port is the data port */ } else { @@ -80,7 +80,7 @@ net_response_t * cmd_inv_handler( char *ip_address, uint16_t port, void *data ) if( ! cmd ) { - logging_printf( LOGGING_ERROR, "cmd_inv_handler: Unable to allocate memory for accept_inv command\n"); + logging_printf( LOGGING_ERROR, "applemidi_inv_responder: Unable to allocate memory for accept_inv command\n"); net_ctx_destroy( &ctx ); return NULL; } @@ -88,7 +88,7 @@ net_response_t * cmd_inv_handler( char *ip_address, uint16_t port, void *data ) accept_inv = net_applemidi_inv_create(); if( ! accept_inv ) { - logging_printf( LOGGING_ERROR, "cmd_inv_handler: Unable to allocate memory for accept_inv command data\n"); + logging_printf( LOGGING_ERROR, "applemidi_inv_responder: Unable to allocate memory for accept_inv command data\n"); free( cmd ); net_ctx_destroy( &ctx ); return NULL; @@ -115,7 +115,7 @@ net_response_t * cmd_inv_handler( char *ip_address, uint16_t port, void *data ) ret = net_applemidi_pack( cmd , &(response->buffer), &(response->len) ); if( ret != 0 ) { - logging_printf( LOGGING_ERROR, "cmd_inv_handler: Unable to pack response to inv command\n"); + logging_printf( LOGGING_ERROR, "applemidi_inv_responder: Unable to pack response to inv command\n"); net_response_destroy( &response ); } } diff --git a/raveloxmidi/src/net_socket.c b/raveloxmidi/src/net_socket.c index 871167c..e6d0cf5 100644 --- a/raveloxmidi/src/net_socket.c +++ b/raveloxmidi/src/net_socket.c @@ -42,7 +42,7 @@ extern int errno; #include "net_socket.h" #include "net_connection.h" -#include "cmd_inv_handler.h" +#include "applemidi_inv.h" #include "cmd_sync_handler.h" #include "cmd_feedback_handler.h" #include "cmd_end_handler.h" @@ -224,7 +224,7 @@ int net_socket_read( int fd ) switch( command->command ) { case NET_APPLEMIDI_CMD_INV: - response = cmd_inv_handler( ip_address, from_port, command->data ); + response = applemidi_inv_responder( ip_address, from_port, command->data ); break; case NET_APPLEMIDI_CMD_ACCEPT: break; From 94de71ec9075172db9846f2e7840b0dcc0388ce5 Mon Sep 17 00:00:00 2001 From: Dave Kelly Date: Wed, 30 Jan 2019 21:06:05 -0800 Subject: [PATCH 08/33] Renamed cmd_end_handler to applemidi_by --- raveloxmidi/include/{cmd_end_handler.h => applemidi_by.h} | 6 +++--- raveloxmidi/src/Makefile.am | 2 +- raveloxmidi/src/{cmd_end_handler.c => applemidi_by.c} | 4 ++-- raveloxmidi/src/net_socket.c | 2 +- 4 files changed, 7 insertions(+), 7 deletions(-) rename raveloxmidi/include/{cmd_end_handler.h => applemidi_by.h} (88%) rename raveloxmidi/src/{cmd_end_handler.c => applemidi_by.c} (91%) diff --git a/raveloxmidi/include/cmd_end_handler.h b/raveloxmidi/include/applemidi_by.h similarity index 88% rename from raveloxmidi/include/cmd_end_handler.h rename to raveloxmidi/include/applemidi_by.h index 9d9d723..ce70f6b 100644 --- a/raveloxmidi/include/cmd_end_handler.h +++ b/raveloxmidi/include/applemidi_by.h @@ -18,9 +18,9 @@ Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -#ifndef CMD_END_HANDLER_H -#define CMD_END_HANDLER_H +#ifndef APPLEMIDI_BY_H +#define APPLEMIDI_BY_H -net_response_t * cmd_end_handler( void *data ); +net_response_t * applemidi_by_responder( void *data ); #endif diff --git a/raveloxmidi/src/Makefile.am b/raveloxmidi/src/Makefile.am index 308c7ab..681edfd 100755 --- a/raveloxmidi/src/Makefile.am +++ b/raveloxmidi/src/Makefile.am @@ -4,8 +4,8 @@ raveloxmidi_SOURCES = \ raveloxmidi.c \ dns_service_publisher.c \ dns_service_discoverer.c \ - cmd_end_handler.c \ applemidi_inv.c \ + applemidi_by.c \ cmd_sync_handler.c \ cmd_feedback_handler.c \ midi_journal.c \ diff --git a/raveloxmidi/src/cmd_end_handler.c b/raveloxmidi/src/applemidi_by.c similarity index 91% rename from raveloxmidi/src/cmd_end_handler.c rename to raveloxmidi/src/applemidi_by.c index 135e6e6..205757f 100644 --- a/raveloxmidi/src/cmd_end_handler.c +++ b/raveloxmidi/src/applemidi_by.c @@ -42,7 +42,7 @@ extern int errno; #include "logging.h" -net_response_t * cmd_end_handler( void *data ) +net_response_t * applemidi_by_responder( void *data ) { net_applemidi_inv *inv = NULL; net_ctx_t *ctx = NULL; @@ -55,7 +55,7 @@ net_response_t * cmd_end_handler( void *data ) if( ! ctx ) { - logging_printf( LOGGING_WARN, "cmd_end_handler:No existing connection found\n"); + logging_printf( LOGGING_WARN, "applemidi_by_responder:No existing connection found\n"); return NULL; } diff --git a/raveloxmidi/src/net_socket.c b/raveloxmidi/src/net_socket.c index e6d0cf5..7f090f6 100644 --- a/raveloxmidi/src/net_socket.c +++ b/raveloxmidi/src/net_socket.c @@ -45,7 +45,7 @@ extern int errno; #include "applemidi_inv.h" #include "cmd_sync_handler.h" #include "cmd_feedback_handler.h" -#include "cmd_end_handler.h" +#include "applemidi_end.h" #include "midi_note.h" #include "midi_control.h" From db241a1f58e7e656e6786c60a12d986f8d33277c Mon Sep 17 00:00:00 2001 From: Dave Kelly Date: Wed, 30 Jan 2019 21:07:03 -0800 Subject: [PATCH 09/33] Corrected include filename --- raveloxmidi/src/net_socket.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/raveloxmidi/src/net_socket.c b/raveloxmidi/src/net_socket.c index 7f090f6..ab902fa 100644 --- a/raveloxmidi/src/net_socket.c +++ b/raveloxmidi/src/net_socket.c @@ -45,7 +45,7 @@ extern int errno; #include "applemidi_inv.h" #include "cmd_sync_handler.h" #include "cmd_feedback_handler.h" -#include "applemidi_end.h" +#include "applemidi_by.h" #include "midi_note.h" #include "midi_control.h" From fc7a23785639912f5f8aa62ff29833eaeaba3b7f Mon Sep 17 00:00:00 2001 From: Dave Kelly Date: Wed, 30 Jan 2019 21:12:01 -0800 Subject: [PATCH 10/33] Renamed cmd_feedback_handler to applemidi_feedback --- .../{cmd_feedback_handler.h => applemidi_feedback.h} | 8 ++++---- raveloxmidi/src/Makefile.am | 2 +- .../{cmd_feedback_handler.c => applemidi_feedback.c} | 10 +++++----- raveloxmidi/src/net_socket.c | 4 ++-- 4 files changed, 12 insertions(+), 12 deletions(-) rename raveloxmidi/include/{cmd_feedback_handler.h => applemidi_feedback.h} (80%) rename raveloxmidi/src/{cmd_feedback_handler.c => applemidi_feedback.c} (81%) diff --git a/raveloxmidi/include/cmd_feedback_handler.h b/raveloxmidi/include/applemidi_feedback.h similarity index 80% rename from raveloxmidi/include/cmd_feedback_handler.h rename to raveloxmidi/include/applemidi_feedback.h index d299c6d..f9f7f96 100644 --- a/raveloxmidi/include/cmd_feedback_handler.h +++ b/raveloxmidi/include/applemidi_feedback.h @@ -18,10 +18,10 @@ Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -#ifndef CMD_feedback_HANDLER_H -#define CMD_feedback_HANDLER_H +#ifndef APPLEMIDI_FEEDBACK_H +#define APPLEMIDI_FEEDBACK_H -net_response_t * cmd_feedback_handler( void *data ); -net_response_t *cmd_feedback_create( uint32_t ssrc, uint16_t rtp_seq ); +net_response_t * applemidi_feedback_handler( void *data ); +net_response_t * applemidi_feedback_create( uint32_t ssrc, uint16_t rtp_seq ); #endif diff --git a/raveloxmidi/src/Makefile.am b/raveloxmidi/src/Makefile.am index 681edfd..34f4fd7 100755 --- a/raveloxmidi/src/Makefile.am +++ b/raveloxmidi/src/Makefile.am @@ -6,8 +6,8 @@ raveloxmidi_SOURCES = \ dns_service_discoverer.c \ applemidi_inv.c \ applemidi_by.c \ + applemidi_feedback.c \ cmd_sync_handler.c \ - cmd_feedback_handler.c \ midi_journal.c \ chapter_p.c \ chapter_n.c \ diff --git a/raveloxmidi/src/cmd_feedback_handler.c b/raveloxmidi/src/applemidi_feedback.c similarity index 81% rename from raveloxmidi/src/cmd_feedback_handler.c rename to raveloxmidi/src/applemidi_feedback.c index 5996590..8f77261 100644 --- a/raveloxmidi/src/cmd_feedback_handler.c +++ b/raveloxmidi/src/applemidi_feedback.c @@ -45,7 +45,7 @@ extern int errno; #include "logging.h" -net_response_t * cmd_feedback_handler( void *data ) +net_response_t * applemidi_feedback_responder( void *data ) { net_applemidi_feedback *feedback; net_ctx_t *ctx = NULL; @@ -58,21 +58,21 @@ net_response_t * cmd_feedback_handler( void *data ) if( ! ctx ) { - logging_printf(LOGGING_DEBUG,"cmd_feedback_handler: No context found (search=%u)\n", feedback->rtp_seq[1]); + logging_printf(LOGGING_DEBUG,"applemidi_feedback_responder: No context found (search=%u)\n", feedback->rtp_seq[1]); return NULL; } - logging_printf( LOGGING_DEBUG, "cmd_feedback_handler: Context found ( search=%u, found=%u )\n", feedback->rtp_seq[1], ctx->seq ); + logging_printf( LOGGING_DEBUG, "applemidi_feedback_responder: Context found ( search=%u, found=%u )\n", feedback->rtp_seq[1], ctx->seq ); if( feedback->rtp_seq[1] >= ctx->seq ) { - logging_printf( LOGGING_DEBUG, "cmd_feedback_handler: Resetting journal\n" ); + logging_printf( LOGGING_DEBUG, "applemidi_feedback_responder: Resetting journal\n" ); journal_reset( ctx->journal ); } return NULL; } -net_response_t *cmd_feedback_create( uint32_t ssrc, uint16_t rtp_seq ) +net_response_t *applemidi_feedback_create( uint32_t ssrc, uint16_t rtp_seq ) { net_applemidi_command *cmd = NULL; net_applemidi_feedback *feedback = NULL; diff --git a/raveloxmidi/src/net_socket.c b/raveloxmidi/src/net_socket.c index ab902fa..cbf3dc9 100644 --- a/raveloxmidi/src/net_socket.c +++ b/raveloxmidi/src/net_socket.c @@ -231,13 +231,13 @@ int net_socket_read( int fd ) case NET_APPLEMIDI_CMD_REJECT: break; case NET_APPLEMIDI_CMD_END: - response = cmd_end_handler( command->data ); + response = applemidi_by_responder( command->data ); break; case NET_APPLEMIDI_CMD_SYNC: response = cmd_sync_handler( command->data ); break; case NET_APPLEMIDI_CMD_FEEDBACK: - response = cmd_feedback_handler( command->data ); + response = applemidi_feedback_responder( command->data ); break; case NET_APPLEMIDI_CMD_BITRATE: break; From 57269c19f10744e84bfde2f719c7033eb9f228f7 Mon Sep 17 00:00:00 2001 From: Dave Kelly Date: Wed, 30 Jan 2019 21:12:49 -0800 Subject: [PATCH 11/33] Corrected include filename --- raveloxmidi/src/net_socket.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/raveloxmidi/src/net_socket.c b/raveloxmidi/src/net_socket.c index cbf3dc9..e48b9ac 100644 --- a/raveloxmidi/src/net_socket.c +++ b/raveloxmidi/src/net_socket.c @@ -44,7 +44,7 @@ extern int errno; #include "applemidi_inv.h" #include "cmd_sync_handler.h" -#include "cmd_feedback_handler.h" +#include "applemidi_feedback.h" #include "applemidi_by.h" #include "midi_note.h" From 7657e5326a3c493fa187a7d218666ae328b53829 Mon Sep 17 00:00:00 2001 From: Dave Kelly Date: Wed, 30 Jan 2019 21:13:59 -0800 Subject: [PATCH 12/33] Fixed compilation errors --- raveloxmidi/include/applemidi_feedback.h | 2 +- raveloxmidi/src/net_socket.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/raveloxmidi/include/applemidi_feedback.h b/raveloxmidi/include/applemidi_feedback.h index f9f7f96..df7690c 100644 --- a/raveloxmidi/include/applemidi_feedback.h +++ b/raveloxmidi/include/applemidi_feedback.h @@ -21,7 +21,7 @@ #ifndef APPLEMIDI_FEEDBACK_H #define APPLEMIDI_FEEDBACK_H -net_response_t * applemidi_feedback_handler( void *data ); +net_response_t * applemidi_feedback_responder( void *data ); net_response_t * applemidi_feedback_create( uint32_t ssrc, uint16_t rtp_seq ); #endif diff --git a/raveloxmidi/src/net_socket.c b/raveloxmidi/src/net_socket.c index e48b9ac..88320bb 100644 --- a/raveloxmidi/src/net_socket.c +++ b/raveloxmidi/src/net_socket.c @@ -463,7 +463,7 @@ int net_socket_read( int fd ) midi_payload_to_commands( midi_payload, MIDI_PAYLOAD_RTP, &midi_commands, &num_midi_commands ); // Sent a FEEBACK packet back to the originating host to ack the MIDI packet - response = cmd_feedback_create( rtp_packet->header.ssrc, rtp_packet->header.seq ); + response = applemidi_feedback_create( rtp_packet->header.ssrc, rtp_packet->header.seq ); if( response ) { size_t bytes_written = 0; From 9e307e7c519f6fe1e59795e3becf6de46ae4ae33 Mon Sep 17 00:00:00 2001 From: Dave Kelly Date: Wed, 30 Jan 2019 21:17:25 -0800 Subject: [PATCH 13/33] Renamed cmd_sync_handler to applemidi_sync --- .../include/{cmd_sync_handler.h => applemidi_sync.h} | 6 +++--- raveloxmidi/src/Makefile.am | 2 +- raveloxmidi/src/{cmd_sync_handler.c => applemidi_sync.c} | 8 ++++---- 3 files changed, 8 insertions(+), 8 deletions(-) rename raveloxmidi/include/{cmd_sync_handler.h => applemidi_sync.h} (88%) rename raveloxmidi/src/{cmd_sync_handler.c => applemidi_sync.c} (86%) diff --git a/raveloxmidi/include/cmd_sync_handler.h b/raveloxmidi/include/applemidi_sync.h similarity index 88% rename from raveloxmidi/include/cmd_sync_handler.h rename to raveloxmidi/include/applemidi_sync.h index 8dfad32..0dc2fa2 100644 --- a/raveloxmidi/include/cmd_sync_handler.h +++ b/raveloxmidi/include/applemidi_sync.h @@ -18,9 +18,9 @@ Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -#ifndef CMD_sync_HANDLER_H -#define CMD_sync_HANDLER_H +#ifndef APPLEMIDI_SYNC_H +#define APPLEMIDI_SYNC_H -net_response_t * cmd_sync_handler( void *data ); +net_response_t * applemidi_sync_responder( void *data ); #endif diff --git a/raveloxmidi/src/Makefile.am b/raveloxmidi/src/Makefile.am index 34f4fd7..03e82db 100755 --- a/raveloxmidi/src/Makefile.am +++ b/raveloxmidi/src/Makefile.am @@ -7,7 +7,7 @@ raveloxmidi_SOURCES = \ applemidi_inv.c \ applemidi_by.c \ applemidi_feedback.c \ - cmd_sync_handler.c \ + applemidi_sync.c \ midi_journal.c \ chapter_p.c \ chapter_n.c \ diff --git a/raveloxmidi/src/cmd_sync_handler.c b/raveloxmidi/src/applemidi_sync.c similarity index 86% rename from raveloxmidi/src/cmd_sync_handler.c rename to raveloxmidi/src/applemidi_sync.c index d30c890..4fbd58a 100644 --- a/raveloxmidi/src/cmd_sync_handler.c +++ b/raveloxmidi/src/applemidi_sync.c @@ -43,7 +43,7 @@ extern int errno; #include "logging.h" -net_response_t * cmd_sync_handler( void *data ) +net_response_t * applemidi_sync_responder( void *data ) { net_applemidi_command *cmd = NULL; net_applemidi_sync *sync = NULL; @@ -64,14 +64,14 @@ net_response_t * cmd_sync_handler( void *data ) if( ! cmd ) { - logging_printf( LOGGING_ERROR, "cmd_sync_handler: Unable to allocate memory for sync command\n"); + logging_printf( LOGGING_ERROR, "applemidi_sync_responder: Unable to allocate memory for sync command\n"); return NULL; } sync_resp = net_applemidi_sync_create(); if( ! sync_resp ) { - logging_printf( LOGGING_ERROR, "cmd_sync_handler: Unable to allocate memory for sync_resp command data\n"); + logging_printf( LOGGING_ERROR, "applemidi_sync_responder: Unable to allocate memory for sync_resp command data\n"); free( cmd ); return NULL; } @@ -109,7 +109,7 @@ net_response_t * cmd_sync_handler( void *data ) ret = net_applemidi_pack( cmd , &(response->buffer), &(response->len) ); if( ret != 0 ) { - logging_printf( LOGGING_ERROR, "cmd_sync_handler: Unable to pack response to sync command\n"); + logging_printf( LOGGING_ERROR, "applemidi_sync_responder: Unable to pack response to sync command\n"); net_response_destroy( &response ); } } From 8a35845190c61f4b1f755b59428384f33fb5e51e Mon Sep 17 00:00:00 2001 From: Dave Kelly Date: Wed, 30 Jan 2019 21:18:16 -0800 Subject: [PATCH 14/33] Corrected include filename --- raveloxmidi/src/net_socket.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/raveloxmidi/src/net_socket.c b/raveloxmidi/src/net_socket.c index 88320bb..58f3f3f 100644 --- a/raveloxmidi/src/net_socket.c +++ b/raveloxmidi/src/net_socket.c @@ -43,7 +43,7 @@ extern int errno; #include "net_connection.h" #include "applemidi_inv.h" -#include "cmd_sync_handler.h" +#include "applemidi_sync.h" #include "applemidi_feedback.h" #include "applemidi_by.h" From 8b53a1fe6d3e3b2743325de37bcae0ec836fad3b Mon Sep 17 00:00:00 2001 From: Dave Kelly Date: Wed, 30 Jan 2019 21:19:20 -0800 Subject: [PATCH 15/33] Fixed compilation error --- raveloxmidi/src/net_socket.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/raveloxmidi/src/net_socket.c b/raveloxmidi/src/net_socket.c index 58f3f3f..1203634 100644 --- a/raveloxmidi/src/net_socket.c +++ b/raveloxmidi/src/net_socket.c @@ -234,7 +234,7 @@ int net_socket_read( int fd ) response = applemidi_by_responder( command->data ); break; case NET_APPLEMIDI_CMD_SYNC: - response = cmd_sync_handler( command->data ); + response = applemidi_sync_responder( command->data ); break; case NET_APPLEMIDI_CMD_FEEDBACK: response = applemidi_feedback_responder( command->data ); From 6a1966c051803aef7f33ce4a08069199451018a8 Mon Sep 17 00:00:00 2001 From: Dave Kelly Date: Wed, 30 Jan 2019 21:40:49 -0800 Subject: [PATCH 16/33] Changed -I (info) option to -i --- raveloxmidi/man/raveloxmidi.1.in | 4 ++-- raveloxmidi/src/raveloxmidi_config.c | 13 ++++++------- 2 files changed, 8 insertions(+), 9 deletions(-) diff --git a/raveloxmidi/man/raveloxmidi.1.in b/raveloxmidi/man/raveloxmidi.1.in index 67bec93..d3ee021 100644 --- a/raveloxmidi/man/raveloxmidi.1.in +++ b/raveloxmidi/man/raveloxmidi.1.in @@ -3,7 +3,7 @@ raveloxmidi - RTP MIDI proxy for NoteOn/NoteOff/ControlChange/ProgramChange events .SH SYNOPSIS .B raveloxmidi -[-c filename] [-d|-I] [-N] [-P filename] [-R] [-h] [-C] [-D] +[-c filename] [-d|-i] [-N] [-P filename] [-R] [-h] [-C] [-D] .B raveloxmidi [--config filename] [--debug|--info] [--nodaemon] [--pidfile filename] [--readonly] [--help] [--dumpconfig] [--discover] @@ -18,7 +18,7 @@ Name of configuration file to use. If no configuration file is provided, some de .B -d Run in debug mode. This will provide debug-level output to either stdout or the configured log file. .TP -.B -I +.B -i Run in info mode. This will provide info-level output to either stdout or the configured log file. .TP .B -N diff --git a/raveloxmidi/src/raveloxmidi_config.c b/raveloxmidi/src/raveloxmidi_config.c index 3d84958..040745d 100644 --- a/raveloxmidi/src/raveloxmidi_config.c +++ b/raveloxmidi/src/raveloxmidi_config.c @@ -133,22 +133,21 @@ void config_init( int argc, char *argv[] ) static struct option long_options[] = { {"config", required_argument, NULL, 'c'}, {"debug", no_argument, NULL, 'd'}, - {"info", no_argument, NULL, 'I'}, + {"info", no_argument, NULL, 'i'}, {"nodaemon", no_argument, NULL, 'N'}, {"pidfile", required_argument, NULL, 'P'}, {"readonly", no_argument, NULL, 'R'}, {"dumpconfig", no_argument, NULL, 'C'}, {"discover", no_argument, NULL, 'D'}, #ifdef HAVE_ALSA - {"listinterfaces", no_argument, NULL, 'L'}, #endif {"help", no_argument, NULL, 'h'}, {0,0,0,0} }; #ifdef HAVE_ALSA - const char *short_options = "c:dIhNP:RLCD"; + const char *short_options = "c:dihNP:RCD"; #else - const char *short_options = "c:dIhNP:RCD"; + const char *short_options = "c:dihNP:RCD"; #endif int c; config_items = NULL; @@ -168,7 +167,7 @@ void config_init( int argc, char *argv[] ) case 'c': config_add_item("config.file", optarg); break; - case 'I': + case 'i': config_add_item("logging.enabled", "yes"); config_add_item("logging.log_level", "info"); break; @@ -334,14 +333,14 @@ void config_dump( void ) void config_usage( void ) { fprintf( stderr, "Usage:\n"); - fprintf( stderr, "\traveloxmidi [-c filename] [-d] [-I] [-R] [-N] [-P filename] [-C] [-D] [-h]"); + fprintf( stderr, "\traveloxmidi [-c filename] [-d] [-i] [-R] [-N] [-P filename] [-C] [-D] [-h]"); fprintf( stderr, "\n"); fprintf( stderr, "\traveloxmidi [--config filename] [--debug] [--info] [--readonly] [--nodaemon] [--pidfile filename] [--dumpconfig] [--discover] [--help]"); fprintf( stderr, "\n"); fprintf( stderr, "\n"); fprintf( stderr, "-c filename\tName of config file to use\n"); fprintf( stderr, "-d\t\tRun in debug mode\n"); - fprintf( stderr, "-d\t\tRun in debug mode\n"); + fprintf( stderr, "-i\t\tRun in info mode\n"); fprintf( stderr, "-N\t\tDo not run in the background\n"); fprintf( stderr, "-P filename\tName of file to write background pid\n"); fprintf( stderr, "-C\t\tDump the current config to stderr\n"); From bfeaa761e857103d78c3106e08e61d59fa41e522 Mon Sep 17 00:00:00 2001 From: Dave Kelly Date: Sun, 3 Feb 2019 18:31:36 -0800 Subject: [PATCH 17/33] Changes to allow service discovery --- ...ce_discoverer.h => dns_service_discover.h} | 15 +- raveloxmidi/include/raveloxmidi_config.h | 1 + raveloxmidi/man/raveloxmidi.1.in | 18 ++- raveloxmidi/src/Makefile.am | 2 +- ...ce_discoverer.c => dns_service_discover.c} | 138 ++++++++++++------ raveloxmidi/src/net_socket.c | 4 +- raveloxmidi/src/raveloxmidi.c | 19 ++- raveloxmidi/src/raveloxmidi_config.c | 15 +- raveloxmidi/src/utils.c | 2 - 9 files changed, 157 insertions(+), 57 deletions(-) rename raveloxmidi/include/{dns_service_discoverer.h => dns_service_discover.h} (72%) rename raveloxmidi/src/{dns_service_discoverer.c => dns_service_discover.c} (56%) diff --git a/raveloxmidi/include/dns_service_discoverer.h b/raveloxmidi/include/dns_service_discover.h similarity index 72% rename from raveloxmidi/include/dns_service_discoverer.h rename to raveloxmidi/include/dns_service_discover.h index b343c16..1a3e3ff 100644 --- a/raveloxmidi/include/dns_service_discoverer.h +++ b/raveloxmidi/include/dns_service_discover.h @@ -21,6 +21,19 @@ #ifndef DNS_SERVICE_DISCOVERER_H #define DNS_SERVICE_DISCOVERER_H -void dns_discover_services( void ); +typedef struct dns_service_t { + char *name; + char *ip_address; + int port; +} dns_service_t; + +int dns_discover_services( void ); +void dns_discover_add( char *name, char *address, int port ); +void dns_discover_free_services( void ); +void dns_discover_init( void ); +void dns_discover_teardown( void ); + +void dns_discover_dump( void ); + #endif diff --git a/raveloxmidi/include/raveloxmidi_config.h b/raveloxmidi/include/raveloxmidi_config.h index af95e70..0e3af88 100644 --- a/raveloxmidi/include/raveloxmidi_config.h +++ b/raveloxmidi/include/raveloxmidi_config.h @@ -13,6 +13,7 @@ void config_teardown( void ); char *config_string_get( char *key ); int config_int_get( char *key ); long config_long_get( char *key ); +int config_is_set( char *key ); void config_add_item(char *key, char *value); void config_dump( void ); diff --git a/raveloxmidi/man/raveloxmidi.1.in b/raveloxmidi/man/raveloxmidi.1.in index d3ee021..78edb35 100644 --- a/raveloxmidi/man/raveloxmidi.1.in +++ b/raveloxmidi/man/raveloxmidi.1.in @@ -3,10 +3,10 @@ raveloxmidi - RTP MIDI proxy for NoteOn/NoteOff/ControlChange/ProgramChange events .SH SYNOPSIS .B raveloxmidi -[-c filename] [-d|-i] [-N] [-P filename] [-R] [-h] [-C] [-D] +[-c filename] [-d|-i] [-N] [-P filename] [-R] [-h] [-C] [-D] [-T seconds] .B raveloxmidi -[--config filename] [--debug|--info] [--nodaemon] [--pidfile filename] [--readonly] [--help] [--dumpconfig] [--discover] +[--config filename] [--debug|--info] [--nodaemon] [--pidfile filename] [--readonly] [--help] [--dumpconfig] [--discover] [--discover-timeout] .SH DESCRIPTION .BR raveloxmidi provides a RTP MIDI proxy to send MIDI NoteOn, NoteOff, ControlChange and ProgramChange events to a remote MIDI device. @@ -26,17 +26,23 @@ Do not run as a daemon. .TP .B -P pidfile File to store the pid of the running process. Default is -.B raveloxmidi.pid in the current directory. +.B raveloxmidi.pid +in the current directory. .TP .B -R Enable readonly mode. This doesn't write anything to disk. .TP .B -h Display help information including default values for some parameters. +.TP .B -C Display the current config to stderr +.TP .B -D Discover available _apple-midi._udp services +.TP +.B -T +Timeout for service discovery. Default is 10 seconds. .SH NOTES The available options for the configuration file are as follows: .TP @@ -61,6 +67,12 @@ Number of connections that can be made to @PACKAGE@. Maximum is 255. Minimum is .B service.name Label to prepend to mDNS service name "_apple-midi._udp". ( default is raveloxmidi ) .TP +.B discover.services +List the available _apple-midi._udp services. This will exit once complete. Default is no. +.TP +.B discover.timeout +Timeout for service discovery. Default is 10 seconds. +.TP .B client.name Label to use when making a rtpMIDI connection to a remote service. ( default is raveloxremote ) .TP diff --git a/raveloxmidi/src/Makefile.am b/raveloxmidi/src/Makefile.am index 03e82db..ca2bfc7 100755 --- a/raveloxmidi/src/Makefile.am +++ b/raveloxmidi/src/Makefile.am @@ -3,7 +3,7 @@ bin_PROGRAMS = raveloxmidi raveloxmidi_SOURCES = \ raveloxmidi.c \ dns_service_publisher.c \ - dns_service_discoverer.c \ + dns_service_discover.c \ applemidi_inv.c \ applemidi_by.c \ applemidi_feedback.c \ diff --git a/raveloxmidi/src/dns_service_discoverer.c b/raveloxmidi/src/dns_service_discover.c similarity index 56% rename from raveloxmidi/src/dns_service_discoverer.c rename to raveloxmidi/src/dns_service_discover.c index 4423b5a..edf6f47 100644 --- a/raveloxmidi/src/dns_service_discoverer.c +++ b/raveloxmidi/src/dns_service_discover.c @@ -27,6 +27,7 @@ #include #include #include +#include #include #include @@ -35,6 +36,20 @@ #include #include +#include + +#include "dns_service_discover.h" + +#include "logging.h" +#include "utils.h" + +#include "raveloxmidi_config.h" + +static pthread_mutex_t discover_mutex; + +static dns_service_t **services = NULL; +static int num_services = 0; + static AvahiThreadedPoll *threaded_poll = NULL; static AvahiClient *client = NULL; @@ -57,32 +72,13 @@ static void resolve_callback( /* Called whenever a service has been resolved successfully or timed out */ switch (event) { - case AVAHI_RESOLVER_FAILURE: - fprintf(stderr, "(Resolver) Failed to resolve service '%s' of type '%s' in domain '%s': %s\n", name, type, domain, avahi_strerror(avahi_client_errno(avahi_service_resolver_get_client(r)))); - break; + case AVAHI_RESOLVER_FAILURE: + logging_printf(LOGGING_WARN, "Failed to resolve service '%s' of type '%s' in domain '%s': %s\n", name, type, domain, avahi_strerror(avahi_client_errno(avahi_service_resolver_get_client(r)))); + break; case AVAHI_RESOLVER_FOUND: { - char a[AVAHI_ADDRESS_STR_MAX], *t; - fprintf(stderr, "Service '%s' of type '%s' in domain '%s':\n", name, type, domain); - avahi_address_snprint(a, sizeof(a), address); - t = avahi_string_list_to_string(txt); - fprintf(stderr, - "\t%s:%u (%s)\n" - "\tTXT=%s\n" - "\tcookie is %u\n" - "\tis_local: %i\n" - "\tour_own: %i\n" - "\twide_area: %i\n" - "\tmulticast: %i\n" - "\tcached: %i\n", - host_name, port, a, - t, - avahi_string_list_get_service_cookie(txt), - !!(flags & AVAHI_LOOKUP_RESULT_LOCAL), - !!(flags & AVAHI_LOOKUP_RESULT_OUR_OWN), - !!(flags & AVAHI_LOOKUP_RESULT_WIDE_AREA), - !!(flags & AVAHI_LOOKUP_RESULT_MULTICAST), - !!(flags & AVAHI_LOOKUP_RESULT_CACHED)); - avahi_free(t); + char a[AVAHI_ADDRESS_STR_MAX]; + avahi_address_snprint(a, sizeof(a), address); + dns_discover_add( name, a, port ); } } avahi_service_resolver_free(r); @@ -105,24 +101,17 @@ static void browse_callback( /* Called whenever a new services becomes available on the LAN or is removed from the LAN */ switch (event) { case AVAHI_BROWSER_FAILURE: - fprintf(stderr, "(Browser) %s\n", avahi_strerror(avahi_client_errno(avahi_service_browser_get_client(b)))); + logging_printf(LOGGING_WARN, "%s\n", avahi_strerror(avahi_client_errno(avahi_service_browser_get_client(b)))); avahi_threaded_poll_quit( threaded_poll ); return; case AVAHI_BROWSER_NEW: - fprintf(stderr, "(Browser) NEW: service '%s' of type '%s' in domain '%s'\n", name, type, domain); - /* We ignore the returned resolver object. In the callback - function we free it. If the server is terminated before - the callback function is called the server will free - the resolver for us. */ if (!(avahi_service_resolver_new(c, interface, protocol, name, type, domain, AVAHI_PROTO_UNSPEC, 0, resolve_callback, c))) - fprintf(stderr, "Failed to resolve service '%s': %s\n", name, avahi_strerror(avahi_client_errno(c))); + logging_printf( LOGGING_WARN, "Failed to resolve service '%s': %s\n", name, avahi_strerror(avahi_client_errno(c))); break; case AVAHI_BROWSER_REMOVE: - fprintf(stderr, "(Browser) REMOVE: service '%s' of type '%s' in domain '%s'\n", name, type, domain); break; case AVAHI_BROWSER_ALL_FOR_NOW: case AVAHI_BROWSER_CACHE_EXHAUSTED: - fprintf(stderr, "(Browser) %s\n", event == AVAHI_BROWSER_CACHE_EXHAUSTED ? "CACHE_EXHAUSTED" : "ALL_FOR_NOW"); break; } } @@ -133,36 +122,36 @@ static void client_callback(AvahiClient *c, AvahiClientState state, AVAHI_GCC_UN /* Called whenever the client or server state changes */ if (state == AVAHI_CLIENT_FAILURE) { - fprintf(stderr, "Server connection failure: %s\n", avahi_strerror(avahi_client_errno(c))); + logging_printf(LOGGING_WARN, "Server connection failure: %s\n", avahi_strerror(avahi_client_errno(c))); avahi_threaded_poll_quit(threaded_poll); } } -void dns_discover_services( void ) +int dns_discover_services( void ) { AvahiServiceBrowser *sb = NULL; int error; struct timeval timeout; if (!(threaded_poll = avahi_threaded_poll_new())) { - fprintf(stderr, "Failed to create threaded poll object.\n"); + logging_printf(LOGGING_WARN, "Failed to create threaded poll object.\n"); goto fail; } - /* Allocate a new client */ + client = avahi_client_new(avahi_threaded_poll_get(threaded_poll), 0, client_callback, NULL, &error); if (!client) { - fprintf(stderr, "Failed to create client: %s\n", avahi_strerror(error)); + logging_printf(LOGGING_WARN, "Failed to create client: %s\n", avahi_strerror(error)); goto fail; } if (!(sb = avahi_service_browser_new(client, AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC, "_apple-midi._udp", NULL, 0, browse_callback, client))) { - fprintf(stderr, "Failed to create service browser: %s\n", avahi_strerror(avahi_client_errno(client))); + logging_printf(LOGGING_WARN, "Failed to create service browser: %s\n", avahi_strerror(avahi_client_errno(client))); goto fail; } avahi_threaded_poll_start(threaded_poll); - timeout.tv_sec = 10; + timeout.tv_sec = config_int_get("discover.timeout"); timeout.tv_usec= 0; select( 0, NULL, NULL, NULL, &timeout ); @@ -174,4 +163,71 @@ void dns_discover_services( void ) if (client) avahi_client_free(client); if (threaded_poll) avahi_threaded_poll_free( threaded_poll ); + + return num_services; +} + +void dns_discover_add( char *name, char *address, int port) +{ + dns_service_t **new_services_list = NULL; + + new_services_list = (dns_service_t ** ) realloc( services, sizeof(dns_service_t) * ( num_services + 1 ) ) ; + + if( new_services_list ) + { + dns_service_t *new_service; + services = new_services_list; + + new_service = (dns_service_t *)malloc( sizeof( dns_service_t ) ); + + if( new_service ) + { + new_service->name = (char *)strdup( name ); + new_service->ip_address = ( char *)strdup( address ); + new_service->port = port; + services[ num_services ] = new_service; + num_services++; + } else { + logging_printf(LOGGING_WARN, "dns_service_discover_add: Unable to allocate memory for new service item\n"); + } + } else { + logging_printf(LOGGING_WARN, "dns_service_discover_add: Unable to allocate memory for new service list\n"); + } +} + +void dns_discover_free_services( void ) +{ + if( ! services ) return; + if( num_services <= 0 ) return; + for(int i = 0; i < num_services; i++) + { + FREENULL( "dns_service_t", (void **)&(services[i]) ); + } + free(services); + services = NULL; +} + +void dns_discover_init( void ) +{ + pthread_mutex_init( &discover_mutex , NULL ); + dns_discover_free_services(); + num_services = 0; +} + +void dns_discover_teardown( void ) +{ + dns_discover_free_services(); + num_services = 0; + pthread_mutex_destroy( &discover_mutex ); +} + +void dns_discover_dump( void ) +{ + if( ! services ) return; + if( num_services <= 0 ) return; + + for( int i = 0; i < num_services; i++ ) + { + fprintf(stderr, "%03d) %s\t%s:%u\n", i, services[i]->name, services[i]->ip_address, services[i]->port ); + } } diff --git a/raveloxmidi/src/net_socket.c b/raveloxmidi/src/net_socket.c index 1203634..b380273 100644 --- a/raveloxmidi/src/net_socket.c +++ b/raveloxmidi/src/net_socket.c @@ -258,7 +258,7 @@ int net_socket_read( int fd ) } else if( (packet[0]==0xaa) && (recv_len == 5) && ( strncmp( &(packet[1]),"STAT",4)==0) ) // Heartbeat request { - unsigned char *buffer="OK"; + char *buffer="OK"; size_t bytes_written = 0; pthread_mutex_lock( &socket_mutex ); bytes_written = sendto( fd, buffer, strlen(buffer), 0 , (void *)&from_addr, from_len); @@ -268,7 +268,7 @@ int net_socket_read( int fd ) } else if( (packet[0]==0xaa) && (recv_len == 5) && ( strncmp( &(packet[1]),"QUIT",4)==0) ) // Shutdown request { - unsigned char *buffer="QT"; + char *buffer="QT"; size_t bytes_written = 0; pthread_mutex_lock( &socket_mutex ); bytes_written = sendto( fd, buffer, strlen(buffer), 0 , (void *)&from_addr, from_len); diff --git a/raveloxmidi/src/raveloxmidi.c b/raveloxmidi/src/raveloxmidi.c index 47afdd5..a24a5bb 100644 --- a/raveloxmidi/src/raveloxmidi.c +++ b/raveloxmidi/src/raveloxmidi.c @@ -33,7 +33,7 @@ #include "utils.h" #include "dns_service_publisher.h" -#include "dns_service_discoverer.h" +#include "dns_service_discover.h" #include "raveloxmidi_config.h" #include "daemon.h" @@ -56,9 +56,19 @@ int main(int argc, char *argv[]) logging_init(); logging_printf( LOGGING_INFO, "%s (%s)\n", PACKAGE, VERSION); - if( is_yes( config_string_get("discover.services" ) ) ) + dns_discover_init(); + + if( config_is_set("discover.services" ) ) { - dns_discover_services(); + int services_found = 0; + services_found = dns_discover_services(); + + if( services_found > 0 ) + { + dns_discover_dump(); + } else { + logging_printf( LOGGING_INFO, "No remote services found\n"); + } goto daemon_stop; } @@ -105,13 +115,14 @@ int main(int argc, char *argv[]) net_socket_loop_teardown(); } + dns_service_publisher_stop(); + net_socket_teardown(); net_ctx_teardown(); #ifdef HAVE_ALSA raveloxmidi_alsa_teardown(); #endif - dns_service_publisher_stop(); daemon_stop: if( running_as_daemon ) diff --git a/raveloxmidi/src/raveloxmidi_config.c b/raveloxmidi/src/raveloxmidi_config.c index 040745d..0703e6d 100644 --- a/raveloxmidi/src/raveloxmidi_config.c +++ b/raveloxmidi/src/raveloxmidi_config.c @@ -54,7 +54,7 @@ static void config_set_defaults( void ) config_add_item("inbound_midi","/dev/sequencer"); config_add_item("file_mode", "0640"); config_add_item("client.name", "raveloxremote"); - + config_add_item("discover.timeout","10"); #ifdef HAVE_ALSA config_add_item("alsa.input_buffer_size", "4096" ); #endif @@ -139,15 +139,16 @@ void config_init( int argc, char *argv[] ) {"readonly", no_argument, NULL, 'R'}, {"dumpconfig", no_argument, NULL, 'C'}, {"discover", no_argument, NULL, 'D'}, + {"discover-timeout", required_argument, NULL, 'T'}, #ifdef HAVE_ALSA #endif {"help", no_argument, NULL, 'h'}, {0,0,0,0} }; #ifdef HAVE_ALSA - const char *short_options = "c:dihNP:RCD"; + const char *short_options = "c:dihNP:RCDT:"; #else - const char *short_options = "c:dihNP:RCD"; + const char *short_options = "c:dihNP:RCDT:"; #endif int c; config_items = NULL; @@ -195,6 +196,9 @@ void config_init( int argc, char *argv[] ) case 'D': config_add_item("discover.services", "yes"); break; + case 'T': + config_add_item("discover.timeout", optarg); + break; } } @@ -258,6 +262,11 @@ long config_long_get( char *key ) return atol( item_string ); } +int config_is_set( char *key ) +{ + return ( config_get_item( key ) != NULL ); +} + static raveloxmidi_config_t *config_get_item( char *key ) { int i = 0 ; diff --git a/raveloxmidi/src/utils.c b/raveloxmidi/src/utils.c index a21b217..384f074 100644 --- a/raveloxmidi/src/utils.c +++ b/raveloxmidi/src/utils.c @@ -293,7 +293,6 @@ int get_sock_addr( char *ip_address, int port, struct sockaddr *socket, socklen_ struct addrinfo *result; int val; char portaddr[32]; - char tmp_address[ INET6_ADDRSTRLEN ]; if( ! ip_address ) return 1; if( ! socket ) return 1; @@ -326,7 +325,6 @@ int get_addr_family(char *ip_address, int port) struct addrinfo *result; int val; char portaddr[32]; - char tmp_address[ INET6_ADDRSTRLEN ]; int family = AF_UNSPEC; if( ! ip_address ) return AF_UNSPEC; From 1176ea2a5780077ac7f031dfddaaf77cdfde67f3 Mon Sep 17 00:00:00 2001 From: Dave Kelly Date: Sat, 16 Feb 2019 18:09:00 -0800 Subject: [PATCH 18/33] Added options to connect to remote RTP MIDI service --- raveloxmidi/include/applemidi_ok.h | 26 ++++ raveloxmidi/include/dns_service_discover.h | 3 +- raveloxmidi/include/net_applemidi.h | 2 + raveloxmidi/include/net_connection.h | 1 + raveloxmidi/include/net_socket.h | 7 +- raveloxmidi/include/remote_connection.h | 27 ++++ raveloxmidi/include/utils.h | 2 + raveloxmidi/src/Makefile.am | 2 + raveloxmidi/src/applemidi_ok.c | 62 ++++++++ raveloxmidi/src/dns_service_discover.c | 31 +++- raveloxmidi/src/net_applemidi.c | 15 ++ raveloxmidi/src/net_connection.c | 6 +- raveloxmidi/src/net_socket.c | 55 +++++-- raveloxmidi/src/raveloxmidi.c | 11 +- raveloxmidi/src/remote_connection.c | 172 +++++++++++++++++++++ raveloxmidi/src/utils.c | 9 ++ 16 files changed, 411 insertions(+), 20 deletions(-) create mode 100644 raveloxmidi/include/applemidi_ok.h create mode 100644 raveloxmidi/include/remote_connection.h create mode 100644 raveloxmidi/src/applemidi_ok.c create mode 100644 raveloxmidi/src/remote_connection.c diff --git a/raveloxmidi/include/applemidi_ok.h b/raveloxmidi/include/applemidi_ok.h new file mode 100644 index 0000000..f85f871 --- /dev/null +++ b/raveloxmidi/include/applemidi_ok.h @@ -0,0 +1,26 @@ +/* + This file is part of raveloxmidi. + + Copyright (C) 2019 Dave Kelly + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef APPLEMIDI_OK_H +#define APPLEMIDI_OK_H + +net_response_t * applemidi_ok_responder( char *ip_address, uint16_t port, void *data ); + +#endif diff --git a/raveloxmidi/include/dns_service_discover.h b/raveloxmidi/include/dns_service_discover.h index 1a3e3ff..49f54a5 100644 --- a/raveloxmidi/include/dns_service_discover.h +++ b/raveloxmidi/include/dns_service_discover.h @@ -28,7 +28,8 @@ typedef struct dns_service_t { } dns_service_t; int dns_discover_services( void ); -void dns_discover_add( char *name, char *address, int port ); +void dns_discover_add( const char *name, char *address, int port ); +dns_service_t *dns_discover_by_name( const char *name ); void dns_discover_free_services( void ); void dns_discover_init( void ); void dns_discover_teardown( void ); diff --git a/raveloxmidi/include/net_applemidi.h b/raveloxmidi/include/net_applemidi.h index d080e5c..f975b12 100644 --- a/raveloxmidi/include/net_applemidi.h +++ b/raveloxmidi/include/net_applemidi.h @@ -86,4 +86,6 @@ int net_applemidi_unpack( net_applemidi_command **command_buffer, unsigned char int net_applemidi_pack( net_applemidi_command *command_buffer, unsigned char **out_buffer, size_t *out_buffer_len ); net_applemidi_command * net_applemidi_cmd_create( uint16_t command ); +void net_applemidi_inv_destroy( net_applemidi_inv **inv ); + #endif diff --git a/raveloxmidi/include/net_connection.h b/raveloxmidi/include/net_connection.h index 0e167d5..9384d6c 100644 --- a/raveloxmidi/include/net_connection.h +++ b/raveloxmidi/include/net_connection.h @@ -43,6 +43,7 @@ typedef struct net_ctx_t { struct net_ctx_t *prev; } net_ctx_t; +net_ctx_t *net_ctx_create( void ); void net_ctx_destroy( net_ctx_t **ctx ); void net_ctx_dump( net_ctx_t *ctx ); void net_ctx_init( void ); diff --git a/raveloxmidi/include/net_socket.h b/raveloxmidi/include/net_socket.h index 512fb2e..23ac286 100644 --- a/raveloxmidi/include/net_socket.h +++ b/raveloxmidi/include/net_socket.h @@ -24,8 +24,8 @@ #include "config.h" void net_socket_add( int new_socket ); -int net_socket_create( int family, char *bind_address, unsigned int port ); -int net_socket_ipv6_create( char *bind_addres, unsigned int port ); +int net_socket_create( int family, char *ip_address, unsigned int port ); +int net_socket_listener_create( int family, char *ip_address, unsigned int port ); int net_socket_init( void ); int net_socket_teardown( void ); @@ -37,6 +37,9 @@ int net_socket_alsa_loop(void); void net_socket_wait_for_alsa(void); void net_socket_loop_shutdown(int signal); +int net_socket_get_data_socket( void ); +int net_socket_get_control_socket( void ); + void net_socket_set_fds( void ); extern uint8_t _max_ctx; diff --git a/raveloxmidi/include/remote_connection.h b/raveloxmidi/include/remote_connection.h new file mode 100644 index 0000000..d063cec --- /dev/null +++ b/raveloxmidi/include/remote_connection.h @@ -0,0 +1,27 @@ +/* + This file is part of raveloxmidi. + + Copyright (C) 2019 Dave Kelly + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef _REMOTE_CONNECTION_H +#define _REMOTE_CONNECTION_H + +void remote_connect_init( void ); +void remote_connect_teardown( void ); + +#endif diff --git a/raveloxmidi/include/utils.h b/raveloxmidi/include/utils.h index 26edbc2..a2e4768 100644 --- a/raveloxmidi/include/utils.h +++ b/raveloxmidi/include/utils.h @@ -41,6 +41,8 @@ char *get_ip_string( struct sockaddr *sa, char *s, size_t maxlen ); int get_sock_addr( char *ip_address, int port, struct sockaddr *socket, socklen_t *socklen); int get_addr_family(char *ip_address, int port); +int random_number( void ); + #define MAX(a,b) ( (a) > (b) ? (a) : (b) ) #define MIN(a,b) ( (a) < (b) ? (a) : (b) ) diff --git a/raveloxmidi/src/Makefile.am b/raveloxmidi/src/Makefile.am index ca2bfc7..a8fa538 100755 --- a/raveloxmidi/src/Makefile.am +++ b/raveloxmidi/src/Makefile.am @@ -5,6 +5,7 @@ raveloxmidi_SOURCES = \ dns_service_publisher.c \ dns_service_discover.c \ applemidi_inv.c \ + applemidi_ok.c \ applemidi_by.c \ applemidi_feedback.c \ applemidi_sync.c \ @@ -21,6 +22,7 @@ raveloxmidi_SOURCES = \ midi_command.c \ net_applemidi.c \ net_connection.c \ + remote_connection.c \ rtp_packet.c \ raveloxmidi_config.c \ daemon.c \ diff --git a/raveloxmidi/src/applemidi_ok.c b/raveloxmidi/src/applemidi_ok.c new file mode 100644 index 0000000..e8e4716 --- /dev/null +++ b/raveloxmidi/src/applemidi_ok.c @@ -0,0 +1,62 @@ +/* + This file is part of raveloxmidi. + + Copyright (C) 2014 Dave Kelly + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +extern int errno; + +#include "config.h" + +#include "net_applemidi.h" +#include "net_connection.h" +#include "net_socket.h" +#include "net_response.h" + +#include "raveloxmidi_config.h" +#include "logging.h" + +net_response_t * applemidi_ok_responder( char *ip_address, uint16_t port, void *data ) +{ + net_applemidi_inv *inv = NULL; + + if( ! data ) return NULL; + inv = ( net_applemidi_inv *) data; + +/* + accept_inv->ssrc = ctx->send_ssrc; + accept_inv->version = 2; + accept_inv->initiator = ctx->initiator; + service_name = config_string_get("service.name"); +*/ + + logging_printf( LOGGING_DEBUG, "applemidi_ok_responder: ssrc=0x%08x version=%u initiator=0x%08x name=%s\n", inv->ssrc, inv->version, inv->initiator, inv->name); + return NULL; +} diff --git a/raveloxmidi/src/dns_service_discover.c b/raveloxmidi/src/dns_service_discover.c index edf6f47..095df0d 100644 --- a/raveloxmidi/src/dns_service_discover.c +++ b/raveloxmidi/src/dns_service_discover.c @@ -167,9 +167,38 @@ int dns_discover_services( void ) return num_services; } -void dns_discover_add( char *name, char *address, int port) +dns_service_t *dns_discover_by_name( const char *name ) +{ + int i = 0; + + if( num_services < 1 ) return NULL; + if( ! services ) return NULL; + + for( i = 0; i < num_services; i++ ) + { + if( strcmp( name, services[i]->name ) == 0 ) + { + return services[i]; + } + } + + return NULL; +} + +void dns_discover_add( const char *name, char *address, int port) { dns_service_t **new_services_list = NULL; + dns_service_t *found_service = NULL; + + if( ! name ) return; + if( ! address ) return; + + // Check for duplicates by name + found_service = dns_discover_by_name( name ); + if( found_service ) + { + return; + } new_services_list = (dns_service_t ** ) realloc( services, sizeof(dns_service_t) * ( num_services + 1 ) ) ; diff --git a/raveloxmidi/src/net_applemidi.c b/raveloxmidi/src/net_applemidi.c index 017baba..484b91a 100644 --- a/raveloxmidi/src/net_applemidi.c +++ b/raveloxmidi/src/net_applemidi.c @@ -113,6 +113,21 @@ net_applemidi_inv * net_applemidi_inv_create( void ) return inv; } +void net_applemidi_inv_destroy( net_applemidi_inv **inv ) +{ + if(! inv ) return; + if(! *inv ) return; + + if( (*inv)->name ) + { + free( (*inv)->name ); + (*inv)->name = NULL; + } + + free( *inv ); + *inv = NULL; +} + net_applemidi_sync * net_applemidi_sync_create( void ) { net_applemidi_sync *sync = NULL; diff --git a/raveloxmidi/src/net_connection.c b/raveloxmidi/src/net_connection.c index 4c9df68..1b7f91c 100644 --- a/raveloxmidi/src/net_connection.c +++ b/raveloxmidi/src/net_connection.c @@ -109,7 +109,7 @@ static void net_ctx_set( net_ctx_t *ctx, uint32_t ssrc, uint32_t initiator, uint ctx->ip_address = ( char *) strdup( ip_address ); } -static net_ctx_t * net_ctx_create( void ) +net_ctx_t * net_ctx_create( void ) { net_ctx_t *new_ctx; journal_t *journal; @@ -194,7 +194,6 @@ net_ctx_t * net_ctx_register( uint32_t ssrc, uint32_t initiator, char *ip_addres net_ctx_t *current_ctx = NULL; net_ctx_t *last_ctx = NULL; net_ctx_t *new_ctx = NULL; - time_t now = 0; unsigned int send_ssrc = 0; /* Check to see if the ssrc already exists */ @@ -216,8 +215,7 @@ net_ctx_t * net_ctx_register( uint32_t ssrc, uint32_t initiator, char *ip_addres last_ctx = net_ctx_get_last(); if( ! _ctx_head ) _ctx_head = new_ctx; - now = time(NULL); - send_ssrc = rand_r( (unsigned int *)&now ); + send_ssrc = random_number(); net_ctx_set( new_ctx, ssrc, initiator, send_ssrc, 0x638F, port, ip_address ); new_ctx->prev = last_ctx; diff --git a/raveloxmidi/src/net_socket.c b/raveloxmidi/src/net_socket.c index b380273..bf6765e 100644 --- a/raveloxmidi/src/net_socket.c +++ b/raveloxmidi/src/net_socket.c @@ -43,6 +43,7 @@ extern int errno; #include "net_connection.h" #include "applemidi_inv.h" +#include "applemidi_ok.h" #include "applemidi_sync.h" #include "applemidi_feedback.h" #include "applemidi_by.h" @@ -98,14 +99,11 @@ void net_socket_add( int new_socket ) sockets[num_sockets - 1 ] = new_socket; } -int net_socket_create(int family, char *bind_address, unsigned int port ) +int net_socket_create(int family, char *ip_address, unsigned int port ) { int new_socket; - struct sockaddr_in6 socket_address; - socklen_t addr_len = 0; - int optionvalue = 0; - logging_printf(LOGGING_DEBUG, "net_socket_create: Creating socket for [%s]:%u, family=%d\n", bind_address, port, family); + logging_printf(LOGGING_DEBUG, "net_socket_create: Creating socket for [%s]:%u, family=%d\n", ip_address, port, family); new_socket = socket(family, SOCK_DGRAM, 0); if( new_socket < 0 ) @@ -113,6 +111,24 @@ int net_socket_create(int family, char *bind_address, unsigned int port ) return errno; } + return new_socket; +} + +int net_socket_listener_create( int family, char *ip_address, unsigned int port ) +{ + int new_socket = -1; + struct sockaddr_in6 socket_address; + socklen_t addr_len = 0; + int optionvalue = 0; + + new_socket = net_socket_create( family, ip_address, port ); + + if( new_socket < 0 ) + { + logging_printf( LOGGING_ERROR, "net_socket_listener_create: Unable to create socket %s:%u : %s\n", ip_address, port, strerror(new_socket)); + return new_socket; + } + switch( family ) { case AF_INET6: @@ -123,7 +139,7 @@ int net_socket_create(int family, char *bind_address, unsigned int port ) break; } - get_sock_addr( bind_address, port, (struct sockaddr *)&socket_address, &addr_len); + get_sock_addr( ip_address, port, (struct sockaddr *)&socket_address, &addr_len); if ( bind(new_socket, (struct sockaddr *)&socket_address, addr_len) < 0 ) { @@ -227,6 +243,7 @@ int net_socket_read( int fd ) response = applemidi_inv_responder( ip_address, from_port, command->data ); break; case NET_APPLEMIDI_CMD_ACCEPT: + applemidi_ok_responder( ip_address, from_port, command->data ); break; case NET_APPLEMIDI_CMD_REJECT: break; @@ -255,7 +272,7 @@ int net_socket_read( int fd ) } net_applemidi_cmd_destroy( &command ); - } else if( (packet[0]==0xaa) && (recv_len == 5) && ( strncmp( &(packet[1]),"STAT",4)==0) ) + } else if( (packet[0]==0xaa) && (recv_len == 5) && ( strncmp( (const char *)&(packet[1]),"STAT",4)==0) ) // Heartbeat request { char *buffer="OK"; @@ -265,7 +282,7 @@ int net_socket_read( int fd ) pthread_mutex_unlock( &socket_mutex ); logging_printf(LOGGING_DEBUG, "net_socket_read: Heartbeat request. Response written: %u\n", bytes_written); - } else if( (packet[0]==0xaa) && (recv_len == 5) && ( strncmp( &(packet[1]),"QUIT",4)==0) ) + } else if( (packet[0]==0xaa) && (recv_len == 5) && ( strncmp( (const char *)&(packet[1]),"QUIT",4)==0) ) // Shutdown request { char *buffer="QT"; @@ -620,9 +637,9 @@ int net_socket_init( void ) case AF_INET: case AF_INET6: if( - net_socket_create( address_family, bind_address, control_port ) || - net_socket_create( address_family, bind_address, data_port ) || - net_socket_create( address_family, bind_address, local_port ) ) + net_socket_listener_create( address_family, bind_address, control_port ) || + net_socket_listener_create( address_family, bind_address, data_port ) || + net_socket_listener_create( address_family, bind_address, local_port ) ) { logging_printf(LOGGING_ERROR, "net_socket_init: Cannot create socket: %s\n", strerror( errno ) ); return -1; @@ -731,3 +748,19 @@ void net_socket_set_fds(void) } } } + +int net_socket_get_data_socket( void ) +{ + if( num_sockets <= 0 ) return -1; + if( ! sockets ) return -1; + + return sockets[DATA_PORT]; +} + +int net_socket_get_control_socket( void ) +{ + if( num_sockets <= 0 ) return -1; + if( ! sockets ) return -1; + + return sockets[DATA_PORT-1]; +} diff --git a/raveloxmidi/src/raveloxmidi.c b/raveloxmidi/src/raveloxmidi.c index a24a5bb..0970746 100644 --- a/raveloxmidi/src/raveloxmidi.c +++ b/raveloxmidi/src/raveloxmidi.c @@ -30,7 +30,8 @@ #include "net_applemidi.h" #include "net_socket.h" #include "net_connection.h" -#include "utils.h" + +#include "remote_connection.h" #include "dns_service_publisher.h" #include "dns_service_discover.h" @@ -44,6 +45,8 @@ #include "raveloxmidi_alsa.h" #endif +#include "utils.h" + static int running_as_daemon=0; int main(int argc, char *argv[]) @@ -90,6 +93,11 @@ int main(int argc, char *argv[]) net_ctx_init(); + if( config_string_get("remote.connect") ) + { + remote_connect_init(); + } + signal( SIGINT , net_socket_loop_shutdown); signal( SIGTERM , net_socket_loop_shutdown); signal( SIGUSR2 , net_socket_loop_shutdown); @@ -117,6 +125,7 @@ int main(int argc, char *argv[]) dns_service_publisher_stop(); + remote_connect_teardown(); net_socket_teardown(); net_ctx_teardown(); diff --git a/raveloxmidi/src/remote_connection.c b/raveloxmidi/src/remote_connection.c new file mode 100644 index 0000000..7838f9b --- /dev/null +++ b/raveloxmidi/src/remote_connection.c @@ -0,0 +1,172 @@ +/* + This file is part of raveloxmidi. + + Copyright (C) 2019 Dave Kelly + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include + +#include +extern int errno; + +#include "config.h" + +#include "net_applemidi.h" +#include "net_response.h" +#include "net_socket.h" +#include "net_connection.h" + +#include "applemidi_inv.h" +#include "applemidi_sync.h" +#include "applemidi_feedback.h" +#include "applemidi_by.h" + +#include "dns_service_discover.h" + +#include "utils.h" + +#include "raveloxmidi_config.h" +#include "logging.h" + +#include "remote_connection.h" + +static int remote_connected = 0; +static int ssrc = 0; +static int initiator = 0; + +void remote_connect_init( void ) +{ + dns_service_t *found_service = NULL; + char *remote_service_name = NULL; + char *client_name = NULL; + net_applemidi_inv *inv = NULL; + net_response_t *response = NULL; + net_applemidi_command *cmd = NULL; + net_ctx_t *ctx; + + remote_service_name = config_string_get("remote.connect"); + + if( (! remote_service_name) || ( strlen( remote_service_name ) <=0 ) ) + { + logging_printf(LOGGING_WARN, "remote_connect_init: remote.connect option is present but not set\n"); + return; + } + + logging_printf(LOGGING_DEBUG, "remote_connect_init: Looking for [%s]\n", remote_service_name); + + remote_connected = 0; + if( dns_discover_services() <= 0 ) + { + logging_printf(LOGGING_WARN, "remote_connect_init: No services available\n"); + return; + } + + + found_service = dns_discover_by_name( remote_service_name ); + + if( ! found_service ) + { + logging_printf(LOGGING_WARN, "remote_connect_init: No service found: %s\n", remote_service_name ); + return; + } + + ssrc = random_number(); + initiator = random_number(); + + // Build the INV packet + inv = net_applemidi_inv_create(); + + if( ! inv ) + { + logging_printf( LOGGING_ERROR, "remote_connect_init: Unable to allocate memory for inv packet\n"); + return; + } + + inv->ssrc = ssrc; + inv->version = 2; + inv->initiator = initiator; + client_name = config_string_get("client.name"); + if( client_name ) + { + inv->name = (char *)strdup( client_name ); + } else { + inv->name = (char *)strdup( "RaveloxMIDIClient" ); + } + + cmd = net_applemidi_cmd_create( NET_APPLEMIDI_CMD_INV ); + + if( ! cmd ) + { + logging_printf( LOGGING_ERROR, "remote_connect_init: Unable to create AppleMIDI command\n"); + net_applemidi_inv_destroy( &inv ); + goto remote_connect_fail; + } + + cmd->data = inv; + + response = net_response_create(); + + if( response ) + { + int ret = 0; + ret = net_applemidi_pack( cmd , &(response->buffer), &(response->len) ); + if( ret != 0 ) + { + logging_printf( LOGGING_ERROR, "remote_connect_init: Unable to pack response to inv command\n"); + } else { + ctx = net_ctx_create(); + ctx->ip_address = ( char * ) strdup( found_service->ip_address ); + ctx->data_port = found_service->port; + + logging_printf( LOGGING_DEBUG, "remote_connect_init: Creating connection context for %s:%u\n", ctx->ip_address, ctx->data_port ); + + if( ! ctx ) + { + logging_printf( LOGGING_ERROR, "remote_connect_init: Unable to create socket context\n"); + } else { + net_ctx_send( net_socket_get_data_socket() , ctx, response->buffer, response->len ); + net_ctx_send( net_socket_get_control_socket() , ctx, response->buffer, response->len ); + } + + net_ctx_destroy( &ctx ); + } + } else { + logging_printf( LOGGING_ERROR, "remote_connect_init: Unable to create response packet\n"); + } + +remote_connect_fail: + net_response_destroy( &response ); + net_applemidi_cmd_destroy( &cmd ); +} + +void remote_connect_teardown( void ) +{ + if( ! remote_connected ) return; +} + diff --git a/raveloxmidi/src/utils.c b/raveloxmidi/src/utils.c index 384f074..f9ee740 100644 --- a/raveloxmidi/src/utils.c +++ b/raveloxmidi/src/utils.c @@ -28,6 +28,7 @@ #include #include #include +#include #include #include @@ -348,3 +349,11 @@ int get_addr_family(char *ip_address, int port) return family; } + +int random_number( void ) +{ + time_t now = 0; + + now = time(NULL); + return rand_r( (unsigned int *)&now ); +} From e72d7dbdbb4c2fb360f1d3d7ecb05cea741f4552 Mon Sep 17 00:00:00 2001 From: Dave Kelly Date: Sat, 23 Mar 2019 18:31:49 -0700 Subject: [PATCH 19/33] More remote connection changes Abstracted key-value list --- raveloxmidi/include/daemon.h | 20 +++ raveloxmidi/include/kv_table.h | 44 ++++++ raveloxmidi/include/net_connection.h | 4 +- raveloxmidi/include/raveloxmidi_config.h | 6 +- raveloxmidi/include/remote_connection.h | 1 + raveloxmidi/src/Makefile.am | 3 +- raveloxmidi/src/applemidi_inv.c | 2 +- raveloxmidi/src/applemidi_ok.c | 35 ++++- raveloxmidi/src/kv_table.c | 174 +++++++++++++++++++++++ raveloxmidi/src/net_applemidi.c | 16 +++ raveloxmidi/src/net_connection.c | 29 ++-- raveloxmidi/src/net_socket.c | 2 +- raveloxmidi/src/raveloxmidi_config.c | 108 +++----------- raveloxmidi/src/remote_connection.c | 90 ++++++++++-- 14 files changed, 414 insertions(+), 120 deletions(-) create mode 100644 raveloxmidi/include/kv_table.h create mode 100644 raveloxmidi/src/kv_table.c diff --git a/raveloxmidi/include/daemon.h b/raveloxmidi/include/daemon.h index 3532b88..a95efe4 100644 --- a/raveloxmidi/include/daemon.h +++ b/raveloxmidi/include/daemon.h @@ -1,3 +1,23 @@ +/* + This file is part of raveloxmidi. + + Copyright (C) 2014 Dave Kelly + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + #ifndef _DAEMON_H #define _DAEMON_H diff --git a/raveloxmidi/include/kv_table.h b/raveloxmidi/include/kv_table.h new file mode 100644 index 0000000..30c1232 --- /dev/null +++ b/raveloxmidi/include/kv_table.h @@ -0,0 +1,44 @@ +/* + This file is part of raveloxmidi. + + Copyright (C) 2019 Dave Kelly + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef KV_TABLE_H +#define KV_TABLE_H + +#include + +typedef struct kv_item_t { + char *key; + char *value; +} kv_item_t; + +typedef struct kv_table_t { + char *name; + size_t count; + kv_item_t **items; +} kv_table_t; + +kv_table_t *kv_table_create( char *name ); +void kv_table_dump( kv_table_t *table ); +void kv_table_reset( kv_table_t *table ); +kv_item_t *kv_find_item( kv_table_t *table, char *key ); +char *kv_get_value( kv_table_t *table, char *key ); +void kv_add_item( kv_table_t *table, char *key, char *value ); + +#endif diff --git a/raveloxmidi/include/net_connection.h b/raveloxmidi/include/net_connection.h index 9384d6c..3d0a000 100644 --- a/raveloxmidi/include/net_connection.h +++ b/raveloxmidi/include/net_connection.h @@ -38,6 +38,7 @@ typedef struct net_ctx_t { uint16_t data_port; time_t start; char * ip_address; + char * name; journal_t *journal; struct net_ctx_t *next; struct net_ctx_t *prev; @@ -50,7 +51,8 @@ void net_ctx_init( void ); void net_ctx_teardown( void ); net_ctx_t * net_ctx_find_by_id( uint8_t id ); net_ctx_t * net_ctx_find_by_ssrc( uint32_t ssrc); -net_ctx_t * net_ctx_register( uint32_t ssrc, uint32_t initiator, char *ip_address, uint16_t port ); +net_ctx_t * net_ctx_find_by_name( char *name ); +net_ctx_t * net_ctx_register( uint32_t ssrc, uint32_t initiator, char *ip_address, uint16_t port , char *name); net_ctx_t * net_ctx_get_last( void ); void net_ctx_add_journal_note( net_ctx_t *ctx, midi_note_t *midi_note ); diff --git a/raveloxmidi/include/raveloxmidi_config.h b/raveloxmidi/include/raveloxmidi_config.h index 0e3af88..198ae55 100644 --- a/raveloxmidi/include/raveloxmidi_config.h +++ b/raveloxmidi/include/raveloxmidi_config.h @@ -1,11 +1,7 @@ #ifndef _RAVELOXMIDI_CONFIG_H #define _RAVELOXMIDI_CONFIG_H -typedef struct raveloxmidi_config_t -{ - char *key; - char *value; -} raveloxmidi_config_t; +#include "kv_table.h" void config_init( int argc, char *argv[] ); void config_teardown( void ); diff --git a/raveloxmidi/include/remote_connection.h b/raveloxmidi/include/remote_connection.h index d063cec..53002ac 100644 --- a/raveloxmidi/include/remote_connection.h +++ b/raveloxmidi/include/remote_connection.h @@ -22,6 +22,7 @@ #define _REMOTE_CONNECTION_H void remote_connect_init( void ); +void remote_connect_ok( char *name ); void remote_connect_teardown( void ); #endif diff --git a/raveloxmidi/src/Makefile.am b/raveloxmidi/src/Makefile.am index a8fa538..2d3581a 100755 --- a/raveloxmidi/src/Makefile.am +++ b/raveloxmidi/src/Makefile.am @@ -28,7 +28,8 @@ raveloxmidi_SOURCES = \ daemon.c \ logging.c \ utils.c \ - raveloxmidi_alsa.c + raveloxmidi_alsa.c \ + kv_table.c raveloxmidi_LDADD = @PTHREAD_LIBS@ @AVAHI_LIBS@ @ALSA_LIBS@ raveloxmidi_CFLAGS = @PTHREAD_CFLAGS@ @AVAHI_CFLAGS@ @ALSA_CFLAGS@ diff --git a/raveloxmidi/src/applemidi_inv.c b/raveloxmidi/src/applemidi_inv.c index 30e66e6..969475d 100644 --- a/raveloxmidi/src/applemidi_inv.c +++ b/raveloxmidi/src/applemidi_inv.c @@ -65,7 +65,7 @@ net_response_t * applemidi_inv_responder( char *ip_address, uint16_t port, void if( ! ctx ) { logging_printf( LOGGING_DEBUG, "applemidi_inv_responder: Registering new connection\n"); - ctx = net_ctx_register( inv->ssrc, inv->initiator, ip_address, port ); + ctx = net_ctx_register( inv->ssrc, inv->initiator, ip_address, port , inv->name ); if( ! ctx ) { diff --git a/raveloxmidi/src/applemidi_ok.c b/raveloxmidi/src/applemidi_ok.c index e8e4716..4c21349 100644 --- a/raveloxmidi/src/applemidi_ok.c +++ b/raveloxmidi/src/applemidi_ok.c @@ -43,20 +43,41 @@ extern int errno; #include "raveloxmidi_config.h" #include "logging.h" +#include "remote_connection.h" + net_response_t * applemidi_ok_responder( char *ip_address, uint16_t port, void *data ) { net_applemidi_inv *inv = NULL; + net_ctx_t *ctx = NULL; if( ! data ) return NULL; inv = ( net_applemidi_inv *) data; + logging_printf( LOGGING_DEBUG, "applemidi_ok_responder: ssrc=0x%08x version=%u initiator=0x%08x name=%s\n", inv->ssrc, inv->version, inv->initiator, inv->name); -/* - accept_inv->ssrc = ctx->send_ssrc; - accept_inv->version = 2; - accept_inv->initiator = ctx->initiator; - service_name = config_string_get("service.name"); -*/ + ctx = net_ctx_find_by_ssrc( inv->ssrc ); + + /* If no context is found, this is a new connection */ + /* We assume that the current port is the control port */ + if( ! ctx ) + { + logging_printf( LOGGING_DEBUG, "applemidi_ok_responder: Registering new connection\n"); + ctx = net_ctx_register( inv->ssrc, inv->initiator, ip_address, port , inv->name); + + /* Set the data port */ + ctx->data_port = port + 1; + + if( ! ctx ) + { + logging_printf( LOGGING_ERROR, "applemidi_okresponder: Error registering connection\n"); + } + + /* Set the remote connect flag if the ssrc is the same one we used */ + remote_connect_ok( inv->name ); + + /* Otherwise, we assume that the current port is the data port */ + } else { + ctx->data_port = port; + } - logging_printf( LOGGING_DEBUG, "applemidi_ok_responder: ssrc=0x%08x version=%u initiator=0x%08x name=%s\n", inv->ssrc, inv->version, inv->initiator, inv->name); return NULL; } diff --git a/raveloxmidi/src/kv_table.c b/raveloxmidi/src/kv_table.c new file mode 100644 index 0000000..198c74e --- /dev/null +++ b/raveloxmidi/src/kv_table.c @@ -0,0 +1,174 @@ +/* + This file is part of raveloxmidi. + + Copyright (C) 2019 Dave Kelly + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#include +#include +#include + +#include "kv_table.h" + +kv_table_t *kv_table_create( char *name ) +{ + kv_table_t *new_table = NULL; + + new_table = ( kv_table_t *)malloc( sizeof( kv_table_t ) ); + if( ! new_table ) + { + return NULL; + } + + if( name ) new_table->name = strdup( name ); + + new_table->items = NULL; + new_table->count = 0; + + return new_table; +} + +void kv_table_dump( kv_table_t *table ) +{ + int i = 0; + + if( ! table ) return; + if( ! table->items ) return; + + if( table->name ) fprintf(stderr,"Table: %s\n", table->name ); + + for( i=0; i < table->count; i++ ) + { + fprintf(stderr, "%s = %s\n", table->items[i]->key, table->items[i]->value); + } +} + +void kv_table_reset( kv_table_t *table ) +{ + int i = 0; + + if( ! table ) return; + if( ! table->items) return; + if( table->count <= 0 ) return; + + for(i=0; i < table->count; i++) + { + if( table->items[i] ) + { + if( table->items[i]->key ) + { + free( table->items[i]->key ); + table->items[i]->key = NULL; + } + if( table->items[i]->value ) + { + free( table->items[i]->value ); + table->items[i]->value = NULL; + } + free( table->items[i] ); + table->items[i] = NULL; + } + } + + free( table->items); + table->items = NULL; + + table->count = 0; + if( table->name ) free( table->name); + table->name = NULL; +} + +kv_item_t *kv_find_item( kv_table_t *table, char *key ) +{ + int i = 0; + + if( ! table ) return NULL; + if( ! key ) return NULL; + if( ! table->items ) return NULL; + if( table->count <= 0 ) return NULL; + + for( i = 0; i < table->count; i++ ) + { + if( strcasecmp( key, table->items[i]->key ) == 0 ) + { + return table->items[i]; + } + } + + return NULL; +} + +char *kv_get_value( kv_table_t *table, char *key ) +{ + kv_item_t *item = NULL; + + item = kv_find_item( table, key ); + if( ! item ) return NULL; + + return item->value; +} + +void kv_add_item( kv_table_t *table, char *key, char *value ) +{ + kv_item_t *new_item = NULL; + kv_item_t **new_item_list = NULL; + + if( ! table ) return; + if( ! key ) return; + + if( strlen( key ) == 0 ) return; + + new_item = kv_find_item( table, key ); + + if( ! new_item ) + { + new_item = (kv_item_t *)malloc( sizeof( kv_item_t ) ); + if( ! new_item ) + { + return; + } + memset( new_item, 0, sizeof( kv_item_t ) ); + new_item->key = (char *)strdup( key ); + if( value ) + { + new_item->value = (char *)strdup( value ); + } else { + new_item->value = NULL; + } + + new_item_list = ( kv_item_t **)realloc( table->items, sizeof( kv_item_t * ) * ( table->count + 1 ) ); + if( ! new_item_list ) + { + if( new_item->value ) free( new_item->value); + if( new_item->key ) free( new_item->key ); + free( new_item ); + return; + } + + table->items = new_item_list; + table->items[ table->count ] = new_item; + table->count += 1; + } else { + if( new_item->value ) free( new_item->value ); + if( value ) + { + new_item->value = ( char * )strdup( value ); + } else { + new_item->value = NULL; + } + } +} diff --git a/raveloxmidi/src/net_applemidi.c b/raveloxmidi/src/net_applemidi.c index 484b91a..f677216 100644 --- a/raveloxmidi/src/net_applemidi.c +++ b/raveloxmidi/src/net_applemidi.c @@ -70,6 +70,22 @@ void net_applemidi_command_dump( net_applemidi_command *command) inv_data->version, inv_data->initiator,inv_data->ssrc,inv_data->name); } + if( command->command == NET_APPLEMIDI_CMD_REJECT ) + { + net_applemidi_inv *reject_data; + reject_data = (net_applemidi_inv *)command->data; + logging_printf(LOGGING_DEBUG,"reject_data:version=%u,initiator=0x%08x,ssrc=0x%08x,name=\"%s\"\n", + reject_data->version, reject_data->initiator,reject_data->ssrc,reject_data->name); + } + + if( command->command == NET_APPLEMIDI_CMD_ACCEPT ) + { + net_applemidi_inv *ok_data; + ok_data = (net_applemidi_inv *)command->data; + logging_printf(LOGGING_DEBUG,"ok_data:version=%u,initiator=0x%08x,ssrc=0x%08x,name=\"%s\"\n", + ok_data->version, ok_data->initiator,ok_data->ssrc,ok_data->name); + } + if( command->command == NET_APPLEMIDI_CMD_END ) { net_applemidi_inv *end_data; diff --git a/raveloxmidi/src/net_connection.c b/raveloxmidi/src/net_connection.c index 1b7f91c..98de3ae 100644 --- a/raveloxmidi/src/net_connection.c +++ b/raveloxmidi/src/net_connection.c @@ -54,6 +54,7 @@ void net_ctx_destroy( net_ctx_t **ctx ) if( ! ctx ) return; if( ! *ctx ) return; + FREENULL( "name",(void **)&((*ctx)->name) ); FREENULL( "ip_address",(void **)&((*ctx)->ip_address) ); journal_destroy( &((*ctx)->journal) ); @@ -91,7 +92,7 @@ void net_ctx_dump( net_ctx_t *ctx ) ctx->ssrc, ctx->send_ssrc, ctx->initiator, ctx->seq, ctx->ip_address, ctx->control_port, ctx->data_port); } -static void net_ctx_set( net_ctx_t *ctx, uint32_t ssrc, uint32_t initiator, uint32_t send_ssrc, uint32_t seq, uint16_t port, char *ip_address ) +static void net_ctx_set( net_ctx_t *ctx, uint32_t ssrc, uint32_t initiator, uint32_t send_ssrc, uint32_t seq, uint16_t port, char *ip_address , char *name) { if( ! ctx ) return; @@ -107,6 +108,7 @@ static void net_ctx_set( net_ctx_t *ctx, uint32_t ssrc, uint32_t initiator, uint free( ctx->ip_address ); } ctx->ip_address = ( char *) strdup( ip_address ); + ctx->name = ( char *) strdup( name ); } net_ctx_t * net_ctx_create( void ) @@ -165,10 +167,19 @@ net_ctx_t * net_ctx_find_by_ssrc( uint32_t ssrc) while( current_ctx ) { - if( current_ctx->ssrc == ssrc ) - { - return current_ctx; - } + if( current_ctx->ssrc == ssrc ) break; + current_ctx = current_ctx->next; + } + + return current_ctx; +} + +net_ctx_t * net_ctx_find_by_name( char *name ) +{ + net_ctx_t *current_ctx = _ctx_head; + while( current_ctx ) + { + if( strcmp( current_ctx->name, name ) == 0 ) break; current_ctx = current_ctx->next; } @@ -189,12 +200,12 @@ net_ctx_t * net_ctx_get_last( void ) return current_ctx; } -net_ctx_t * net_ctx_register( uint32_t ssrc, uint32_t initiator, char *ip_address, uint16_t port ) +net_ctx_t * net_ctx_register( uint32_t ssrc, uint32_t initiator, char *ip_address, uint16_t port, char *name ) { net_ctx_t *current_ctx = NULL; net_ctx_t *last_ctx = NULL; net_ctx_t *new_ctx = NULL; - unsigned int send_ssrc = 0; + uint32_t send_ssrc = 0; /* Check to see if the ssrc already exists */ new_ctx = net_ctx_find_by_ssrc( ssrc ); @@ -217,10 +228,10 @@ net_ctx_t * net_ctx_register( uint32_t ssrc, uint32_t initiator, char *ip_addres send_ssrc = random_number(); - net_ctx_set( new_ctx, ssrc, initiator, send_ssrc, 0x638F, port, ip_address ); + net_ctx_set( new_ctx, ssrc, initiator, send_ssrc, 0x638F, port, ip_address , name); new_ctx->prev = last_ctx; - if( last_ctx ) last_ctx->next = new_ctx; + if( last_ctx ) last_ctx->next = new_ctx, name; for( net_ctx_iter_start_head(); net_ctx_iter_has_next(); net_ctx_iter_next() ) { diff --git a/raveloxmidi/src/net_socket.c b/raveloxmidi/src/net_socket.c index bf6765e..ce6ffe7 100644 --- a/raveloxmidi/src/net_socket.c +++ b/raveloxmidi/src/net_socket.c @@ -246,6 +246,7 @@ int net_socket_read( int fd ) applemidi_ok_responder( ip_address, from_port, command->data ); break; case NET_APPLEMIDI_CMD_REJECT: + logging_printf( LOGGING_ERROR, "net_socket_read: Connection rejected host=%s, port=%u\n", ip_address, from_port); break; case NET_APPLEMIDI_CMD_END: response = applemidi_by_responder( command->data ); @@ -258,7 +259,6 @@ int net_socket_read( int fd ) break; case NET_APPLEMIDI_CMD_BITRATE: break; - ;; } if( response ) diff --git a/raveloxmidi/src/raveloxmidi_config.c b/raveloxmidi/src/raveloxmidi_config.c index 0703e6d..2be5dc6 100644 --- a/raveloxmidi/src/raveloxmidi_config.c +++ b/raveloxmidi/src/raveloxmidi_config.c @@ -33,8 +33,7 @@ extern int errno; #include "raveloxmidi_config.h" #include "logging.h" -static int num_items = 0; -static raveloxmidi_config_t **config_items = NULL; +static kv_table_t *config_items = NULL; static void config_set_defaults( void ) { @@ -44,7 +43,7 @@ static void config_set_defaults( void ) config_add_item("network.socket_timeout" , "30" ); config_add_item("network.max_connections", "8"); config_add_item("service.name", "raveloxmidi"); - config_add_item("run_as_daemon", "yes"); + config_add_item("run_as_daemon", "no"); config_add_item("daemon.pid_file","raveloxmidi.pid"); config_add_item("logging.enabled", "yes"); config_add_item("logging.log_file", NULL); @@ -61,8 +60,6 @@ static void config_set_defaults( void ) } -static raveloxmidi_config_t *config_get_item( char *key ); - static void config_load_file( char *filename ) { @@ -151,8 +148,14 @@ void config_init( int argc, char *argv[] ) const char *short_options = "c:dihNP:RCDT:"; #endif int c; - config_items = NULL; + config_items = kv_table_create("config_items"); + if( ! config_items ) + { + fprintf(stderr,"Unable to initialise config table\n"); + exit(1); + } + config_set_defaults(); while(1) @@ -212,34 +215,24 @@ void config_init( int argc, char *argv[] ) void config_teardown( void ) { - int i = 0; - - logging_printf( LOGGING_DEBUG, "config_teardown config_items=%p num_items=%u\n", config_items, num_items - 1 ); - if( ! config_items ) return; - if( num_items == 0 ) return; - - for( i = 0 ; i < num_items ; i++ ) + if( ! config_items ) { - if( config_items[i]->value ) free( config_items[i]->value ); - if( config_items[i]->key ) free( config_items[i]->key ); - if( config_items[i] ) free( config_items[i] ); + fprintf( stderr, "NO CONFIG ITEMS\n"); + return; } - if( config_items ) free( config_items ); + logging_printf( LOGGING_DEBUG, "config_teardown config_items=%p count=%lu\n", config_items, config_items->count ); - num_items = 0; + kv_table_reset( config_items ); + + free( config_items ); config_items = NULL; } /* Public version */ char *config_string_get( char *key ) { - raveloxmidi_config_t *item = NULL; - - item = config_get_item( key ); - - if( ! item ) return NULL; - return item->value; + return kv_get_value( config_items, key ); } int config_int_get( char *key ) @@ -264,79 +257,20 @@ long config_long_get( char *key ) int config_is_set( char *key ) { - return ( config_get_item( key ) != NULL ); -} - -static raveloxmidi_config_t *config_get_item( char *key ) -{ - int i = 0 ; - - if( num_items <= 0 ) return NULL; - if( ! config_items ) return NULL; - - for( i=0; i < num_items ; i ++ ) - { - if( strcasecmp( key, config_items[i]->key ) == 0 ) - { - return config_items[i]; - } - } - - return NULL; + return ( kv_find_item( config_items, key ) != NULL ); } void config_add_item(char *key, char *value ) { - raveloxmidi_config_t *new_item, *found_item; - raveloxmidi_config_t **new_config_item_list = NULL; - - found_item = config_get_item( key ); - if( ! found_item ) - { - new_item = ( raveloxmidi_config_t *)malloc( sizeof( raveloxmidi_config_t )); - if( new_item ) - { - new_item->key = (char *)strdup( key ); - if( value ) - { - new_item->value = ( char *)strdup( value ); - } else { - new_item->value = NULL; - } - - new_config_item_list = (raveloxmidi_config_t **)realloc(config_items, sizeof( raveloxmidi_config_t * ) * (num_items + 1) ); - if( ! new_config_item_list ) - { - fprintf(stderr, "config_add_item: Insufficient memory to create new config item\n"); - free( new_item ); - return; - } - config_items = new_config_item_list; - config_items[ num_items ] = new_item; - num_items++; - } - /* Overwrite any existing item that has the same key */ - } else { - if( found_item->value ) free(found_item->value); - if( value ) - { - found_item->value = ( char *)strdup( value ); - } else { - found_item->value = NULL; - } - } + kv_add_item( config_items, key, value ); } void config_dump( void ) { - int i = 0; if( ! config_items ) return; - if( num_items == 0 ) return; + if( config_items->count <= 0 ) return; - for( i = 0 ; i < num_items; i++ ) - { - fprintf( stderr, "%s = %s\n", config_items[i]->key, config_items[i]->value ); - } + kv_table_dump( config_items ); } void config_usage( void ) diff --git a/raveloxmidi/src/remote_connection.c b/raveloxmidi/src/remote_connection.c index 7838f9b..bc1f922 100644 --- a/raveloxmidi/src/remote_connection.c +++ b/raveloxmidi/src/remote_connection.c @@ -57,8 +57,8 @@ extern int errno; #include "remote_connection.h" static int remote_connected = 0; -static int ssrc = 0; -static int initiator = 0; +static uint32_t remote_connect_ssrc = 0; +static uint32_t remote_initiator = 0; void remote_connect_init( void ) { @@ -96,8 +96,8 @@ void remote_connect_init( void ) return; } - ssrc = random_number(); - initiator = random_number(); + remote_connect_ssrc = random_number(); + remote_initiator = random_number(); // Build the INV packet inv = net_applemidi_inv_create(); @@ -108,9 +108,9 @@ void remote_connect_init( void ) return; } - inv->ssrc = ssrc; + inv->ssrc = remote_connect_ssrc; inv->version = 2; - inv->initiator = initiator; + inv->initiator = remote_initiator; client_name = config_string_get("client.name"); if( client_name ) { @@ -143,6 +143,10 @@ void remote_connect_init( void ) ctx = net_ctx_create(); ctx->ip_address = ( char * ) strdup( found_service->ip_address ); ctx->data_port = found_service->port; + ctx->control_port = found_service->port + 1; + ctx->ssrc = inv->ssrc; + ctx->initiator = inv->initiator; + ctx->seq = 0x638E; logging_printf( LOGGING_DEBUG, "remote_connect_init: Creating connection context for %s:%u\n", ctx->ip_address, ctx->data_port ); @@ -151,7 +155,6 @@ void remote_connect_init( void ) logging_printf( LOGGING_ERROR, "remote_connect_init: Unable to create socket context\n"); } else { net_ctx_send( net_socket_get_data_socket() , ctx, response->buffer, response->len ); - net_ctx_send( net_socket_get_control_socket() , ctx, response->buffer, response->len ); } net_ctx_destroy( &ctx ); @@ -165,8 +168,79 @@ void remote_connect_init( void ) net_applemidi_cmd_destroy( &cmd ); } +void remote_connect_ok( char *remote_name ) +{ + if( net_ctx_find_by_name( remote_name ) ) + { + remote_connected = 1; + } +} + void remote_connect_teardown( void ) { + net_applemidi_inv *by = NULL; + net_response_t *response = NULL; + net_applemidi_command *cmd = NULL; + char *remote_service_name = NULL; + char *client_name = NULL; + net_ctx_t *ctx; + if( ! remote_connected ) return; -} + remote_service_name = config_string_get("remote.connect"); + + logging_printf( LOGGING_DEBUG, "remote_connect_teardown: Disconnecting from [%s]\n", remote_service_name); + + // Build the BY packet + by = net_applemidi_inv_create(); + + if( ! by ) + { + logging_printf( LOGGING_ERROR, "remote_connect_teardown: Unable to allocate memory for by packet\n"); + return; + } + + by->ssrc = remote_connect_ssrc; + by->version = 2; + by->initiator = 0; + client_name = NULL; + + cmd = net_applemidi_cmd_create( NET_APPLEMIDI_CMD_END ); + + if( ! cmd ) + { + logging_printf( LOGGING_ERROR, "remote_connect_teardown: Unable to create AppleMIDI command\n"); + net_applemidi_inv_destroy( &by ); + goto remote_teardown_fail; + } + + cmd->data = by; + + response = net_response_create(); + + if( response ) + { + int ret = 0; + ret = net_applemidi_pack( cmd , &(response->buffer), &(response->len) ); + if( ret != 0 ) + { + logging_printf( LOGGING_ERROR, "remote_connect_teardown: Unable to pack response to by command\n"); + } else { + ctx = net_ctx_find_by_name( remote_service_name ); + if( ! ctx ) + { + logging_printf( LOGGING_ERROR, "remote_connect_teardown: Unable to find connection for [%s]\n", remote_service_name); + } else { + net_ctx_send( net_socket_get_data_socket() , ctx, response->buffer, response->len ); + hex_dump( response->buffer, response->len ); + } + } + } else { + logging_printf( LOGGING_ERROR, "remote_connect_teardown: Unable to create response packet\n"); + } + +remote_teardown_fail: + net_response_destroy( &response ); + net_applemidi_cmd_destroy( &cmd ); + net_applemidi_inv_destroy( &by ); +} From 3025f59e99ba0da61811265dbe1e30dc705015ce Mon Sep 17 00:00:00 2001 From: Dave Kelly Date: Sun, 24 Mar 2019 14:09:00 -0700 Subject: [PATCH 20/33] Refactoring outbound communication to remote devices --- python/note_send.py | 4 +- raveloxmidi/include/net_distribute.h | 26 +++ raveloxmidi/include/net_socket.h | 2 + raveloxmidi/src/Makefile.am | 3 +- raveloxmidi/src/net_distribute.c | 227 +++++++++++++++++++++++++++ raveloxmidi/src/net_socket.c | 198 +++-------------------- raveloxmidi/src/remote_connection.c | 6 +- 7 files changed, 287 insertions(+), 179 deletions(-) create mode 100644 raveloxmidi/include/net_distribute.h create mode 100644 raveloxmidi/src/net_distribute.c diff --git a/python/note_send.py b/python/note_send.py index c45db8a..4e62261 100755 --- a/python/note_send.py +++ b/python/note_send.py @@ -22,13 +22,13 @@ s.connect( connect_tuple ) # Note ON -bytes = struct.pack( "BBBB", 0xaa, 0x96, 0x3c, 0x7f ) +bytes = struct.pack( "BBBB", 0xaa, 0x96, 0x30, 0x7f ) s.send( bytes ) time.sleep( 0.25 ); # Note OFF -bytes = struct.pack( "BBBB", 0xaa, 0x86, 0x3c, 0x7f ) +bytes = struct.pack( "BBBB", 0xaa, 0x86, 0x30, 0x7f ) s.send( bytes ) s.close() diff --git a/raveloxmidi/include/net_distribute.h b/raveloxmidi/include/net_distribute.h new file mode 100644 index 0000000..fb47541 --- /dev/null +++ b/raveloxmidi/include/net_distribute.h @@ -0,0 +1,26 @@ +/* + This file is part of raveloxmidi. + + Copyright (C) 2019 Dave Kelly + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef _NET_DISTRIBUTE_H +#define _NET_DISTRIBUTE_H + +void net_distribute_midi( char *packet, size_t recv_len ); + +#endif diff --git a/raveloxmidi/include/net_socket.h b/raveloxmidi/include/net_socket.h index 23ac286..1c0c0f4 100644 --- a/raveloxmidi/include/net_socket.h +++ b/raveloxmidi/include/net_socket.h @@ -23,6 +23,8 @@ #include "config.h" +void net_socket_lock( void ); +void net_socket_unlock( void ); void net_socket_add( int new_socket ); int net_socket_create( int family, char *ip_address, unsigned int port ); int net_socket_listener_create( int family, char *ip_address, unsigned int port ); diff --git a/raveloxmidi/src/Makefile.am b/raveloxmidi/src/Makefile.am index 2d3581a..e6600bc 100755 --- a/raveloxmidi/src/Makefile.am +++ b/raveloxmidi/src/Makefile.am @@ -29,7 +29,8 @@ raveloxmidi_SOURCES = \ logging.c \ utils.c \ raveloxmidi_alsa.c \ - kv_table.c + kv_table.c \ + net_distribute.c raveloxmidi_LDADD = @PTHREAD_LIBS@ @AVAHI_LIBS@ @ALSA_LIBS@ raveloxmidi_CFLAGS = @PTHREAD_CFLAGS@ @AVAHI_CFLAGS@ @ALSA_CFLAGS@ diff --git a/raveloxmidi/src/net_distribute.c b/raveloxmidi/src/net_distribute.c new file mode 100644 index 0000000..bba061d --- /dev/null +++ b/raveloxmidi/src/net_distribute.c @@ -0,0 +1,227 @@ +/* + This file is part of raveloxmidi. + + Copyright (C) 2019 Dave Kelly + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include + +#include +extern int errno; + +#include "config.h" + +#include "net_applemidi.h" +#include "net_response.h" +#include "net_socket.h" +#include "net_connection.h" + +#include "applemidi_inv.h" +#include "applemidi_ok.h" +#include "applemidi_sync.h" +#include "applemidi_feedback.h" +#include "applemidi_by.h" + +#include "midi_note.h" +#include "midi_control.h" +#include "midi_program.h" + +#include "rtp_packet.h" +#include "midi_command.h" +#include "midi_payload.h" +#include "utils.h" + +#include "raveloxmidi_config.h" +#include "logging.h" + +#include "raveloxmidi_alsa.h" + +/* Send MIDI commands to all connections */ +void net_distribute_midi( char *packet, size_t recv_len ) +{ + rtp_packet_t *rtp_packet = NULL; + unsigned char *packed_rtp_buffer = NULL; + size_t packed_rtp_buffer_len = 0; + + midi_note_t *midi_note = NULL; + midi_control_t *midi_control = NULL; + midi_program_t *midi_program = NULL; + midi_payload_t *initial_midi_payload = NULL; + + + unsigned char *packed_rtp_payload = NULL; + + midi_command_t *midi_commands=NULL; + size_t num_midi_commands=0; + size_t midi_command_index = 0; + + char *packed_journal = NULL; + size_t packed_journal_len = 0; + char *description = NULL; + enum midi_message_type_t message_type = 0; + size_t midi_payload_len = 0; + + + // Convert the buffer into a set of commands + midi_payload_len = recv_len - 1; + initial_midi_payload = midi_payload_create(); + midi_payload_set_buffer( initial_midi_payload, packet + 1 , &midi_payload_len ); + midi_payload_to_commands( initial_midi_payload, MIDI_PAYLOAD_STREAM, &midi_commands, &num_midi_commands ); + midi_payload_destroy( &initial_midi_payload ); + + for( midi_command_index = 0 ; midi_command_index < num_midi_commands ; midi_command_index++ ) + { + midi_payload_t *single_midi_payload = NULL; + unsigned char *packed_payload = NULL; + size_t packed_payload_len = 0; + int ret = 0; + + /* Extract a single command as a midi payload */ + midi_command_to_payload( &(midi_commands[ midi_command_index ]), &single_midi_payload ); + if( ! single_midi_payload ) continue; + + midi_command_map( &(midi_commands[ midi_command_index ]), &description, &message_type ); + midi_command_dump( &(midi_commands[ midi_command_index ]) ); + switch( message_type ) + { + case MIDI_NOTE_OFF: + case MIDI_NOTE_ON: + ret = midi_note_from_command( &(midi_commands[midi_command_index]), &midi_note); + midi_note_dump( midi_note ); + break; + case MIDI_CONTROL_CHANGE: + ret = midi_control_from_command( &(midi_commands[midi_command_index]), &midi_control); + midi_control_dump( midi_control ); + break; + case MIDI_PROGRAM_CHANGE: + ret = midi_program_from_command( &(midi_commands[midi_command_index]), &midi_program); + midi_program_dump( midi_program ); + break; + default: + break; + } + + // Build the RTP packet + for( net_ctx_iter_start_head() ; net_ctx_iter_has_current(); net_ctx_iter_next()) + { + net_ctx_t *current_ctx = net_ctx_iter_current(); + + logging_printf( LOGGING_DEBUG, "net_distribute: net_ctx_iter_current()=%p\n", current_ctx ); + if(! current_ctx ) continue; + + // Get a journal if there is one + net_socket_lock(); + net_ctx_journal_pack( current_ctx , &packed_journal, &packed_journal_len); + net_socket_unlock(); + + if( packed_journal_len > 0 ) + { + midi_payload_set_j( single_midi_payload ); + } else { + midi_payload_unset_j( single_midi_payload ); + } + + // We have to pack the payload again each time because some connections may not have a journal + // and the flag to indicate the journal being present is in the payload + midi_payload_pack( single_midi_payload, &packed_payload, &packed_payload_len ); + logging_printf(LOGGING_DEBUG, "net_distribute: packed_payload: buffer=%p,packed_payload_len=%u packed_journal_len=%u\n", packed_payload, packed_payload_len, packed_journal_len); + + // Join the packed MIDI payload and the journal together + packed_rtp_payload = (unsigned char *)malloc( packed_payload_len + packed_journal_len ); + memset( packed_rtp_payload, 0, packed_payload_len + packed_journal_len ); + memcpy( packed_rtp_payload, packed_payload , packed_payload_len ); + memcpy( packed_rtp_payload + packed_payload_len , packed_journal, packed_journal_len ); + + rtp_packet = rtp_packet_create(); + net_ctx_increment_seq( current_ctx ); + + // Transfer the connection details to the RTP packet + net_ctx_update_rtp_fields( current_ctx , rtp_packet ); + + // Add the MIDI data to the RTP packet + rtp_packet->payload_len = packed_payload_len + packed_journal_len; + + rtp_packet->payload = (unsigned char *)malloc( rtp_packet->payload_len ); + memcpy( rtp_packet->payload, packed_rtp_payload, rtp_packet->payload_len ); + rtp_packet_dump( rtp_packet ); + + // Pack the RTP data + rtp_packet_pack( rtp_packet, &packed_rtp_buffer, &packed_rtp_buffer_len ); + + net_socket_lock(); + net_ctx_send( net_socket_get_data_socket(), current_ctx, packed_rtp_buffer, packed_rtp_buffer_len ); + net_socket_unlock(); + + FREENULL( "packed_rtp_buffer", (void **)&packed_rtp_buffer ); + rtp_packet_destroy( &rtp_packet ); + + FREENULL( "packed_rtp_payload", (void **)&packed_rtp_payload ); + FREENULL( "packed_journal", (void **)&packed_journal ); + + switch( message_type ) + { + case MIDI_NOTE_OFF: + case MIDI_NOTE_ON: + net_ctx_add_journal_note( current_ctx , midi_note ); + break; + case MIDI_CONTROL_CHANGE: + net_ctx_add_journal_control( current_ctx, midi_control ); + break; + case MIDI_PROGRAM_CHANGE: + net_ctx_add_journal_program( current_ctx, midi_program ); + break; + default: + continue; + } + } + + // Clean up + FREENULL( "packed_payload", (void **)&packed_payload ); + midi_payload_destroy( &single_midi_payload ); + switch( message_type ) + { + case MIDI_NOTE_OFF: + case MIDI_NOTE_ON: + midi_note_destroy( &midi_note ); + break; + case MIDI_CONTROL_CHANGE: + midi_control_destroy( &midi_control ); + break; + case MIDI_PROGRAM_CHANGE: + midi_program_destroy( &midi_program ); + break; + default: + break; + } + + midi_command_reset( &(midi_commands[midi_command_index]) ); + } + + free( midi_commands ); +} diff --git a/raveloxmidi/src/net_socket.c b/raveloxmidi/src/net_socket.c index ce6ffe7..04706e7 100644 --- a/raveloxmidi/src/net_socket.c +++ b/raveloxmidi/src/net_socket.c @@ -41,6 +41,7 @@ extern int errno; #include "net_response.h" #include "net_socket.h" #include "net_connection.h" +#include "net_distribute.h" #include "applemidi_inv.h" #include "applemidi_ok.h" @@ -83,6 +84,16 @@ int pipe_fd[2]; static void set_shutdown_lock( int i ); +void net_socket_lock( void ) +{ + pthread_mutex_lock( &socket_mutex ); +} + +void net_socket_unlock( void ) +{ + pthread_mutex_unlock( &socket_mutex ); +} + void net_socket_add( int new_socket ) { int *new_socket_list = NULL; @@ -264,9 +275,9 @@ int net_socket_read( int fd ) if( response ) { size_t bytes_written = 0; - pthread_mutex_lock( &socket_mutex ); + net_socket_lock(); bytes_written = sendto( fd, response->buffer, response->len , 0 , (void *)&from_addr, from_len); - pthread_mutex_unlock( &socket_mutex ); + net_socket_unlock(); logging_printf( LOGGING_DEBUG, "net_socket_read: write(bytes=%u,socket=%d,host=%s,port=%u)\n", bytes_written, fd,ip_address, from_port ); net_response_destroy( &response ); } @@ -277,9 +288,9 @@ int net_socket_read( int fd ) { char *buffer="OK"; size_t bytes_written = 0; - pthread_mutex_lock( &socket_mutex ); + net_socket_lock(); bytes_written = sendto( fd, buffer, strlen(buffer), 0 , (void *)&from_addr, from_len); - pthread_mutex_unlock( &socket_mutex ); + net_socket_unlock(); logging_printf(LOGGING_DEBUG, "net_socket_read: Heartbeat request. Response written: %u\n", bytes_written); } else if( (packet[0]==0xaa) && (recv_len == 5) && ( strncmp( (const char *)&(packet[1]),"QUIT",4)==0) ) @@ -287,9 +298,9 @@ int net_socket_read( int fd ) { char *buffer="QT"; size_t bytes_written = 0; - pthread_mutex_lock( &socket_mutex ); + net_socket_lock(); bytes_written = sendto( fd, buffer, strlen(buffer), 0 , (void *)&from_addr, from_len); - pthread_mutex_unlock( &socket_mutex ); + net_socket_unlock(); logging_printf(LOGGING_DEBUG, "net_socket_read: Shutdown request. Response written: %u\n", bytes_written); logging_printf(LOGGING_NORMAL, "Shutdown request received on local socket\n"); set_shutdown_lock(1); @@ -298,168 +309,9 @@ int net_socket_read( int fd ) #else } else if( packet[0] == 0xaa ) #endif - // MIDI note on internal socket or ALSA rawmidi device + // MIDI data on internal socket or ALSA rawmidi device { - rtp_packet_t *rtp_packet = NULL; - unsigned char *packed_rtp_buffer = NULL; - size_t packed_rtp_buffer_len = 0; - - midi_note_t *midi_note = NULL; - midi_control_t *midi_control = NULL; - midi_program_t *midi_program = NULL; - midi_payload_t *initial_midi_payload = NULL; - - - unsigned char *packed_rtp_payload = NULL; - - midi_command_t *midi_commands=NULL; - size_t num_midi_commands=0; - size_t midi_command_index = 0; - - char *packed_journal = NULL; - size_t packed_journal_len = 0; - char *description = NULL; - enum midi_message_type_t message_type = 0; - size_t midi_payload_len = 0; - - - // Convert the buffer into a set of commands - midi_payload_len = recv_len - 1; - initial_midi_payload = midi_payload_create(); - midi_payload_set_buffer( initial_midi_payload, packet + 1 , &midi_payload_len ); - midi_payload_to_commands( initial_midi_payload, MIDI_PAYLOAD_STREAM, &midi_commands, &num_midi_commands ); - midi_payload_destroy( &initial_midi_payload ); - - for( midi_command_index = 0 ; midi_command_index < num_midi_commands ; midi_command_index++ ) - { - midi_payload_t *single_midi_payload = NULL; - unsigned char *packed_payload = NULL; - size_t packed_payload_len = 0; - - /* Extract a single command as a midi payload */ - midi_command_to_payload( &(midi_commands[ midi_command_index ]), &single_midi_payload ); - if( ! single_midi_payload ) continue; - - midi_command_map( &(midi_commands[ midi_command_index ]), &description, &message_type ); - midi_command_dump( &(midi_commands[ midi_command_index ]) ); - switch( message_type ) - { - case MIDI_NOTE_OFF: - case MIDI_NOTE_ON: - ret = midi_note_from_command( &(midi_commands[midi_command_index]), &midi_note); - midi_note_dump( midi_note ); - break; - case MIDI_CONTROL_CHANGE: - ret = midi_control_from_command( &(midi_commands[midi_command_index]), &midi_control); - midi_control_dump( midi_control ); - break; - case MIDI_PROGRAM_CHANGE: - ret = midi_program_from_command( &(midi_commands[midi_command_index]), &midi_program); - midi_program_dump( midi_program ); - break; - default: - break; - } - - // Build the RTP packet - for( net_ctx_iter_start_head() ; net_ctx_iter_has_current(); net_ctx_iter_next()) - { - net_ctx_t *current_ctx = net_ctx_iter_current(); - - logging_printf( LOGGING_DEBUG, "net_ctx_iter_current()=%p\n", current_ctx ); - if(! current_ctx ) continue; - - // Get a journal if there is one - pthread_mutex_lock( &socket_mutex ); - net_ctx_journal_pack( current_ctx , &packed_journal, &packed_journal_len); - pthread_mutex_unlock( &socket_mutex ); - - if( packed_journal_len > 0 ) - { - midi_payload_set_j( single_midi_payload ); - } else { - midi_payload_unset_j( single_midi_payload ); - } - - // We have to pack the payload again each time because some connections may not have a journal - // and the flag to indicate the journal being present is in the payload - midi_payload_pack( single_midi_payload, &packed_payload, &packed_payload_len ); - logging_printf(LOGGING_DEBUG, "packed_payload: buffer=%p,packed_payload_len=%u packed_journal_len=%u\n", packed_payload, packed_payload_len, packed_journal_len); - - // Join the packed MIDI payload and the journal together - packed_rtp_payload = (unsigned char *)malloc( packed_payload_len + packed_journal_len ); - memset( packed_rtp_payload, 0, packed_payload_len + packed_journal_len ); - memcpy( packed_rtp_payload, packed_payload , packed_payload_len ); - memcpy( packed_rtp_payload + packed_payload_len , packed_journal, packed_journal_len ); - logging_printf(LOGGING_DEBUG, "packed_rtp_payload\n"); - - rtp_packet = rtp_packet_create(); - net_ctx_increment_seq( current_ctx ); - - // Transfer the connection details to the RTP packet - net_ctx_update_rtp_fields( current_ctx , rtp_packet ); - - // Add the MIDI data to the RTP packet - rtp_packet->payload_len = packed_payload_len + packed_journal_len; - - rtp_packet->payload = (unsigned char *)malloc( rtp_packet->payload_len ); - memcpy( rtp_packet->payload, packed_rtp_payload, rtp_packet->payload_len ); - rtp_packet_dump( rtp_packet ); - - // Pack the RTP data - rtp_packet_pack( rtp_packet, &packed_rtp_buffer, &packed_rtp_buffer_len ); - - pthread_mutex_lock( &socket_mutex ); - net_ctx_send( sockets[ DATA_PORT ], current_ctx, packed_rtp_buffer, packed_rtp_buffer_len ); - pthread_mutex_unlock( &socket_mutex ); - - FREENULL( "packed_rtp_buffer", (void **)&packed_rtp_buffer ); - rtp_packet_destroy( &rtp_packet ); - - FREENULL( "packed_rtp_payload", (void **)&packed_rtp_payload ); - FREENULL( "packed_journal", (void **)&packed_journal ); - - switch( message_type ) - { - case MIDI_NOTE_OFF: - case MIDI_NOTE_ON: - net_ctx_add_journal_note( current_ctx , midi_note ); - break; - case MIDI_CONTROL_CHANGE: - net_ctx_add_journal_control( current_ctx, midi_control ); - break; - case MIDI_PROGRAM_CHANGE: - net_ctx_add_journal_program( current_ctx, midi_program ); - break; - default: - continue; - } - } - - // Clean up - FREENULL( "packed_payload", (void **)&packed_payload ); - midi_payload_destroy( &single_midi_payload ); - switch( message_type ) - { - case MIDI_NOTE_OFF: - case MIDI_NOTE_ON: - midi_note_destroy( &midi_note ); - break; - case MIDI_CONTROL_CHANGE: - midi_control_destroy( &midi_control ); - break; - case MIDI_PROGRAM_CHANGE: - midi_program_destroy( &midi_program ); - break; - default: - break; - } - - midi_command_reset( &(midi_commands[midi_command_index]) ); - } - - free( midi_commands ); - + net_distribute_midi( packet, recv_len ); } else { // RTP MIDI inbound from remote socket rtp_packet_t *rtp_packet = NULL; @@ -484,9 +336,9 @@ int net_socket_read( int fd ) if( response ) { size_t bytes_written = 0; - pthread_mutex_lock( &socket_mutex ); + net_socket_lock(); bytes_written = sendto( fd, response->buffer, response->len , 0 , (void *)&from_addr, from_len); - pthread_mutex_unlock( &socket_mutex ); + net_socket_unlock(); logging_printf( LOGGING_DEBUG, "net_socket_read: feedback write(bytes=%u,socket=%d,host=%s,port=%u)\n", bytes_written, fd,ip_address, from_port); net_response_destroy( &response ); } @@ -514,16 +366,16 @@ int net_socket_read( int fd ) if( inbound_midi_fd >= 0 ) { - pthread_mutex_lock( &socket_mutex ); + net_socket_lock(); bytes_written = write( inbound_midi_fd, raw_buffer, 1 + midi_commands[midi_command_index].data_len ); - pthread_mutex_unlock( &socket_mutex ); + net_socket_unlock(); logging_printf( LOGGING_DEBUG, "net_socket_read: inbound MIDI write(bytes=%u)\n", bytes_written ); } #ifdef HAVE_ALSA - pthread_mutex_lock( &socket_mutex ); + net_socket_lock(); raveloxmidi_alsa_write( raw_buffer, 1 + midi_commands[midi_command_index].data_len ); - pthread_mutex_unlock( &socket_mutex ); + net_socket_unlock(); #endif free( raw_buffer ); } diff --git a/raveloxmidi/src/remote_connection.c b/raveloxmidi/src/remote_connection.c index bc1f922..728afbb 100644 --- a/raveloxmidi/src/remote_connection.c +++ b/raveloxmidi/src/remote_connection.c @@ -142,8 +142,8 @@ void remote_connect_init( void ) } else { ctx = net_ctx_create(); ctx->ip_address = ( char * ) strdup( found_service->ip_address ); - ctx->data_port = found_service->port; - ctx->control_port = found_service->port + 1; + ctx->control_port = found_service->port; + ctx->data_port = found_service->port + 1; ctx->ssrc = inv->ssrc; ctx->initiator = inv->initiator; ctx->seq = 0x638E; @@ -154,7 +154,7 @@ void remote_connect_init( void ) { logging_printf( LOGGING_ERROR, "remote_connect_init: Unable to create socket context\n"); } else { - net_ctx_send( net_socket_get_data_socket() , ctx, response->buffer, response->len ); + net_ctx_send( net_socket_get_control_socket() , ctx, response->buffer, response->len ); } net_ctx_destroy( &ctx ); From 6b134d72ddfcc2ad9a273ac1c68dbfefe4081b6f Mon Sep 17 00:00:00 2001 From: Dave Kelly Date: Sun, 24 Mar 2019 14:10:32 -0700 Subject: [PATCH 21/33] Added .99 version number for experimental identification --- raveloxmidi/configure.ac | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/raveloxmidi/configure.ac b/raveloxmidi/configure.ac index 6141a60..504c5bf 100755 --- a/raveloxmidi/configure.ac +++ b/raveloxmidi/configure.ac @@ -3,7 +3,7 @@ AC_CANONICAL_HOST AC_CANONICAL_BUILD AC_CANONICAL_TARGET -AM_INIT_AUTOMAKE(raveloxmidi, 0.6.0) +AM_INIT_AUTOMAKE(raveloxmidi, 0.6.99) AC_CONFIG_HEADERS([config.h]) AC_GNU_SOURCE From 9d09610d18ae3a5563c3ac81ef53baee4ef56dc6 Mon Sep 17 00:00:00 2001 From: Dave Kelly Date: Sun, 31 Mar 2019 09:27:32 -0700 Subject: [PATCH 22/33] More changes for remote connections --- raveloxmidi/include/net_applemidi.h | 1 + raveloxmidi/include/net_connection.h | 5 +- raveloxmidi/src/applemidi_ok.c | 8 +-- raveloxmidi/src/net_applemidi.c | 11 ++- raveloxmidi/src/net_connection.c | 12 ++-- raveloxmidi/src/net_distribute.c | 2 +- raveloxmidi/src/raveloxmidi.c | 10 +-- raveloxmidi/src/raveloxmidi_config.c | 2 +- raveloxmidi/src/remote_connection.c | 100 ++++++++++++++++++++++----- 9 files changed, 114 insertions(+), 37 deletions(-) diff --git a/raveloxmidi/include/net_applemidi.h b/raveloxmidi/include/net_applemidi.h index f975b12..8c48598 100644 --- a/raveloxmidi/include/net_applemidi.h +++ b/raveloxmidi/include/net_applemidi.h @@ -80,6 +80,7 @@ typedef struct net_applemidi_bitrate { void net_applemidi_command_dump( net_applemidi_command *command); net_applemidi_inv * net_applemidi_inv_create( void ); net_applemidi_sync * net_applemidi_sync_create( void ); +void net_applemidi_sync_destroy( net_applemidi_sync ** ); net_applemidi_feedback * net_applemidi_feedback_create( void ); int net_applemidi_cmd_destroy( net_applemidi_command **command ); int net_applemidi_unpack( net_applemidi_command **command_buffer, unsigned char *in_buffer, size_t in_buffer_len); diff --git a/raveloxmidi/include/net_connection.h b/raveloxmidi/include/net_connection.h index 3d0a000..ee59428 100644 --- a/raveloxmidi/include/net_connection.h +++ b/raveloxmidi/include/net_connection.h @@ -29,6 +29,9 @@ // Maximum number of connection entries in the connection table #define MAX_CTX 8 +#define USE_DATA_PORT 0 +#define USE_CONTROL_PORT 1 + typedef struct net_ctx_t { uint32_t ssrc; uint32_t send_ssrc; @@ -63,7 +66,7 @@ void net_ctx_journal_dump( net_ctx_t *ctx); void net_ctx_journal_pack( net_ctx_t *ctx, char **journal_buffer, size_t *journal_buffer_size); void net_ctx_journal_reset( net_ctx_t *ctx ); void net_ctx_update_rtp_fields( net_ctx_t *ctx, rtp_packet_t *rtp_packet); -void net_ctx_send( int socket, net_ctx_t *ctx, unsigned char *buffer, size_t buffer_len ); +void net_ctx_send( int socket, net_ctx_t *ctx, unsigned char *buffer, size_t buffer_len , int use_control ); void net_ctx_increment_seq( net_ctx_t *ctx ); void net_ctx_iter_start_head(void); diff --git a/raveloxmidi/src/applemidi_ok.c b/raveloxmidi/src/applemidi_ok.c index 4c21349..f963070 100644 --- a/raveloxmidi/src/applemidi_ok.c +++ b/raveloxmidi/src/applemidi_ok.c @@ -61,14 +61,14 @@ net_response_t * applemidi_ok_responder( char *ip_address, uint16_t port, void * if( ! ctx ) { logging_printf( LOGGING_DEBUG, "applemidi_ok_responder: Registering new connection\n"); - ctx = net_ctx_register( inv->ssrc, inv->initiator, ip_address, port , inv->name); - - /* Set the data port */ - ctx->data_port = port + 1; + ctx = net_ctx_register( inv->ssrc, inv->initiator, ip_address, port, inv->name); if( ! ctx ) { logging_printf( LOGGING_ERROR, "applemidi_okresponder: Error registering connection\n"); + } else { + ctx->data_port = port; + ctx->send_ssrc = inv->initiator; } /* Set the remote connect flag if the ssrc is the same one we used */ diff --git a/raveloxmidi/src/net_applemidi.c b/raveloxmidi/src/net_applemidi.c index f677216..401c9db 100644 --- a/raveloxmidi/src/net_applemidi.c +++ b/raveloxmidi/src/net_applemidi.c @@ -158,6 +158,15 @@ net_applemidi_sync * net_applemidi_sync_create( void ) return sync; } +void net_applemidi_sync_destroy( net_applemidi_sync **sync ) +{ + if( ! sync ) return; + if( ! *sync ) return; + + free( *sync ); + *sync = NULL; +} + net_applemidi_feedback * net_applemidi_feedback_create( void ) { net_applemidi_feedback *feedback = NULL; @@ -516,7 +525,7 @@ int net_applemidi_pack( net_applemidi_command *command_buffer, unsigned char **o net_applemidi_command * net_applemidi_cmd_create( uint16_t command ) { - net_applemidi_command *new_command; + net_applemidi_command *new_command = NULL; new_command = ( net_applemidi_command *) malloc( sizeof( net_applemidi_command ) ); if( new_command ) diff --git a/raveloxmidi/src/net_connection.c b/raveloxmidi/src/net_connection.c index 98de3ae..2eccbc2 100644 --- a/raveloxmidi/src/net_connection.c +++ b/raveloxmidi/src/net_connection.c @@ -207,6 +207,7 @@ net_ctx_t * net_ctx_register( uint32_t ssrc, uint32_t initiator, char *ip_addres net_ctx_t *new_ctx = NULL; uint32_t send_ssrc = 0; + logging_printf( LOGGING_DEBUG, "net_ctx_register: ssrc=0x%08x initiator=0x%08x ip_address=[%s] port=%u name=[%s]\n", ssrc, initiator, ip_address, port, name ); /* Check to see if the ssrc already exists */ new_ctx = net_ctx_find_by_ssrc( ssrc ); if( ! new_ctx ) @@ -310,11 +311,12 @@ void net_ctx_increment_seq( net_ctx_t *ctx ) ctx->seq += 1; } -void net_ctx_send( int send_socket, net_ctx_t *ctx, unsigned char *buffer, size_t buffer_len ) +void net_ctx_send( int send_socket, net_ctx_t *ctx, unsigned char *buffer, size_t buffer_len , int use_control) { struct sockaddr_in6 send_address; ssize_t bytes_sent = 0; socklen_t addr_len = 0; + int port_number = 0; if( ! buffer ) return; if( buffer_len <= 0 ) return; @@ -325,16 +327,16 @@ void net_ctx_send( int send_socket, net_ctx_t *ctx, unsigned char *buffer, size_ /* Set up the destination address */ memset((char *)&send_address, 0, sizeof( send_address)); - get_sock_addr( ctx->ip_address, ctx->data_port, (struct sockaddr *)&send_address, &addr_len); + port_number = ( use_control == USE_CONTROL_PORT ? ctx->control_port : ctx->data_port ); + get_sock_addr( ctx->ip_address, port_number, (struct sockaddr *)&send_address, &addr_len); - logging_printf(LOGGING_DEBUG, "net_ctx_send: send_address size=%d\n", sizeof( send_address ) ); bytes_sent = sendto( send_socket, buffer, buffer_len , 0 , (struct sockaddr *)&send_address, addr_len); if( bytes_sent < 0 ) { - logging_printf( LOGGING_ERROR, "net_ctx_send: Failed to send %u bytes to [%s]:%u\t%s\n", buffer_len, ctx->ip_address, ctx->data_port, strerror( errno )); + logging_printf( LOGGING_ERROR, "net_ctx_send: Failed to send %u bytes to [%s]:%u\t%s\n", buffer_len, ctx->ip_address, port_number, strerror( errno )); } else { - logging_printf( LOGGING_DEBUG, "net_ctx_send: write( bytes=%u,host=%s,port=%u)\n", bytes_sent, ctx->ip_address, ctx->data_port ); + logging_printf( LOGGING_DEBUG, "net_ctx_send: write( bytes=%u,host=[%s]:%u, use_control=%d)\n", bytes_sent, ctx->ip_address, port_number , use_control ); } } diff --git a/raveloxmidi/src/net_distribute.c b/raveloxmidi/src/net_distribute.c index bba061d..d1fe4f3 100644 --- a/raveloxmidi/src/net_distribute.c +++ b/raveloxmidi/src/net_distribute.c @@ -175,7 +175,7 @@ void net_distribute_midi( char *packet, size_t recv_len ) rtp_packet_pack( rtp_packet, &packed_rtp_buffer, &packed_rtp_buffer_len ); net_socket_lock(); - net_ctx_send( net_socket_get_data_socket(), current_ctx, packed_rtp_buffer, packed_rtp_buffer_len ); + net_ctx_send( net_socket_get_data_socket(), current_ctx, packed_rtp_buffer, packed_rtp_buffer_len , USE_DATA_PORT ); net_socket_unlock(); FREENULL( "packed_rtp_buffer", (void **)&packed_rtp_buffer ); diff --git a/raveloxmidi/src/raveloxmidi.c b/raveloxmidi/src/raveloxmidi.c index 0970746..7f50739 100644 --- a/raveloxmidi/src/raveloxmidi.c +++ b/raveloxmidi/src/raveloxmidi.c @@ -93,11 +93,6 @@ int main(int argc, char *argv[]) net_ctx_init(); - if( config_string_get("remote.connect") ) - { - remote_connect_init(); - } - signal( SIGINT , net_socket_loop_shutdown); signal( SIGTERM , net_socket_loop_shutdown); signal( SIGUSR2 , net_socket_loop_shutdown); @@ -112,6 +107,11 @@ int main(int argc, char *argv[]) { logging_printf(LOGGING_ERROR, "Unable to create publish thread\n"); } else { + if( config_string_get("remote.connect") ) + { + remote_connect_init(); + } + net_socket_loop_init(); #ifdef HAVE_ALSA net_socket_alsa_loop(); diff --git a/raveloxmidi/src/raveloxmidi_config.c b/raveloxmidi/src/raveloxmidi_config.c index 2be5dc6..9ec96f8 100644 --- a/raveloxmidi/src/raveloxmidi_config.c +++ b/raveloxmidi/src/raveloxmidi_config.c @@ -53,7 +53,7 @@ static void config_set_defaults( void ) config_add_item("inbound_midi","/dev/sequencer"); config_add_item("file_mode", "0640"); config_add_item("client.name", "raveloxremote"); - config_add_item("discover.timeout","10"); + config_add_item("discover.timeout","5"); #ifdef HAVE_ALSA config_add_item("alsa.input_buffer_size", "4096" ); #endif diff --git a/raveloxmidi/src/remote_connection.c b/raveloxmidi/src/remote_connection.c index 728afbb..4b0430d 100644 --- a/raveloxmidi/src/remote_connection.c +++ b/raveloxmidi/src/remote_connection.c @@ -96,6 +96,7 @@ void remote_connect_init( void ) return; } + logging_printf( LOGGING_DEBUG, "remote_connect_init: Found [%s] [%s:%d]\n", found_service->name, found_service->ip_address, found_service->port); remote_connect_ssrc = random_number(); remote_initiator = random_number(); @@ -141,20 +142,23 @@ void remote_connect_init( void ) logging_printf( LOGGING_ERROR, "remote_connect_init: Unable to pack response to inv command\n"); } else { ctx = net_ctx_create(); - ctx->ip_address = ( char * ) strdup( found_service->ip_address ); - ctx->control_port = found_service->port; - ctx->data_port = found_service->port + 1; - ctx->ssrc = inv->ssrc; - ctx->initiator = inv->initiator; - ctx->seq = 0x638E; - - logging_printf( LOGGING_DEBUG, "remote_connect_init: Creating connection context for %s:%u\n", ctx->ip_address, ctx->data_port ); if( ! ctx ) { logging_printf( LOGGING_ERROR, "remote_connect_init: Unable to create socket context\n"); } else { - net_ctx_send( net_socket_get_control_socket() , ctx, response->buffer, response->len ); + ctx->ip_address = ( char * ) strdup( found_service->ip_address ); + ctx->control_port = found_service->port; + ctx->data_port = found_service->port+1; + ctx->ssrc = inv->ssrc; + ctx->send_ssrc = inv->ssrc; + ctx->initiator = inv->initiator; + ctx->seq = 0x638E; + + logging_printf( LOGGING_DEBUG, "remote_connect_init: Creating connection context for %s data=%u control=%u\n", ctx->ip_address, ctx->data_port, ctx->control_port ); + net_ctx_send( net_socket_get_control_socket() , ctx, response->buffer, response->len , USE_CONTROL_PORT ); + ctx->seq++; + net_ctx_send( net_socket_get_data_socket() , ctx, response->buffer, response->len , USE_DATA_PORT ); } net_ctx_destroy( &ctx ); @@ -166,14 +170,7 @@ void remote_connect_init( void ) remote_connect_fail: net_response_destroy( &response ); net_applemidi_cmd_destroy( &cmd ); -} - -void remote_connect_ok( char *remote_name ) -{ - if( net_ctx_find_by_name( remote_name ) ) - { - remote_connected = 1; - } + net_applemidi_inv_destroy( &inv ); } void remote_connect_teardown( void ) @@ -201,7 +198,7 @@ void remote_connect_teardown( void ) by->ssrc = remote_connect_ssrc; by->version = 2; - by->initiator = 0; + by->initiator = remote_connect_ssrc; client_name = NULL; cmd = net_applemidi_cmd_create( NET_APPLEMIDI_CMD_END ); @@ -231,7 +228,7 @@ void remote_connect_teardown( void ) { logging_printf( LOGGING_ERROR, "remote_connect_teardown: Unable to find connection for [%s]\n", remote_service_name); } else { - net_ctx_send( net_socket_get_data_socket() , ctx, response->buffer, response->len ); + net_ctx_send( net_socket_get_control_socket() , ctx, response->buffer, response->len , USE_CONTROL_PORT); hex_dump( response->buffer, response->len ); } } @@ -244,3 +241,68 @@ void remote_connect_teardown( void ) net_applemidi_cmd_destroy( &cmd ); net_applemidi_inv_destroy( &by ); } + +void remote_connect_ok( char *remote_name ) +{ + net_applemidi_sync *sync_packet = NULL; + net_response_t *response = NULL; + net_applemidi_command *cmd = NULL; + net_ctx_t *ctx; + + if( ! remote_name ) return; + + ctx = net_ctx_find_by_name( remote_name ); + + if( ! ctx ) + { + logging_printf( LOGGING_DEBUG, "remote_connect_ok: No context found for [%s]\n", remote_name ); + return; + } + + remote_connected = 1; + logging_printf(LOGGING_DEBUG, "remote_connect_ok: Connection found for [%s]\n", remote_name); + + // Build the SYNC packet + sync_packet = net_applemidi_sync_create(); + + if( ! sync_packet ) + { + logging_printf( LOGGING_ERROR, "remote_connect_ok: Unable to allocate memory for sync_packet packet\n"); + return; + } + + sync_packet->ssrc = ctx->send_ssrc; + sync_packet->count = 0; + sync_packet->timestamp1 = time(0); + + cmd = net_applemidi_cmd_create( NET_APPLEMIDI_CMD_SYNC ); + + if( ! cmd ) + { + logging_printf( LOGGING_ERROR, "remote_connect_ok: Unable to create AppleMIDI command\n"); + goto remote_ok_fail; + } + + cmd->data = sync_packet; + + response = net_response_create(); + + if( response ) + { + int ret = 0; + ret = net_applemidi_pack( cmd , &(response->buffer), &(response->len) ); + if( ret != 0 ) + { + logging_printf( LOGGING_ERROR, "remote_connect_ok: Unable to pack response to sync_packet command\n"); + } else { + net_ctx_send( net_socket_get_control_socket() , ctx, response->buffer, response->len , USE_CONTROL_PORT ); + } + } else { + logging_printf( LOGGING_ERROR, "remote_connect_ok: Unable to create response packet\n"); + } + +remote_ok_fail: + net_response_destroy( &response ); + net_applemidi_cmd_destroy( &cmd ); + net_applemidi_sync_destroy( &sync_packet ); +} From c0d75186e765f6b53e4a21a04338be5460a518b6 Mon Sep 17 00:00:00 2001 From: Dave Kelly Date: Sun, 31 Mar 2019 09:38:33 -0700 Subject: [PATCH 23/33] Fixed some compiler warnings --- raveloxmidi/include/net_distribute.h | 2 +- raveloxmidi/src/net_connection.c | 2 +- raveloxmidi/src/net_distribute.c | 4 ++-- raveloxmidi/src/remote_connection.c | 2 -- 4 files changed, 4 insertions(+), 6 deletions(-) diff --git a/raveloxmidi/include/net_distribute.h b/raveloxmidi/include/net_distribute.h index fb47541..2840245 100644 --- a/raveloxmidi/include/net_distribute.h +++ b/raveloxmidi/include/net_distribute.h @@ -21,6 +21,6 @@ #ifndef _NET_DISTRIBUTE_H #define _NET_DISTRIBUTE_H -void net_distribute_midi( char *packet, size_t recv_len ); +void net_distribute_midi( unsigned char *packet, size_t recv_len ); #endif diff --git a/raveloxmidi/src/net_connection.c b/raveloxmidi/src/net_connection.c index 2eccbc2..b25e778 100644 --- a/raveloxmidi/src/net_connection.c +++ b/raveloxmidi/src/net_connection.c @@ -232,7 +232,7 @@ net_ctx_t * net_ctx_register( uint32_t ssrc, uint32_t initiator, char *ip_addres net_ctx_set( new_ctx, ssrc, initiator, send_ssrc, 0x638F, port, ip_address , name); new_ctx->prev = last_ctx; - if( last_ctx ) last_ctx->next = new_ctx, name; + if( last_ctx ) last_ctx->next = new_ctx; for( net_ctx_iter_start_head(); net_ctx_iter_has_next(); net_ctx_iter_next() ) { diff --git a/raveloxmidi/src/net_distribute.c b/raveloxmidi/src/net_distribute.c index d1fe4f3..d360e6c 100644 --- a/raveloxmidi/src/net_distribute.c +++ b/raveloxmidi/src/net_distribute.c @@ -63,7 +63,7 @@ extern int errno; #include "raveloxmidi_alsa.h" /* Send MIDI commands to all connections */ -void net_distribute_midi( char *packet, size_t recv_len ) +void net_distribute_midi( unsigned char *packet, size_t recv_len ) { rtp_packet_t *rtp_packet = NULL; unsigned char *packed_rtp_buffer = NULL; @@ -100,7 +100,7 @@ void net_distribute_midi( char *packet, size_t recv_len ) midi_payload_t *single_midi_payload = NULL; unsigned char *packed_payload = NULL; size_t packed_payload_len = 0; - int ret = 0; + int ret; /* Extract a single command as a midi payload */ midi_command_to_payload( &(midi_commands[ midi_command_index ]), &single_midi_payload ); diff --git a/raveloxmidi/src/remote_connection.c b/raveloxmidi/src/remote_connection.c index 4b0430d..a39ec94 100644 --- a/raveloxmidi/src/remote_connection.c +++ b/raveloxmidi/src/remote_connection.c @@ -179,7 +179,6 @@ void remote_connect_teardown( void ) net_response_t *response = NULL; net_applemidi_command *cmd = NULL; char *remote_service_name = NULL; - char *client_name = NULL; net_ctx_t *ctx; if( ! remote_connected ) return; @@ -199,7 +198,6 @@ void remote_connect_teardown( void ) by->ssrc = remote_connect_ssrc; by->version = 2; by->initiator = remote_connect_ssrc; - client_name = NULL; cmd = net_applemidi_cmd_create( NET_APPLEMIDI_CMD_END ); From b4cc232fc3f2a86e7202f4b7da3a55d13630e747 Mon Sep 17 00:00:00 2001 From: Dave Kelly Date: Mon, 1 Apr 2019 20:46:53 -0700 Subject: [PATCH 24/33] General memory corruption fixes --- raveloxmidi/configure.ac | 2 +- raveloxmidi/include/net_socket.h | 1 - raveloxmidi/src/applemidi_ok.c | 15 +++--- raveloxmidi/src/dns_service_discover.c | 4 +- raveloxmidi/src/logging.c | 2 +- raveloxmidi/src/net_applemidi.c | 66 ++++++++++++-------------- raveloxmidi/src/net_connection.c | 14 ++++-- raveloxmidi/src/net_distribute.c | 4 -- raveloxmidi/src/net_socket.c | 2 +- raveloxmidi/src/raveloxmidi.c | 3 ++ raveloxmidi/src/remote_connection.c | 10 ++-- raveloxmidi/src/utils.c | 7 +-- 12 files changed, 65 insertions(+), 65 deletions(-) diff --git a/raveloxmidi/configure.ac b/raveloxmidi/configure.ac index 504c5bf..2052940 100755 --- a/raveloxmidi/configure.ac +++ b/raveloxmidi/configure.ac @@ -12,7 +12,6 @@ AC_PROG_INSTALL AC_SYS_LARGEFILE - PKG_PROG_PKG_CONFIG PKG_CHECK_MODULES(AVAHI, avahi-client ) @@ -38,4 +37,5 @@ then AC_SUBST(DEB_ARCH) AC_OUTPUT( DEBIAN/control pkgscripts/build_deb ) fi + AC_OUTPUT(Makefile src/Makefile man/Makefile man/raveloxmidi.1 raveloxmidi.spec) diff --git a/raveloxmidi/include/net_socket.h b/raveloxmidi/include/net_socket.h index 1c0c0f4..32e6ce0 100644 --- a/raveloxmidi/include/net_socket.h +++ b/raveloxmidi/include/net_socket.h @@ -43,7 +43,6 @@ int net_socket_get_data_socket( void ); int net_socket_get_control_socket( void ); void net_socket_set_fds( void ); -extern uint8_t _max_ctx; /* Indicate which socket should be the data port */ #define DATA_PORT 1 diff --git a/raveloxmidi/src/applemidi_ok.c b/raveloxmidi/src/applemidi_ok.c index f963070..b30bd22 100644 --- a/raveloxmidi/src/applemidi_ok.c +++ b/raveloxmidi/src/applemidi_ok.c @@ -47,32 +47,31 @@ extern int errno; net_response_t * applemidi_ok_responder( char *ip_address, uint16_t port, void *data ) { - net_applemidi_inv *inv = NULL; + net_applemidi_inv *ok_packet = NULL; net_ctx_t *ctx = NULL; if( ! data ) return NULL; - inv = ( net_applemidi_inv *) data; - logging_printf( LOGGING_DEBUG, "applemidi_ok_responder: ssrc=0x%08x version=%u initiator=0x%08x name=%s\n", inv->ssrc, inv->version, inv->initiator, inv->name); + ok_packet = ( net_applemidi_inv *) data; + logging_printf( LOGGING_DEBUG, "applemidi_ok_responder: address=[%s]:%u ssrc=0x%08x version=%u initiator=0x%08x name=%s\n", ip_address, port, ok_packet->ssrc, ok_packet->version, ok_packet->initiator, ok_packet->name); - ctx = net_ctx_find_by_ssrc( inv->ssrc ); + ctx = net_ctx_find_by_ssrc( ok_packet->ssrc ); /* If no context is found, this is a new connection */ /* We assume that the current port is the control port */ if( ! ctx ) { - logging_printf( LOGGING_DEBUG, "applemidi_ok_responder: Registering new connection\n"); - ctx = net_ctx_register( inv->ssrc, inv->initiator, ip_address, port, inv->name); + ctx = net_ctx_register( ok_packet->ssrc, ok_packet->initiator, ip_address, port, ok_packet->name); if( ! ctx ) { logging_printf( LOGGING_ERROR, "applemidi_okresponder: Error registering connection\n"); } else { ctx->data_port = port; - ctx->send_ssrc = inv->initiator; + ctx->send_ssrc = ok_packet->initiator; } /* Set the remote connect flag if the ssrc is the same one we used */ - remote_connect_ok( inv->name ); + remote_connect_ok( ok_packet->name ); /* Otherwise, we assume that the current port is the data port */ } else { diff --git a/raveloxmidi/src/dns_service_discover.c b/raveloxmidi/src/dns_service_discover.c index 095df0d..3d563ee 100644 --- a/raveloxmidi/src/dns_service_discover.c +++ b/raveloxmidi/src/dns_service_discover.c @@ -230,10 +230,13 @@ void dns_discover_free_services( void ) if( num_services <= 0 ) return; for(int i = 0; i < num_services; i++) { + if( services[i]->name ) free( services[i]->name ); + if( services[i]->ip_address) free( services[i]->ip_address); FREENULL( "dns_service_t", (void **)&(services[i]) ); } free(services); services = NULL; + num_services = 0; } void dns_discover_init( void ) @@ -246,7 +249,6 @@ void dns_discover_init( void ) void dns_discover_teardown( void ) { dns_discover_free_services(); - num_services = 0; pthread_mutex_destroy( &discover_mutex ); } diff --git a/raveloxmidi/src/logging.c b/raveloxmidi/src/logging.c index c284e06..5200ae9 100644 --- a/raveloxmidi/src/logging.c +++ b/raveloxmidi/src/logging.c @@ -140,7 +140,7 @@ void logging_printf(int level, const char *format, ...) if( ! prefix_disabled ) { - fprintf( logging_fp , "[%lu]\t%s: ", time( NULL ) , logging_value_to_name( loglevel_map, level ) ); + fprintf( logging_fp , "[%lu]\t[tid=%lu]\t%s: ", time( NULL ) , pthread_self(), logging_value_to_name( loglevel_map, level ) ); } va_start(ap, format); diff --git a/raveloxmidi/src/net_applemidi.c b/raveloxmidi/src/net_applemidi.c index 401c9db..06d36d3 100644 --- a/raveloxmidi/src/net_applemidi.c +++ b/raveloxmidi/src/net_applemidi.c @@ -175,8 +175,7 @@ net_applemidi_feedback * net_applemidi_feedback_create( void ) if( feedback ) { - memset( feedback , 0, sizeof( net_applemidi_feedback ) ); - } + memset( feedback , 0, sizeof( net_applemidi_feedback ) ); } return feedback; } @@ -188,50 +187,41 @@ int net_applemidi_cmd_destroy( net_applemidi_command **command ) return NET_APPLEMIDI_DONE; } - if( (*command)->command == NET_APPLEMIDI_CMD_INV || - (*command)->command == NET_APPLEMIDI_CMD_ACCEPT || - (*command)->command == NET_APPLEMIDI_CMD_REJECT || - (*command)->command == NET_APPLEMIDI_CMD_END - ) + switch( (*command)->command ) { - if( (*command)->data ) - { - net_applemidi_inv *inv; - inv = (net_applemidi_inv *)(*command)->data; - if( inv->name ) + case NET_APPLEMIDI_CMD_INV: + case NET_APPLEMIDI_CMD_ACCEPT: + case NET_APPLEMIDI_CMD_REJECT: + case NET_APPLEMIDI_CMD_END: + if( (*command)->data ) { - free(inv->name); - inv->name = NULL; + net_applemidi_inv *inv = (net_applemidi_inv *)(*command)->data; + if( inv->name ) + { + free( inv->name ); + inv->name = NULL; + } } - free( (*command)->data ); - (*command)->data = NULL; - } - free( *command ); - *command = NULL; - return NET_APPLEMIDI_DONE; + break; + default: + break; } - if( (*command)->command == NET_APPLEMIDI_CMD_SYNC || - (*command)->command == NET_APPLEMIDI_CMD_FEEDBACK || - (*command)->command == NET_APPLEMIDI_CMD_BITRATE ) + if( (*command)->data ) { - if( (*command)->data ) - { - free( (*command)->data ); - (*command)->data = NULL; - } - free( *command ); - *command = NULL; - return NET_APPLEMIDI_DONE; + free( (*command)->data ); + (*command)->data = NULL; } + free( *command ); + *command = NULL; return NET_APPLEMIDI_DONE; } -int net_applemidi_unpack( net_applemidi_command **command_buffer, unsigned char *in_buffer, size_t in_buffer_len) +int net_applemidi_unpack( net_applemidi_command **command_buffer, unsigned char *in_buffer, size_t buffer_len) { - - unsigned char *p; + unsigned char *p = NULL; + size_t in_buffer_len = 0; if( ! in_buffer ) { @@ -239,6 +229,8 @@ int net_applemidi_unpack( net_applemidi_command **command_buffer, unsigned char return NET_APPLEMIDI_NEED_DATA; } + in_buffer_len = buffer_len; + if( in_buffer_len < NET_APPLEMIDI_COMMAND_SIZE ) { *command_buffer = NULL; @@ -285,7 +277,11 @@ int net_applemidi_unpack( net_applemidi_command **command_buffer, unsigned char if( in_buffer_len > 0 ) { - inv->name = strndup( (const char *)p, in_buffer_len ); + if( p ) + { + inv->name = ( char * )strdup( (const char *)p ); + in_buffer_len = 0; + } } else { inv->name = NULL; } diff --git a/raveloxmidi/src/net_connection.c b/raveloxmidi/src/net_connection.c index b25e778..f76abae 100644 --- a/raveloxmidi/src/net_connection.c +++ b/raveloxmidi/src/net_connection.c @@ -35,6 +35,7 @@ extern int errno; #include "midi_journal.h" #include "net_connection.h" +#include "net_socket.h" #include "rtp_packet.h" #include "utils.h" @@ -165,12 +166,14 @@ net_ctx_t * net_ctx_find_by_ssrc( uint32_t ssrc) { net_ctx_t *current_ctx = _ctx_head; - while( current_ctx ) + logging_printf( LOGGING_DEBUG, "net_ctx_find_by_ssrc: ssrc=0x%08x\n", ssrc ); + for( net_ctx_iter_start_head() ; net_ctx_iter_has_current(); net_ctx_iter_next()) { + current_ctx = net_ctx_iter_current(); if( current_ctx->ssrc == ssrc ) break; - current_ctx = current_ctx->next; } + logging_printf( LOGGING_DEBUG, "net_ctx_find_by_ssrc: ctx=%p\n", current_ctx ); return current_ctx; } @@ -208,8 +211,10 @@ net_ctx_t * net_ctx_register( uint32_t ssrc, uint32_t initiator, char *ip_addres uint32_t send_ssrc = 0; logging_printf( LOGGING_DEBUG, "net_ctx_register: ssrc=0x%08x initiator=0x%08x ip_address=[%s] port=%u name=[%s]\n", ssrc, initiator, ip_address, port, name ); + /* Check to see if the ssrc already exists */ new_ctx = net_ctx_find_by_ssrc( ssrc ); + if( ! new_ctx ) { new_ctx = net_ctx_create(); @@ -223,11 +228,10 @@ net_ctx_t * net_ctx_register( uint32_t ssrc, uint32_t initiator, char *ip_addres return NULL; } - last_ctx = net_ctx_get_last(); if( ! _ctx_head ) _ctx_head = new_ctx; - send_ssrc = random_number(); + send_ssrc = 0x4157; net_ctx_set( new_ctx, ssrc, initiator, send_ssrc, 0x638F, port, ip_address , name); new_ctx->prev = last_ctx; @@ -330,7 +334,9 @@ void net_ctx_send( int send_socket, net_ctx_t *ctx, unsigned char *buffer, size_ port_number = ( use_control == USE_CONTROL_PORT ? ctx->control_port : ctx->data_port ); get_sock_addr( ctx->ip_address, port_number, (struct sockaddr *)&send_address, &addr_len); + net_socket_lock(); bytes_sent = sendto( send_socket, buffer, buffer_len , 0 , (struct sockaddr *)&send_address, addr_len); + net_socket_unlock(); if( bytes_sent < 0 ) { diff --git a/raveloxmidi/src/net_distribute.c b/raveloxmidi/src/net_distribute.c index d360e6c..dfe18f0 100644 --- a/raveloxmidi/src/net_distribute.c +++ b/raveloxmidi/src/net_distribute.c @@ -136,9 +136,7 @@ void net_distribute_midi( unsigned char *packet, size_t recv_len ) if(! current_ctx ) continue; // Get a journal if there is one - net_socket_lock(); net_ctx_journal_pack( current_ctx , &packed_journal, &packed_journal_len); - net_socket_unlock(); if( packed_journal_len > 0 ) { @@ -174,9 +172,7 @@ void net_distribute_midi( unsigned char *packet, size_t recv_len ) // Pack the RTP data rtp_packet_pack( rtp_packet, &packed_rtp_buffer, &packed_rtp_buffer_len ); - net_socket_lock(); net_ctx_send( net_socket_get_data_socket(), current_ctx, packed_rtp_buffer, packed_rtp_buffer_len , USE_DATA_PORT ); - net_socket_unlock(); FREENULL( "packed_rtp_buffer", (void **)&packed_rtp_buffer ); rtp_packet_destroy( &rtp_packet ); diff --git a/raveloxmidi/src/net_socket.c b/raveloxmidi/src/net_socket.c index 04706e7..9097f52 100644 --- a/raveloxmidi/src/net_socket.c +++ b/raveloxmidi/src/net_socket.c @@ -254,7 +254,7 @@ int net_socket_read( int fd ) response = applemidi_inv_responder( ip_address, from_port, command->data ); break; case NET_APPLEMIDI_CMD_ACCEPT: - applemidi_ok_responder( ip_address, from_port, command->data ); + response = applemidi_ok_responder( ip_address, from_port, command->data ); break; case NET_APPLEMIDI_CMD_REJECT: logging_printf( LOGGING_ERROR, "net_socket_read: Connection rejected host=%s, port=%u\n", ip_address, from_port); diff --git a/raveloxmidi/src/raveloxmidi.c b/raveloxmidi/src/raveloxmidi.c index 7f50739..febf5e1 100644 --- a/raveloxmidi/src/raveloxmidi.c +++ b/raveloxmidi/src/raveloxmidi.c @@ -112,6 +112,8 @@ int main(int argc, char *argv[]) remote_connect_init(); } + dns_discover_teardown(); + net_socket_loop_init(); #ifdef HAVE_ALSA net_socket_alsa_loop(); @@ -139,6 +141,7 @@ int main(int argc, char *argv[]) daemon_teardown(); } + config_teardown(); logging_teardown(); diff --git a/raveloxmidi/src/remote_connection.c b/raveloxmidi/src/remote_connection.c index a39ec94..0f29fa7 100644 --- a/raveloxmidi/src/remote_connection.c +++ b/raveloxmidi/src/remote_connection.c @@ -170,7 +170,6 @@ void remote_connect_init( void ) remote_connect_fail: net_response_destroy( &response ); net_applemidi_cmd_destroy( &cmd ); - net_applemidi_inv_destroy( &inv ); } void remote_connect_teardown( void ) @@ -237,7 +236,6 @@ void remote_connect_teardown( void ) remote_teardown_fail: net_response_destroy( &response ); net_applemidi_cmd_destroy( &cmd ); - net_applemidi_inv_destroy( &by ); } void remote_connect_ok( char *remote_name ) @@ -260,7 +258,8 @@ void remote_connect_ok( char *remote_name ) remote_connected = 1; logging_printf(LOGGING_DEBUG, "remote_connect_ok: Connection found for [%s]\n", remote_name); - // Build the SYNC packet +/* + Build the SYNC packet sync_packet = net_applemidi_sync_create(); if( ! sync_packet ) @@ -271,13 +270,13 @@ void remote_connect_ok( char *remote_name ) sync_packet->ssrc = ctx->send_ssrc; sync_packet->count = 0; - sync_packet->timestamp1 = time(0); cmd = net_applemidi_cmd_create( NET_APPLEMIDI_CMD_SYNC ); if( ! cmd ) { logging_printf( LOGGING_ERROR, "remote_connect_ok: Unable to create AppleMIDI command\n"); + net_applemidi_sync_destroy( &sync_packet ); goto remote_ok_fail; } @@ -298,9 +297,8 @@ void remote_connect_ok( char *remote_name ) } else { logging_printf( LOGGING_ERROR, "remote_connect_ok: Unable to create response packet\n"); } +*/ -remote_ok_fail: net_response_destroy( &response ); net_applemidi_cmd_destroy( &cmd ); - net_applemidi_sync_destroy( &sync_packet ); } diff --git a/raveloxmidi/src/utils.c b/raveloxmidi/src/utils.c index f9ee740..e538602 100644 --- a/raveloxmidi/src/utils.c +++ b/raveloxmidi/src/utils.c @@ -352,8 +352,9 @@ int get_addr_family(char *ip_address, int port) int random_number( void ) { - time_t now = 0; + static unsigned int seedp = 0; - now = time(NULL); - return rand_r( (unsigned int *)&now ); + seedp = time(NULL); + + return rand_r( &seedp ); } From adafcd0992d6b46602042a8d40ad0266c37890b3 Mon Sep 17 00:00:00 2001 From: Dave Kelly Date: Wed, 10 Apr 2019 15:37:26 -0700 Subject: [PATCH 25/33] More remote connection changes --- raveloxmidi/include/net_connection.h | 2 +- raveloxmidi/include/utils.h | 3 +- raveloxmidi/src/applemidi_inv.c | 5 ++- raveloxmidi/src/applemidi_ok.c | 4 +-- raveloxmidi/src/applemidi_sync.c | 9 ++++- raveloxmidi/src/dns_service_discover.c | 1 + raveloxmidi/src/net_connection.c | 32 +++++++++--------- raveloxmidi/src/net_distribute.c | 9 +++-- raveloxmidi/src/net_socket.c | 11 +++--- raveloxmidi/src/raveloxmidi_config.c | 1 - raveloxmidi/src/remote_connection.c | 39 +++++++++++---------- raveloxmidi/src/utils.c | 47 ++++++++------------------ 12 files changed, 75 insertions(+), 88 deletions(-) diff --git a/raveloxmidi/include/net_connection.h b/raveloxmidi/include/net_connection.h index ee59428..336d917 100644 --- a/raveloxmidi/include/net_connection.h +++ b/raveloxmidi/include/net_connection.h @@ -66,7 +66,7 @@ void net_ctx_journal_dump( net_ctx_t *ctx); void net_ctx_journal_pack( net_ctx_t *ctx, char **journal_buffer, size_t *journal_buffer_size); void net_ctx_journal_reset( net_ctx_t *ctx ); void net_ctx_update_rtp_fields( net_ctx_t *ctx, rtp_packet_t *rtp_packet); -void net_ctx_send( int socket, net_ctx_t *ctx, unsigned char *buffer, size_t buffer_len , int use_control ); +void net_ctx_send( net_ctx_t *ctx, unsigned char *buffer, size_t buffer_len , int use_control ); void net_ctx_increment_seq( net_ctx_t *ctx ); void net_ctx_iter_start_head(void); diff --git a/raveloxmidi/include/utils.h b/raveloxmidi/include/utils.h index a2e4768..3975826 100644 --- a/raveloxmidi/include/utils.h +++ b/raveloxmidi/include/utils.h @@ -38,8 +38,7 @@ int is_yes( const char *value ); int is_no( const char *value ); char *get_ip_string( struct sockaddr *sa, char *s, size_t maxlen ); -int get_sock_addr( char *ip_address, int port, struct sockaddr *socket, socklen_t *socklen); -int get_addr_family(char *ip_address, int port); +int get_sock_info( char *ip_address, int port, struct sockaddr *socket, socklen_t *socklen, int *family); int random_number( void ); diff --git a/raveloxmidi/src/applemidi_inv.c b/raveloxmidi/src/applemidi_inv.c index 969475d..46fae93 100644 --- a/raveloxmidi/src/applemidi_inv.c +++ b/raveloxmidi/src/applemidi_inv.c @@ -71,9 +71,8 @@ net_response_t * applemidi_inv_responder( char *ip_address, uint16_t port, void { logging_printf( LOGGING_ERROR, "applemidi_inv_responder: Error registering connection\n"); } - /* Otherwise, we assume that the current port is the data port */ - } else { - ctx->data_port = port; + //} else { + // ctx->data_port = port; } cmd = net_applemidi_cmd_create( NET_APPLEMIDI_CMD_ACCEPT ); diff --git a/raveloxmidi/src/applemidi_ok.c b/raveloxmidi/src/applemidi_ok.c index b30bd22..7adef4d 100644 --- a/raveloxmidi/src/applemidi_ok.c +++ b/raveloxmidi/src/applemidi_ok.c @@ -54,13 +54,13 @@ net_response_t * applemidi_ok_responder( char *ip_address, uint16_t port, void * ok_packet = ( net_applemidi_inv *) data; logging_printf( LOGGING_DEBUG, "applemidi_ok_responder: address=[%s]:%u ssrc=0x%08x version=%u initiator=0x%08x name=%s\n", ip_address, port, ok_packet->ssrc, ok_packet->version, ok_packet->initiator, ok_packet->name); - ctx = net_ctx_find_by_ssrc( ok_packet->ssrc ); + ctx = net_ctx_find_by_ssrc( ok_packet->initiator ); /* If no context is found, this is a new connection */ /* We assume that the current port is the control port */ if( ! ctx ) { - ctx = net_ctx_register( ok_packet->ssrc, ok_packet->initiator, ip_address, port, ok_packet->name); + ctx = net_ctx_register( ok_packet->initiator, ok_packet->initiator, ip_address, port, ok_packet->name); if( ! ctx ) { diff --git a/raveloxmidi/src/applemidi_sync.c b/raveloxmidi/src/applemidi_sync.c index 4fbd58a..f4e1f4f 100644 --- a/raveloxmidi/src/applemidi_sync.c +++ b/raveloxmidi/src/applemidi_sync.c @@ -52,13 +52,19 @@ net_response_t * applemidi_sync_responder( void *data ) net_response_t *response = NULL; uint32_t delta = 0; + logging_printf( LOGGING_DEBUG, "applemidi_sync_responder: start\n"); + if( ! data ) return NULL; sync = ( net_applemidi_sync *) data; ctx = net_ctx_find_by_ssrc( sync->ssrc); - if( ! ctx ) return NULL; + if( ! ctx ) + { + logging_printf( LOGGING_DEBUG, "applemidi_sync_responder: No context found for ssrc=%s\n", sync->ssrc ); + return NULL; + } cmd = net_applemidi_cmd_create( NET_APPLEMIDI_CMD_SYNC ); @@ -111,6 +117,7 @@ net_response_t * applemidi_sync_responder( void *data ) { logging_printf( LOGGING_ERROR, "applemidi_sync_responder: Unable to pack response to sync command\n"); net_response_destroy( &response ); + response = NULL; } } diff --git a/raveloxmidi/src/dns_service_discover.c b/raveloxmidi/src/dns_service_discover.c index 3d563ee..2486706 100644 --- a/raveloxmidi/src/dns_service_discover.c +++ b/raveloxmidi/src/dns_service_discover.c @@ -193,6 +193,7 @@ void dns_discover_add( const char *name, char *address, int port) if( ! name ) return; if( ! address ) return; + logging_printf( LOGGING_DEBUG, "dns_discover_add: name=\"%s\" address=[%s]:%d\n", name, address, port ); // Check for duplicates by name found_service = dns_discover_by_name( name ); if( found_service ) diff --git a/raveloxmidi/src/net_connection.c b/raveloxmidi/src/net_connection.c index f76abae..832803b 100644 --- a/raveloxmidi/src/net_connection.c +++ b/raveloxmidi/src/net_connection.c @@ -101,7 +101,8 @@ static void net_ctx_set( net_ctx_t *ctx, uint32_t ssrc, uint32_t initiator, uint ctx->send_ssrc = send_ssrc; ctx->initiator = initiator; ctx->seq = seq; - ctx->control_port = port; + ctx->data_port = port; + ctx->control_port = port + 1; ctx->start = time( NULL ); if( ctx->ip_address ) @@ -173,7 +174,7 @@ net_ctx_t * net_ctx_find_by_ssrc( uint32_t ssrc) if( current_ctx->ssrc == ssrc ) break; } - logging_printf( LOGGING_DEBUG, "net_ctx_find_by_ssrc: ctx=%p\n", current_ctx ); + logging_printf( LOGGING_DEBUG, "net_ctx_find_by_ssrc: found=%s\n", (current_ctx ? "yes" : "no")); return current_ctx; } @@ -231,7 +232,7 @@ net_ctx_t * net_ctx_register( uint32_t ssrc, uint32_t initiator, char *ip_addres last_ctx = net_ctx_get_last(); if( ! _ctx_head ) _ctx_head = new_ctx; - send_ssrc = 0x4157; + send_ssrc = initiator; net_ctx_set( new_ctx, ssrc, initiator, send_ssrc, 0x638F, port, ip_address , name); new_ctx->prev = last_ctx; @@ -315,12 +316,14 @@ void net_ctx_increment_seq( net_ctx_t *ctx ) ctx->seq += 1; } -void net_ctx_send( int send_socket, net_ctx_t *ctx, unsigned char *buffer, size_t buffer_len , int use_control) +void net_ctx_send( net_ctx_t *ctx, unsigned char *buffer, size_t buffer_len , int use_control) { - struct sockaddr_in6 send_address; + struct sockaddr_in6 send_address, socket_address; ssize_t bytes_sent = 0; - socklen_t addr_len = 0; + socklen_t addr_len = 0, socket_addr_len = 0; int port_number = 0; + int family = AF_UNSPEC; + int send_socket = 0; if( ! buffer ) return; if( buffer_len <= 0 ) return; @@ -331,8 +334,13 @@ void net_ctx_send( int send_socket, net_ctx_t *ctx, unsigned char *buffer, size_ /* Set up the destination address */ memset((char *)&send_address, 0, sizeof( send_address)); - port_number = ( use_control == USE_CONTROL_PORT ? ctx->control_port : ctx->data_port ); - get_sock_addr( ctx->ip_address, port_number, (struct sockaddr *)&send_address, &addr_len); + port_number = ( use_control == USE_CONTROL_PORT ? ctx->data_port : ctx->control_port ); + get_sock_info( ctx->ip_address, port_number, (struct sockaddr *)&send_address, &addr_len, &family); + + send_socket = ( use_control == USE_CONTROL_PORT ? net_socket_get_control_socket() : net_socket_get_data_socket() ); + socket_addr_len = sizeof( socket_address ); + getsockname(send_socket , (struct sockaddr *)&socket_address, &socket_addr_len); + logging_printf( LOGGING_DEBUG, "net_ctx_send: outbound socket=%d\n", ntohs( ((struct sockaddr_in *)&socket_address)->sin_port ) ); net_socket_lock(); bytes_sent = sendto( send_socket, buffer, buffer_len , 0 , (struct sockaddr *)&send_address, addr_len); @@ -349,45 +357,38 @@ void net_ctx_send( int send_socket, net_ctx_t *ctx, unsigned char *buffer, size_ void net_ctx_iter_start_head(void) { _iterator_current = _ctx_head; - logging_printf(LOGGING_DEBUG,"net_ctx_iter_start_head: current=%p\n", _iterator_current ); } void net_ctx_iter_start_tail(void) { _iterator_current = net_ctx_get_last(); - logging_printf(LOGGING_DEBUG,"net_ctx_iter_start_end: current=%p\n", _iterator_current ); } net_ctx_t *net_ctx_iter_current(void) { - logging_printf(LOGGING_DEBUG,"net_ctx_iter_current: current=%p\n", _iterator_current ); return _iterator_current; } int net_ctx_iter_has_current( void ) { - logging_printf(LOGGING_DEBUG,"net_ctx_iter_has_current: current=%p\n", _iterator_current ); return ( _iterator_current ? 1 : 0 ); } int net_ctx_iter_has_next(void) { - logging_printf(LOGGING_DEBUG,"net_ctx_iter_has_next: current=%p\n", _iterator_current ); if(! _iterator_current ) return 0; return (_iterator_current->next ? 1 : 0); } int net_ctx_iter_has_prev(void) { - logging_printf(LOGGING_DEBUG,"net_ctx_iter_has_prev: current=%p\n", _iterator_current ); if(! _iterator_current ) return 0; return (_iterator_current->prev ? 1 : 0); } void net_ctx_iter_next(void) { - logging_printf(LOGGING_DEBUG,"net_ctx_iter_next: current=%p\n", _iterator_current ); if(_iterator_current) { _iterator_current = _iterator_current->next; @@ -396,7 +397,6 @@ void net_ctx_iter_next(void) void net_ctx_iter_prev(void) { - logging_printf(LOGGING_DEBUG,"net_ctx_iter_prev: current=%p\n", _iterator_current ); if(_iterator_current) { _iterator_current = _iterator_current->prev; diff --git a/raveloxmidi/src/net_distribute.c b/raveloxmidi/src/net_distribute.c index dfe18f0..8f8a548 100644 --- a/raveloxmidi/src/net_distribute.c +++ b/raveloxmidi/src/net_distribute.c @@ -100,7 +100,6 @@ void net_distribute_midi( unsigned char *packet, size_t recv_len ) midi_payload_t *single_midi_payload = NULL; unsigned char *packed_payload = NULL; size_t packed_payload_len = 0; - int ret; /* Extract a single command as a midi payload */ midi_command_to_payload( &(midi_commands[ midi_command_index ]), &single_midi_payload ); @@ -112,15 +111,15 @@ void net_distribute_midi( unsigned char *packet, size_t recv_len ) { case MIDI_NOTE_OFF: case MIDI_NOTE_ON: - ret = midi_note_from_command( &(midi_commands[midi_command_index]), &midi_note); + midi_note_from_command( &(midi_commands[midi_command_index]), &midi_note); midi_note_dump( midi_note ); break; case MIDI_CONTROL_CHANGE: - ret = midi_control_from_command( &(midi_commands[midi_command_index]), &midi_control); + midi_control_from_command( &(midi_commands[midi_command_index]), &midi_control); midi_control_dump( midi_control ); break; case MIDI_PROGRAM_CHANGE: - ret = midi_program_from_command( &(midi_commands[midi_command_index]), &midi_program); + midi_program_from_command( &(midi_commands[midi_command_index]), &midi_program); midi_program_dump( midi_program ); break; default: @@ -172,7 +171,7 @@ void net_distribute_midi( unsigned char *packet, size_t recv_len ) // Pack the RTP data rtp_packet_pack( rtp_packet, &packed_rtp_buffer, &packed_rtp_buffer_len ); - net_ctx_send( net_socket_get_data_socket(), current_ctx, packed_rtp_buffer, packed_rtp_buffer_len , USE_DATA_PORT ); + net_ctx_send( current_ctx, packed_rtp_buffer, packed_rtp_buffer_len , USE_DATA_PORT ); FREENULL( "packed_rtp_buffer", (void **)&packed_rtp_buffer ); rtp_packet_destroy( &rtp_packet ); diff --git a/raveloxmidi/src/net_socket.c b/raveloxmidi/src/net_socket.c index 9097f52..434957d 100644 --- a/raveloxmidi/src/net_socket.c +++ b/raveloxmidi/src/net_socket.c @@ -150,7 +150,7 @@ int net_socket_listener_create( int family, char *ip_address, unsigned int port break; } - get_sock_addr( ip_address, port, (struct sockaddr *)&socket_address, &addr_len); + get_sock_info( ip_address, port, (struct sockaddr *)&socket_address, &addr_len, NULL); if ( bind(new_socket, (struct sockaddr *)&socket_address, addr_len) < 0 ) { @@ -209,7 +209,6 @@ int net_socket_read( int fd ) } else { #endif recv_len = recvfrom( fd, packet, NET_APPLEMIDI_UDPSIZE, 0, (struct sockaddr *)&from_addr, &from_len ); - logging_printf(LOGGING_DEBUG, "net_socket_read: from_len=%u\n", from_len ); get_ip_string( (struct sockaddr *)&from_addr, ip_address, INET6_ADDRSTRLEN ); from_port = ntohs( ((struct sockaddr_in *)&from_addr)->sin_port ); #ifdef HAVE_ALSA @@ -278,7 +277,7 @@ int net_socket_read( int fd ) net_socket_lock(); bytes_written = sendto( fd, response->buffer, response->len , 0 , (void *)&from_addr, from_len); net_socket_unlock(); - logging_printf( LOGGING_DEBUG, "net_socket_read: write(bytes=%u,socket=%d,host=%s,port=%u)\n", bytes_written, fd,ip_address, from_port ); + logging_printf( LOGGING_DEBUG, "net_socket_read: response write(bytes=%u,socket=%d,host=%s,port=%u)\n", bytes_written, fd,ip_address, from_port ); net_response_destroy( &response ); } @@ -481,7 +480,7 @@ int net_socket_init( void ) local_port = config_int_get("network.local.port"); bind_address = config_string_get("network.bind_address"); - address_family = get_addr_family( bind_address , control_port ); + get_sock_info( bind_address , control_port , NULL, NULL, &address_family); logging_printf(LOGGING_DEBUG, "net_socket_init: network.bind_address=[%s], family=%d\n", bind_address, address_family); switch( address_family ) @@ -606,7 +605,7 @@ int net_socket_get_data_socket( void ) if( num_sockets <= 0 ) return -1; if( ! sockets ) return -1; - return sockets[DATA_PORT]; + return sockets[DATA_PORT - 1]; } int net_socket_get_control_socket( void ) @@ -614,5 +613,5 @@ int net_socket_get_control_socket( void ) if( num_sockets <= 0 ) return -1; if( ! sockets ) return -1; - return sockets[DATA_PORT-1]; + return sockets[DATA_PORT]; } diff --git a/raveloxmidi/src/raveloxmidi_config.c b/raveloxmidi/src/raveloxmidi_config.c index 9ec96f8..2a6ecad 100644 --- a/raveloxmidi/src/raveloxmidi_config.c +++ b/raveloxmidi/src/raveloxmidi_config.c @@ -52,7 +52,6 @@ static void config_set_defaults( void ) config_add_item("readonly","no"); config_add_item("inbound_midi","/dev/sequencer"); config_add_item("file_mode", "0640"); - config_add_item("client.name", "raveloxremote"); config_add_item("discover.timeout","5"); #ifdef HAVE_ALSA config_add_item("alsa.input_buffer_size", "4096" ); diff --git a/raveloxmidi/src/remote_connection.c b/raveloxmidi/src/remote_connection.c index 0f29fa7..1758f87 100644 --- a/raveloxmidi/src/remote_connection.c +++ b/raveloxmidi/src/remote_connection.c @@ -96,7 +96,7 @@ void remote_connect_init( void ) return; } - logging_printf( LOGGING_DEBUG, "remote_connect_init: Found [%s] [%s:%d]\n", found_service->name, found_service->ip_address, found_service->port); + logging_printf( LOGGING_DEBUG, "remote_connect_init: Found name=\"%s\" address=[%s]:%d\n", found_service->name, found_service->ip_address, found_service->port); remote_connect_ssrc = random_number(); remote_initiator = random_number(); @@ -112,7 +112,7 @@ void remote_connect_init( void ) inv->ssrc = remote_connect_ssrc; inv->version = 2; inv->initiator = remote_initiator; - client_name = config_string_get("client.name"); + client_name = config_string_get("service.name"); if( client_name ) { inv->name = (char *)strdup( client_name ); @@ -156,9 +156,9 @@ void remote_connect_init( void ) ctx->seq = 0x638E; logging_printf( LOGGING_DEBUG, "remote_connect_init: Creating connection context for %s data=%u control=%u\n", ctx->ip_address, ctx->data_port, ctx->control_port ); - net_ctx_send( net_socket_get_control_socket() , ctx, response->buffer, response->len , USE_CONTROL_PORT ); + net_ctx_send( ctx, response->buffer, response->len , USE_DATA_PORT ); ctx->seq++; - net_ctx_send( net_socket_get_data_socket() , ctx, response->buffer, response->len , USE_DATA_PORT ); + net_ctx_send( ctx, response->buffer, response->len , USE_CONTROL_PORT ); } net_ctx_destroy( &ctx ); @@ -225,7 +225,7 @@ void remote_connect_teardown( void ) { logging_printf( LOGGING_ERROR, "remote_connect_teardown: Unable to find connection for [%s]\n", remote_service_name); } else { - net_ctx_send( net_socket_get_control_socket() , ctx, response->buffer, response->len , USE_CONTROL_PORT); + net_ctx_send( ctx, response->buffer, response->len , USE_CONTROL_PORT); hex_dump( response->buffer, response->len ); } } @@ -243,7 +243,7 @@ void remote_connect_ok( char *remote_name ) net_applemidi_sync *sync_packet = NULL; net_response_t *response = NULL; net_applemidi_command *cmd = NULL; - net_ctx_t *ctx; + net_ctx_t *ctx = NULL; if( ! remote_name ) return; @@ -258,8 +258,7 @@ void remote_connect_ok( char *remote_name ) remote_connected = 1; logging_printf(LOGGING_DEBUG, "remote_connect_ok: Connection found for [%s]\n", remote_name); -/* - Build the SYNC packet + // Build the SYNC packet sync_packet = net_applemidi_sync_create(); if( ! sync_packet ) @@ -270,6 +269,9 @@ void remote_connect_ok( char *remote_name ) sync_packet->ssrc = ctx->send_ssrc; sync_packet->count = 0; + sync_packet->timestamp1 = time(NULL); + sync_packet->timestamp2 = 0; + sync_packet->timestamp3 = 0; cmd = net_applemidi_cmd_create( NET_APPLEMIDI_CMD_SYNC ); @@ -284,21 +286,22 @@ void remote_connect_ok( char *remote_name ) response = net_response_create(); - if( response ) + if( ! response ) { + logging_printf( LOGGING_ERROR, "remote_connect_ok: Unable to create response packet\n"); + goto remote_ok_fail; + } + int ret = 0; - ret = net_applemidi_pack( cmd , &(response->buffer), &(response->len) ); - if( ret != 0 ) - { - logging_printf( LOGGING_ERROR, "remote_connect_ok: Unable to pack response to sync_packet command\n"); - } else { - net_ctx_send( net_socket_get_control_socket() , ctx, response->buffer, response->len , USE_CONTROL_PORT ); - } + ret = net_applemidi_pack( cmd , &(response->buffer), &(response->len) ); + if( ret != 0 ) + { + logging_printf( LOGGING_ERROR, "remote_connect_ok: Unable to pack response to sync_packet command\n"); } else { - logging_printf( LOGGING_ERROR, "remote_connect_ok: Unable to create response packet\n"); + net_ctx_send( ctx, response->buffer, response->len , USE_CONTROL_PORT ); } -*/ +remote_ok_fail: net_response_destroy( &response ); net_applemidi_cmd_destroy( &cmd ); } diff --git a/raveloxmidi/src/utils.c b/raveloxmidi/src/utils.c index e538602..450635c 100644 --- a/raveloxmidi/src/utils.c +++ b/raveloxmidi/src/utils.c @@ -223,7 +223,7 @@ void FREENULL( const char *description, void **ptr ) if( ! ptr ) return; if( ! *ptr ) return; - logging_printf(LOGGING_DEBUG,"FREENULL: description=\"%s\",ptr=%p\n", description, *ptr); + logging_printf(LOGGING_DEBUG,"FREENULL: \"%s\"=%p\n", description, *ptr); free( *ptr ); *ptr = NULL; } @@ -288,7 +288,7 @@ char *get_ip_string( struct sockaddr *sa, char *s, size_t maxlen ) return s; } -int get_sock_addr( char *ip_address, int port, struct sockaddr *socket, socklen_t *socklen) +int get_sock_info( char *ip_address, int port, struct sockaddr *socket, socklen_t *socklen, int *family) { struct addrinfo hints; struct addrinfo *result; @@ -296,7 +296,6 @@ int get_sock_addr( char *ip_address, int port, struct sockaddr *socket, socklen_ char portaddr[32]; if( ! ip_address ) return 1; - if( ! socket ) return 1; memset( &hints, 0, sizeof( hints ) ); memset( portaddr, 0, sizeof( portaddr ) ); @@ -312,42 +311,24 @@ int get_sock_addr( char *ip_address, int port, struct sockaddr *socket, socklen_ return 1; } - memset( socket, 0, sizeof( struct sockaddr ) ); - memcpy( socket, result->ai_addr, result->ai_addrlen ); - *socklen = result->ai_addrlen; - - freeaddrinfo( result ); - return 0; -} - -int get_addr_family(char *ip_address, int port) -{ - struct addrinfo hints; - struct addrinfo *result; - int val; - char portaddr[32]; - int family = AF_UNSPEC; - - if( ! ip_address ) return AF_UNSPEC; + if( socket ) + { + memset( socket, 0, sizeof( struct sockaddr ) ); + memcpy( socket, result->ai_addr, result->ai_addrlen ); + } - memset( &hints, 0, sizeof( hints ) ); - memset( portaddr, 0, sizeof( portaddr ) ); - sprintf( portaddr, "%d", port ); - hints.ai_family = AF_UNSPEC; - hints.ai_socktype = SOCK_DGRAM; + if( socklen ) + { + *socklen = result->ai_addrlen; + } - val = getaddrinfo(ip_address, portaddr, &hints, &result ); - if( val ) + if( family ) { - logging_printf(LOGGING_WARN, "get_addr_family: Invalid address: [%s]:%d\n", ip_address, port ); - freeaddrinfo( result ); - return AF_UNSPEC; + *family = result->ai_family; } - family = result->ai_family; freeaddrinfo( result ); - return family; - + return 0; } int random_number( void ) From 2af8042c6a328812bd54251413236020c73ca375 Mon Sep 17 00:00:00 2001 From: Dave Kelly Date: Thu, 11 Apr 2019 09:33:51 -0700 Subject: [PATCH 26/33] More remote connection code changes Fixed bug in config file read if no CR/LF --- raveloxmidi/src/applemidi_ok.c | 4 ++-- raveloxmidi/src/applemidi_sync.c | 13 ++++++++++- raveloxmidi/src/net_connection.c | 33 +++++++++++++++++----------- raveloxmidi/src/net_socket.c | 8 +++---- raveloxmidi/src/raveloxmidi_config.c | 2 +- raveloxmidi/src/remote_connection.c | 4 ++-- 6 files changed, 41 insertions(+), 23 deletions(-) diff --git a/raveloxmidi/src/applemidi_ok.c b/raveloxmidi/src/applemidi_ok.c index 7adef4d..9a0ba6b 100644 --- a/raveloxmidi/src/applemidi_ok.c +++ b/raveloxmidi/src/applemidi_ok.c @@ -60,13 +60,13 @@ net_response_t * applemidi_ok_responder( char *ip_address, uint16_t port, void * /* We assume that the current port is the control port */ if( ! ctx ) { - ctx = net_ctx_register( ok_packet->initiator, ok_packet->initiator, ip_address, port, ok_packet->name); + ctx = net_ctx_register( ok_packet->ssrc, ok_packet->initiator, ip_address, port, ok_packet->name); if( ! ctx ) { logging_printf( LOGGING_ERROR, "applemidi_okresponder: Error registering connection\n"); } else { - ctx->data_port = port; + ctx->control_port = port; ctx->send_ssrc = ok_packet->initiator; } diff --git a/raveloxmidi/src/applemidi_sync.c b/raveloxmidi/src/applemidi_sync.c index f4e1f4f..a283780 100644 --- a/raveloxmidi/src/applemidi_sync.c +++ b/raveloxmidi/src/applemidi_sync.c @@ -40,6 +40,7 @@ extern int errno; #include "net_connection.h" #include "net_socket.h" #include "net_response.h" +#include "utils.h" #include "logging.h" @@ -51,6 +52,7 @@ net_response_t * applemidi_sync_responder( void *data ) net_ctx_t *ctx = NULL; net_response_t *response = NULL; uint32_t delta = 0; + time_t current_time = 0; logging_printf( LOGGING_DEBUG, "applemidi_sync_responder: start\n"); @@ -66,6 +68,8 @@ net_response_t * applemidi_sync_responder( void *data ) return NULL; } + net_ctx_dump( ctx ); + cmd = net_applemidi_cmd_create( NET_APPLEMIDI_CMD_SYNC ); if( ! cmd ) @@ -90,7 +94,12 @@ net_response_t * applemidi_sync_responder( void *data ) sync_resp->timestamp2 = sync->timestamp2; sync_resp->timestamp3 = sync->timestamp3; - delta = time( NULL ) - ctx->start; + logging_printf( LOGGING_DEBUG, "applemidi_sync_responder: now=%u start=%u delta=0x%08x\n", current_time, ctx->start, delta ); + + current_time = time( NULL ); + delta = current_time - ctx->start; + + logging_printf( LOGGING_DEBUG, "applemidi_sync_responder: now=%u start=%u delta=0x%08x\n", current_time, ctx->start, delta ); switch( sync_resp->count ) { @@ -107,6 +116,8 @@ net_response_t * applemidi_sync_responder( void *data ) cmd->data = sync_resp; + net_applemidi_command_dump( cmd ); + response = net_response_create(); if( response ) diff --git a/raveloxmidi/src/net_connection.c b/raveloxmidi/src/net_connection.c index 832803b..0c7e6a7 100644 --- a/raveloxmidi/src/net_connection.c +++ b/raveloxmidi/src/net_connection.c @@ -89,8 +89,8 @@ void net_ctx_dump( net_ctx_t *ctx ) { if( ! ctx ) return; - logging_printf( LOGGING_DEBUG, "net_ctx: ssrc=0x%08x,send_ssrc=0x%08x,initiator=0x%08x,seq=0x%08x,host=%s,control=%u,data=%u\n", - ctx->ssrc, ctx->send_ssrc, ctx->initiator, ctx->seq, ctx->ip_address, ctx->control_port, ctx->data_port); + logging_printf( LOGGING_DEBUG, "net_ctx: ssrc=0x%08x,send_ssrc=0x%08x,initiator=0x%08x,seq=0x%08x,host=%s,control=%u,data=%u start=%u\n", + ctx->ssrc, ctx->send_ssrc, ctx->initiator, ctx->seq, ctx->ip_address, ctx->control_port, ctx->data_port, ctx->start); } static void net_ctx_set( net_ctx_t *ctx, uint32_t ssrc, uint32_t initiator, uint32_t send_ssrc, uint32_t seq, uint16_t port, char *ip_address , char *name) @@ -171,11 +171,11 @@ net_ctx_t * net_ctx_find_by_ssrc( uint32_t ssrc) for( net_ctx_iter_start_head() ; net_ctx_iter_has_current(); net_ctx_iter_next()) { current_ctx = net_ctx_iter_current(); - if( current_ctx->ssrc == ssrc ) break; + if( current_ctx->ssrc == ssrc ) return current_ctx; } - logging_printf( LOGGING_DEBUG, "net_ctx_find_by_ssrc: found=%s\n", (current_ctx ? "yes" : "no")); - return current_ctx; + logging_printf( LOGGING_DEBUG, "net_ctx_find_by_ssrc: not found\n"); + return NULL; } net_ctx_t * net_ctx_find_by_name( char *name ) @@ -221,6 +221,7 @@ net_ctx_t * net_ctx_register( uint32_t ssrc, uint32_t initiator, char *ip_addres new_ctx = net_ctx_create(); } else { logging_printf(LOGGING_WARN, "net_ctx_register: net_ctx already exists\n"); + goto register_end; } if( ! new_ctx ) @@ -229,16 +230,22 @@ net_ctx_t * net_ctx_register( uint32_t ssrc, uint32_t initiator, char *ip_addres return NULL; } - last_ctx = net_ctx_get_last(); - if( ! _ctx_head ) _ctx_head = new_ctx; - send_ssrc = initiator; - net_ctx_set( new_ctx, ssrc, initiator, send_ssrc, 0x638F, port, ip_address , name); - new_ctx->prev = last_ctx; - - if( last_ctx ) last_ctx->next = new_ctx; + /* Add the connection to the list */ + if( ! _ctx_head ) + { + _ctx_head = new_ctx; + } else { + last_ctx = net_ctx_get_last(); + if( last_ctx ) + { + last_ctx->next = new_ctx; + } + new_ctx->prev = last_ctx; + } +register_end: for( net_ctx_iter_start_head(); net_ctx_iter_has_next(); net_ctx_iter_next() ) { current_ctx = net_ctx_iter_current(); @@ -343,7 +350,7 @@ void net_ctx_send( net_ctx_t *ctx, unsigned char *buffer, size_t buffer_len , in logging_printf( LOGGING_DEBUG, "net_ctx_send: outbound socket=%d\n", ntohs( ((struct sockaddr_in *)&socket_address)->sin_port ) ); net_socket_lock(); - bytes_sent = sendto( send_socket, buffer, buffer_len , 0 , (struct sockaddr *)&send_address, addr_len); + bytes_sent = sendto( send_socket, buffer, buffer_len , MSG_CONFIRM, (struct sockaddr *)&send_address, addr_len); net_socket_unlock(); if( bytes_sent < 0 ) diff --git a/raveloxmidi/src/net_socket.c b/raveloxmidi/src/net_socket.c index 434957d..98eef7c 100644 --- a/raveloxmidi/src/net_socket.c +++ b/raveloxmidi/src/net_socket.c @@ -275,7 +275,7 @@ int net_socket_read( int fd ) { size_t bytes_written = 0; net_socket_lock(); - bytes_written = sendto( fd, response->buffer, response->len , 0 , (void *)&from_addr, from_len); + bytes_written = sendto( fd, response->buffer, response->len , MSG_CONFIRM, (void *)&from_addr, from_len); net_socket_unlock(); logging_printf( LOGGING_DEBUG, "net_socket_read: response write(bytes=%u,socket=%d,host=%s,port=%u)\n", bytes_written, fd,ip_address, from_port ); net_response_destroy( &response ); @@ -288,7 +288,7 @@ int net_socket_read( int fd ) char *buffer="OK"; size_t bytes_written = 0; net_socket_lock(); - bytes_written = sendto( fd, buffer, strlen(buffer), 0 , (void *)&from_addr, from_len); + bytes_written = sendto( fd, buffer, strlen(buffer), MSG_CONFIRM, (void *)&from_addr, from_len); net_socket_unlock(); logging_printf(LOGGING_DEBUG, "net_socket_read: Heartbeat request. Response written: %u\n", bytes_written); @@ -298,7 +298,7 @@ int net_socket_read( int fd ) char *buffer="QT"; size_t bytes_written = 0; net_socket_lock(); - bytes_written = sendto( fd, buffer, strlen(buffer), 0 , (void *)&from_addr, from_len); + bytes_written = sendto( fd, buffer, strlen(buffer), MSG_CONFIRM, (void *)&from_addr, from_len); net_socket_unlock(); logging_printf(LOGGING_DEBUG, "net_socket_read: Shutdown request. Response written: %u\n", bytes_written); logging_printf(LOGGING_NORMAL, "Shutdown request received on local socket\n"); @@ -336,7 +336,7 @@ int net_socket_read( int fd ) { size_t bytes_written = 0; net_socket_lock(); - bytes_written = sendto( fd, response->buffer, response->len , 0 , (void *)&from_addr, from_len); + bytes_written = sendto( fd, response->buffer, response->len , MSG_CONFIRM, (void *)&from_addr, from_len); net_socket_unlock(); logging_printf( LOGGING_DEBUG, "net_socket_read: feedback write(bytes=%u,socket=%d,host=%s,port=%u)\n", bytes_written, fd,ip_address, from_port); net_response_destroy( &response ); diff --git a/raveloxmidi/src/raveloxmidi_config.c b/raveloxmidi/src/raveloxmidi_config.c index 2a6ecad..5350f8a 100644 --- a/raveloxmidi/src/raveloxmidi_config.c +++ b/raveloxmidi/src/raveloxmidi_config.c @@ -82,7 +82,7 @@ static void config_load_file( char *filename ) char *return_value = NULL; return_value = fgets( config_line , MAX_CONFIG_LINE, config_file ); - if( feof( config_file) ) break; + if( feof( config_file) && !return_value ) break; if( ! return_value ) { diff --git a/raveloxmidi/src/remote_connection.c b/raveloxmidi/src/remote_connection.c index 1758f87..dd40e70 100644 --- a/raveloxmidi/src/remote_connection.c +++ b/raveloxmidi/src/remote_connection.c @@ -270,8 +270,8 @@ void remote_connect_ok( char *remote_name ) sync_packet->ssrc = ctx->send_ssrc; sync_packet->count = 0; sync_packet->timestamp1 = time(NULL); - sync_packet->timestamp2 = 0; - sync_packet->timestamp3 = 0; + sync_packet->timestamp2 = random_number(); + sync_packet->timestamp3 = random_number(); cmd = net_applemidi_cmd_create( NET_APPLEMIDI_CMD_SYNC ); From c66f3ec4f53e3b1a4e09ecec177a4fe86619479c Mon Sep 17 00:00:00 2001 From: Dave Kelly Date: Sat, 27 Apr 2019 23:26:22 -0700 Subject: [PATCH 27/33] More remote connection code --- raveloxmidi/autogen.sh | 1 + raveloxmidi/configure.ac | 2 + raveloxmidi/include/dns_service_discover.h | 2 +- raveloxmidi/include/dns_service_publisher.h | 2 + raveloxmidi/include/net_connection.h | 11 ++ raveloxmidi/include/net_response.h | 3 + raveloxmidi/include/net_socket.h | 2 + raveloxmidi/include/remote_connection.h | 2 + raveloxmidi/include/utils.h | 6 + raveloxmidi/man/raveloxmidi.1.in | 10 +- raveloxmidi/src/applemidi_by.c | 1 + raveloxmidi/src/applemidi_inv.c | 2 - raveloxmidi/src/applemidi_ok.c | 53 +++-- raveloxmidi/src/dns_service_discover.c | 22 ++- raveloxmidi/src/dns_service_publisher.c | 17 +- raveloxmidi/src/net_applemidi.c | 1 + raveloxmidi/src/net_connection.c | 93 +++++++-- raveloxmidi/src/net_response.c | 111 +++++++++++ raveloxmidi/src/net_socket.c | 22 ++- raveloxmidi/src/raveloxmidi.c | 42 ++-- raveloxmidi/src/raveloxmidi_config.c | 17 +- raveloxmidi/src/remote_connection.c | 208 +++++++------------- raveloxmidi/src/utils.c | 34 +++- 23 files changed, 431 insertions(+), 233 deletions(-) diff --git a/raveloxmidi/autogen.sh b/raveloxmidi/autogen.sh index 36d9c72..7e9c433 100755 --- a/raveloxmidi/autogen.sh +++ b/raveloxmidi/autogen.sh @@ -5,6 +5,7 @@ set -x rm -f Makefile aclocal + autoconf autoheader diff --git a/raveloxmidi/configure.ac b/raveloxmidi/configure.ac index 2052940..2c96f16 100755 --- a/raveloxmidi/configure.ac +++ b/raveloxmidi/configure.ac @@ -3,6 +3,8 @@ AC_CANONICAL_HOST AC_CANONICAL_BUILD AC_CANONICAL_TARGET +AC_CONFIG_MACRO_DIRS([m4]) + AM_INIT_AUTOMAKE(raveloxmidi, 0.6.99) AC_CONFIG_HEADERS([config.h]) diff --git a/raveloxmidi/include/dns_service_discover.h b/raveloxmidi/include/dns_service_discover.h index 49f54a5..e8fb593 100644 --- a/raveloxmidi/include/dns_service_discover.h +++ b/raveloxmidi/include/dns_service_discover.h @@ -27,7 +27,7 @@ typedef struct dns_service_t { int port; } dns_service_t; -int dns_discover_services( void ); +int dns_discover_services( int use_ipv4, int use_ipv6 ); void dns_discover_add( const char *name, char *address, int port ); dns_service_t *dns_discover_by_name( const char *name ); void dns_discover_free_services( void ); diff --git a/raveloxmidi/include/dns_service_publisher.h b/raveloxmidi/include/dns_service_publisher.h index e05817c..6b63d45 100644 --- a/raveloxmidi/include/dns_service_publisher.h +++ b/raveloxmidi/include/dns_service_publisher.h @@ -25,6 +25,8 @@ typedef struct dns_service_desc_t { char *name; char *service; int port; + int publish_ipv4; + int publish_ipv6; } dns_service_desc_t; void dns_service_publisher_cleanup( void ); diff --git a/raveloxmidi/include/net_connection.h b/raveloxmidi/include/net_connection.h index 336d917..d53d5e2 100644 --- a/raveloxmidi/include/net_connection.h +++ b/raveloxmidi/include/net_connection.h @@ -32,7 +32,15 @@ #define USE_DATA_PORT 0 #define USE_CONTROL_PORT 1 +typedef enum net_ctx_status_t { + NET_CTX_STATUS_IDLE, + NET_CTX_STATUS_FIRST_INV, + NET_CTX_STATUS_SECOND_INV, + NET_CTX_STATUS_REMOTE_CONNECTION, +} net_ctx_status_t; + typedef struct net_ctx_t { + net_ctx_status_t status; uint32_t ssrc; uint32_t send_ssrc; uint32_t initiator; @@ -50,13 +58,16 @@ typedef struct net_ctx_t { net_ctx_t *net_ctx_create( void ); void net_ctx_destroy( net_ctx_t **ctx ); void net_ctx_dump( net_ctx_t *ctx ); +void net_ctx_dump_all( void ); void net_ctx_init( void ); void net_ctx_teardown( void ); net_ctx_t * net_ctx_find_by_id( uint8_t id ); net_ctx_t * net_ctx_find_by_ssrc( uint32_t ssrc); +net_ctx_t * net_ctx_find_by_initiator( uint32_t initiator); net_ctx_t * net_ctx_find_by_name( char *name ); net_ctx_t * net_ctx_register( uint32_t ssrc, uint32_t initiator, char *ip_address, uint16_t port , char *name); net_ctx_t * net_ctx_get_last( void ); +char *net_ctx_status_to_string( net_ctx_status_t status ); void net_ctx_add_journal_note( net_ctx_t *ctx, midi_note_t *midi_note ); void net_ctx_add_journal_control( net_ctx_t *ctx, midi_control_t *midi_control ); diff --git a/raveloxmidi/include/net_response.h b/raveloxmidi/include/net_response.h index 2e8f762..8a8083c 100644 --- a/raveloxmidi/include/net_response.h +++ b/raveloxmidi/include/net_response.h @@ -29,4 +29,7 @@ typedef struct net_response_t { net_response_t * net_response_create( void ); void net_response_destroy( net_response_t **response ); +net_response_t *net_response_inv( uint32_t ssrc, uint32_t initiator, char *name); +net_response_t *net_response_sync( uint32_t send_ssrc ); + #endif diff --git a/raveloxmidi/include/net_socket.h b/raveloxmidi/include/net_socket.h index 32e6ce0..07152ff 100644 --- a/raveloxmidi/include/net_socket.h +++ b/raveloxmidi/include/net_socket.h @@ -38,11 +38,13 @@ int net_socket_fd_loop(void); int net_socket_alsa_loop(void); void net_socket_wait_for_alsa(void); void net_socket_loop_shutdown(int signal); +int net_socket_get_shutdown_lock( void) ; int net_socket_get_data_socket( void ); int net_socket_get_control_socket( void ); void net_socket_set_fds( void ); +int net_socket_get_shutdown_fd( void ); /* Indicate which socket should be the data port */ #define DATA_PORT 1 diff --git a/raveloxmidi/include/remote_connection.h b/raveloxmidi/include/remote_connection.h index 53002ac..9afd5e4 100644 --- a/raveloxmidi/include/remote_connection.h +++ b/raveloxmidi/include/remote_connection.h @@ -24,5 +24,7 @@ void remote_connect_init( void ); void remote_connect_ok( char *name ); void remote_connect_teardown( void ); +void remote_connect_sync_start( void ); +void remote_connect_wait_for_thread( void ); #endif diff --git a/raveloxmidi/include/utils.h b/raveloxmidi/include/utils.h index 3975826..6f53e5a 100644 --- a/raveloxmidi/include/utils.h +++ b/raveloxmidi/include/utils.h @@ -42,6 +42,12 @@ int get_sock_info( char *ip_address, int port, struct sockaddr *socket, socklen_ int random_number( void ); +void GET_MASTER_LOCK( void ); +void RELEASE_MASTER_LOCK( void ); + +void utils_init( void ); +void utils_teardown( void ); + #define MAX(a,b) ( (a) > (b) ? (a) : (b) ) #define MIN(a,b) ( (a) < (b) ? (a) : (b) ) diff --git a/raveloxmidi/man/raveloxmidi.1.in b/raveloxmidi/man/raveloxmidi.1.in index 78edb35..6337a32 100644 --- a/raveloxmidi/man/raveloxmidi.1.in +++ b/raveloxmidi/man/raveloxmidi.1.in @@ -3,10 +3,10 @@ raveloxmidi - RTP MIDI proxy for NoteOn/NoteOff/ControlChange/ProgramChange events .SH SYNOPSIS .B raveloxmidi -[-c filename] [-d|-i] [-N] [-P filename] [-R] [-h] [-C] [-D] [-T seconds] +[-c filename] [-d|-i] [-N] [-P filename] [-R] [-h] [-C] [-T seconds] .B raveloxmidi -[--config filename] [--debug|--info] [--nodaemon] [--pidfile filename] [--readonly] [--help] [--dumpconfig] [--discover] [--discover-timeout] +[--config filename] [--debug|--info] [--nodaemon] [--pidfile filename] [--readonly] [--help] [--dumpconfig] .SH DESCRIPTION .BR raveloxmidi provides a RTP MIDI proxy to send MIDI NoteOn, NoteOff, ControlChange and ProgramChange events to a remote MIDI device. @@ -37,12 +37,6 @@ Display help information including default values for some parameters. .TP .B -C Display the current config to stderr -.TP -.B -D -Discover available _apple-midi._udp services -.TP -.B -T -Timeout for service discovery. Default is 10 seconds. .SH NOTES The available options for the configuration file are as follows: .TP diff --git a/raveloxmidi/src/applemidi_by.c b/raveloxmidi/src/applemidi_by.c index 205757f..dcb5793 100644 --- a/raveloxmidi/src/applemidi_by.c +++ b/raveloxmidi/src/applemidi_by.c @@ -47,6 +47,7 @@ net_response_t * applemidi_by_responder( void *data ) net_applemidi_inv *inv = NULL; net_ctx_t *ctx = NULL; + logging_printf( LOGGING_DEBUG, "applemidi_by_responder: data=%p\n", data ); if( ! data ) return NULL; inv = ( net_applemidi_inv *) data; diff --git a/raveloxmidi/src/applemidi_inv.c b/raveloxmidi/src/applemidi_inv.c index 46fae93..d91d1d0 100644 --- a/raveloxmidi/src/applemidi_inv.c +++ b/raveloxmidi/src/applemidi_inv.c @@ -71,8 +71,6 @@ net_response_t * applemidi_inv_responder( char *ip_address, uint16_t port, void { logging_printf( LOGGING_ERROR, "applemidi_inv_responder: Error registering connection\n"); } - //} else { - // ctx->data_port = port; } cmd = net_applemidi_cmd_create( NET_APPLEMIDI_CMD_ACCEPT ); diff --git a/raveloxmidi/src/applemidi_ok.c b/raveloxmidi/src/applemidi_ok.c index 9a0ba6b..96440e6 100644 --- a/raveloxmidi/src/applemidi_ok.c +++ b/raveloxmidi/src/applemidi_ok.c @@ -41,6 +41,7 @@ extern int errno; #include "net_response.h" #include "raveloxmidi_config.h" +#include "utils.h" #include "logging.h" #include "remote_connection.h" @@ -49,34 +50,46 @@ net_response_t * applemidi_ok_responder( char *ip_address, uint16_t port, void * { net_applemidi_inv *ok_packet = NULL; net_ctx_t *ctx = NULL; + net_response_t *response = NULL; if( ! data ) return NULL; + ok_packet = ( net_applemidi_inv *) data; logging_printf( LOGGING_DEBUG, "applemidi_ok_responder: address=[%s]:%u ssrc=0x%08x version=%u initiator=0x%08x name=%s\n", ip_address, port, ok_packet->ssrc, ok_packet->version, ok_packet->initiator, ok_packet->name); - ctx = net_ctx_find_by_ssrc( ok_packet->initiator ); + ctx = net_ctx_find_by_initiator( ok_packet->initiator ); - /* If no context is found, this is a new connection */ - /* We assume that the current port is the control port */ if( ! ctx ) { - ctx = net_ctx_register( ok_packet->ssrc, ok_packet->initiator, ip_address, port, ok_packet->name); - - if( ! ctx ) - { - logging_printf( LOGGING_ERROR, "applemidi_okresponder: Error registering connection\n"); - } else { - ctx->control_port = port; - ctx->send_ssrc = ok_packet->initiator; - } - - /* Set the remote connect flag if the ssrc is the same one we used */ - remote_connect_ok( ok_packet->name ); - - /* Otherwise, we assume that the current port is the data port */ - } else { - ctx->data_port = port; + logging_printf(LOGGING_WARN,"applemidi_ok_responder: Unexpected OK from ssrc=0x%08x\n", ok_packet->ssrc); + return NULL; + } + + logging_printf( LOGGING_DEBUG, "applemidi_ok_responder: address=[%s]:%u status=%s\n", ip_address, port, net_ctx_status_to_string(ctx->status )); + switch( ctx->status ) + { + case NET_CTX_STATUS_FIRST_INV: + response = net_response_inv( ctx->send_ssrc, ctx->initiator, config_string_get("client.name") ); + ctx->ssrc = ok_packet->ssrc; + net_ctx_dump_all(); + net_ctx_send( ctx, response->buffer, response->len , USE_DATA_PORT ); + hex_dump( response->buffer, response->len ); + net_response_destroy( &response ); + response = NULL; + ctx->status = NET_CTX_STATUS_SECOND_INV; + break; + case NET_CTX_STATUS_SECOND_INV: + response = net_response_sync( ctx->send_ssrc ); + net_ctx_send( ctx, response->buffer, response->len, USE_CONTROL_PORT ); + hex_dump( response->buffer, response->len ); + net_response_destroy( &response ); + response = NULL; + ctx->status = NET_CTX_STATUS_REMOTE_CONNECTION; + remote_connect_sync_start(); + break; + default: + break; } - return NULL; + return response; } diff --git a/raveloxmidi/src/dns_service_discover.c b/raveloxmidi/src/dns_service_discover.c index 2486706..1f4f6ca 100644 --- a/raveloxmidi/src/dns_service_discover.c +++ b/raveloxmidi/src/dns_service_discover.c @@ -127,30 +127,42 @@ static void client_callback(AvahiClient *c, AvahiClientState state, AVAHI_GCC_UN } } -int dns_discover_services( void ) +int dns_discover_services( int use_ipv4, int use_ipv6 ) { AvahiServiceBrowser *sb = NULL; int error; struct timeval timeout; + AvahiProtocol protocol; if (!(threaded_poll = avahi_threaded_poll_new())) { - logging_printf(LOGGING_WARN, "Failed to create threaded poll object.\n"); + logging_printf(LOGGING_WARN, "dns_discover_services: Failed to create threaded poll object.\n"); goto fail; } client = avahi_client_new(avahi_threaded_poll_get(threaded_poll), 0, client_callback, NULL, &error); if (!client) { - logging_printf(LOGGING_WARN, "Failed to create client: %s\n", avahi_strerror(error)); + logging_printf(LOGGING_WARN, "dns_discover_services: Failed to create client: %s\n", avahi_strerror(error)); goto fail; } - if (!(sb = avahi_service_browser_new(client, AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC, "_apple-midi._udp", NULL, 0, browse_callback, client))) { - logging_printf(LOGGING_WARN, "Failed to create service browser: %s\n", avahi_strerror(avahi_client_errno(client))); + if( use_ipv4 && use_ipv6 ) + { + protocol = AVAHI_PROTO_UNSPEC; + } else if ( use_ipv4 ) { + protocol = AVAHI_PROTO_INET; + } else { + protocol = AVAHI_PROTO_INET6; + } + + if (!(sb = avahi_service_browser_new(client, AVAHI_IF_UNSPEC, protocol, "_apple-midi._udp", NULL, 0, browse_callback, client))) { + logging_printf(LOGGING_WARN, "dns_discover_services: Failed to create service browser: %s\n", avahi_strerror(avahi_client_errno(client))); goto fail; } avahi_threaded_poll_start(threaded_poll); + + /* Keep the threads running until the timeout */ timeout.tv_sec = config_int_get("discover.timeout"); timeout.tv_usec= 0; select( 0, NULL, NULL, NULL, &timeout ); diff --git a/raveloxmidi/src/dns_service_publisher.c b/raveloxmidi/src/dns_service_publisher.c index 7112ff6..bc98911 100644 --- a/raveloxmidi/src/dns_service_publisher.c +++ b/raveloxmidi/src/dns_service_publisher.c @@ -49,6 +49,8 @@ static AvahiClient *client = NULL; static char *sd_name_copy = NULL; static char *sd_service_copy = NULL; static int sd_port = 0; +static int use_ipv4 = 0; +static int use_ipv6 = 0; static void create_services(AvahiClient *c); @@ -97,6 +99,7 @@ static void entry_group_callback(AvahiEntryGroup *g, AvahiEntryGroupState state, static void create_services(AvahiClient *c) { char *n, r[128]; int ret; + AvahiProtocol protocol; assert(c); /* If this is the first time we're called, let's create a new @@ -117,7 +120,16 @@ static void create_services(AvahiClient *c) { /* Create some random TXT data */ snprintf(r, sizeof(r), "random=%i", rand()); - if ((ret = avahi_entry_group_add_service(group, AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC, 0, sd_name_copy , sd_service_copy , NULL, NULL, sd_port, "test=blah", r, NULL)) < 0) { + if( use_ipv4 && use_ipv6 ) + { + protocol = AVAHI_PROTO_UNSPEC; + } else if( use_ipv4 ) { + protocol = AVAHI_PROTO_INET; + } else { + protocol = AVAHI_PROTO_INET6; + } + + if ((ret = avahi_entry_group_add_service(group, AVAHI_IF_UNSPEC, protocol, 0, sd_name_copy , sd_service_copy , NULL, NULL, sd_port, "test=blah", r, NULL)) < 0) { if (ret == AVAHI_ERR_COLLISION) goto collision; @@ -246,6 +258,9 @@ int dns_service_publisher_start( dns_service_desc_t *service_desc ) sd_service_copy = avahi_strdup( service_desc->service ); sd_port = service_desc->port; + use_ipv4 = service_desc->publish_ipv4; + use_ipv6 = service_desc->publish_ipv6; + client = avahi_client_new(avahi_threaded_poll_get(threaded_poll), 0, client_callback, NULL, &error); if (! client) { diff --git a/raveloxmidi/src/net_applemidi.c b/raveloxmidi/src/net_applemidi.c index 06d36d3..adeabf8 100644 --- a/raveloxmidi/src/net_applemidi.c +++ b/raveloxmidi/src/net_applemidi.c @@ -182,6 +182,7 @@ net_applemidi_feedback * net_applemidi_feedback_create( void ) int net_applemidi_cmd_destroy( net_applemidi_command **command ) { + if( ! *command ) { return NET_APPLEMIDI_DONE; diff --git a/raveloxmidi/src/net_connection.c b/raveloxmidi/src/net_connection.c index 0c7e6a7..6da4929 100644 --- a/raveloxmidi/src/net_connection.c +++ b/raveloxmidi/src/net_connection.c @@ -87,22 +87,33 @@ void net_ctx_destroy( net_ctx_t **ctx ) void net_ctx_dump( net_ctx_t *ctx ) { + DEBUG_ONLY; if( ! ctx ) return; - logging_printf( LOGGING_DEBUG, "net_ctx: ssrc=0x%08x,send_ssrc=0x%08x,initiator=0x%08x,seq=0x%08x,host=%s,control=%u,data=%u start=%u\n", + logging_printf( LOGGING_DEBUG, "net_ctx: ssrc=0x%08x,send_ssrc=0x%08x,initiator=0x%08x,seq=%u,host=%s,control=%u,data=%u start=%u\n", ctx->ssrc, ctx->send_ssrc, ctx->initiator, ctx->seq, ctx->ip_address, ctx->control_port, ctx->data_port, ctx->start); } -static void net_ctx_set( net_ctx_t *ctx, uint32_t ssrc, uint32_t initiator, uint32_t send_ssrc, uint32_t seq, uint16_t port, char *ip_address , char *name) +void net_ctx_dump_all( void ) +{ + DEBUG_ONLY; + logging_printf( LOGGING_DEBUG, "net_ctx_dump_all: start\n"); + for( net_ctx_iter_start_head() ; net_ctx_iter_has_current(); net_ctx_iter_next()) + { + net_ctx_dump( net_ctx_iter_current() ); + } + logging_printf( LOGGING_DEBUG, "net_ctx_dump_all: end\n"); +} + +static void net_ctx_set( net_ctx_t *ctx, uint32_t ssrc, uint32_t initiator, uint32_t send_ssrc, uint16_t port, char *ip_address , char *name) { if( ! ctx ) return; ctx->ssrc = ssrc; ctx->send_ssrc = send_ssrc; ctx->initiator = initiator; - ctx->seq = seq; - ctx->data_port = port; - ctx->control_port = port + 1; + ctx->control_port = port; + ctx->data_port = port+1; ctx->start = time( NULL ); if( ctx->ip_address ) @@ -127,7 +138,7 @@ net_ctx_t * net_ctx_create( void ) } memset( new_ctx, 0, sizeof( net_ctx_t ) ); - new_ctx->seq = 0x0000; + new_ctx->seq = 1; journal_init( &journal ); @@ -135,6 +146,8 @@ net_ctx_t * net_ctx_create( void ) new_ctx->next = NULL; new_ctx->prev = NULL; + new_ctx->status = NET_CTX_STATUS_IDLE; + return new_ctx; } @@ -165,29 +178,60 @@ void net_ctx_teardown( void ) net_ctx_t * net_ctx_find_by_ssrc( uint32_t ssrc) { - net_ctx_t *current_ctx = _ctx_head; + net_ctx_t *current_ctx = NULL; logging_printf( LOGGING_DEBUG, "net_ctx_find_by_ssrc: ssrc=0x%08x\n", ssrc ); for( net_ctx_iter_start_head() ; net_ctx_iter_has_current(); net_ctx_iter_next()) { current_ctx = net_ctx_iter_current(); - if( current_ctx->ssrc == ssrc ) return current_ctx; + if( current_ctx ) + { + if( current_ctx->ssrc == ssrc ) return current_ctx; + } } logging_printf( LOGGING_DEBUG, "net_ctx_find_by_ssrc: not found\n"); return NULL; } +net_ctx_t * net_ctx_find_by_initiator( uint32_t initiator) +{ + net_ctx_t *current_ctx = NULL; + + logging_printf( LOGGING_DEBUG, "net_ctx_find_by_initiator: initiator=0x%08x\n", initiator ); + + net_ctx_dump_all(); + for( net_ctx_iter_start_head() ; net_ctx_iter_has_current(); net_ctx_iter_next()) + { + current_ctx = net_ctx_iter_current(); + if( current_ctx ) + { + if( current_ctx->initiator == initiator ) return current_ctx; + } + } + + logging_printf( LOGGING_DEBUG, "net_ctx_find_by_initiator: not found\n"); + return NULL; +} + net_ctx_t * net_ctx_find_by_name( char *name ) { - net_ctx_t *current_ctx = _ctx_head; - while( current_ctx ) + net_ctx_t *current_ctx = NULL; + + if( ! name ) return NULL; + + logging_printf( LOGGING_DEBUG, "net_ctx_find_by_name: name=[%s]\n", name); + for( net_ctx_iter_start_head() ; net_ctx_iter_has_current(); net_ctx_iter_next() ) { - if( strcmp( current_ctx->name, name ) == 0 ) break; - current_ctx = current_ctx->next; + current_ctx = net_ctx_iter_current(); + if( current_ctx ) + { + if( strcmp( current_ctx->name, name ) == 0 ) return current_ctx; + } } - return current_ctx; + logging_printf( LOGGING_DEBUG, "net_ctx_find_by_name: not found\n"); + return NULL; } net_ctx_t * net_ctx_get_last( void ) @@ -206,7 +250,6 @@ net_ctx_t * net_ctx_get_last( void ) net_ctx_t * net_ctx_register( uint32_t ssrc, uint32_t initiator, char *ip_address, uint16_t port, char *name ) { - net_ctx_t *current_ctx = NULL; net_ctx_t *last_ctx = NULL; net_ctx_t *new_ctx = NULL; uint32_t send_ssrc = 0; @@ -231,7 +274,7 @@ net_ctx_t * net_ctx_register( uint32_t ssrc, uint32_t initiator, char *ip_addres } send_ssrc = initiator; - net_ctx_set( new_ctx, ssrc, initiator, send_ssrc, 0x638F, port, ip_address , name); + net_ctx_set( new_ctx, ssrc, initiator, send_ssrc, port, ip_address , name); /* Add the connection to the list */ if( ! _ctx_head ) @@ -246,11 +289,7 @@ net_ctx_t * net_ctx_register( uint32_t ssrc, uint32_t initiator, char *ip_addres new_ctx->prev = last_ctx; } register_end: - for( net_ctx_iter_start_head(); net_ctx_iter_has_next(); net_ctx_iter_next() ) - { - current_ctx = net_ctx_iter_current(); - net_ctx_dump( current_ctx ); - } + net_ctx_dump_all(); return new_ctx; } @@ -341,7 +380,7 @@ void net_ctx_send( net_ctx_t *ctx, unsigned char *buffer, size_t buffer_len , in /* Set up the destination address */ memset((char *)&send_address, 0, sizeof( send_address)); - port_number = ( use_control == USE_CONTROL_PORT ? ctx->data_port : ctx->control_port ); + port_number = ( use_control == USE_CONTROL_PORT ? ctx->control_port : ctx->data_port ); get_sock_info( ctx->ip_address, port_number, (struct sockaddr *)&send_address, &addr_len, &family); send_socket = ( use_control == USE_CONTROL_PORT ? net_socket_get_control_socket() : net_socket_get_data_socket() ); @@ -409,3 +448,15 @@ void net_ctx_iter_prev(void) _iterator_current = _iterator_current->prev; } } + +char *net_ctx_status_to_string( net_ctx_status_t status ) +{ + switch( status ) + { + case NET_CTX_STATUS_IDLE: return "idle"; + case NET_CTX_STATUS_FIRST_INV: return "first_inv"; + case NET_CTX_STATUS_SECOND_INV: return "second_inv"; + case NET_CTX_STATUS_REMOTE_CONNECTION: return "remote_connection"; + default: return "unknown"; + } +} diff --git a/raveloxmidi/src/net_response.c b/raveloxmidi/src/net_response.c index ee71919..76e6cd3 100644 --- a/raveloxmidi/src/net_response.c +++ b/raveloxmidi/src/net_response.c @@ -21,6 +21,7 @@ #include #include #include +#include #include #include @@ -32,6 +33,8 @@ #include #include "net_response.h" +#include "net_applemidi.h" +#include "net_connection.h" #include "utils.h" #include "logging.h" #include "config.h" @@ -64,3 +67,111 @@ void net_response_destroy( net_response_t **response ) free( *response ); *response = NULL; } + +net_response_t *net_response_inv( uint32_t ssrc, uint32_t initiator, char *name ) +{ + net_applemidi_inv *inv = NULL; + net_response_t *response = NULL; + net_applemidi_command *cmd = NULL; + + // Build the INV packet + inv = net_applemidi_inv_create(); + + if( ! inv ) + { + logging_printf( LOGGING_ERROR, "net_response_inv: Cannot create INV packet\n"); + return NULL; + } + + inv->ssrc = ssrc; + inv->version = 2; + inv->initiator = initiator; + if( name ) + { + inv->name = (char *)strdup( name ); + } else { + inv->name = (char *)strdup( "RaveloxMIDIClient" ); + } + + cmd = net_applemidi_cmd_create( NET_APPLEMIDI_CMD_INV ); + + if( cmd ) + { + cmd->data = inv; + response = net_response_create(); + if( ! response ) + { + logging_printf( LOGGING_ERROR, "net_response_inv: Unable to create RESPONSE packet\n"); + } else { + int ret = 0; + ret = net_applemidi_pack( cmd , &(response->buffer), &(response->len) ); + net_applemidi_cmd_destroy( &cmd ); + if( ret != 0 ) + { + logging_printf( LOGGING_ERROR, "Unable to pack RESPONSE packet\n"); + } else { + return response; + } + } + + } else { + logging_printf( LOGGING_ERROR, "net_response_inv: Unable to create AppleMIDI command\n"); + } + + net_response_destroy( &response ); + net_applemidi_cmd_destroy( &cmd ); + + return NULL; +} + +net_response_t *net_response_sync( uint32_t send_ssrc ) +{ + net_applemidi_sync *sync = NULL; + net_response_t *response = NULL; + net_applemidi_command *cmd = NULL; + + sync = net_applemidi_sync_create(); + + if( ! sync ) + { + logging_printf( LOGGING_ERROR, "net_response_sync: Unable to allocate memory for sync packet\n"); + return NULL; + } + + sync->ssrc = send_ssrc; + sync->count = 0; + sync->timestamp1 = time(NULL); + sync->timestamp2 = 0; + sync->timestamp3 = 0; + + cmd = net_applemidi_cmd_create( NET_APPLEMIDI_CMD_SYNC ); + + if( cmd ) + { + cmd->data = sync; + + response = net_response_create(); + + if( response ) + { + int ret = 0; + ret = net_applemidi_pack( cmd , &(response->buffer), &(response->len) ); + if( ret != 0 ) + { + logging_printf( LOGGING_ERROR, "net_response_sync: Unable to pack response to sync command\n"); + } else { + net_applemidi_cmd_destroy( &cmd ); + return response; + } + } else { + logging_printf( LOGGING_ERROR, "net_response_sync: Unable to create response packet\n"); + } + } else { + logging_printf( LOGGING_ERROR, "net_response_sync: Unable to create AppleMIDI command\n"); + } + + net_response_destroy( &response ); + net_applemidi_cmd_destroy( &cmd ); + + return NULL; +} diff --git a/raveloxmidi/src/net_socket.c b/raveloxmidi/src/net_socket.c index 98eef7c..b7b8a1a 100644 --- a/raveloxmidi/src/net_socket.c +++ b/raveloxmidi/src/net_socket.c @@ -80,7 +80,7 @@ static pthread_mutex_t shutdown_lock; static pthread_mutex_t socket_mutex; pthread_t alsa_listener_thread; int socket_timeout = 0; -int pipe_fd[2]; +int pipe_fd[2] = { 0, 0 }; static void set_shutdown_lock( int i ); @@ -191,7 +191,7 @@ int net_socket_read( int fd ) struct sockaddr_storage from_addr; int output_enabled = 0; char ip_address[ INET6_ADDRSTRLEN ]; - int from_port = 0; + uint16_t from_port = 0; net_applemidi_command *command; int ret = 0; @@ -401,6 +401,15 @@ static void set_shutdown_lock( int i ) pthread_mutex_unlock( &shutdown_lock ); } +int net_socket_get_shutdown_lock( void ) +{ + int i = 0; + pthread_mutex_lock( &shutdown_lock ); + i = net_socket_shutdown; + pthread_mutex_unlock( &shutdown_lock ); + return i; +} + void net_socket_loop_init() { int err = 0; @@ -605,7 +614,7 @@ int net_socket_get_data_socket( void ) if( num_sockets <= 0 ) return -1; if( ! sockets ) return -1; - return sockets[DATA_PORT - 1]; + return sockets[DATA_PORT]; } int net_socket_get_control_socket( void ) @@ -613,5 +622,10 @@ int net_socket_get_control_socket( void ) if( num_sockets <= 0 ) return -1; if( ! sockets ) return -1; - return sockets[DATA_PORT]; + return sockets[DATA_PORT - 1]; +} + +int net_socket_get_shutdown_fd( void ) +{ + return pipe_fd[0]; } diff --git a/raveloxmidi/src/raveloxmidi.c b/raveloxmidi/src/raveloxmidi.c index febf5e1..b5cb5a4 100644 --- a/raveloxmidi/src/raveloxmidi.c +++ b/raveloxmidi/src/raveloxmidi.c @@ -54,26 +54,18 @@ int main(int argc, char *argv[]) dns_service_desc_t service_desc; int ret = 0; + utils_init(); + config_init( argc, argv); logging_init(); logging_printf( LOGGING_INFO, "%s (%s)\n", PACKAGE, VERSION); - dns_discover_init(); - - if( config_is_set("discover.services" ) ) - { - int services_found = 0; - services_found = dns_discover_services(); - - if( services_found > 0 ) - { - dns_discover_dump(); - } else { - logging_printf( LOGGING_INFO, "No remote services found\n"); - } - goto daemon_stop; - } + service_desc.name = config_string_get("service.name"); + service_desc.service = "_apple-midi._udp"; + service_desc.port = config_int_get("network.control.port"); + service_desc.publish_ipv4 = is_yes( config_string_get("service.ipv4")); + service_desc.publish_ipv6 = is_yes( config_string_get("service.ipv6")); #ifdef HAVE_ALSA raveloxmidi_alsa_init( config_string_get("alsa.input_device") , config_string_get("alsa.output_device") , config_int_get("alsa.input_buffer_size") ); @@ -97,28 +89,28 @@ int main(int argc, char *argv[]) signal( SIGTERM , net_socket_loop_shutdown); signal( SIGUSR2 , net_socket_loop_shutdown); - service_desc.name = config_string_get("service.name"); - service_desc.service = "_apple-midi._udp"; - service_desc.port = config_int_get("network.control.port"); - ret = dns_service_publisher_start( &service_desc ); if( ret != 0 ) { logging_printf(LOGGING_ERROR, "Unable to create publish thread\n"); } else { + net_socket_loop_init(); + if( config_string_get("remote.connect") ) { + dns_discover_init(); remote_connect_init(); + dns_discover_teardown(); } - dns_discover_teardown(); - - net_socket_loop_init(); + if( net_socket_get_shutdown_lock() == 0 ) + { #ifdef HAVE_ALSA - net_socket_alsa_loop(); + net_socket_alsa_loop(); #endif - net_socket_fd_loop(); + net_socket_fd_loop(); + } #ifdef HAVE_ALSA net_socket_wait_for_alsa(); #endif @@ -146,5 +138,7 @@ int main(int argc, char *argv[]) logging_teardown(); + utils_teardown(); + return 0; } diff --git a/raveloxmidi/src/raveloxmidi_config.c b/raveloxmidi/src/raveloxmidi_config.c index 5350f8a..8f95de4 100644 --- a/raveloxmidi/src/raveloxmidi_config.c +++ b/raveloxmidi/src/raveloxmidi_config.c @@ -43,6 +43,8 @@ static void config_set_defaults( void ) config_add_item("network.socket_timeout" , "30" ); config_add_item("network.max_connections", "8"); config_add_item("service.name", "raveloxmidi"); + config_add_item("service.ipv4", "yes"); + config_add_item("service.ipv6", "no"); config_add_item("run_as_daemon", "no"); config_add_item("daemon.pid_file","raveloxmidi.pid"); config_add_item("logging.enabled", "yes"); @@ -53,6 +55,7 @@ static void config_set_defaults( void ) config_add_item("inbound_midi","/dev/sequencer"); config_add_item("file_mode", "0640"); config_add_item("discover.timeout","5"); + config_add_item("sync.interval","10"); #ifdef HAVE_ALSA config_add_item("alsa.input_buffer_size", "4096" ); #endif @@ -134,18 +137,12 @@ void config_init( int argc, char *argv[] ) {"pidfile", required_argument, NULL, 'P'}, {"readonly", no_argument, NULL, 'R'}, {"dumpconfig", no_argument, NULL, 'C'}, - {"discover", no_argument, NULL, 'D'}, - {"discover-timeout", required_argument, NULL, 'T'}, #ifdef HAVE_ALSA #endif {"help", no_argument, NULL, 'h'}, {0,0,0,0} }; -#ifdef HAVE_ALSA - const char *short_options = "c:dihNP:RCDT:"; -#else - const char *short_options = "c:dihNP:RCDT:"; -#endif + const char *short_options = "c:dihNP:RC"; int c; config_items = kv_table_create("config_items"); @@ -195,12 +192,6 @@ void config_init( int argc, char *argv[] ) case 'C': dump_config = 1; break; - case 'D': - config_add_item("discover.services", "yes"); - break; - case 'T': - config_add_item("discover.timeout", optarg); - break; } } diff --git a/raveloxmidi/src/remote_connection.c b/raveloxmidi/src/remote_connection.c index dd40e70..cec3556 100644 --- a/raveloxmidi/src/remote_connection.c +++ b/raveloxmidi/src/remote_connection.c @@ -56,19 +56,17 @@ extern int errno; #include "remote_connection.h" -static int remote_connected = 0; -static uint32_t remote_connect_ssrc = 0; -static uint32_t remote_initiator = 0; +pthread_t sync_thread; void remote_connect_init( void ) { dns_service_t *found_service = NULL; char *remote_service_name = NULL; char *client_name = NULL; - net_applemidi_inv *inv = NULL; net_response_t *response = NULL; - net_applemidi_command *cmd = NULL; net_ctx_t *ctx; + int use_ipv4, use_ipv6; + uint32_t initiator = 0, ssrc = 0; remote_service_name = config_string_get("remote.connect"); @@ -80,14 +78,15 @@ void remote_connect_init( void ) logging_printf(LOGGING_DEBUG, "remote_connect_init: Looking for [%s]\n", remote_service_name); - remote_connected = 0; - if( dns_discover_services() <= 0 ) + use_ipv4 = is_yes( config_string_get("service.ipv4") ) ; + use_ipv6 = is_yes( config_string_get("service.ipv6") ) ; + + if( dns_discover_services( use_ipv4, use_ipv6 ) <= 0 ) { logging_printf(LOGGING_WARN, "remote_connect_init: No services available\n"); return; } - found_service = dns_discover_by_name( remote_service_name ); if( ! found_service ) @@ -97,79 +96,32 @@ void remote_connect_init( void ) } logging_printf( LOGGING_DEBUG, "remote_connect_init: Found name=\"%s\" address=[%s]:%d\n", found_service->name, found_service->ip_address, found_service->port); - remote_connect_ssrc = random_number(); - remote_initiator = random_number(); + ssrc = random_number(); + initiator = random_number(); - // Build the INV packet - inv = net_applemidi_inv_create(); - - if( ! inv ) + client_name = config_string_get("client.name"); + if( !client_name ) { - logging_printf( LOGGING_ERROR, "remote_connect_init: Unable to allocate memory for inv packet\n"); - return; + client_name = (char *)strdup( "RaveloxMIDIClient" ); } - inv->ssrc = remote_connect_ssrc; - inv->version = 2; - inv->initiator = remote_initiator; - client_name = config_string_get("service.name"); - if( client_name ) - { - inv->name = (char *)strdup( client_name ); - } else { - inv->name = (char *)strdup( "RaveloxMIDIClient" ); - } - - cmd = net_applemidi_cmd_create( NET_APPLEMIDI_CMD_INV ); - - if( ! cmd ) - { - logging_printf( LOGGING_ERROR, "remote_connect_init: Unable to create AppleMIDI command\n"); - net_applemidi_inv_destroy( &inv ); - goto remote_connect_fail; - } - - cmd->data = inv; - - response = net_response_create(); + response = net_response_inv( ssrc, initiator, client_name ); if( response ) { - int ret = 0; - ret = net_applemidi_pack( cmd , &(response->buffer), &(response->len) ); - if( ret != 0 ) + ctx = net_ctx_register( ssrc, initiator, found_service->ip_address, found_service->port, found_service->name ); + + if( ! ctx ) { - logging_printf( LOGGING_ERROR, "remote_connect_init: Unable to pack response to inv command\n"); + logging_printf( LOGGING_ERROR, "remote_connect_init: Unable to create socket context\n"); } else { - ctx = net_ctx_create(); - - if( ! ctx ) - { - logging_printf( LOGGING_ERROR, "remote_connect_init: Unable to create socket context\n"); - } else { - ctx->ip_address = ( char * ) strdup( found_service->ip_address ); - ctx->control_port = found_service->port; - ctx->data_port = found_service->port+1; - ctx->ssrc = inv->ssrc; - ctx->send_ssrc = inv->ssrc; - ctx->initiator = inv->initiator; - ctx->seq = 0x638E; - - logging_printf( LOGGING_DEBUG, "remote_connect_init: Creating connection context for %s data=%u control=%u\n", ctx->ip_address, ctx->data_port, ctx->control_port ); - net_ctx_send( ctx, response->buffer, response->len , USE_DATA_PORT ); - ctx->seq++; - net_ctx_send( ctx, response->buffer, response->len , USE_CONTROL_PORT ); - } - - net_ctx_destroy( &ctx ); + ctx->status = NET_CTX_STATUS_FIRST_INV; + logging_printf( LOGGING_DEBUG, "remote_connect_init: Sending INV request to [%s]:%d\n", ctx->ip_address, ctx->control_port ); + net_ctx_send( ctx, response->buffer, response->len , USE_CONTROL_PORT ); } - } else { - logging_printf( LOGGING_ERROR, "remote_connect_init: Unable to create response packet\n"); } -remote_connect_fail: net_response_destroy( &response ); - net_applemidi_cmd_destroy( &cmd ); } void remote_connect_teardown( void ) @@ -180,11 +132,20 @@ void remote_connect_teardown( void ) char *remote_service_name = NULL; net_ctx_t *ctx; - if( ! remote_connected ) return; remote_service_name = config_string_get("remote.connect"); logging_printf( LOGGING_DEBUG, "remote_connect_teardown: Disconnecting from [%s]\n", remote_service_name); + remote_connect_wait_for_thread(); + + ctx = net_ctx_find_by_name( remote_service_name ); + + if( ! ctx ) + { + logging_printf( LOGGING_ERROR, "remote_connect_teardown: Unable to find connection for [%s]\n", remote_service_name); + return; + }; + // Build the BY packet by = net_applemidi_inv_create(); @@ -194,9 +155,9 @@ void remote_connect_teardown( void ) return; } - by->ssrc = remote_connect_ssrc; + by->ssrc = ctx->send_ssrc; by->version = 2; - by->initiator = remote_connect_ssrc; + by->initiator = ctx->initiator; cmd = net_applemidi_cmd_create( NET_APPLEMIDI_CMD_END ); @@ -219,15 +180,8 @@ void remote_connect_teardown( void ) { logging_printf( LOGGING_ERROR, "remote_connect_teardown: Unable to pack response to by command\n"); } else { - ctx = net_ctx_find_by_name( remote_service_name ); - - if( ! ctx ) - { - logging_printf( LOGGING_ERROR, "remote_connect_teardown: Unable to find connection for [%s]\n", remote_service_name); - } else { - net_ctx_send( ctx, response->buffer, response->len , USE_CONTROL_PORT); - hex_dump( response->buffer, response->len ); - } + net_ctx_send( ctx, response->buffer, response->len , USE_CONTROL_PORT); + hex_dump( response->buffer, response->len ); } } else { logging_printf( LOGGING_ERROR, "remote_connect_teardown: Unable to create response packet\n"); @@ -238,70 +192,60 @@ void remote_connect_teardown( void ) net_applemidi_cmd_destroy( &cmd ); } -void remote_connect_ok( char *remote_name ) +static void *remote_connect_sync_thread( void *data ) { - net_applemidi_sync *sync_packet = NULL; - net_response_t *response = NULL; - net_applemidi_command *cmd = NULL; + net_response_t *response; net_ctx_t *ctx = NULL; + char *remote_service_name = NULL; + int shutdown_fd = 0; + fd_set read_fds; + struct timeval tv; - if( ! remote_name ) return; - - ctx = net_ctx_find_by_name( remote_name ); + logging_printf( LOGGING_DEBUG, "remote_connect_sync_thread: start\n"); + logging_printf( LOGGING_DEBUG, "rmeote_connect_sync_thread: sync.interval=%s\n", config_string_get("sync.interval")); - if( ! ctx ) - { - logging_printf( LOGGING_DEBUG, "remote_connect_ok: No context found for [%s]\n", remote_name ); - return; - } + shutdown_fd = net_socket_get_shutdown_fd(); + logging_printf( LOGGING_DEBUG, "remote_connect_sync_thread: shutdown_fd=%u\n", shutdown_fd ); - remote_connected = 1; - logging_printf(LOGGING_DEBUG, "remote_connect_ok: Connection found for [%s]\n", remote_name); + remote_service_name = config_string_get("remote.connect"); + ctx = net_ctx_find_by_name( remote_service_name ); - // Build the SYNC packet - sync_packet = net_applemidi_sync_create(); - - if( ! sync_packet ) + while( ctx && (net_socket_get_shutdown_lock()==0) ) { - logging_printf( LOGGING_ERROR, "remote_connect_ok: Unable to allocate memory for sync_packet packet\n"); - return; + FD_ZERO( &read_fds ); + FD_SET( shutdown_fd, &read_fds ); + memset( &tv, 0, sizeof( struct timeval ) ); + tv.tv_sec = config_int_get("sync.interval"); + select( shutdown_fd + 1, &read_fds, NULL , NULL , &tv ); + if( net_socket_get_shutdown_lock() == 1 ) + { + logging_printf(LOGGING_DEBUG, "remote_connect_sync_thread: shutdown received during poll\n"); + break; + } + response = net_response_sync( ctx->send_ssrc ); + net_ctx_send( ctx, response->buffer, response->len, USE_CONTROL_PORT ); + hex_dump( response->buffer, response->len ); + net_response_destroy( &response ); } - sync_packet->ssrc = ctx->send_ssrc; - sync_packet->count = 0; - sync_packet->timestamp1 = time(NULL); - sync_packet->timestamp2 = random_number(); - sync_packet->timestamp3 = random_number(); - - cmd = net_applemidi_cmd_create( NET_APPLEMIDI_CMD_SYNC ); - - if( ! cmd ) + if( net_socket_get_shutdown_lock() == 1 ) { - logging_printf( LOGGING_ERROR, "remote_connect_ok: Unable to create AppleMIDI command\n"); - net_applemidi_sync_destroy( &sync_packet ); - goto remote_ok_fail; + logging_printf(LOGGING_DEBUG, "remote_connect_sync_thread: shutdown received\n"); } + logging_printf( LOGGING_DEBUG, "remote_connect_sync_thread: stop\n"); - cmd->data = sync_packet; - - response = net_response_create(); + return NULL; +} - if( ! response ) - { - logging_printf( LOGGING_ERROR, "remote_connect_ok: Unable to create response packet\n"); - goto remote_ok_fail; - } - - int ret = 0; - ret = net_applemidi_pack( cmd , &(response->buffer), &(response->len) ); - if( ret != 0 ) - { - logging_printf( LOGGING_ERROR, "remote_connect_ok: Unable to pack response to sync_packet command\n"); - } else { - net_ctx_send( ctx, response->buffer, response->len , USE_CONTROL_PORT ); - } +void remote_connect_sync_start( void ) +{ + logging_printf( LOGGING_DEBUG, "remote_connect_sync_start: Starting sync thread\n"); + pthread_create( &sync_thread, NULL, remote_connect_sync_thread, NULL ); +} -remote_ok_fail: - net_response_destroy( &response ); - net_applemidi_cmd_destroy( &cmd ); +void remote_connect_wait_for_thread( void ) +{ + logging_printf( LOGGING_DEBUG, "remote_connect_wait_for_thread: Waiting\n"); + pthread_join( sync_thread, NULL ); + logging_printf( LOGGING_DEBUG, "remote_connect_wait_for_thread: Done\n"); } diff --git a/raveloxmidi/src/utils.c b/raveloxmidi/src/utils.c index 450635c..326242e 100644 --- a/raveloxmidi/src/utils.c +++ b/raveloxmidi/src/utils.c @@ -34,12 +34,18 @@ #include #include +#include + #include extern int errno; #include "config.h" #include "logging.h" +#include "utils.h" + +static pthread_mutex_t master_lock; + extern int errno; uint64_t ntohll(const uint64_t value) @@ -197,9 +203,10 @@ void hex_dump( unsigned char *buffer, size_t len ) /* Only do a hex dump at debug level */ DEBUG_ONLY; + GET_MASTER_LOCK(); logging_prefix_disable(); - logging_printf(LOGGING_DEBUG, "hexdump(%p , %u)\n", buffer, len ); + logging_printf(LOGGING_DEBUG, "hex_dump(%p , %u)\n", buffer, len ); if( ! buffer ) return; if( len <= 0 ) return; @@ -213,9 +220,11 @@ void hex_dump( unsigned char *buffer, size_t len ) logging_printf(LOGGING_DEBUG, "%02x %c\t", c, isprint(c) ? c : '.' ); } logging_printf(LOGGING_DEBUG, "\n"); - logging_printf(LOGGING_DEBUG, "-- end hexdump\n"); + logging_printf(LOGGING_DEBUG, "-- end hex_dump\n"); logging_prefix_enable(); + + RELEASE_MASTER_LOCK(); } void FREENULL( const char *description, void **ptr ) @@ -339,3 +348,24 @@ int random_number( void ) return rand_r( &seedp ); } + +void GET_MASTER_LOCK( void ) +{ + pthread_mutex_lock( &master_lock ); +} + +void RELEASE_MASTER_LOCK( void ) +{ + pthread_mutex_unlock( &master_lock ); +} + +void utils_init( void ) +{ + pthread_mutex_init( &master_lock , NULL); +} + +void utils_teardown( void ) +{ + pthread_mutex_destroy( &master_lock ); +} + From 10f02e812e9f9cc2a052b9d1d732395f953b48f5 Mon Sep 17 00:00:00 2001 From: Dave Kelly Date: Sun, 28 Apr 2019 13:20:31 -0700 Subject: [PATCH 28/33] More remote connection code Added some mutex locking around the connection table --- raveloxmidi/include/net_connection.h | 2 ++ raveloxmidi/src/net_connection.c | 53 +++++++++++++++++++++++----- raveloxmidi/src/net_socket.c | 1 + raveloxmidi/src/remote_connection.c | 12 +++++-- 4 files changed, 57 insertions(+), 11 deletions(-) diff --git a/raveloxmidi/include/net_connection.h b/raveloxmidi/include/net_connection.h index d53d5e2..886e87f 100644 --- a/raveloxmidi/include/net_connection.h +++ b/raveloxmidi/include/net_connection.h @@ -59,6 +59,8 @@ net_ctx_t *net_ctx_create( void ); void net_ctx_destroy( net_ctx_t **ctx ); void net_ctx_dump( net_ctx_t *ctx ); void net_ctx_dump_all( void ); +void net_ctx_lock( void ); +void net_ctx_unlock( void ); void net_ctx_init( void ); void net_ctx_teardown( void ); net_ctx_t * net_ctx_find_by_id( uint8_t id ); diff --git a/raveloxmidi/src/net_connection.c b/raveloxmidi/src/net_connection.c index 6da4929..8cb0309 100644 --- a/raveloxmidi/src/net_connection.c +++ b/raveloxmidi/src/net_connection.c @@ -28,6 +28,8 @@ #include +#include + #include extern int errno; @@ -44,9 +46,20 @@ extern int errno; static net_ctx_t *_ctx_head = NULL; static unsigned int _max_ctx = 0; - static net_ctx_t *_iterator_current = NULL; +static pthread_mutex_t ctx_mutex; + +void net_ctx_lock( void ) +{ + pthread_mutex_lock( &ctx_mutex ); +} + +void net_ctx_unlock( void ) +{ + pthread_mutex_unlock( &ctx_mutex ); +} + void net_ctx_destroy( net_ctx_t **ctx ) { net_ctx_t *next_ctx = NULL; @@ -55,6 +68,8 @@ void net_ctx_destroy( net_ctx_t **ctx ) if( ! ctx ) return; if( ! *ctx ) return; + net_ctx_lock(); + FREENULL( "name",(void **)&((*ctx)->name) ); FREENULL( "ip_address",(void **)&((*ctx)->ip_address) ); journal_destroy( &((*ctx)->journal) ); @@ -82,7 +97,8 @@ void net_ctx_destroy( net_ctx_t **ctx ) _ctx_head = next_ctx; } - FREENULL( "net_ctx_remove: ctx",(void**)ctx ); + FREENULL( "net_ctx_destroy: ctx", (void**)ctx ); + net_ctx_unlock(); } void net_ctx_dump( net_ctx_t *ctx ) @@ -98,10 +114,12 @@ void net_ctx_dump_all( void ) { DEBUG_ONLY; logging_printf( LOGGING_DEBUG, "net_ctx_dump_all: start\n"); + net_ctx_lock(); for( net_ctx_iter_start_head() ; net_ctx_iter_has_current(); net_ctx_iter_next()) { net_ctx_dump( net_ctx_iter_current() ); } + net_ctx_unlock(); logging_printf( LOGGING_DEBUG, "net_ctx_dump_all: end\n"); } @@ -158,8 +176,9 @@ void net_ctx_init( void ) if( _max_ctx == 0 ) _max_ctx = 1; _ctx_head = NULL; -} + pthread_mutex_init( &ctx_mutex, NULL ); +} void net_ctx_teardown( void ) { @@ -174,6 +193,8 @@ void net_ctx_teardown( void ) net_ctx_destroy( ¤t_ctx ); current_ctx = prev_ctx; } + + pthread_mutex_destroy( &ctx_mutex ); } net_ctx_t * net_ctx_find_by_ssrc( uint32_t ssrc) @@ -181,15 +202,20 @@ net_ctx_t * net_ctx_find_by_ssrc( uint32_t ssrc) net_ctx_t *current_ctx = NULL; logging_printf( LOGGING_DEBUG, "net_ctx_find_by_ssrc: ssrc=0x%08x\n", ssrc ); + net_ctx_lock(); for( net_ctx_iter_start_head() ; net_ctx_iter_has_current(); net_ctx_iter_next()) { current_ctx = net_ctx_iter_current(); if( current_ctx ) { - if( current_ctx->ssrc == ssrc ) return current_ctx; + if( current_ctx->ssrc == ssrc ) + { + net_ctx_unlock(); + return current_ctx; + } } } - + net_ctx_unlock(); logging_printf( LOGGING_DEBUG, "net_ctx_find_by_ssrc: not found\n"); return NULL; } @@ -200,16 +226,21 @@ net_ctx_t * net_ctx_find_by_initiator( uint32_t initiator) logging_printf( LOGGING_DEBUG, "net_ctx_find_by_initiator: initiator=0x%08x\n", initiator ); - net_ctx_dump_all(); + net_ctx_lock(); for( net_ctx_iter_start_head() ; net_ctx_iter_has_current(); net_ctx_iter_next()) { current_ctx = net_ctx_iter_current(); if( current_ctx ) { - if( current_ctx->initiator == initiator ) return current_ctx; + if( current_ctx->initiator == initiator ) + { + net_ctx_unlock(); + return current_ctx; + } } } + net_ctx_unlock(); logging_printf( LOGGING_DEBUG, "net_ctx_find_by_initiator: not found\n"); return NULL; } @@ -221,15 +252,21 @@ net_ctx_t * net_ctx_find_by_name( char *name ) if( ! name ) return NULL; logging_printf( LOGGING_DEBUG, "net_ctx_find_by_name: name=[%s]\n", name); + net_ctx_lock(); for( net_ctx_iter_start_head() ; net_ctx_iter_has_current(); net_ctx_iter_next() ) { current_ctx = net_ctx_iter_current(); if( current_ctx ) { - if( strcmp( current_ctx->name, name ) == 0 ) return current_ctx; + if( strcmp( current_ctx->name, name ) == 0 ) + { + net_ctx_unlock(); + return current_ctx; + } } } + net_ctx_unlock(); logging_printf( LOGGING_DEBUG, "net_ctx_find_by_name: not found\n"); return NULL; } diff --git a/raveloxmidi/src/net_socket.c b/raveloxmidi/src/net_socket.c index b7b8a1a..d503fb5 100644 --- a/raveloxmidi/src/net_socket.c +++ b/raveloxmidi/src/net_socket.c @@ -469,6 +469,7 @@ void net_socket_loop_shutdown(int signal) { logging_printf(LOGGING_INFO, "net_socket_loop_shutdown: signal=%d action=shutdown\n", signal); set_shutdown_lock( 1 ); + write( pipe_fd[0] , "X", 1 ); close( pipe_fd[0] ); close( pipe_fd[1] ); } diff --git a/raveloxmidi/src/remote_connection.c b/raveloxmidi/src/remote_connection.c index cec3556..d4fd5ce 100644 --- a/raveloxmidi/src/remote_connection.c +++ b/raveloxmidi/src/remote_connection.c @@ -208,15 +208,21 @@ static void *remote_connect_sync_thread( void *data ) logging_printf( LOGGING_DEBUG, "remote_connect_sync_thread: shutdown_fd=%u\n", shutdown_fd ); remote_service_name = config_string_get("remote.connect"); - ctx = net_ctx_find_by_name( remote_service_name ); - while( ctx && (net_socket_get_shutdown_lock()==0) ) + while( net_socket_get_shutdown_lock()==0 ) { + ctx = net_ctx_find_by_name( remote_service_name ); + if( ! ctx ) + { + logging_printf( LOGGING_DEBUG, "remote_connect_sync_thread: No remote connection context\n"); + break; + } FD_ZERO( &read_fds ); FD_SET( shutdown_fd, &read_fds ); memset( &tv, 0, sizeof( struct timeval ) ); tv.tv_sec = config_int_get("sync.interval"); - select( shutdown_fd + 1, &read_fds, NULL , NULL , &tv ); + select( shutdown_fd + 1, NULL, NULL , &read_fds, &tv ); + logging_printf( LOGGING_DEBUG, "remote_connect_sync_thread: select()=\"%s\"\n", strerror( errno ) ); if( net_socket_get_shutdown_lock() == 1 ) { logging_printf(LOGGING_DEBUG, "remote_connect_sync_thread: shutdown received during poll\n"); From 3c20899869653fb9c8fc3c05e5d5e0088a9704c6 Mon Sep 17 00:00:00 2001 From: Dave Kelly Date: Mon, 29 Apr 2019 20:17:57 -0700 Subject: [PATCH 29/33] More remote connection code --- raveloxmidi/src/applemidi_ok.c | 1 - raveloxmidi/src/net_connection.c | 2 +- raveloxmidi/src/net_socket.c | 1 + raveloxmidi/src/remote_connection.c | 11 +++++++---- 4 files changed, 9 insertions(+), 6 deletions(-) diff --git a/raveloxmidi/src/applemidi_ok.c b/raveloxmidi/src/applemidi_ok.c index 96440e6..9ed71f1 100644 --- a/raveloxmidi/src/applemidi_ok.c +++ b/raveloxmidi/src/applemidi_ok.c @@ -71,7 +71,6 @@ net_response_t * applemidi_ok_responder( char *ip_address, uint16_t port, void * case NET_CTX_STATUS_FIRST_INV: response = net_response_inv( ctx->send_ssrc, ctx->initiator, config_string_get("client.name") ); ctx->ssrc = ok_packet->ssrc; - net_ctx_dump_all(); net_ctx_send( ctx, response->buffer, response->len , USE_DATA_PORT ); hex_dump( response->buffer, response->len ); net_response_destroy( &response ); diff --git a/raveloxmidi/src/net_connection.c b/raveloxmidi/src/net_connection.c index 8cb0309..5cb2ea3 100644 --- a/raveloxmidi/src/net_connection.c +++ b/raveloxmidi/src/net_connection.c @@ -310,7 +310,7 @@ net_ctx_t * net_ctx_register( uint32_t ssrc, uint32_t initiator, char *ip_addres return NULL; } - send_ssrc = initiator; + send_ssrc = random_number(); net_ctx_set( new_ctx, ssrc, initiator, send_ssrc, port, ip_address , name); /* Add the connection to the list */ diff --git a/raveloxmidi/src/net_socket.c b/raveloxmidi/src/net_socket.c index d503fb5..45b0879 100644 --- a/raveloxmidi/src/net_socket.c +++ b/raveloxmidi/src/net_socket.c @@ -470,6 +470,7 @@ void net_socket_loop_shutdown(int signal) logging_printf(LOGGING_INFO, "net_socket_loop_shutdown: signal=%d action=shutdown\n", signal); set_shutdown_lock( 1 ); write( pipe_fd[0] , "X", 1 ); + write( pipe_fd[1] , "X", 1 ); close( pipe_fd[0] ); close( pipe_fd[1] ); } diff --git a/raveloxmidi/src/remote_connection.c b/raveloxmidi/src/remote_connection.c index d4fd5ce..ad6f631 100644 --- a/raveloxmidi/src/remote_connection.c +++ b/raveloxmidi/src/remote_connection.c @@ -115,6 +115,7 @@ void remote_connect_init( void ) { logging_printf( LOGGING_ERROR, "remote_connect_init: Unable to create socket context\n"); } else { + ctx->send_ssrc = ssrc; ctx->status = NET_CTX_STATUS_FIRST_INV; logging_printf( LOGGING_DEBUG, "remote_connect_init: Sending INV request to [%s]:%d\n", ctx->ip_address, ctx->control_port ); net_ctx_send( ctx, response->buffer, response->len , USE_CONTROL_PORT ); @@ -200,6 +201,7 @@ static void *remote_connect_sync_thread( void *data ) int shutdown_fd = 0; fd_set read_fds; struct timeval tv; + int sync_interval = 0; logging_printf( LOGGING_DEBUG, "remote_connect_sync_thread: start\n"); logging_printf( LOGGING_DEBUG, "rmeote_connect_sync_thread: sync.interval=%s\n", config_string_get("sync.interval")); @@ -208,8 +210,9 @@ static void *remote_connect_sync_thread( void *data ) logging_printf( LOGGING_DEBUG, "remote_connect_sync_thread: shutdown_fd=%u\n", shutdown_fd ); remote_service_name = config_string_get("remote.connect"); + sync_interval = config_int_get("sync.interval"); - while( net_socket_get_shutdown_lock()==0 ) + do { ctx = net_ctx_find_by_name( remote_service_name ); if( ! ctx ) @@ -220,8 +223,8 @@ static void *remote_connect_sync_thread( void *data ) FD_ZERO( &read_fds ); FD_SET( shutdown_fd, &read_fds ); memset( &tv, 0, sizeof( struct timeval ) ); - tv.tv_sec = config_int_get("sync.interval"); - select( shutdown_fd + 1, NULL, NULL , &read_fds, &tv ); + tv.tv_sec = sync_interval; + select( shutdown_fd + 1, &read_fds, NULL , NULL, &tv ); logging_printf( LOGGING_DEBUG, "remote_connect_sync_thread: select()=\"%s\"\n", strerror( errno ) ); if( net_socket_get_shutdown_lock() == 1 ) { @@ -232,7 +235,7 @@ static void *remote_connect_sync_thread( void *data ) net_ctx_send( ctx, response->buffer, response->len, USE_CONTROL_PORT ); hex_dump( response->buffer, response->len ); net_response_destroy( &response ); - } + } while( 1 ); if( net_socket_get_shutdown_lock() == 1 ) { From 6c32a14e82a1a0e0d817eb8462402b188586c9e7 Mon Sep 17 00:00:00 2001 From: Dave Kelly Date: Mon, 29 Apr 2019 21:29:03 -0700 Subject: [PATCH 30/33] Updated man page, README and FAQ Set remote connection name dependent on config options --- FAQ.md | 114 ++++++++++++++++++++ README.md | 130 +++------------------- raveloxmidi/configure.ac | 3 + raveloxmidi/man/raveloxmidi.1.in | 162 ++++++++++++++++++---------- raveloxmidi/src/remote_connection.c | 7 +- 5 files changed, 244 insertions(+), 172 deletions(-) diff --git a/FAQ.md b/FAQ.md index 2d7890a..7f55019 100644 --- a/FAQ.md +++ b/FAQ.md @@ -7,3 +7,117 @@ publish-aaaa-on-ipv4=no ``` Obviously, if you want to use IPv6, both those options should be set to yes You will need to restart Avahi for those changes to be picked up. + +2. How to configure and test ALSA Support + +The autotools configure script will automatically detect the presence of ALSA libraries and will build the code for support. +raveloxmidi uses the rawmidi interface so the snd-virmidi module must be loaded. + +The following steps can be taken to test everything is working: + +1. Ensure the snd-virmidi module is loaded. + +```modprobe snd-virmidi``` + +2. Verify the device names + +```sudo amidi -l``` will give output like +``` +Dir Device Name +IO hw:0,0 ES1371 +IO hw:1,0 Virtual Raw MIDI (16 subdevices) +IO hw:1,1 Virtual Raw MIDI (16 subdevices) +IO hw:1,2 Virtual Raw MIDI (16 subdevices) +IO hw:1,3 Virtual Raw MIDI (16 subdevices) +``` + +3. Install timidity and run it with the ALSA interface + +```timidity -iA``` will output the available ports to connect to (for example): + +``` +Opening sequencer port: 128:0 128:1 128:2 128:3 +``` + +4. In a raveloxmidi config file, add the option: + +```alsa.output_device = hw:1,0,0``` + +The device name will vary depending on the setup. + +5. Run raveloxmidi with the config file. In debug mode, the debug output should show lines like: + +``` +[1534193901] DEBUG: raveloxmidi_alsa_init: ret=0 Success +[1534193901] DEBUG: rawmidi: handle="hw:1,0,0" hw_id="VirMidi" hw_driver_name="Virtual Raw MIDI" flags=7 card=1 device=0 +[1534193901] DEBUG: rawmidi: handle="hw:1,0,0" hw_id="VirMidi" hw_driver_name="Virtual Raw MIDI" flags=7 card=1 device=0 +``` +6. Determine the port number for hw:1,0,0 using aconnect + +```aconnect -l``` + +This will show output like: +``` +client 0: 'System' [type=kernel] +0 'Timer ' +1 'Announce ' +client 14: 'Midi Through' [type=kernel] +0 'Midi Through Port-0' +client 16: 'Ensoniq AudioPCI' [type=kernel,card=0] +0 'ES1371 ' +client 20: 'Virtual Raw MIDI 1-0' [type=kernel,card=1] +0 'VirMIDI 1-0 ' +``` + +This shows that ```hw:1,0,0``` is port ```20:0``` + +7. Connected the port to timidty: + +```aconnect 20:0 128:0``` + +8. On the remote machine, make a connection to raveloxmidi. I have tested this with OS X. +9. (For example) In Logic Pro X, create a new external MIDI track and use the raveloxmidi connection. +10. Using the keyboard GUI in Logic Pro X, tap a few notes. The notes are played through Timidity. + + +For input support: + +1. Repeat steps 1 and 2 above if the module isn't loaded. + +2. In a raveloxmidi config file, add the option: + +```alsa.input_device = hw:1,1,0``` + +The device name will vary depending on the setup but it MUST be different from the device configuired as the output device. + +3. Run raveloxmidi with the config file. In debug mode, the debug output should show lines like: +``` +[1534193901] DEBUG: raveloxmidi_alsa_init: ret=0 Success +[1534193901] DEBUG: rawmidi: handle="hw:1,0,0" hw_id="VirMidi" hw_driver_name="Virtual Raw MIDI" flags=7 card=1 device=0 +[1534193901] DEBUG: rawmidi: handle="hw:1,1,0" hw_id="VirMidi" hw_driver_name="Virtual Raw MIDI" flags=7 card=1 device=0 +``` +4. Determine the port number for ```hw:1,1,0``` using aconnect + +```aconnect -l``` will show output like: +``` +client 0: 'System' [type=kernel] +0 'Timer ' +1 'Announce ' +client 14: 'Midi Through' [type=kernel] +0 'Midi Through Port-0' +client 16: 'Ensoniq AudioPCI' [type=kernel,card=0] +0 'ES1371 ' +client 20: 'Virtual Raw MIDI 1-0' [type=kernel,card=1] +0 'VirMIDI 1-0 ' +client 21: 'Virtual Raw MIDI 1-0' [type=kernel,card=1] +0 'VirMIDI 1-0 ' +``` +This shows that ```hw:1,1,0``` is port ```21:0``` + +5. On the remote machine make a connection raveloxmidi. +6. Run your favourite music making software that will make MIDI connections. +7. On the local machine, Using aplaymidi, take a .mid file and run: + +```aplaymidi -p 21:0 name-of-midi-file.mid``` + +The MIDI events should be processed through the remote software. diff --git a/README.md b/README.md index 176bb51..194e519 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,7 @@ The reason for writing this was to generate note events from a Raspberry Pi to s Thanks to feedback from a couple of users, I've also tested this with rtpMIDI on Windows talking to FL Studio 11. -The build will auto-detect ALSA and build rawmidi support. See below for ALSA requirements. Thanks to Daniel Collins (malacalypse) for being the guinea pig for this. +The build will auto-detect ALSA and build rawmidi support. Please read **FAQ.md** for ALSA requirements. Thanks to Daniel Collins (malacalypse) for being the guinea pig for this. Except for the Avahi code, it's all mine but I have leaned heavily on the following references: @@ -85,7 +85,7 @@ For debugging, you can run ```raveloxmidi -N -d``` to keep raveloxmidi in the fo ``` network.bind_address IP address that raveloxmidi listens on. This can be an IPv4 or IPv6 address. - Default is 0.0.0.0 ( meaning all interfaces ). IPv6 equivalent is :: + Default is 0.0.0.0 ( meaning all IPv4 interfaces ). IPv6 equivalent is :: network.control.port Main RTP MIDI listening port for new connections and shutdowns. Used in the zeroconf definition for the RTP MIDI service. @@ -96,15 +96,25 @@ network.data.port network.local.port Local listening port for accepting MIDI events. Default is 5006. +service.ipv4 + Indicate whether Avahi service should use IPv4 addresses. Default is yes. +service.ipv6 + Indicate whether Avahi service should use IPv6 addressed. Default is no. network.max_connections Maximum number of incoming connections that can be stored. Default is 8. service.name Name used in the zeroconf definition for the RTP MIDI service. Default is 'raveloxmidi'. +remote.connect + Name of remote service to connect to. +client.name + Name to use when connecting to remote service. If not defined, service.name will be used. network.socket_timeout Polling timeout for the listening sockets. Default is 30 seconds. +discover.timeout + Length of time in seconds to wait for new remote services to be seen. Default is 5 seconds. run_as_daemon Specifies that raveloxmidi should run in the background. Default is yes. @@ -129,6 +139,8 @@ inbound_midi file_mode File permissions on the inbound_midi file if it needs to be created. Specify as Unix octal permissions. Default is 0640. +sync.interval + Interval in seconds between SYNC commands for timing purposes. Default is 10s. ``` If ALSA is detected, the following options are also available: @@ -142,117 +154,3 @@ alsa.input_buffer_size Size of the buffer to use for reading data from the input device. Default is 4096. Maximum is 65535. ``` - -## ALSA Support - -The autotools configure script will automatically detect the presence of ALSA libraries and will build the code for support. -raveloxmidi uses the rawmidi interface so the snd-virmidi module must be loaded. - -The following steps can be taken to test everything is working: - -1. Ensure the snd-virmidi module is loaded. - -```modprobe snd-virmidi``` - -2. Verify the device names - -```sudo amidi -l``` will give output like -``` -Dir Device Name -IO hw:0,0 ES1371 -IO hw:1,0 Virtual Raw MIDI (16 subdevices) -IO hw:1,1 Virtual Raw MIDI (16 subdevices) -IO hw:1,2 Virtual Raw MIDI (16 subdevices) -IO hw:1,3 Virtual Raw MIDI (16 subdevices) -``` - -3. Install timidity and run it with the ALSA interface - -```timidity -iA``` will output the available ports to connect to (for example): - -``` -Opening sequencer port: 128:0 128:1 128:2 128:3 -``` - -4. In a raveloxmidi config file, add the option: - -```alsa.output_device = hw:1,0,0``` - -The device name will vary depending on the setup. - -5. Run raveloxmidi with the config file. In debug mode, the debug output should show lines like: - -``` -[1534193901] DEBUG: raveloxmidi_alsa_init: ret=0 Success -[1534193901] DEBUG: rawmidi: handle="hw:1,0,0" hw_id="VirMidi" hw_driver_name="Virtual Raw MIDI" flags=7 card=1 device=0 -[1534193901] DEBUG: rawmidi: handle="hw:1,0,0" hw_id="VirMidi" hw_driver_name="Virtual Raw MIDI" flags=7 card=1 device=0 -``` -6. Determine the port number for hw:1,0,0 using aconnect - -```aconnect -l``` - -This will show output like: -``` -client 0: 'System' [type=kernel] -0 'Timer ' -1 'Announce ' -client 14: 'Midi Through' [type=kernel] -0 'Midi Through Port-0' -client 16: 'Ensoniq AudioPCI' [type=kernel,card=0] -0 'ES1371 ' -client 20: 'Virtual Raw MIDI 1-0' [type=kernel,card=1] -0 'VirMIDI 1-0 ' -``` - -This shows that ```hw:1,0,0``` is port ```20:0``` - -7. Connected the port to timidty: - -```aconnect 20:0 128:0``` - -8. On the remote machine, make a connection to raveloxmidi. I have tested this with OS X. -9. (For example) In Logic Pro X, create a new external MIDI track and use the raveloxmidi connection. -10. Using the keyboard GUI in Logic Pro X, tap a few notes. The notes are played through Timidity. - - -For input support: - -1. Repeat steps 1 and 2 above if the module isn't loaded. - -2. In a raveloxmidi config file, add the option: - -```alsa.input_device = hw:1,1,0``` - -The device name will vary depending on the setup but it MUST be different from the device configuired as the output device. - -3. Run raveloxmidi with the config file. In debug mode, the debug output should show lines like: -``` -[1534193901] DEBUG: raveloxmidi_alsa_init: ret=0 Success -[1534193901] DEBUG: rawmidi: handle="hw:1,0,0" hw_id="VirMidi" hw_driver_name="Virtual Raw MIDI" flags=7 card=1 device=0 -[1534193901] DEBUG: rawmidi: handle="hw:1,1,0" hw_id="VirMidi" hw_driver_name="Virtual Raw MIDI" flags=7 card=1 device=0 -``` -4. Determine the port number for ```hw:1,1,0``` using aconnect - -```aconnect -l``` will show output like: -``` -client 0: 'System' [type=kernel] -0 'Timer ' -1 'Announce ' -client 14: 'Midi Through' [type=kernel] -0 'Midi Through Port-0' -client 16: 'Ensoniq AudioPCI' [type=kernel,card=0] -0 'ES1371 ' -client 20: 'Virtual Raw MIDI 1-0' [type=kernel,card=1] -0 'VirMIDI 1-0 ' -client 21: 'Virtual Raw MIDI 1-0' [type=kernel,card=1] -0 'VirMIDI 1-0 ' -``` -This shows that ```hw:1,1,0``` is port ```21:0``` - -5. On the remote machine make a connection raveloxmidi. -6. Run your favourite music making software that will make MIDI connections. -7. On the local machine, Using aplaymidi, take a .mid file and run: - -```aplaymidi -p 21:0 name-of-midi-file.mid``` - -The MIDI events should be processed through the remote software. diff --git a/raveloxmidi/configure.ac b/raveloxmidi/configure.ac index 2c96f16..9a973bd 100755 --- a/raveloxmidi/configure.ac +++ b/raveloxmidi/configure.ac @@ -40,4 +40,7 @@ then AC_OUTPUT( DEBIAN/control pkgscripts/build_deb ) fi +COPYRIGHT_YEAR="`date +'%Y'`" +AC_SUBST(COPYRIGHT_YEAR) + AC_OUTPUT(Makefile src/Makefile man/Makefile man/raveloxmidi.1 raveloxmidi.spec) diff --git a/raveloxmidi/man/raveloxmidi.1.in b/raveloxmidi/man/raveloxmidi.1.in index 6337a32..5495d49 100644 --- a/raveloxmidi/man/raveloxmidi.1.in +++ b/raveloxmidi/man/raveloxmidi.1.in @@ -1,18 +1,16 @@ .TH raveloxmidi "@VERSION@" .SH NAME -raveloxmidi - RTP MIDI proxy for NoteOn/NoteOff/ControlChange/ProgramChange events +raveloxmidi \- RTP MIDI proxy for NoteOn/NoteOff/ControlChange/ProgramChange events .SH SYNOPSIS -.B raveloxmidi -[-c filename] [-d|-i] [-N] [-P filename] [-R] [-h] [-C] [-T seconds] +\fBraveloxmidi\fP [-c filename] [-d|-i] [-N] [-P \fIfilename\fP] [-R] [-h] [-C] -.B raveloxmidi -[--config filename] [--debug|--info] [--nodaemon] [--pidfile filename] [--readonly] [--help] [--dumpconfig] +\fBraveloxmidi\fP [\-\-config \fIfilename\fP] [\-\-debug|\-\-info] [\-\-nodaemon] [\-\-pidfile \fIfilename\fP] [\-\-readonly] [\-\-help] [\-\-dumpconfig] .SH DESCRIPTION .BR raveloxmidi provides a RTP MIDI proxy to send MIDI NoteOn, NoteOff, ControlChange and ProgramChange events to a remote MIDI device. .SH OPTIONS .TP -.B -c filename +.B -c \fIfilename\fP Name of configuration file to use. If no configuration file is provided, some defaults are assumed. See below for details. .TP .B -d @@ -24,10 +22,10 @@ Run in info mode. This will provide info-level output to either stdout or the co .B -N Do not run as a daemon. .TP -.B -P pidfile -File to store the pid of the running process. Default is -.B raveloxmidi.pid -in the current directory. +.B -P \fIpidfile\fP +File to store the pid of the running process. +.br +Default is \fBraveloxmidi.pid \fP in the current directory. .TP .B -R Enable readonly mode. This doesn't write anything to disk. @@ -41,73 +39,127 @@ Display the current config to stderr The available options for the configuration file are as follows: .TP .B network.bind_address -Address to bind the listening sockets. This can be IPv4 or IPv6 ( default is 0.0.0.0 ) +IP address that raveloxmidi listens on. This can be an IPv4 or IPv6 address. +.br +Default is 0.0.0.0 ( meaning all IPv4 interfaces ). IPv6 equivalent is :: .TP -.B network.rtpmidi.port -Port to listen on for RTP MIDI events from remote clients ( default is 5004 ) +.B network.control.port +Main RTP MIDI listening port for new connections and shutdowns. Used in the Avahi definition for the RTP MIDI service. +.br +Default is 5004. .TP -.B network.rtsp.port -Port to listen on for RTSP events from remote clients ( default is 5005 ) +.B network.data.port +Listening port for all other data in the conversation. +.br +Default is 5005. .TP .B network.local.port -Port to listen on for local MIDI ( default is 5006 ) +Local listening port for accepting MIDI events. +.br +Default is 5006. .TP -.B network.socket_timeout -Polling interval (in seconds) to listen for network events ( default is 30 ) +.B service.ipv4 +Indicate whether Avahi service should use IPv4 addresses. +.br +Default is yes. +.TP +.B service.ipv6 +Indicate whether Avahi service should use IPv6 addressed. +.br +Default is no. .TP .B network.max_connections -Number of connections that can be made to @PACKAGE@. Maximum is 255. Minimum is 1. ( default is 8 ). +Maximum number of incoming connections that can be stored. +.br +Default is 8. .TP .B service.name -Label to prepend to mDNS service name "_apple-midi._udp". ( default is raveloxmidi ) +Name used in the Avahi definition for the RTP MIDI service. +.br +Default is \fBraveloxmidi\fP. .TP -.B discover.services -List the available _apple-midi._udp services. This will exit once complete. Default is no. -.TP -.B discover.timeout -Timeout for service discovery. Default is 10 seconds. +.B remote.connect +Name of remote service to connect to. .TP .B client.name -Label to use when making a rtpMIDI connection to a remote service. ( default is raveloxremote ) -.TP -.B run_as_daemon -Run the binary in the background. Can be yes or no. ( default is yes ). -.TP -.B daemon.pid_file -Name of file to write pid of background process. ( Default is raveloxmidi.pid ). +Name to use when connecting to remote service. If not defined, service.name will be used. .TP -.B logging.enabled -Write logging events to stdout or a named file. Can be yes or no. ( default is yes ). -.TP -.B logging.log_file -Name of file to write logging events. If no filename is supplied, logging events will go to stdout. ( default is null ). -.TP -.B logging.log_level -Level of logging events to be written if enabled. Can be -.B DEBUG, INFO, NORMAL, WARNING or ERROR -( default is NORMAL ) -.TP -.B security.check -Enables or disables rudimentary check on the named pid file to prevent the daemon.pid_file option being used to overwrite executable files. Can be yes or no. ( default is yes ). -.TP -.B inbound_midi -Name of file to write inbound MIDI events to. This file is governed by the security check option. Default is -.B /dev/sequencer +.B network.socket_timeout +Polling timeout for the listening sockets. +.br +Default is 30 seconds. .TP -.B file_mode -File permissions on the inbound_midi file if it needs to be created. Specify as Unix octal permissions. Default is 0640. +.B discover.timeout +Length of time in seconds to wait for new remote services to be seen. +.br +Default is 5 seconds. .TP -.B The following options are available if raveloxmidi is built with ALSA support: +.B run_as_daemon +Specifies that raveloxmidi should run in the background. +.br +Default is yes. +.TP +.B +daemon.pid_file +If raveloxmidi is run in the background. The pid for the process is written to this file. +.br +Default is \fBraveloxmidi.pid\fP. +.TP +.B +logging.enabled +Set to yes to write output to a log file. Set to no to disable. +.br +Default is yes. +.TP +.B +logging.log_file +Name of file to write logging to. +.br +Default is \fBstderr\fP. +.TP +.B +logging.log_level +Threshold for log events. Acceptable values are \fBdebug\fP , \fBinfo\fP , \fBnormal\fP , \fBwarning\fP and \fBerror\fP. +.br +Default is normal. +.TP +.B +security.check +If set to yes, it is not possible to write the daemon pid to a file with executable permissions. +.br +Default is yes. +.TP +.B +inbound_midi +Name of file to write inbound MIDI events to. This file is governed by the security check option. +.br +Default is \fB/dev/sequencer\fP. +.TP +.B +file_mode +File permissions on the inbound_midi file if it needs to be created. Specify as Unix octal permissions. +.br +Default is 0640. +.TP +.B +sync.interval +Interval in seconds between SYNC commands for timing purposes. +.br +Default is 10s. +.TP +If ALSA is detected, the following options are also available: .TP .B alsa.output_device Name of the rawmidi ALSA device to send MIDI events to. .TP .B alsa.input_device Name of the rawmidi ALSA device to read MIDI events from. -.TP +.TP .B alsa.input_buffer_size -Size of the buffer to use for reading data from the input device. Default is 4096. Maximum is 65535. +Size of the buffer to use for reading data from the input device. +.br +Default is 4096. Maximum is 65535. .fi .SH AUTHOR .B raveloxmidi -is developed by Dave Kelly (c) 2014 +is developed by Dave Kelly (c) @COPYRIGHT_YEAR@ diff --git a/raveloxmidi/src/remote_connection.c b/raveloxmidi/src/remote_connection.c index ad6f631..99591a7 100644 --- a/raveloxmidi/src/remote_connection.c +++ b/raveloxmidi/src/remote_connection.c @@ -100,9 +100,14 @@ void remote_connect_init( void ) initiator = random_number(); client_name = config_string_get("client.name"); + if( !client_name ) { - client_name = (char *)strdup( "RaveloxMIDIClient" ); + client_name = config_string_get("service.name"); + if( ! client_name ) + { + client_name = "RaveloxMIDIClient"; + } } response = net_response_inv( ssrc, initiator, client_name ); From 126a5973041b901994b2267e42f9aa33291d8b18 Mon Sep 17 00:00:00 2001 From: Dave Kelly Date: Thu, 16 May 2019 21:36:03 -0700 Subject: [PATCH 31/33] More remote connection code --- README.md | 3 ++- python/note_send.py | 4 +-- raveloxmidi/configure.ac | 6 ++--- raveloxmidi/include/net_connection.h | 2 +- raveloxmidi/include/utils.h | 5 ++-- raveloxmidi/man/raveloxmidi.1.in | 5 +--- raveloxmidi/src/Makefile.am | 2 +- raveloxmidi/src/applemidi_ok.c | 3 ++- raveloxmidi/src/applemidi_sync.c | 10 ++++---- raveloxmidi/src/net_connection.c | 8 ++++-- raveloxmidi/src/net_socket.c | 5 ++-- raveloxmidi/src/raveloxmidi_config.c | 2 +- raveloxmidi/src/remote_connection.c | 8 ++---- raveloxmidi/src/utils.c | 38 ++++++++++++++++++---------- 14 files changed, 55 insertions(+), 46 deletions(-) diff --git a/README.md b/README.md index 194e519..f6c8916 100644 --- a/README.md +++ b/README.md @@ -18,6 +18,7 @@ Except for the Avahi code, it's all mine but I have leaned heavily on the follow Note: Where possible, I've tried to use RTP MIDI to mean the protocol and rtpMIDI to mean the software written by Tobias Erichsen. Some mistakes may be present but, in most cases, I am referring to the protocol +Some Apple documentation is available at https://developer.apple.com/library/archive/documentation/Audio/Conceptual/MIDINetworkDriverProtocol/MIDI/MIDI.html I'm doing this purely for fun and don't expect anyone else to use it but I'm happy to accept suggestions if you ever come across this code. @@ -140,7 +141,7 @@ file_mode File permissions on the inbound_midi file if it needs to be created. Specify as Unix octal permissions. Default is 0640. sync.interval - Interval in seconds between SYNC commands for timing purposes. Default is 10s. + Interval in seconds between SYNC commands for timing purposes. Default is 60s. ``` If ALSA is detected, the following options are also available: diff --git a/python/note_send.py b/python/note_send.py index 4e62261..c8ffab0 100755 --- a/python/note_send.py +++ b/python/note_send.py @@ -22,13 +22,13 @@ s.connect( connect_tuple ) # Note ON -bytes = struct.pack( "BBBB", 0xaa, 0x96, 0x30, 0x7f ) +bytes = struct.pack( "BBBB", 0xaa, 0x90, 0x30, 0x40 ) s.send( bytes ) time.sleep( 0.25 ); # Note OFF -bytes = struct.pack( "BBBB", 0xaa, 0x86, 0x30, 0x7f ) +bytes = struct.pack( "BBBB", 0xaa, 0x80, 0x30, 0x40 ) s.send( bytes ) s.close() diff --git a/raveloxmidi/configure.ac b/raveloxmidi/configure.ac index 9a973bd..442e5e2 100755 --- a/raveloxmidi/configure.ac +++ b/raveloxmidi/configure.ac @@ -1,11 +1,9 @@ -AC_INIT() +AC_INIT([raveloxmidi],[0.6.99]) AC_CANONICAL_HOST AC_CANONICAL_BUILD AC_CANONICAL_TARGET -AC_CONFIG_MACRO_DIRS([m4]) - -AM_INIT_AUTOMAKE(raveloxmidi, 0.6.99) +AM_INIT_AUTOMAKE AC_CONFIG_HEADERS([config.h]) AC_GNU_SOURCE diff --git a/raveloxmidi/include/net_connection.h b/raveloxmidi/include/net_connection.h index 886e87f..d28f89c 100644 --- a/raveloxmidi/include/net_connection.h +++ b/raveloxmidi/include/net_connection.h @@ -47,7 +47,7 @@ typedef struct net_ctx_t { uint32_t seq; uint16_t control_port; uint16_t data_port; - time_t start; + long start; char * ip_address; char * name; journal_t *journal; diff --git a/raveloxmidi/include/utils.h b/raveloxmidi/include/utils.h index 6f53e5a..4b043d4 100644 --- a/raveloxmidi/include/utils.h +++ b/raveloxmidi/include/utils.h @@ -41,9 +41,10 @@ char *get_ip_string( struct sockaddr *sa, char *s, size_t maxlen ); int get_sock_info( char *ip_address, int port, struct sockaddr *socket, socklen_t *socklen, int *family); int random_number( void ); +long time_in_microseconds( void ); -void GET_MASTER_LOCK( void ); -void RELEASE_MASTER_LOCK( void ); +void utils_lock( void ); +void utils_unlock( void ); void utils_init( void ); void utils_teardown( void ); diff --git a/raveloxmidi/man/raveloxmidi.1.in b/raveloxmidi/man/raveloxmidi.1.in index 5495d49..5615c65 100644 --- a/raveloxmidi/man/raveloxmidi.1.in +++ b/raveloxmidi/man/raveloxmidi.1.in @@ -81,9 +81,6 @@ Default is \fBraveloxmidi\fP. .B remote.connect Name of remote service to connect to. .TP -.B client.name -Name to use when connecting to remote service. If not defined, service.name will be used. -.TP .B network.socket_timeout Polling timeout for the listening sockets. .br @@ -145,7 +142,7 @@ Default is 0640. sync.interval Interval in seconds between SYNC commands for timing purposes. .br -Default is 10s. +Default is 60s per \rBhttps://developer.apple.com/library/archive/documentation/Audio/Conceptual/MIDINetworkDriverProtocol/MIDI/MIDI.html\fP .TP If ALSA is detected, the following options are also available: .TP diff --git a/raveloxmidi/src/Makefile.am b/raveloxmidi/src/Makefile.am index e6600bc..5e8b3b1 100755 --- a/raveloxmidi/src/Makefile.am +++ b/raveloxmidi/src/Makefile.am @@ -37,4 +37,4 @@ raveloxmidi_CFLAGS = @PTHREAD_CFLAGS@ @AVAHI_CFLAGS@ @ALSA_CFLAGS@ EXTRA_DIST = -INCLUDES = -I ../include +AM_CPPFLAGS = -I ../include diff --git a/raveloxmidi/src/applemidi_ok.c b/raveloxmidi/src/applemidi_ok.c index 9ed71f1..57f9c79 100644 --- a/raveloxmidi/src/applemidi_ok.c +++ b/raveloxmidi/src/applemidi_ok.c @@ -69,7 +69,7 @@ net_response_t * applemidi_ok_responder( char *ip_address, uint16_t port, void * switch( ctx->status ) { case NET_CTX_STATUS_FIRST_INV: - response = net_response_inv( ctx->send_ssrc, ctx->initiator, config_string_get("client.name") ); + response = net_response_inv( ctx->send_ssrc, ctx->initiator, config_string_get("service.name") ); ctx->ssrc = ok_packet->ssrc; net_ctx_send( ctx, response->buffer, response->len , USE_DATA_PORT ); hex_dump( response->buffer, response->len ); @@ -84,6 +84,7 @@ net_response_t * applemidi_ok_responder( char *ip_address, uint16_t port, void * net_response_destroy( &response ); response = NULL; ctx->status = NET_CTX_STATUS_REMOTE_CONNECTION; + logging_printf( LOGGING_INFO, "Remote connection established to [%s]\n", ok_packet->name ); remote_connect_sync_start(); break; default: diff --git a/raveloxmidi/src/applemidi_sync.c b/raveloxmidi/src/applemidi_sync.c index a283780..2b9272e 100644 --- a/raveloxmidi/src/applemidi_sync.c +++ b/raveloxmidi/src/applemidi_sync.c @@ -51,8 +51,8 @@ net_response_t * applemidi_sync_responder( void *data ) net_applemidi_sync *sync_resp = NULL; net_ctx_t *ctx = NULL; net_response_t *response = NULL; - uint32_t delta = 0; - time_t current_time = 0; + long delta = 0; + long current_time = 0; logging_printf( LOGGING_DEBUG, "applemidi_sync_responder: start\n"); @@ -94,12 +94,12 @@ net_response_t * applemidi_sync_responder( void *data ) sync_resp->timestamp2 = sync->timestamp2; sync_resp->timestamp3 = sync->timestamp3; - logging_printf( LOGGING_DEBUG, "applemidi_sync_responder: now=%u start=%u delta=0x%08x\n", current_time, ctx->start, delta ); + memcpy( sync_resp->padding, sync->padding, 3 ); - current_time = time( NULL ); + current_time = time_in_microseconds(); delta = current_time - ctx->start; - logging_printf( LOGGING_DEBUG, "applemidi_sync_responder: now=%u start=%u delta=0x%08x\n", current_time, ctx->start, delta ); + logging_printf( LOGGING_DEBUG, "applemidi_sync_responder: now=%ld start=%ld delta=%ld\n", current_time, ctx->start, delta ); switch( sync_resp->count ) { diff --git a/raveloxmidi/src/net_connection.c b/raveloxmidi/src/net_connection.c index 5cb2ea3..dd87e27 100644 --- a/raveloxmidi/src/net_connection.c +++ b/raveloxmidi/src/net_connection.c @@ -132,7 +132,7 @@ static void net_ctx_set( net_ctx_t *ctx, uint32_t ssrc, uint32_t initiator, uint ctx->initiator = initiator; ctx->control_port = port; ctx->data_port = port+1; - ctx->start = time( NULL ); + ctx->start = time_in_microseconds(); if( ctx->ip_address ) { @@ -140,6 +140,9 @@ static void net_ctx_set( net_ctx_t *ctx, uint32_t ssrc, uint32_t initiator, uint } ctx->ip_address = ( char *) strdup( ip_address ); ctx->name = ( char *) strdup( name ); + + logging_printf( LOGGING_DEBUG, "net_ctx_set\n"); + net_ctx_dump( ctx ); } net_ctx_t * net_ctx_create( void ) @@ -261,6 +264,7 @@ net_ctx_t * net_ctx_find_by_name( char *name ) if( strcmp( current_ctx->name, name ) == 0 ) { net_ctx_unlock(); + logging_printf( LOGGING_DEBUG, "net_ctx_find_by_name: found\n"); return current_ctx; } } @@ -388,7 +392,7 @@ void net_ctx_update_rtp_fields( net_ctx_t *ctx, rtp_packet_t *rtp_packet) if( ! ctx ) return; rtp_packet->header.seq = ctx->seq; - rtp_packet->header.timestamp = time(0) - ctx->start; + rtp_packet->header.timestamp = time_in_microseconds() - ctx->start; rtp_packet->header.ssrc = ctx->send_ssrc; } diff --git a/raveloxmidi/src/net_socket.c b/raveloxmidi/src/net_socket.c index 45b0879..2cc9c45 100644 --- a/raveloxmidi/src/net_socket.c +++ b/raveloxmidi/src/net_socket.c @@ -467,10 +467,11 @@ int net_socket_fd_loop() void net_socket_loop_shutdown(int signal) { + int ret = 0; logging_printf(LOGGING_INFO, "net_socket_loop_shutdown: signal=%d action=shutdown\n", signal); set_shutdown_lock( 1 ); - write( pipe_fd[0] , "X", 1 ); - write( pipe_fd[1] , "X", 1 ); + ret = write( pipe_fd[0] , "X", 1 ); + ret = write( pipe_fd[1] , "X", 1 ); close( pipe_fd[0] ); close( pipe_fd[1] ); } diff --git a/raveloxmidi/src/raveloxmidi_config.c b/raveloxmidi/src/raveloxmidi_config.c index 8f95de4..7819687 100644 --- a/raveloxmidi/src/raveloxmidi_config.c +++ b/raveloxmidi/src/raveloxmidi_config.c @@ -55,7 +55,7 @@ static void config_set_defaults( void ) config_add_item("inbound_midi","/dev/sequencer"); config_add_item("file_mode", "0640"); config_add_item("discover.timeout","5"); - config_add_item("sync.interval","10"); + config_add_item("sync.interval","60"); #ifdef HAVE_ALSA config_add_item("alsa.input_buffer_size", "4096" ); #endif diff --git a/raveloxmidi/src/remote_connection.c b/raveloxmidi/src/remote_connection.c index 99591a7..2f0bb8a 100644 --- a/raveloxmidi/src/remote_connection.c +++ b/raveloxmidi/src/remote_connection.c @@ -99,15 +99,11 @@ void remote_connect_init( void ) ssrc = random_number(); initiator = random_number(); - client_name = config_string_get("client.name"); + client_name = config_string_get("service.name"); if( !client_name ) { - client_name = config_string_get("service.name"); - if( ! client_name ) - { - client_name = "RaveloxMIDIClient"; - } + client_name = "RaveloxMIDIClient"; } response = net_response_inv( ssrc, initiator, client_name ); diff --git a/raveloxmidi/src/utils.c b/raveloxmidi/src/utils.c index 326242e..3896b95 100644 --- a/raveloxmidi/src/utils.c +++ b/raveloxmidi/src/utils.c @@ -44,7 +44,8 @@ extern int errno; #include "utils.h" -static pthread_mutex_t master_lock; +static pthread_mutex_t utils_thread_lock; +static unsigned int random_seed = 0; extern int errno; @@ -203,7 +204,7 @@ void hex_dump( unsigned char *buffer, size_t len ) /* Only do a hex dump at debug level */ DEBUG_ONLY; - GET_MASTER_LOCK(); + utils_lock(); logging_prefix_disable(); logging_printf(LOGGING_DEBUG, "hex_dump(%p , %u)\n", buffer, len ); @@ -224,7 +225,7 @@ void hex_dump( unsigned char *buffer, size_t len ) logging_prefix_enable(); - RELEASE_MASTER_LOCK(); + utils_unlock(); } void FREENULL( const char *description, void **ptr ) @@ -342,30 +343,39 @@ int get_sock_info( char *ip_address, int port, struct sockaddr *socket, socklen_ int random_number( void ) { - static unsigned int seedp = 0; - - seedp = time(NULL); + int ret = 0; + + utils_lock(); + ret = rand_r( &random_seed ); + utils_unlock(); - return rand_r( &seedp ); + return ret; } -void GET_MASTER_LOCK( void ) +long time_in_microseconds( void ) +{ + struct timeval currentTime; + gettimeofday( ¤tTime, NULL ); + return currentTime.tv_sec * (int)1e6 + currentTime.tv_usec; +} + +void utils_lock( void ) { - pthread_mutex_lock( &master_lock ); + pthread_mutex_lock( &utils_thread_lock ); } -void RELEASE_MASTER_LOCK( void ) +void utils_unlock( void ) { - pthread_mutex_unlock( &master_lock ); + pthread_mutex_unlock( &utils_thread_lock ); } void utils_init( void ) { - pthread_mutex_init( &master_lock , NULL); + pthread_mutex_init( &utils_thread_lock , NULL); + random_seed = time(NULL); } void utils_teardown( void ) { - pthread_mutex_destroy( &master_lock ); + pthread_mutex_destroy( &utils_thread_lock ); } - From 644766ae554247d2ca726e7f36b6e929a530cdfe Mon Sep 17 00:00:00 2001 From: Dave Kelly Date: Thu, 16 May 2019 22:34:31 -0700 Subject: [PATCH 32/33] Remote connection code --- raveloxmidi/src/utils.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/raveloxmidi/src/utils.c b/raveloxmidi/src/utils.c index 3896b95..4a72748 100644 --- a/raveloxmidi/src/utils.c +++ b/raveloxmidi/src/utils.c @@ -356,7 +356,7 @@ long time_in_microseconds( void ) { struct timeval currentTime; gettimeofday( ¤tTime, NULL ); - return currentTime.tv_sec * (int)1e6 + currentTime.tv_usec; + return ( currentTime.tv_sec * (int)1e6 + currentTime.tv_usec ) / 100 ; } void utils_lock( void ) From af84b1f73d7e48eba52504b76d81e5ab29070236 Mon Sep 17 00:00:00 2001 From: Dave Kelly Date: Fri, 17 May 2019 20:10:26 -0700 Subject: [PATCH 33/33] Fixed AppleMIDI interaction with remote connection --- raveloxmidi/include/net_response.h | 2 +- raveloxmidi/src/applemidi_ok.c | 2 +- raveloxmidi/src/net_applemidi.c | 2 +- raveloxmidi/src/net_response.c | 8 ++++---- raveloxmidi/src/remote_connection.c | 2 +- 5 files changed, 8 insertions(+), 8 deletions(-) diff --git a/raveloxmidi/include/net_response.h b/raveloxmidi/include/net_response.h index 8a8083c..16c5152 100644 --- a/raveloxmidi/include/net_response.h +++ b/raveloxmidi/include/net_response.h @@ -30,6 +30,6 @@ net_response_t * net_response_create( void ); void net_response_destroy( net_response_t **response ); net_response_t *net_response_inv( uint32_t ssrc, uint32_t initiator, char *name); -net_response_t *net_response_sync( uint32_t send_ssrc ); +net_response_t *net_response_sync( uint32_t send_ssrc , long start_time); #endif diff --git a/raveloxmidi/src/applemidi_ok.c b/raveloxmidi/src/applemidi_ok.c index 57f9c79..f5ea9c0 100644 --- a/raveloxmidi/src/applemidi_ok.c +++ b/raveloxmidi/src/applemidi_ok.c @@ -78,7 +78,7 @@ net_response_t * applemidi_ok_responder( char *ip_address, uint16_t port, void * ctx->status = NET_CTX_STATUS_SECOND_INV; break; case NET_CTX_STATUS_SECOND_INV: - response = net_response_sync( ctx->send_ssrc ); + response = net_response_sync( ctx->send_ssrc , ctx->start ); net_ctx_send( ctx, response->buffer, response->len, USE_CONTROL_PORT ); hex_dump( response->buffer, response->len ); net_response_destroy( &response ); diff --git a/raveloxmidi/src/net_applemidi.c b/raveloxmidi/src/net_applemidi.c index adeabf8..443dc88 100644 --- a/raveloxmidi/src/net_applemidi.c +++ b/raveloxmidi/src/net_applemidi.c @@ -152,7 +152,7 @@ net_applemidi_sync * net_applemidi_sync_create( void ) if( sync ) { - memset( sync, 0 , sizeof( net_applemidi_sync ) ); + memset( sync, 0, sizeof( net_applemidi_sync ) ); } return sync; diff --git a/raveloxmidi/src/net_response.c b/raveloxmidi/src/net_response.c index 76e6cd3..2254aa4 100644 --- a/raveloxmidi/src/net_response.c +++ b/raveloxmidi/src/net_response.c @@ -124,7 +124,7 @@ net_response_t *net_response_inv( uint32_t ssrc, uint32_t initiator, char *name return NULL; } -net_response_t *net_response_sync( uint32_t send_ssrc ) +net_response_t *net_response_sync( uint32_t send_ssrc , long start_time ) { net_applemidi_sync *sync = NULL; net_response_t *response = NULL; @@ -140,9 +140,9 @@ net_response_t *net_response_sync( uint32_t send_ssrc ) sync->ssrc = send_ssrc; sync->count = 0; - sync->timestamp1 = time(NULL); - sync->timestamp2 = 0; - sync->timestamp3 = 0; + sync->timestamp1 = time_in_microseconds() - start_time; + sync->timestamp2 = random_number(); + sync->timestamp3 = random_number(); cmd = net_applemidi_cmd_create( NET_APPLEMIDI_CMD_SYNC ); diff --git a/raveloxmidi/src/remote_connection.c b/raveloxmidi/src/remote_connection.c index 2f0bb8a..0336c69 100644 --- a/raveloxmidi/src/remote_connection.c +++ b/raveloxmidi/src/remote_connection.c @@ -232,7 +232,7 @@ static void *remote_connect_sync_thread( void *data ) logging_printf(LOGGING_DEBUG, "remote_connect_sync_thread: shutdown received during poll\n"); break; } - response = net_response_sync( ctx->send_ssrc ); + response = net_response_sync( ctx->send_ssrc , ctx->start ); net_ctx_send( ctx, response->buffer, response->len, USE_CONTROL_PORT ); hex_dump( response->buffer, response->len ); net_response_destroy( &response );