aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorcbdev <cb@cbcdn.com>2020-04-25 23:33:54 +0200
committercbdev <cb@cbcdn.com>2020-04-25 23:33:54 +0200
commit3691faaaf6da4d479c31b0246949be2f4a02b8b5 (patch)
tree3fcf25a5c1bd7eccb7d4128b6a8b1b77ff424c49
parentceefbdb7eddfdccd7b1b6cb452f920382cdae4b0 (diff)
downloadmidimonster-3691faaaf6da4d479c31b0246949be2f4a02b8b5.tar.gz
midimonster-3691faaaf6da4d479c31b0246949be2f4a02b8b5.tar.bz2
midimonster-3691faaaf6da4d479c31b0246949be2f4a02b8b5.zip
Implement maweb fallback connections
-rw-r--r--backends/maweb.c109
-rw-r--r--backends/maweb.h7
-rw-r--r--backends/maweb.md12
3 files changed, 95 insertions, 33 deletions
diff --git a/backends/maweb.c b/backends/maweb.c
index c2f6311..192c69e 100644
--- a/backends/maweb.c
+++ b/backends/maweb.c
@@ -163,19 +163,29 @@ static int maweb_configure_instance(instance* inst, char* option, char* value){
LOGPF("Invalid host specified for instance %s", inst->name);
return 1;
}
- free(data->host);
- data->host = strdup(host);
- free(data->port);
- data->port = NULL;
- if(port){
- data->port = strdup(port);
+
+ data->host = realloc(data->host, (data->hosts + 1) * sizeof(char*));
+ data->port = realloc(data->port, (data->hosts + 1) * sizeof(char*));
+
+ if(!data->host || !data->port){
+ LOG("Failed to allocate memory");
+ return 1;
+ }
+
+ data->host[data->hosts] = strdup(host);
+ data->port[data->hosts] = port ? strdup(port) : NULL;
+ if(!data->host[data->hosts] || (port && !data->port[data->hosts])){
+ LOG("Failed to allocate memory");
+ free(data->host[data->hosts]);
+ free(data->port[data->hosts]);
+ return 1;
}
+
+ data->hosts++;
return 0;
}
else if(!strcmp(option, "user")){
- free(data->user);
- data->user = strdup(value);
- return 0;
+ return mmbackend_strdup(&data->user, value);
}
else if(!strcmp(option, "password")){
#ifndef MAWEB_NO_LIBSSL
@@ -629,9 +639,11 @@ static int maweb_handle_message(instance* inst, char* payload, size_t payload_le
}
static int maweb_connect(instance* inst){
+ int rv = 1;
maweb_instance_data* data = (maweb_instance_data*) inst->impl;
- if(!data->host){
- return 1;
+ if(!data->host || !data->host[data->next_host]){
+ LOGPF("Invalid host configuration on instance %s, host %" PRIsize_t, inst->name, data->next_host + 1);
+ goto bail;
}
//unregister old fd from core
@@ -639,9 +651,14 @@ static int maweb_connect(instance* inst){
mm_manage_fd(data->fd, BACKEND_NAME, 0, NULL);
}
- data->fd = mmbackend_socket(data->host, data->port ? data->port : MAWEB_DEFAULT_PORT, SOCK_STREAM, 0, 0, 1);
+ LOGPF("Connecting to host %" PRIsize_t " of %" PRIsize_t " on %s", data->next_host + 1, data->hosts, inst->name);
+
+ data->fd = mmbackend_socket(data->host[data->next_host],
+ data->port[data->next_host] ? data->port[data->next_host] : MAWEB_DEFAULT_PORT,
+ SOCK_STREAM, 0, 0, 1);
+
if(data->fd < 0){
- return 1;
+ goto bail;
}
data->state = ws_new;
@@ -654,15 +671,20 @@ static int maweb_connect(instance* inst){
|| mmbackend_send_str(data->fd, "Sec-WebSocket-Key: rbEQrXMEvCm4ZUjkj6juBQ==\r\n")
|| mmbackend_send_str(data->fd, "\r\n")){
LOG("Failed to communicate with peer");
- return 1;
+ goto bail;
}
//register new fd
if(mm_manage_fd(data->fd, BACKEND_NAME, 1, (void*) inst)){
LOG("Failed to register FD");
- return 1;
+ goto bail;
}
- return 0;
+
+ rv = 0;
+bail:
+ data->next_host++;
+ data->next_host %= data->hosts;
+ return rv;
}
static ssize_t maweb_handle_lines(instance* inst, ssize_t bytes_read){
@@ -693,6 +715,21 @@ static ssize_t maweb_handle_lines(instance* inst, ssize_t bytes_read){
return data->offset + begin;
}
+static int maweb_establish(instance* inst){
+ maweb_instance_data* data = (maweb_instance_data*) inst->impl;
+ uint8_t connected = 0;
+ size_t start = data->next_host;
+
+ do{
+ if(!maweb_connect(inst)){
+ connected = 1;
+ break;
+ }
+ } while(data->next_host != start);
+
+ return connected ? 0 : 1;
+}
+
static ssize_t maweb_handle_ws(instance* inst, ssize_t bytes_read){
maweb_instance_data* data = (maweb_instance_data*) inst->impl;
size_t header_length = 2;
@@ -775,12 +812,18 @@ static int maweb_handle_fd(instance* inst){
bytes_read = recv(data->fd, data->buffer + data->offset, bytes_left - 1, 0);
if(bytes_read < 0){
LOGPF("Failed to receive on %s: %s", inst->name, mmbackend_socket_strerror(errno));
- //TODO close, reopen
- return 1;
+ if(maweb_establish(inst)){
+ LOGPF("Failed to reconnect with any configured host on instance %s", inst->name);
+ return 1;
+ }
+ return 0;
}
else if(bytes_read == 0){
- //client closed connection
- //TODO try to reopen
+ //client closed connection, try to reopen the connection
+ if(maweb_establish(inst)){
+ LOGPF("Failed to reconnect with any configured host on instance %s", inst->name);
+ return 1;
+ }
return 0;
}
@@ -1003,8 +1046,13 @@ static int maweb_start(size_t n, instance** inst){
maweb_instance_data* data = NULL;
for(u = 0; u < n; u++){
- //sort channels
data = (maweb_instance_data*) inst[u]->impl;
+ if(!data->hosts){
+ LOGPF("No hosts configured on instance %s", inst[u]->name);
+ return 1;
+ }
+
+ //sort channels
qsort(data->channel, data->channels, sizeof(maweb_channel_data), channel_comparator);
//re-set channel identifiers
@@ -1012,9 +1060,9 @@ static int maweb_start(size_t n, instance** inst){
data->channel[p].chan->ident = p;
}
- if(maweb_connect(inst[u])){
- LOGPF("Failed to open connection for instance %s", inst[u]->name);
- free(inst);
+ //try to connect to any available host
+ if(maweb_establish(inst[u])){
+ LOGPF("Failed to connect to any host configured on instance %s", inst[u]->name);
return 1;
}
}
@@ -1027,15 +1075,26 @@ static int maweb_start(size_t n, instance** inst){
}
static int maweb_shutdown(size_t n, instance** inst){
- size_t u;
+ size_t u, p;
maweb_instance_data* data = NULL;
for(u = 0; u < n; u++){
data = (maweb_instance_data*) inst[u]->impl;
+
+ for(p = 0; p < data->hosts; p++){
+ //one of these might have failed to allocate
+ if(data->host){
+ free(data->host[p]);
+ }
+ if(data->port){
+ free(data->port[p]);
+ }
+ }
free(data->host);
data->host = NULL;
free(data->port);
data->port = NULL;
+
free(data->user);
data->user = NULL;
free(data->pass);
diff --git a/backends/maweb.h b/backends/maweb.h
index 80835d9..85ca09d 100644
--- a/backends/maweb.h
+++ b/backends/maweb.h
@@ -79,8 +79,11 @@ typedef struct /*_maweb_channel*/ {
} maweb_channel_data;
typedef struct /*_maweb_instance_data*/ {
- char* host;
- char* port;
+ size_t next_host;
+ size_t hosts;
+ char** host;
+ char** port;
+
char* user;
char* pass;
diff --git a/backends/maweb.md b/backends/maweb.md
index eddf1a5..1547919 100644
--- a/backends/maweb.md
+++ b/backends/maweb.md
@@ -18,17 +18,17 @@ Web Remote. Set a web remote password using the option below the activation sett
| Option | Example value | Default value | Description |
|---------------|-----------------------|-----------------------|---------------------------------------------------------------|
-| `interval` | `100` | `50` | Query interval for input data polling (in msec) |
-| `quiet` | `1` | `0` | Turn off some warning messages, for use by experts |
+| `interval` | `100` | `50` | Query interval for input data polling (in msec). |
+| `quiet` | `1` | `0` | Turn off some warning messages, for use by experts. |
#### Instance configuration
| Option | Example value | Default value | Description |
|---------------|-----------------------|-----------------------|---------------------------------------------------------------|
-| `host` | `10.23.42.21 80` | none | Host address (and optional port) of the MA Web Remote |
-| `user` | `midimonster` | none | User for the remote session (GrandMA2) |
-| `password` | `midimonster` | `midimonster` | Password for the remote session |
-| `cmdline` | `console` | `remote` | Commandline key handling mode (see below) |
+| `host` | `10.23.42.21 80` | none | Host address (and optional port) of the MA Web Remote. When specified multiple times, the instance will connect the next address when the current connection fails. |
+| `user` | `midimonster` | none | User for the remote session (GrandMA2). |
+| `password` | `midimonster` | `midimonster` | Password for the remote session. |
+| `cmdline` | `console` | `remote` | Commandline key handling mode (see below). |
The per-instance command line mode may be one of `remote`, `console` or `downgrade`. The first option handles
command keys with a "virtual" commandline belonging to the Web Remote connection. Any commands entered are