Files
flexnbd-c/src/flexnbd.c

288 lines
6.0 KiB
C
Raw Normal View History

/* 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/>.
*/
/** main() function for parsing and dispatching commands. Each mode has
* a corresponding structure which is filled in and passed to a do_ function
* elsewhere in the program.
*/
2012-06-27 15:45:33 +01:00
#include "flexnbd.h"
#include "serve.h"
#include "util.h"
2012-06-27 15:45:33 +01:00
#include "control.h"
#include "status.h"
2012-05-15 02:42:03 +01:00
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
2012-06-27 15:45:33 +01:00
#include <sys/signalfd.h>
#include <fcntl.h>
#include <unistd.h>
#include <signal.h>
2012-05-15 02:42:03 +01:00
#include <getopt.h>
2012-06-07 17:47:43 +01:00
#include "acl.h"
2012-06-27 15:45:33 +01:00
int flexnbd_build_signal_fd(void)
{
2012-06-27 15:45:33 +01:00
sigset_t mask;
int sfd;
2012-05-15 02:42:03 +01:00
2012-06-27 15:45:33 +01:00
sigemptyset( &mask );
sigaddset( &mask, SIGTERM );
sigaddset( &mask, SIGQUIT );
sigaddset( &mask, SIGINT );
2012-05-15 02:42:03 +01:00
FATAL_UNLESS( 0 == pthread_sigmask( SIG_BLOCK, &mask, NULL ),
2012-06-27 15:45:33 +01:00
"Signal blocking failed" );
2012-06-27 15:45:33 +01:00
sfd = signalfd( -1, &mask, 0 );
FATAL_IF( -1 == sfd, "Failed to get a signal fd" );
2012-06-27 15:45:33 +01:00
return sfd;
}
2012-06-27 15:45:33 +01:00
void flexnbd_create_shared(
struct flexnbd * flexnbd,
2012-06-27 15:45:33 +01:00
const char * s_ctrl_sock)
{
2012-06-27 15:45:33 +01:00
NULLCHECK( flexnbd );
if ( s_ctrl_sock ){
flexnbd->control =
2012-06-27 15:45:33 +01:00
control_create( flexnbd, s_ctrl_sock );
}
else {
flexnbd->control = NULL;
}
2012-06-27 15:45:33 +01:00
flexnbd->signal_fd = flexnbd_build_signal_fd();
2012-06-21 18:01:50 +01:00
}
2012-06-27 15:45:33 +01:00
struct flexnbd * flexnbd_create_serving(
char* s_ip_address,
char* s_port,
char* s_file,
char* s_ctrl_sock,
2012-06-27 15:45:33 +01:00
int default_deny,
int acl_entries,
char** s_acl_entries,
int max_nbd_clients)
{
2012-06-27 15:45:33 +01:00
struct flexnbd * flexnbd = xmalloc( sizeof( struct flexnbd ) );
flexnbd->serve = server_create(
2012-06-27 15:45:33 +01:00
flexnbd,
s_ip_address,
s_port,
s_file,
2012-06-27 15:45:33 +01:00
default_deny,
acl_entries,
s_acl_entries,
max_nbd_clients,
2012-06-27 15:45:33 +01:00
1);
flexnbd_create_shared( flexnbd,
s_ctrl_sock );
2012-06-27 15:45:33 +01:00
return flexnbd;
}
2012-06-27 15:45:33 +01:00
struct flexnbd * flexnbd_create_listening(
char* s_ip_address,
char* s_port,
2012-06-27 15:45:33 +01:00
char* s_file,
char* s_ctrl_sock,
2012-06-27 15:45:33 +01:00
int default_deny,
int acl_entries,
char** s_acl_entries )
{
2012-06-27 15:45:33 +01:00
struct flexnbd * flexnbd = xmalloc( sizeof( struct flexnbd ) );
flexnbd->serve = server_create(
2012-06-27 15:45:33 +01:00
flexnbd,
s_ip_address,
s_port,
s_file,
2012-06-27 15:45:33 +01:00
default_deny,
acl_entries,
s_acl_entries,
1, 0);
2012-06-27 15:45:33 +01:00
flexnbd_create_shared( flexnbd, s_ctrl_sock );
return flexnbd;
}
struct flexnbd * flexnbd_create_proxying(
char* s_downstream_address,
char* s_downstream_port,
char* s_upstream_address,
char* s_upstream_port,
char* s_upstream_bind
)
{
struct flexnbd * flexnbd = xmalloc( sizeof( struct flexnbd ) );
flexnbd->proxy = proxy_create(
flexnbd,
s_downstream_address,
s_downstream_port,
s_upstream_address,
s_upstream_port,
s_upstream_bind);
flexnbd_create_shared( flexnbd, NULL );
return flexnbd;
}
2012-06-27 15:45:33 +01:00
void flexnbd_spawn_control(struct flexnbd * flexnbd )
{
2012-06-27 15:45:33 +01:00
NULLCHECK( flexnbd );
NULLCHECK( flexnbd->control );
2012-06-27 15:45:33 +01:00
pthread_t * control_thread = &flexnbd->control->thread;
FATAL_UNLESS( 0 == pthread_create(
control_thread,
NULL,
control_runner,
2012-06-27 15:45:33 +01:00
flexnbd->control ),
"Couldn't create the control thread" );
}
2012-06-27 15:45:33 +01:00
void flexnbd_stop_control( struct flexnbd * flexnbd )
{
NULLCHECK( flexnbd );
NULLCHECK( flexnbd->control );
2012-06-27 15:45:33 +01:00
control_signal_close( flexnbd->control );
pthread_t tid = flexnbd->control->thread;
FATAL_UNLESS( 0 == pthread_join( tid, NULL ),
"Failed joining the control thread" );
debug( "Control thread %p pthread_join returned", tid );
}
2012-06-21 18:01:50 +01:00
2012-06-27 15:45:33 +01:00
int flexnbd_signal_fd( struct flexnbd * flexnbd )
2012-06-21 18:01:50 +01:00
{
2012-06-27 15:45:33 +01:00
NULLCHECK( flexnbd );
return flexnbd->signal_fd;
}
2012-06-21 18:01:50 +01:00
2012-06-27 15:45:33 +01:00
void flexnbd_destroy( struct flexnbd * flexnbd )
{
NULLCHECK( flexnbd );
if ( flexnbd->control ) {
control_destroy( flexnbd->control );
2012-06-21 18:01:50 +01:00
}
2012-07-13 11:31:22 +01:00
2012-06-27 15:45:33 +01:00
close( flexnbd->signal_fd );
free( flexnbd );
2012-06-21 18:01:50 +01:00
}
2012-06-27 15:45:33 +01:00
struct server * flexnbd_server( struct flexnbd * flexnbd )
2012-05-15 02:42:03 +01:00
{
2012-06-27 15:45:33 +01:00
NULLCHECK( flexnbd );
return flexnbd->serve;
}
2012-06-27 15:45:33 +01:00
void flexnbd_replace_acl( struct flexnbd * flexnbd, struct acl * acl )
{
NULLCHECK( flexnbd );
server_replace_acl( flexnbd_server(flexnbd), acl );
}
2012-06-27 15:45:33 +01:00
struct status * flexnbd_status_create( struct flexnbd * flexnbd )
{
2012-06-27 15:45:33 +01:00
NULLCHECK( flexnbd );
struct status * status;
status = status_create( flexnbd_server( flexnbd ) );
2012-06-27 15:45:33 +01:00
return status;
}
2012-06-27 15:45:33 +01:00
void flexnbd_set_server( struct flexnbd * flexnbd, struct server * serve )
{
NULLCHECK( flexnbd );
flexnbd->serve = serve;
}
/* Get the default_deny of the current server object. */
2012-06-27 15:45:33 +01:00
int flexnbd_default_deny( struct flexnbd * flexnbd )
{
2012-06-27 15:45:33 +01:00
NULLCHECK( flexnbd );
return server_default_deny( flexnbd->serve );
}
char * flexnbd_incomplete_filename( struct flexnbd * flexnbd )
{
NULLCHECK( flexnbd );
struct server * serve = flexnbd_server( flexnbd );
return serve->filename_incomplete;
}
void make_writable( const char * filename )
{
NULLCHECK( filename );
FATAL_IF_NEGATIVE( chmod( filename, S_IWUSR ),
"Couldn't chmod %s: %s",
filename,
strerror( errno ) );
}
2012-06-27 15:45:33 +01:00
int flexnbd_serve( struct flexnbd * flexnbd )
{
2012-06-27 15:45:33 +01:00
NULLCHECK( flexnbd );
int success;
struct self_pipe * open_signal = NULL;
2012-06-27 15:45:33 +01:00
if ( flexnbd->control ){
debug( "Spawning control thread" );
flexnbd_spawn_control( flexnbd );
open_signal = flexnbd->control->open_signal;
}
2012-06-27 15:45:33 +01:00
success = do_serve( flexnbd->serve, open_signal );
debug("do_serve success is %d", success );
2012-06-27 15:45:33 +01:00
if ( flexnbd->control ) {
debug( "Stopping control thread" );
flexnbd_stop_control( flexnbd );
2012-06-28 13:29:22 +01:00
debug("Control thread stopped");
}
2012-06-27 15:45:33 +01:00
return success;
2012-05-15 02:42:03 +01:00
}
int flexnbd_proxy( struct flexnbd * flexnbd )
{
NULLCHECK( flexnbd );
int success;
success = do_proxy( flexnbd->proxy );
debug("do_proxy success is %d", success );
return success;
}