2012-05-29 04:03:28 +01:00
|
|
|
/* FlexNBD server (C) Bytemark Hosting 2012
|
|
|
|
|
|
|
|
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, see <http://www.gnu.org/licenses/>.
|
|
|
|
*/
|
|
|
|
|
|
|
|
/** The control server responds on a UNIX socket and services our "remote"
|
|
|
|
* commands which are used for changing the access control list, initiating
|
|
|
|
* a mirror process, or asking for status. The protocol is pretty simple -
|
|
|
|
* after connecting the client sends a series of LF-terminated lines, followed
|
|
|
|
* by a blank line (i.e. double LF). The first line is taken to be the command
|
|
|
|
* name to invoke, and the lines before the double LF are its arguments.
|
|
|
|
*
|
|
|
|
* These commands can be invoked remotely from the command line, with the
|
|
|
|
* client code to be found in remote.c
|
|
|
|
*/
|
|
|
|
|
2012-06-22 10:05:41 +01:00
|
|
|
#include "control.h"
|
2012-06-27 15:45:33 +01:00
|
|
|
#include "mirror.h"
|
2012-06-06 10:45:07 +01:00
|
|
|
#include "serve.h"
|
2012-05-23 00:42:14 +01:00
|
|
|
#include "util.h"
|
|
|
|
#include "ioutil.h"
|
|
|
|
#include "parse.h"
|
|
|
|
#include "readwrite.h"
|
|
|
|
#include "bitset.h"
|
2012-06-06 12:41:03 +01:00
|
|
|
#include "self_pipe.h"
|
2012-06-07 17:47:43 +01:00
|
|
|
#include "acl.h"
|
2012-06-22 10:05:41 +01:00
|
|
|
#include "status.h"
|
2012-06-27 15:45:33 +01:00
|
|
|
#include "mbox.h"
|
2012-05-23 00:42:14 +01:00
|
|
|
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <sys/un.h>
|
2012-05-24 01:39:35 +01:00
|
|
|
#include <unistd.h>
|
2012-05-23 00:42:14 +01:00
|
|
|
|
2012-06-22 10:05:41 +01:00
|
|
|
|
2012-07-15 21:57:36 +01:00
|
|
|
struct control * control_create(
|
|
|
|
struct flexnbd * flexnbd,
|
|
|
|
const char * csn)
|
2012-06-22 10:05:41 +01:00
|
|
|
{
|
2012-06-27 15:45:33 +01:00
|
|
|
struct control * control = xmalloc( sizeof( struct control ) );
|
2012-06-22 10:05:41 +01:00
|
|
|
|
2012-06-27 15:45:33 +01:00
|
|
|
NULLCHECK( csn );
|
2012-06-22 10:05:41 +01:00
|
|
|
|
2012-06-27 15:45:33 +01:00
|
|
|
control->flexnbd = flexnbd;
|
|
|
|
control->socket_name = csn;
|
|
|
|
control->close_signal = self_pipe_create();
|
2012-07-15 21:57:36 +01:00
|
|
|
control->mirror_state_mbox = mbox_create();
|
2012-06-13 15:51:37 +01:00
|
|
|
|
2012-06-27 15:45:33 +01:00
|
|
|
return control;
|
2012-06-22 10:05:41 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-06-27 15:45:33 +01:00
|
|
|
void control_signal_close( struct control * control)
|
2012-06-22 10:05:41 +01:00
|
|
|
{
|
2012-06-27 15:45:33 +01:00
|
|
|
|
|
|
|
NULLCHECK( control );
|
|
|
|
self_pipe_signal( control->close_signal );
|
2012-06-22 10:05:41 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-06-27 15:45:33 +01:00
|
|
|
void control_destroy( struct control * control )
|
2012-06-22 10:05:41 +01:00
|
|
|
{
|
2012-06-27 15:45:33 +01:00
|
|
|
NULLCHECK( control );
|
2012-06-13 15:51:37 +01:00
|
|
|
|
2012-07-15 21:57:36 +01:00
|
|
|
mbox_destroy( control->mirror_state_mbox );
|
2012-06-27 15:45:33 +01:00
|
|
|
self_pipe_destroy( control->close_signal );
|
|
|
|
free( control );
|
2012-06-13 15:51:37 +01:00
|
|
|
}
|
|
|
|
|
2012-07-15 21:57:36 +01:00
|
|
|
struct control_client * control_client_create(
|
|
|
|
struct flexnbd * flexnbd,
|
|
|
|
int client_fd ,
|
|
|
|
struct mbox * state_mbox )
|
2012-06-13 15:51:37 +01:00
|
|
|
{
|
2012-06-27 15:45:33 +01:00
|
|
|
NULLCHECK( flexnbd );
|
2012-06-13 15:51:37 +01:00
|
|
|
|
2012-06-27 15:45:33 +01:00
|
|
|
struct control_client * control_client =
|
|
|
|
xmalloc( sizeof( struct control_client ) );
|
2012-06-13 15:51:37 +01:00
|
|
|
|
2012-06-27 15:45:33 +01:00
|
|
|
control_client->socket = client_fd;
|
|
|
|
control_client->flexnbd = flexnbd;
|
2012-07-15 21:57:36 +01:00
|
|
|
control_client->mirror_state_mbox = state_mbox;
|
2012-06-27 15:45:33 +01:00
|
|
|
return control_client;
|
|
|
|
}
|
2012-05-29 04:03:28 +01:00
|
|
|
|
2012-05-23 00:42:14 +01:00
|
|
|
|
2012-05-29 04:03:28 +01:00
|
|
|
|
2012-06-27 15:45:33 +01:00
|
|
|
void control_client_destroy( struct control_client * client )
|
2012-06-13 15:45:59 +01:00
|
|
|
{
|
2012-06-27 15:45:33 +01:00
|
|
|
NULLCHECK( client );
|
|
|
|
free( client );
|
2012-06-13 15:45:59 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-06-27 15:45:33 +01:00
|
|
|
void control_respond(struct control_client * client);
|
2012-06-21 17:12:06 +01:00
|
|
|
|
2012-06-27 15:45:33 +01:00
|
|
|
void control_handle_client( struct control * control, int client_fd )
|
2012-06-13 15:45:59 +01:00
|
|
|
{
|
2012-06-27 15:45:33 +01:00
|
|
|
NULLCHECK( control );
|
|
|
|
NULLCHECK( control->flexnbd );
|
|
|
|
struct control_client * control_client =
|
2012-07-15 21:57:36 +01:00
|
|
|
control_client_create(
|
|
|
|
control->flexnbd,
|
|
|
|
client_fd ,
|
|
|
|
control->mirror_state_mbox);
|
2012-06-27 15:45:33 +01:00
|
|
|
|
|
|
|
/* We intentionally don't spawn a thread for the client here.
|
|
|
|
* This is to avoid having more than one thread potentially
|
|
|
|
* waiting on the migration commit status.
|
2012-06-21 17:12:06 +01:00
|
|
|
*/
|
2012-06-27 15:45:33 +01:00
|
|
|
control_respond( control_client );
|
2012-06-13 15:45:59 +01:00
|
|
|
}
|
|
|
|
|
2012-06-21 17:12:06 +01:00
|
|
|
|
2012-06-27 15:45:33 +01:00
|
|
|
void control_accept_client( struct control * control )
|
2012-05-23 00:42:14 +01:00
|
|
|
{
|
2012-06-22 10:05:41 +01:00
|
|
|
|
2012-06-27 15:45:33 +01:00
|
|
|
int client_fd;
|
|
|
|
union mysockaddr client_address;
|
|
|
|
socklen_t addrlen = sizeof( union mysockaddr );
|
2012-06-22 10:05:41 +01:00
|
|
|
|
2012-06-27 15:45:33 +01:00
|
|
|
client_fd = accept( control->control_fd, &client_address.generic, &addrlen );
|
|
|
|
FATAL_IF( -1 == client_fd, "control accept failed" );
|
2012-06-13 15:45:59 +01:00
|
|
|
|
2012-06-27 15:45:33 +01:00
|
|
|
control_handle_client( control, client_fd );
|
2012-06-22 10:05:41 +01:00
|
|
|
}
|
|
|
|
|
2012-06-27 15:45:33 +01:00
|
|
|
int control_accept( struct control * control )
|
2012-06-22 10:05:41 +01:00
|
|
|
{
|
2012-06-27 15:45:33 +01:00
|
|
|
NULLCHECK( control );
|
2012-06-13 13:44:21 +01:00
|
|
|
|
2012-06-27 15:45:33 +01:00
|
|
|
fd_set fds;
|
2012-06-22 10:05:41 +01:00
|
|
|
|
2012-06-27 15:45:33 +01:00
|
|
|
FD_ZERO( &fds );
|
|
|
|
FD_SET( control->control_fd, &fds );
|
|
|
|
self_pipe_fd_set( control->close_signal, &fds );
|
2012-06-28 13:29:22 +01:00
|
|
|
debug("Control thread selecting");
|
2012-06-27 15:45:33 +01:00
|
|
|
FATAL_UNLESS( 0 < select( FD_SETSIZE, &fds, NULL, NULL, NULL ),
|
|
|
|
"Control select failed." );
|
2012-06-22 10:05:41 +01:00
|
|
|
|
2012-06-27 15:45:33 +01:00
|
|
|
if ( self_pipe_fd_isset( control->close_signal, &fds ) ){
|
|
|
|
return 0;
|
2012-05-29 04:03:28 +01:00
|
|
|
}
|
2012-06-27 15:45:33 +01:00
|
|
|
|
|
|
|
if ( FD_ISSET( control->control_fd, &fds ) ) {
|
|
|
|
control_accept_client( control );
|
2012-05-23 00:42:14 +01:00
|
|
|
}
|
2012-06-27 15:45:33 +01:00
|
|
|
return 1;
|
2012-06-22 10:05:41 +01:00
|
|
|
}
|
2012-06-13 15:45:59 +01:00
|
|
|
|
2012-06-22 10:05:41 +01:00
|
|
|
|
2012-06-27 15:45:33 +01:00
|
|
|
void control_accept_loop( struct control * control )
|
2012-06-22 10:05:41 +01:00
|
|
|
{
|
2012-06-27 15:45:33 +01:00
|
|
|
while( control_accept( control ) );
|
2012-06-22 10:05:41 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-06-27 15:45:33 +01:00
|
|
|
int open_control_socket( const char * socket_name )
|
|
|
|
{
|
|
|
|
struct sockaddr_un bind_address;
|
|
|
|
int control_fd;
|
2012-05-29 04:03:28 +01:00
|
|
|
|
2012-06-27 15:45:33 +01:00
|
|
|
if (!socket_name) {
|
|
|
|
fatal( "Tried to open a control socket without a socket name" );
|
2012-06-22 10:05:41 +01:00
|
|
|
}
|
|
|
|
|
2012-06-27 15:45:33 +01:00
|
|
|
control_fd = socket(AF_UNIX, SOCK_STREAM, 0);
|
|
|
|
FATAL_IF_NEGATIVE(control_fd ,
|
|
|
|
"Couldn't create control socket");
|
|
|
|
|
|
|
|
memset(&bind_address, 0, sizeof(struct sockaddr_un));
|
|
|
|
bind_address.sun_family = AF_UNIX;
|
|
|
|
strncpy(bind_address.sun_path, socket_name, sizeof(bind_address.sun_path)-1);
|
|
|
|
|
2012-07-13 14:09:52 +01:00
|
|
|
//unlink(socket_name); /* ignore failure */
|
2012-06-27 15:45:33 +01:00
|
|
|
|
|
|
|
FATAL_IF_NEGATIVE(
|
|
|
|
bind(control_fd , &bind_address, sizeof(bind_address)),
|
2012-07-13 14:09:52 +01:00
|
|
|
"Couldn't bind control socket to %s: %s",
|
|
|
|
socket_name, strerror( errno )
|
2012-06-27 15:45:33 +01:00
|
|
|
);
|
|
|
|
|
|
|
|
FATAL_IF_NEGATIVE(
|
|
|
|
listen(control_fd , 5),
|
|
|
|
"Couldn't listen on control socket"
|
|
|
|
);
|
|
|
|
return control_fd;
|
2012-06-22 10:05:41 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-06-27 15:45:33 +01:00
|
|
|
void control_listen(struct control* control)
|
2012-06-22 10:05:41 +01:00
|
|
|
{
|
2012-06-27 15:45:33 +01:00
|
|
|
NULLCHECK( control );
|
|
|
|
control->control_fd = open_control_socket( control->socket_name );
|
2012-06-22 10:05:41 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-06-27 15:45:33 +01:00
|
|
|
void control_serve( struct control * control )
|
2012-06-22 10:05:41 +01:00
|
|
|
{
|
2012-06-27 15:45:33 +01:00
|
|
|
NULLCHECK( control );
|
|
|
|
control_listen( control );
|
|
|
|
while( control_accept( control ) );
|
2012-06-22 10:05:41 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-07-13 14:09:52 +01:00
|
|
|
void control_cleanup(
|
|
|
|
struct control * control,
|
|
|
|
int fatal __attribute__((unused)) )
|
|
|
|
{
|
|
|
|
NULLCHECK( control );
|
|
|
|
unlink( control->socket_name );
|
|
|
|
close( control->control_fd );
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-06-27 15:45:33 +01:00
|
|
|
void * control_runner( void * control_uncast )
|
2012-06-22 10:05:41 +01:00
|
|
|
{
|
2012-07-11 09:43:16 +01:00
|
|
|
debug("Control thread");
|
2012-06-27 15:45:33 +01:00
|
|
|
NULLCHECK( control_uncast );
|
|
|
|
struct control * control = (struct control *)control_uncast;
|
2012-06-22 10:05:41 +01:00
|
|
|
|
2012-07-13 14:09:52 +01:00
|
|
|
error_set_handler( (cleanup_handler*)control_cleanup, control );
|
|
|
|
|
2012-06-27 15:45:33 +01:00
|
|
|
control_serve( control );
|
2012-07-13 14:09:52 +01:00
|
|
|
|
|
|
|
control_cleanup( control, 0 );
|
2012-05-23 00:42:14 +01:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2012-06-13 15:45:59 +01:00
|
|
|
|
2012-06-27 15:45:33 +01:00
|
|
|
#define write_socket(msg) write(client_fd, (msg "\n"), strlen((msg))+1)
|
2012-05-23 00:42:14 +01:00
|
|
|
|
2012-06-27 15:45:33 +01:00
|
|
|
void control_write_mirror_response( enum mirror_state mirror_state, int client_fd )
|
2012-06-22 10:05:41 +01:00
|
|
|
{
|
2012-06-27 15:45:33 +01:00
|
|
|
switch (mirror_state) {
|
|
|
|
case MS_INIT:
|
|
|
|
case MS_UNKNOWN:
|
|
|
|
write_socket( "1: Mirror failed to initialise" );
|
|
|
|
fatal( "Impossible mirror state: %d", mirror_state );
|
|
|
|
case MS_FAIL_CONNECT:
|
|
|
|
write_socket( "1: Mirror failed to connect");
|
|
|
|
break;
|
|
|
|
case MS_FAIL_REJECTED:
|
|
|
|
write_socket( "1: Mirror was rejected" );
|
|
|
|
break;
|
|
|
|
case MS_FAIL_NO_HELLO:
|
|
|
|
write_socket( "1: Remote server failed to respond");
|
|
|
|
break;
|
|
|
|
case MS_FAIL_SIZE_MISMATCH:
|
|
|
|
write_socket( "1: Remote size does not match local size" );
|
|
|
|
break;
|
|
|
|
case MS_GO:
|
|
|
|
case MS_DONE: /* Yes, I know we know better, but it's simpler this way */
|
|
|
|
write_socket( "0: Mirror started" );
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
fatal( "Unhandled mirror state: %d", mirror_state );
|
2012-06-22 10:05:41 +01:00
|
|
|
}
|
|
|
|
}
|
2012-06-27 15:45:33 +01:00
|
|
|
#undef write_socket
|
|
|
|
|
2012-06-22 10:05:41 +01:00
|
|
|
|
2012-07-15 21:57:36 +01:00
|
|
|
/* Call this in the thread where you want to receive the mirror state */
|
|
|
|
enum mirror_state control_client_mirror_wait(
|
|
|
|
struct control_client* client)
|
|
|
|
{
|
|
|
|
NULLCHECK( client );
|
|
|
|
NULLCHECK( client->mirror_state_mbox );
|
|
|
|
|
|
|
|
struct mbox * mbox = client->mirror_state_mbox;
|
|
|
|
enum mirror_state mirror_state;
|
|
|
|
enum mirror_state * contents;
|
|
|
|
|
|
|
|
contents = (enum mirror_state*)mbox_receive( mbox );
|
|
|
|
NULLCHECK( contents );
|
|
|
|
|
|
|
|
mirror_state = *contents;
|
|
|
|
|
|
|
|
free( contents );
|
|
|
|
|
|
|
|
return mirror_state;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-06-27 15:45:33 +01:00
|
|
|
#define write_socket(msg) write(client->socket, (msg "\n"), strlen((msg))+1)
|
2012-05-29 04:03:28 +01:00
|
|
|
/** Command parser to start mirror process from socket input */
|
2012-06-27 15:45:33 +01:00
|
|
|
int control_mirror(struct control_client* client, int linesc, char** lines)
|
2012-05-23 00:42:14 +01:00
|
|
|
{
|
2012-06-13 15:45:59 +01:00
|
|
|
NULLCHECK( client );
|
|
|
|
|
2012-06-27 15:45:33 +01:00
|
|
|
struct flexnbd * flexnbd = client->flexnbd;
|
2012-06-22 10:05:41 +01:00
|
|
|
union mysockaddr *connect_to = xmalloc( sizeof( union mysockaddr ) );
|
|
|
|
union mysockaddr *connect_from = NULL;
|
|
|
|
uint64_t max_Bps = 0;
|
2012-05-24 01:39:35 +01:00
|
|
|
int action_at_finish;
|
2012-06-11 13:57:03 +01:00
|
|
|
int raw_port;
|
2012-05-23 00:42:14 +01:00
|
|
|
|
2012-06-06 12:35:01 +01:00
|
|
|
|
2012-05-24 01:39:35 +01:00
|
|
|
if (linesc < 2) {
|
|
|
|
write_socket("1: mirror takes at least two parameters");
|
2012-05-23 14:03:30 +01:00
|
|
|
return -1;
|
|
|
|
}
|
2012-06-06 12:35:01 +01:00
|
|
|
|
2012-06-22 10:05:41 +01:00
|
|
|
if (parse_ip_to_sockaddr(&connect_to->generic, lines[0]) == 0) {
|
2012-05-23 14:03:30 +01:00
|
|
|
write_socket("1: bad IP address");
|
|
|
|
return -1;
|
|
|
|
}
|
2012-05-23 00:42:14 +01:00
|
|
|
|
2012-06-11 13:57:03 +01:00
|
|
|
raw_port = atoi(lines[1]);
|
|
|
|
if (raw_port < 0 || raw_port > 65535) {
|
2012-05-23 14:03:30 +01:00
|
|
|
write_socket("1: bad IP port number");
|
|
|
|
return -1;
|
|
|
|
}
|
2012-06-22 10:05:41 +01:00
|
|
|
connect_to->v4.sin_port = htobe16(raw_port);
|
2012-06-06 12:35:01 +01:00
|
|
|
|
2012-05-24 01:39:35 +01:00
|
|
|
if (linesc > 2) {
|
2012-06-22 10:05:41 +01:00
|
|
|
connect_from = xmalloc( sizeof( union mysockaddr ) );
|
|
|
|
if (parse_ip_to_sockaddr(&connect_from->generic, lines[2]) == 0) {
|
2012-06-06 12:35:01 +01:00
|
|
|
write_socket("1: bad bind address");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-06-22 10:05:41 +01:00
|
|
|
if (linesc > 3) { max_Bps = atoi(lines[2]); }
|
2012-05-24 01:39:35 +01:00
|
|
|
|
2012-06-12 15:08:07 +01:00
|
|
|
action_at_finish = ACTION_EXIT;
|
2012-06-06 12:35:01 +01:00
|
|
|
if (linesc > 4) {
|
2012-06-12 15:08:07 +01:00
|
|
|
if (strcmp("exit", lines[3]) == 0) {
|
2012-05-24 01:39:35 +01:00
|
|
|
action_at_finish = ACTION_EXIT;
|
2012-06-11 14:34:17 +01:00
|
|
|
}
|
|
|
|
else if (strcmp("nothing", lines[3]) == 0) {
|
2012-05-24 01:39:35 +01:00
|
|
|
action_at_finish = ACTION_NOTHING;
|
2012-06-11 14:34:17 +01:00
|
|
|
}
|
2012-05-24 01:39:35 +01:00
|
|
|
else {
|
2012-06-12 15:08:07 +01:00
|
|
|
write_socket("1: action must be 'exit' or 'nothing'");
|
2012-05-24 01:39:35 +01:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-06-06 12:35:01 +01:00
|
|
|
if (linesc > 5) {
|
2012-05-24 01:39:35 +01:00
|
|
|
write_socket("1: unrecognised parameters to mirror");
|
|
|
|
return -1;
|
|
|
|
}
|
2012-06-06 12:35:01 +01:00
|
|
|
|
2012-06-27 15:45:33 +01:00
|
|
|
/* In theory, we should never have to worry about the switch
|
|
|
|
* lock here, since we should never be able to start more than
|
|
|
|
* one mirror at a time. This is enforced by only accepting a
|
|
|
|
* single client at a time on the control socket.
|
|
|
|
*/
|
2012-07-11 09:43:16 +01:00
|
|
|
flexnbd_lock_switch( flexnbd );
|
2012-06-27 15:45:33 +01:00
|
|
|
{
|
|
|
|
struct server * serve = flexnbd_server(flexnbd);
|
2012-07-16 11:21:56 +01:00
|
|
|
|
|
|
|
if ( serve->mirror_super ) {
|
|
|
|
warn( "Tried to start a second mirror run" );
|
|
|
|
write_socket( "1: mirror already running" );
|
|
|
|
} else {
|
|
|
|
serve->mirror_super = mirror_super_create(
|
|
|
|
serve->filename,
|
|
|
|
connect_to,
|
|
|
|
connect_from,
|
|
|
|
max_Bps ,
|
|
|
|
action_at_finish,
|
|
|
|
client->mirror_state_mbox );
|
|
|
|
serve->mirror = serve->mirror_super->mirror;
|
|
|
|
|
|
|
|
FATAL_IF( 0 != pthread_create(
|
|
|
|
&serve->mirror_super->thread,
|
|
|
|
NULL,
|
|
|
|
mirror_super_runner,
|
|
|
|
serve
|
|
|
|
),
|
|
|
|
"Failed to create mirror thread"
|
|
|
|
);
|
|
|
|
|
|
|
|
debug("Control thread mirror super waiting");
|
|
|
|
enum mirror_state state =
|
|
|
|
control_client_mirror_wait( client );
|
|
|
|
debug("Control thread writing response");
|
|
|
|
control_write_mirror_response( state, client->socket );
|
|
|
|
}
|
2012-06-27 15:45:33 +01:00
|
|
|
}
|
2012-07-11 09:43:16 +01:00
|
|
|
debug( "Control thread unlocking switch" );
|
|
|
|
flexnbd_unlock_switch( flexnbd );
|
2012-06-22 10:05:41 +01:00
|
|
|
debug( "Control thread going away." );
|
2012-05-29 04:03:28 +01:00
|
|
|
|
2012-05-23 14:03:30 +01:00
|
|
|
return 0;
|
2012-05-23 00:42:14 +01:00
|
|
|
}
|
|
|
|
|
2012-06-27 15:45:33 +01:00
|
|
|
#undef write_socket
|
|
|
|
|
|
|
|
|
2012-05-29 04:03:28 +01:00
|
|
|
/** Command parser to alter access control list from socket input */
|
2012-06-27 15:45:33 +01:00
|
|
|
int control_acl(struct control_client* client, int linesc, char** lines)
|
2012-05-23 00:42:14 +01:00
|
|
|
{
|
2012-06-07 17:47:43 +01:00
|
|
|
NULLCHECK( client );
|
2012-06-27 15:45:33 +01:00
|
|
|
NULLCHECK( client->flexnbd );
|
|
|
|
struct flexnbd * flexnbd = client->flexnbd;
|
|
|
|
|
|
|
|
int default_deny = flexnbd_default_deny( flexnbd );
|
|
|
|
struct acl * new_acl = acl_create( linesc, lines, default_deny );
|
2012-06-07 17:47:43 +01:00
|
|
|
|
|
|
|
if (new_acl->len != linesc) {
|
2012-05-29 00:59:12 +01:00
|
|
|
write(client->socket, "1: bad spec: ", 13);
|
2012-06-07 17:47:43 +01:00
|
|
|
write(client->socket, lines[new_acl->len],
|
2012-06-27 15:45:33 +01:00
|
|
|
strlen(lines[new_acl->len]));
|
2012-05-23 00:42:14 +01:00
|
|
|
write(client->socket, "\n", 1);
|
2012-06-07 17:47:43 +01:00
|
|
|
acl_destroy( new_acl );
|
2012-05-23 00:42:14 +01:00
|
|
|
}
|
|
|
|
else {
|
2012-06-27 15:45:33 +01:00
|
|
|
flexnbd_replace_acl( flexnbd, new_acl );
|
|
|
|
write( client->socket, "0: updated", 10);
|
2012-05-23 00:42:14 +01:00
|
|
|
}
|
2012-06-27 15:45:33 +01:00
|
|
|
|
2012-05-23 14:03:30 +01:00
|
|
|
return 0;
|
2012-05-23 00:42:14 +01:00
|
|
|
}
|
|
|
|
|
2012-05-29 04:03:28 +01:00
|
|
|
/** FIXME: add some useful statistics */
|
2012-06-11 13:57:03 +01:00
|
|
|
int control_status(
|
2012-06-27 15:45:33 +01:00
|
|
|
struct control_client* client,
|
2012-06-11 13:57:03 +01:00
|
|
|
int linesc __attribute__ ((unused)),
|
|
|
|
char** lines __attribute__((unused))
|
|
|
|
)
|
2012-05-23 00:42:14 +01:00
|
|
|
{
|
2012-06-22 10:05:41 +01:00
|
|
|
NULLCHECK( client );
|
2012-06-27 15:45:33 +01:00
|
|
|
NULLCHECK( client->flexnbd );
|
|
|
|
struct status * status = flexnbd_status_create( client->flexnbd );
|
|
|
|
|
2012-06-22 10:05:41 +01:00
|
|
|
write( client->socket, "0: ", 3 );
|
|
|
|
status_write( status, client->socket );
|
|
|
|
status_destroy( status );
|
|
|
|
|
2012-05-23 14:03:30 +01:00
|
|
|
return 0;
|
2012-05-23 00:42:14 +01:00
|
|
|
}
|
2012-05-23 14:03:30 +01:00
|
|
|
|
2012-07-13 14:09:52 +01:00
|
|
|
void control_client_cleanup(struct control_client* client,
|
2012-06-11 13:57:03 +01:00
|
|
|
int fatal __attribute__ ((unused)) )
|
2012-06-09 02:25:12 +01:00
|
|
|
{
|
2012-06-11 14:34:17 +01:00
|
|
|
if (client->socket) { close(client->socket); }
|
2012-07-11 09:43:16 +01:00
|
|
|
|
|
|
|
/* This is wrongness */
|
|
|
|
if ( server_io_locked( client->flexnbd->serve ) ) { server_unlock_io( client->flexnbd->serve ); }
|
|
|
|
if ( server_acl_locked( client->flexnbd->serve ) ) { server_unlock_acl( client->flexnbd->serve ); }
|
|
|
|
if ( flexnbd_switch_locked( client->flexnbd ) ) { flexnbd_unlock_switch( client->flexnbd ); }
|
|
|
|
|
2012-06-27 15:45:33 +01:00
|
|
|
control_client_destroy( client );
|
2012-06-09 02:25:12 +01:00
|
|
|
}
|
|
|
|
|
2012-05-29 04:03:28 +01:00
|
|
|
/** Master command parser for control socket connections, delegates quickly */
|
2012-06-27 15:45:33 +01:00
|
|
|
void control_respond(struct control_client * client)
|
2012-05-23 00:42:14 +01:00
|
|
|
{
|
2012-05-23 14:03:30 +01:00
|
|
|
char **lines = NULL;
|
2012-06-28 13:29:22 +01:00
|
|
|
|
2012-07-13 14:09:52 +01:00
|
|
|
error_set_handler((cleanup_handler*) control_client_cleanup, client);
|
2012-06-28 13:29:22 +01:00
|
|
|
|
|
|
|
int i, linesc;
|
|
|
|
linesc = read_lines_until_blankline(client->socket, 256, &lines);
|
|
|
|
|
|
|
|
if (linesc < 1)
|
|
|
|
{
|
|
|
|
write(client->socket, "9: missing command\n", 19);
|
|
|
|
/* ignore failure */
|
|
|
|
}
|
|
|
|
else if (strcmp(lines[0], "acl") == 0) {
|
|
|
|
info("acl command received" );
|
|
|
|
if (control_acl(client, linesc-1, lines+1) < 0) {
|
|
|
|
debug("acl command failed");
|
2012-05-23 14:03:30 +01:00
|
|
|
}
|
2012-06-28 13:29:22 +01:00
|
|
|
}
|
|
|
|
else if (strcmp(lines[0], "mirror") == 0) {
|
|
|
|
info("mirror command received" );
|
|
|
|
if (control_mirror(client, linesc-1, lines+1) < 0) {
|
|
|
|
debug("mirror command failed");
|
2012-05-23 00:42:14 +01:00
|
|
|
}
|
2012-06-28 13:29:22 +01:00
|
|
|
}
|
|
|
|
else if (strcmp(lines[0], "status") == 0) {
|
|
|
|
info("status command received" );
|
|
|
|
if (control_status(client, linesc-1, lines+1) < 0) {
|
|
|
|
debug("status command failed");
|
2012-06-11 14:34:17 +01:00
|
|
|
}
|
2012-05-23 00:42:14 +01:00
|
|
|
}
|
2012-06-28 13:29:22 +01:00
|
|
|
else {
|
|
|
|
write(client->socket, "10: unknown command\n", 23);
|
|
|
|
}
|
|
|
|
|
|
|
|
for (i=0; i<linesc; i++) {
|
|
|
|
free(lines[i]);
|
|
|
|
}
|
|
|
|
free(lines);
|
|
|
|
|
2012-07-13 14:09:52 +01:00
|
|
|
control_client_cleanup(client, 0);
|
2012-06-22 10:05:41 +01:00
|
|
|
debug("control command handled" );
|
2012-05-23 00:42:14 +01:00
|
|
|
}
|
|
|
|
|