Files
flexnbd-c/src/server/flexnbd.c

249 lines
5.8 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)
{
2018-02-20 10:05:35 +00:00
sigset_t mask;
int sfd;
2012-05-15 02:42:03 +01:00
2018-02-20 10:05:35 +00:00
sigemptyset(&mask);
sigaddset(&mask, SIGTERM);
sigaddset(&mask, SIGQUIT);
sigaddset(&mask, SIGINT);
2012-05-15 02:42:03 +01:00
2018-02-20 10:05:35 +00:00
FATAL_UNLESS(0 == pthread_sigmask(SIG_BLOCK, &mask, NULL),
"Signal blocking failed");
2018-02-20 10:05:35 +00:00
sfd = signalfd(-1, &mask, 0);
FATAL_IF(-1 == sfd, "Failed to get a signal fd");
2018-02-20 10:05:35 +00:00
return sfd;
2012-06-27 15:45:33 +01:00
}
2018-02-20 10:05:35 +00:00
void flexnbd_create_shared(struct flexnbd *flexnbd,
const char *s_ctrl_sock)
{
2018-02-20 10:05:35 +00:00
NULLCHECK(flexnbd);
if (s_ctrl_sock) {
flexnbd->control = control_create(flexnbd, s_ctrl_sock);
} else {
flexnbd->control = NULL;
}
flexnbd->signal_fd = flexnbd_build_signal_fd();
2012-06-21 18:01:50 +01:00
}
2018-02-20 10:05:35 +00:00
struct flexnbd *flexnbd_create_serving(char *s_ip_address,
char *s_port,
char *s_file,
char *s_ctrl_sock,
int default_deny,
int acl_entries,
char **s_acl_entries,
int max_nbd_clients,
int use_killswitch)
{
2018-02-20 10:05:35 +00:00
struct flexnbd *flexnbd = xmalloc(sizeof(struct flexnbd));
flexnbd->serve = server_create(flexnbd,
s_ip_address,
s_port,
s_file,
default_deny,
acl_entries,
s_acl_entries,
max_nbd_clients, use_killswitch, 1);
flexnbd_create_shared(flexnbd, s_ctrl_sock);
// Beats installing one handler per client instance
if (use_killswitch) {
struct sigaction act = {
.sa_sigaction = client_killswitch_hit,
.sa_flags = SA_RESTART | SA_SIGINFO
};
FATAL_UNLESS(0 == sigaction(CLIENT_KILLSWITCH_SIGNAL, &act, NULL),
"Installing client killswitch signal failed");
}
return flexnbd;
}
2018-02-20 10:05:35 +00:00
struct flexnbd *flexnbd_create_listening(char *s_ip_address,
char *s_port,
char *s_file,
char *s_ctrl_sock,
int default_deny,
int acl_entries,
char **s_acl_entries)
{
2018-02-20 10:05:35 +00:00
struct flexnbd *flexnbd = xmalloc(sizeof(struct flexnbd));
flexnbd->serve = server_create(flexnbd,
s_ip_address,
s_port,
s_file,
default_deny,
acl_entries, s_acl_entries, 1, 0, 0);
flexnbd_create_shared(flexnbd, s_ctrl_sock);
// listen can't use killswitch, as mirror may pause on sending things
// for a very long time.
return flexnbd;
}
2018-02-20 10:05:35 +00:00
void flexnbd_spawn_control(struct flexnbd *flexnbd)
{
2018-02-20 10:05:35 +00:00
NULLCHECK(flexnbd);
NULLCHECK(flexnbd->control);
2018-02-20 10:05:35 +00:00
pthread_t *control_thread = &flexnbd->control->thread;
2018-02-20 10:05:35 +00:00
FATAL_UNLESS(0 == pthread_create(control_thread,
NULL,
control_runner,
flexnbd->control),
"Couldn't create the control thread");
2012-06-27 15:45:33 +01:00
}
2018-02-20 10:05:35 +00:00
void flexnbd_stop_control(struct flexnbd *flexnbd)
2012-06-27 15:45:33 +01:00
{
2018-02-20 10:05:35 +00:00
NULLCHECK(flexnbd);
NULLCHECK(flexnbd->control);
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
2018-02-20 10:05:35 +00:00
int flexnbd_signal_fd(struct flexnbd *flexnbd)
2012-06-21 18:01:50 +01:00
{
2018-02-20 10:05:35 +00:00
NULLCHECK(flexnbd);
return flexnbd->signal_fd;
2012-06-27 15:45:33 +01:00
}
2012-06-21 18:01:50 +01:00
2018-02-20 10:05:35 +00:00
void flexnbd_destroy(struct flexnbd *flexnbd)
2012-06-27 15:45:33 +01:00
{
2018-02-20 10:05:35 +00:00
NULLCHECK(flexnbd);
if (flexnbd->control) {
control_destroy(flexnbd->control);
}
2012-07-13 11:31:22 +01:00
2018-02-20 10:05:35 +00:00
close(flexnbd->signal_fd);
free(flexnbd);
2012-06-21 18:01:50 +01:00
}
2018-02-20 10:05:35 +00:00
struct server *flexnbd_server(struct flexnbd *flexnbd)
2012-05-15 02:42:03 +01:00
{
2018-02-20 10:05:35 +00:00
NULLCHECK(flexnbd);
return flexnbd->serve;
2012-06-27 15:45:33 +01:00
}
2018-02-20 10:05:35 +00:00
void flexnbd_replace_acl(struct flexnbd *flexnbd, struct acl *acl)
2012-06-27 15:45:33 +01:00
{
2018-02-20 10:05:35 +00:00
NULLCHECK(flexnbd);
server_replace_acl(flexnbd_server(flexnbd), acl);
}
2018-02-20 10:05:35 +00:00
struct status *flexnbd_status_create(struct flexnbd *flexnbd)
{
2018-02-20 10:05:35 +00:00
NULLCHECK(flexnbd);
struct status *status;
2018-02-20 10:05:35 +00:00
status = status_create(flexnbd_server(flexnbd));
return status;
2012-06-27 15:45:33 +01:00
}
2018-02-20 10:05:35 +00:00
void flexnbd_set_server(struct flexnbd *flexnbd, struct server *serve)
2012-06-27 15:45:33 +01:00
{
2018-02-20 10:05:35 +00:00
NULLCHECK(flexnbd);
flexnbd->serve = serve;
}
/* Get the default_deny of the current server object. */
2018-02-20 10:05:35 +00:00
int flexnbd_default_deny(struct flexnbd *flexnbd)
{
2018-02-20 10:05:35 +00:00
NULLCHECK(flexnbd);
return server_default_deny(flexnbd->serve);
}
2018-02-20 10:05:35 +00:00
void make_writable(const char *filename)
{
2018-02-20 10:05:35 +00:00
NULLCHECK(filename);
FATAL_IF_NEGATIVE(chmod(filename, S_IWUSR),
"Couldn't chmod %s: %s", filename, strerror(errno));
}
2018-02-20 10:05:35 +00:00
int flexnbd_serve(struct flexnbd *flexnbd)
{
2018-02-20 10:05:35 +00:00
NULLCHECK(flexnbd);
int success;
struct self_pipe *open_signal = NULL;
if (flexnbd->control) {
debug("Spawning control thread");
flexnbd_spawn_control(flexnbd);
open_signal = flexnbd->control->open_signal;
}
success = do_serve(flexnbd->serve, open_signal);
debug("do_serve success is %d", success);
if (flexnbd->control) {
debug("Stopping control thread");
flexnbd_stop_control(flexnbd);
debug("Control thread stopped");
}
return success;
2012-05-15 02:42:03 +01:00
}