diff options
-rw-r--r-- | backends/maweb.c | 109 | ||||
-rw-r--r-- | backends/maweb.h | 7 | ||||
-rw-r--r-- | backends/maweb.md | 12 |
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 |