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-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-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-05-29 04:03:28 +01:00
|
|
|
/** The mirror code will split NBD writes, making them this long as a maximum */
|
|
|
|
static const int mirror_longest_write = 8<<20;
|
|
|
|
|
|
|
|
/** If, during a mirror pass, we have sent this number of bytes or fewer, we
|
|
|
|
* go to freeze the I/O and finish it off. This is just a guess.
|
|
|
|
*/
|
2012-06-11 13:57:03 +01:00
|
|
|
static const unsigned int mirror_last_pass_after_bytes_written = 100<<20;
|
2012-05-23 00:42:14 +01:00
|
|
|
|
2012-05-29 04:03:28 +01:00
|
|
|
/** The largest number of full passes we'll do - the last one will always
|
|
|
|
* cause the I/O to freeze, however many bytes are left to copy.
|
|
|
|
*/
|
|
|
|
static const int mirror_maximum_passes = 7;
|
|
|
|
|
|
|
|
/** Thread launched to drive mirror process */
|
2012-05-23 00:42:14 +01:00
|
|
|
void* mirror_runner(void* serve_params_uncast)
|
|
|
|
{
|
2012-05-29 04:03:28 +01:00
|
|
|
const int last_pass = mirror_maximum_passes-1;
|
2012-05-23 00:42:14 +01:00
|
|
|
int pass;
|
2012-06-06 10:35:50 +01:00
|
|
|
struct server *serve = (struct server*) serve_params_uncast;
|
2012-05-23 00:42:14 +01:00
|
|
|
struct bitset_mapping *map = serve->mirror->dirty_map;
|
|
|
|
|
2012-05-29 04:03:28 +01:00
|
|
|
for (pass=0; pass < mirror_maximum_passes; pass++) {
|
2012-05-23 00:42:14 +01:00
|
|
|
uint64_t current = 0;
|
2012-05-24 01:39:35 +01:00
|
|
|
uint64_t written = 0;
|
2012-05-23 00:42:14 +01:00
|
|
|
|
|
|
|
debug("mirror start pass=%d", pass);
|
|
|
|
|
2012-05-29 04:03:28 +01:00
|
|
|
if (pass == last_pass) {
|
2012-06-06 13:44:38 +01:00
|
|
|
server_lock_io( serve );
|
2012-05-29 04:03:28 +01:00
|
|
|
}
|
|
|
|
|
2012-05-23 00:42:14 +01:00
|
|
|
while (current < serve->size) {
|
2012-05-24 01:39:35 +01:00
|
|
|
int run;
|
|
|
|
|
2012-05-29 04:03:28 +01:00
|
|
|
run = bitset_run_count(map, current, mirror_longest_write);
|
2012-05-23 00:42:14 +01:00
|
|
|
|
|
|
|
debug("mirror current=%ld, run=%d", current, run);
|
|
|
|
|
2012-05-29 04:03:28 +01:00
|
|
|
/* FIXME: we could avoid sending sparse areas of the
|
|
|
|
* disc here, and probably save a lot of bandwidth and
|
|
|
|
* time (if we know the destination starts off zeroed).
|
|
|
|
*/
|
2012-05-23 00:42:14 +01:00
|
|
|
if (bitset_is_set_at(map, current)) {
|
2012-05-29 04:03:28 +01:00
|
|
|
/* We've found a dirty area, send it */
|
2012-05-23 00:42:14 +01:00
|
|
|
debug("^^^ writing");
|
|
|
|
|
2012-05-29 04:03:28 +01:00
|
|
|
/* We need to stop the main thread from working
|
|
|
|
* because it might corrupt the dirty map. This
|
|
|
|
* is likely to slow things down but will be
|
|
|
|
* safe.
|
|
|
|
*/
|
2012-06-06 13:44:38 +01:00
|
|
|
if (pass < last_pass) {
|
|
|
|
server_lock_io( serve );
|
|
|
|
}
|
2012-05-29 04:03:28 +01:00
|
|
|
|
|
|
|
/** FIXME: do something useful with bytes/second */
|
|
|
|
|
|
|
|
/** FIXME: error handling code here won't unlock */
|
2012-05-23 00:42:14 +01:00
|
|
|
socket_nbd_write(
|
|
|
|
serve->mirror->client,
|
|
|
|
current,
|
|
|
|
run,
|
|
|
|
0,
|
|
|
|
serve->mirror->mapped + current
|
|
|
|
);
|
|
|
|
|
2012-05-29 04:03:28 +01:00
|
|
|
/* now mark it clean */
|
2012-05-23 00:42:14 +01:00
|
|
|
bitset_clear_range(map, current, run);
|
2012-05-29 04:03:28 +01:00
|
|
|
|
2012-06-06 13:44:38 +01:00
|
|
|
if (pass < last_pass) {
|
|
|
|
server_unlock_io( serve );
|
|
|
|
}
|
2012-05-29 04:03:28 +01:00
|
|
|
|
2012-05-24 01:39:35 +01:00
|
|
|
written += run;
|
2012-05-23 00:42:14 +01:00
|
|
|
}
|
|
|
|
current += run;
|
2012-06-09 02:25:12 +01:00
|
|
|
|
|
|
|
if (serve->mirror->signal_abandon) {
|
2012-06-11 14:34:17 +01:00
|
|
|
if (pass == last_pass) { server_unlock_io( serve ); }
|
2012-06-09 02:25:12 +01:00
|
|
|
close(serve->mirror->client);
|
|
|
|
goto abandon_mirror;
|
|
|
|
}
|
2012-05-23 00:42:14 +01:00
|
|
|
}
|
2012-05-24 01:39:35 +01:00
|
|
|
|
2012-05-29 04:03:28 +01:00
|
|
|
/* if we've not written anything */
|
2012-06-11 14:34:17 +01:00
|
|
|
if (written < mirror_last_pass_after_bytes_written) {
|
2012-05-29 04:03:28 +01:00
|
|
|
pass = last_pass;
|
2012-06-11 14:34:17 +01:00
|
|
|
}
|
2012-05-29 04:03:28 +01:00
|
|
|
}
|
2012-06-11 14:34:17 +01:00
|
|
|
|
2012-05-29 04:03:28 +01:00
|
|
|
|
2012-06-09 02:25:12 +01:00
|
|
|
/* a successful finish ends here */
|
2012-05-29 04:03:28 +01:00
|
|
|
switch (serve->mirror->action_at_finish)
|
|
|
|
{
|
|
|
|
case ACTION_PROXY:
|
|
|
|
debug("proxy!");
|
|
|
|
serve->proxy_fd = serve->mirror->client;
|
|
|
|
/* don't close our file descriptor, we still need it! */
|
|
|
|
break;
|
|
|
|
case ACTION_EXIT:
|
|
|
|
debug("exit!");
|
2012-06-09 02:25:12 +01:00
|
|
|
close(serve->mirror->client);
|
2012-06-06 12:41:03 +01:00
|
|
|
serve_signal_close( serve );
|
2012-05-29 04:03:28 +01:00
|
|
|
/* fall through */
|
|
|
|
case ACTION_NOTHING:
|
|
|
|
debug("nothing!");
|
|
|
|
close(serve->mirror->client);
|
2012-05-23 00:42:14 +01:00
|
|
|
}
|
2012-06-09 02:25:12 +01:00
|
|
|
server_unlock_io( serve );
|
2012-05-23 00:42:14 +01:00
|
|
|
|
2012-06-09 02:25:12 +01:00
|
|
|
abandon_mirror:
|
2012-05-29 04:03:28 +01:00
|
|
|
free(serve->mirror->dirty_map);
|
|
|
|
free(serve->mirror);
|
|
|
|
serve->mirror = NULL; /* and we're gone */
|
|
|
|
|
2012-05-23 00:42:14 +01:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2012-05-23 14:03:30 +01:00
|
|
|
#define write_socket(msg) write(client->socket, (msg "\n"), strlen((msg))+1)
|
2012-05-23 00:42:14 +01:00
|
|
|
|
2012-05-29 04:03:28 +01:00
|
|
|
/** Command parser to start mirror process from socket input */
|
2012-05-23 14:03:30 +01:00
|
|
|
int control_mirror(struct control_params* client, int linesc, char** lines)
|
2012-05-23 00:42:14 +01:00
|
|
|
{
|
|
|
|
off64_t size, remote_size;
|
|
|
|
int fd, map_fd;
|
|
|
|
struct mirror_status *mirror;
|
|
|
|
union mysockaddr connect_to;
|
2012-06-06 12:35:01 +01:00
|
|
|
union mysockaddr connect_from;
|
|
|
|
int use_connect_from = 0;
|
2012-05-24 01:39:35 +01:00
|
|
|
uint64_t max_bytes_per_second;
|
|
|
|
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-05-29 00:59:12 +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-11 13:57:03 +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-06 12:35:01 +01:00
|
|
|
if (parse_ip_to_sockaddr(&connect_from.generic, lines[2]) == 0) {
|
|
|
|
write_socket("1: bad bind address");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
use_connect_from = 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
max_bytes_per_second = 0;
|
|
|
|
if (linesc > 3) {
|
2012-05-24 01:39:35 +01:00
|
|
|
max_bytes_per_second = atoi(lines[2]);
|
|
|
|
}
|
|
|
|
|
|
|
|
action_at_finish = ACTION_PROXY;
|
2012-06-06 12:35:01 +01:00
|
|
|
if (linesc > 4) {
|
2012-06-11 14:34:17 +01:00
|
|
|
if (strcmp("proxy", lines[3]) == 0) {
|
2012-05-24 01:39:35 +01:00
|
|
|
action_at_finish = ACTION_PROXY;
|
2012-06-11 14:34:17 +01:00
|
|
|
}
|
|
|
|
else 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 {
|
|
|
|
write_socket("1: action must be one of 'proxy', 'exit' or 'nothing'");
|
|
|
|
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
|
|
|
|
|
|
|
/** I don't like use_connect_from but socket_connect doesn't take *mysockaddr :( */
|
2012-06-11 14:34:17 +01:00
|
|
|
if (use_connect_from) {
|
2012-06-06 12:35:01 +01:00
|
|
|
fd = socket_connect(&connect_to.generic, &connect_from.generic);
|
2012-06-11 14:34:17 +01:00
|
|
|
}
|
|
|
|
else {
|
2012-06-06 12:35:01 +01:00
|
|
|
fd = socket_connect(&connect_to.generic, NULL);
|
2012-06-11 14:34:17 +01:00
|
|
|
}
|
2012-05-24 01:39:35 +01:00
|
|
|
|
2012-05-23 00:42:14 +01:00
|
|
|
|
|
|
|
remote_size = socket_nbd_read_hello(fd);
|
|
|
|
remote_size = remote_size; // shush compiler
|
|
|
|
|
|
|
|
mirror = xmalloc(sizeof(struct mirror_status));
|
|
|
|
mirror->client = fd;
|
2012-05-24 01:39:35 +01:00
|
|
|
mirror->max_bytes_per_second = max_bytes_per_second;
|
|
|
|
mirror->action_at_finish = action_at_finish;
|
2012-05-23 00:42:14 +01:00
|
|
|
|
2012-06-09 02:25:12 +01:00
|
|
|
FATAL_IF_NEGATIVE(
|
2012-05-23 00:42:14 +01:00
|
|
|
open_and_mmap(
|
|
|
|
client->serve->filename,
|
|
|
|
&map_fd,
|
|
|
|
&size,
|
|
|
|
(void**) &mirror->mapped
|
|
|
|
),
|
|
|
|
"Failed to open and mmap %s",
|
|
|
|
client->serve->filename
|
|
|
|
);
|
|
|
|
|
|
|
|
mirror->dirty_map = bitset_alloc(size, 4096);
|
|
|
|
bitset_set_range(mirror->dirty_map, 0, size);
|
|
|
|
|
|
|
|
client->serve->mirror = mirror;
|
|
|
|
|
2012-06-09 02:25:12 +01:00
|
|
|
FATAL_IF_NEGATIVE( /* FIXME should free mirror on error */
|
2012-05-23 00:42:14 +01:00
|
|
|
pthread_create(
|
|
|
|
&mirror->thread,
|
|
|
|
NULL,
|
|
|
|
mirror_runner,
|
|
|
|
client->serve
|
|
|
|
),
|
|
|
|
"Failed to create mirror thread"
|
|
|
|
);
|
2012-05-23 14:03:30 +01:00
|
|
|
|
2012-05-29 04:03:28 +01:00
|
|
|
write_socket("0: mirror started");
|
|
|
|
|
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
|
|
|
/** Command parser to alter access control list from socket input */
|
2012-05-23 14:03:30 +01:00
|
|
|
int control_acl(struct control_params* client, int linesc, char** lines)
|
2012-05-23 00:42:14 +01:00
|
|
|
{
|
2012-06-07 17:47:43 +01:00
|
|
|
NULLCHECK( client );
|
|
|
|
|
|
|
|
struct acl * old_acl = client->serve->acl;
|
|
|
|
struct acl * new_acl = acl_create( linesc, lines, old_acl ? old_acl->default_deny : 0 );
|
2012-05-23 00:42:14 +01:00
|
|
|
|
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],
|
|
|
|
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-08 10:32:33 +01:00
|
|
|
server_replace_acl( client->serve, new_acl );
|
2012-05-23 14:03:30 +01:00
|
|
|
write_socket("0: updated");
|
2012-05-23 00:42:14 +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(
|
|
|
|
struct control_params* client __attribute__ ((unused)),
|
|
|
|
int linesc __attribute__ ((unused)),
|
|
|
|
char** lines __attribute__((unused))
|
|
|
|
)
|
2012-05-23 00:42:14 +01:00
|
|
|
{
|
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-06-11 13:57:03 +01:00
|
|
|
void control_cleanup(struct control_params* client,
|
|
|
|
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-06-09 02:25:12 +01:00
|
|
|
free(client);
|
|
|
|
}
|
|
|
|
|
2012-05-29 04:03:28 +01:00
|
|
|
/** Master command parser for control socket connections, delegates quickly */
|
2012-05-23 00:42:14 +01:00
|
|
|
void* control_serve(void* client_uncast)
|
|
|
|
{
|
|
|
|
struct control_params* client = (struct control_params*) client_uncast;
|
2012-05-23 14:03:30 +01:00
|
|
|
char **lines = NULL;
|
|
|
|
int finished=0;
|
2012-05-23 00:42:14 +01:00
|
|
|
|
2012-06-09 02:25:12 +01:00
|
|
|
error_set_handler((cleanup_handler*) control_cleanup, client);
|
|
|
|
|
2012-05-23 14:03:30 +01:00
|
|
|
while (!finished) {
|
|
|
|
int i, linesc;
|
|
|
|
linesc = read_lines_until_blankline(client->socket, 256, &lines);
|
2012-05-23 00:42:14 +01:00
|
|
|
|
2012-05-23 14:03:30 +01:00
|
|
|
if (linesc < 1)
|
|
|
|
{
|
|
|
|
write(client->socket, "9: missing command\n", 19);
|
|
|
|
finished = 1;
|
|
|
|
/* ignore failure */
|
|
|
|
}
|
|
|
|
else if (strcmp(lines[0], "acl") == 0) {
|
2012-06-11 14:34:17 +01:00
|
|
|
if (control_acl(client, linesc-1, lines+1) < 0) {
|
2012-05-23 14:03:30 +01:00
|
|
|
finished = 1;
|
2012-06-11 14:34:17 +01:00
|
|
|
}
|
2012-05-23 14:03:30 +01:00
|
|
|
}
|
|
|
|
else if (strcmp(lines[0], "mirror") == 0) {
|
2012-06-11 14:34:17 +01:00
|
|
|
if (control_mirror(client, linesc-1, lines+1) < 0) {
|
2012-05-23 14:03:30 +01:00
|
|
|
finished = 1;
|
2012-06-11 14:34:17 +01:00
|
|
|
}
|
2012-05-23 14:03:30 +01:00
|
|
|
}
|
|
|
|
else if (strcmp(lines[0], "status") == 0) {
|
2012-06-11 14:34:17 +01:00
|
|
|
if (control_status(client, linesc-1, lines+1) < 0) {
|
2012-05-23 14:03:30 +01:00
|
|
|
finished = 1;
|
2012-06-11 14:34:17 +01:00
|
|
|
}
|
2012-05-23 14:03:30 +01:00
|
|
|
}
|
2012-05-23 00:42:14 +01:00
|
|
|
else {
|
2012-05-23 14:03:30 +01:00
|
|
|
write(client->socket, "10: unknown command\n", 23);
|
|
|
|
finished = 1;
|
2012-05-23 00:42:14 +01:00
|
|
|
}
|
2012-05-23 14:03:30 +01:00
|
|
|
|
2012-06-11 14:34:17 +01:00
|
|
|
for (i=0; i<linesc; i++) {
|
2012-05-23 14:03:30 +01:00
|
|
|
free(lines[i]);
|
2012-06-11 14:34:17 +01:00
|
|
|
}
|
2012-05-23 14:03:30 +01:00
|
|
|
free(lines);
|
2012-05-23 00:42:14 +01:00
|
|
|
}
|
|
|
|
|
2012-06-09 02:25:12 +01:00
|
|
|
control_cleanup(client, 0);
|
|
|
|
|
2012-05-23 00:42:14 +01:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2012-06-11 13:57:03 +01:00
|
|
|
void accept_control_connection(struct server* params, int client_fd,
|
|
|
|
union mysockaddr* client_address __attribute__ ((unused)) )
|
2012-05-23 00:42:14 +01:00
|
|
|
{
|
|
|
|
pthread_t control_thread;
|
|
|
|
struct control_params* control_params;
|
|
|
|
|
|
|
|
control_params = xmalloc(sizeof(struct control_params));
|
|
|
|
control_params->socket = client_fd;
|
|
|
|
control_params->serve = params;
|
|
|
|
|
2012-06-09 02:25:12 +01:00
|
|
|
FATAL_IF_NEGATIVE(
|
2012-05-23 00:42:14 +01:00
|
|
|
pthread_create(
|
|
|
|
&control_thread,
|
|
|
|
NULL,
|
|
|
|
control_serve,
|
|
|
|
control_params
|
|
|
|
),
|
|
|
|
"Failed to create client thread"
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2012-06-06 10:35:50 +01:00
|
|
|
void serve_open_control_socket(struct server* params)
|
2012-05-23 00:42:14 +01:00
|
|
|
{
|
|
|
|
struct sockaddr_un bind_address;
|
|
|
|
|
2012-06-11 14:34:17 +01:00
|
|
|
if (!params->control_socket_name) { return; }
|
2012-05-23 00:42:14 +01:00
|
|
|
|
2012-06-06 10:35:50 +01:00
|
|
|
params->control_fd = socket(AF_UNIX, SOCK_STREAM, 0);
|
2012-06-09 02:25:12 +01:00
|
|
|
FATAL_IF_NEGATIVE(params->control_fd ,
|
2012-05-23 00:42:14 +01:00
|
|
|
"Couldn't create control socket");
|
|
|
|
|
|
|
|
memset(&bind_address, 0, sizeof(bind_address));
|
|
|
|
bind_address.sun_family = AF_UNIX;
|
2012-05-29 00:59:12 +01:00
|
|
|
strncpy(bind_address.sun_path, params->control_socket_name, sizeof(bind_address.sun_path)-1);
|
2012-05-23 00:42:14 +01:00
|
|
|
|
|
|
|
unlink(params->control_socket_name); /* ignore failure */
|
|
|
|
|
2012-06-09 02:25:12 +01:00
|
|
|
FATAL_IF_NEGATIVE(
|
2012-06-06 10:35:50 +01:00
|
|
|
bind(params->control_fd , &bind_address, sizeof(bind_address)),
|
2012-05-23 00:42:14 +01:00
|
|
|
"Couldn't bind control socket to %s",
|
|
|
|
params->control_socket_name
|
|
|
|
);
|
|
|
|
|
2012-06-09 02:25:12 +01:00
|
|
|
FATAL_IF_NEGATIVE(
|
2012-06-06 10:35:50 +01:00
|
|
|
listen(params->control_fd , 5),
|
2012-05-23 00:42:14 +01:00
|
|
|
"Couldn't listen on control socket"
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|