Merge, just renaming old error macros.

This commit is contained in:
Matthew Bloch
2012-06-09 02:37:23 +01:00
10 changed files with 502 additions and 87 deletions

View File

@@ -34,6 +34,75 @@ static inline void* sockaddr_address_data(struct sockaddr* sockaddr)
return NULL;
}
struct server * server_create (
char* s_ip_address,
char* s_port,
char* s_file,
char *s_ctrl_sock,
int default_deny,
int acl_entries,
char** s_acl_entries )
{
struct server * out;
out = xmalloc( sizeof( struct server ) );
out->tcp_backlog = 10; /* does this need to be settable? */
if (s_ip_address == NULL)
fatal("No IP address supplied");
if (s_port == NULL)
fatal("No port number supplied");
if (s_file == NULL)
fatal("No filename supplied");
if (parse_ip_to_sockaddr(&out->bind_to.generic, s_ip_address) == 0)
fatal("Couldn't parse server address '%s' (use 0 if "
"you want to bind to all IPs)", s_ip_address);
/* control_socket_name is optional. It just won't get created if
* we pass NULL. */
out->control_socket_name = s_ctrl_sock;
out->acl = acl_create( acl_entries, s_acl_entries, default_deny );
if (out->acl && out->acl->len != acl_entries)
fatal("Bad ACL entry '%s'", s_acl_entries[out->acl->len]);
out->bind_to.v4.sin_port = atoi(s_port);
if (out->bind_to.v4.sin_port < 0 || out->bind_to.v4.sin_port > 65535)
fatal("Port number must be >= 0 and <= 65535");
out->bind_to.v4.sin_port = htobe16(out->bind_to.v4.sin_port);
out->filename = s_file;
out->filename_incomplete = xmalloc(strlen(s_file)+11+1);
strcpy(out->filename_incomplete, s_file);
strcpy(out->filename_incomplete + strlen(s_file), ".INCOMPLETE");
pthread_mutex_init(&out->l_io, NULL);
pthread_mutex_init(&out->l_acl, NULL);
out->close_signal = self_pipe_create();
out->acl_updated_signal = self_pipe_create();
NULLCHECK( out->close_signal );
NULLCHECK( out->acl_updated_signal );
return out;
}
void server_destroy( struct server * serve )
{
self_pipe_destroy( serve->acl_updated_signal );
self_pipe_destroy( serve->close_signal );
pthread_mutex_destroy( &serve->l_acl );
pthread_mutex_destroy( &serve->l_io );
if ( serve->acl ) { acl_destroy( serve->acl ); }
free( serve );
}
void server_dirty(struct server *serve, off64_t from, int len)
{
NULLCHECK( serve );
@@ -42,29 +111,51 @@ void server_dirty(struct server *serve, off64_t from, int len)
bitset_set_range(serve->mirror->dirty_map, from, len);
}
int server_lock_io( struct server * serve)
#define SERVER_LOCK( s, f, msg ) \
{ NULLCHECK( s ); \
FATAL_IF_NEGATIVE( pthread_mutex_lock( &s->f ), msg ); }
#define SERVER_UNLOCK( s, f, msg ) \
{ NULLCHECK( s ); \
FATAL_IF_NEGATIVE( pthread_mutex_unlock( &s->f ), msg ); }
void server_lock_io( struct server * serve)
{
NULLCHECK( serve );
FATAL_IF_NEGATIVE(
pthread_mutex_lock(&serve->l_io),
"Problem with I/O lock"
);
return 1;
SERVER_LOCK( serve, l_io, "Problem with I/O lock" );
}
void server_unlock_io( struct server* serve )
{
NULLCHECK( serve );
FATAL_IF_NEGATIVE(
pthread_mutex_unlock(&serve->l_io),
"Problem with I/O unlock"
);
SERVER_UNLOCK( serve, l_io, "Problem with I/O unlock" );
}
void server_lock_acl( struct server *serve )
{
SERVER_LOCK( serve, l_acl, "Problem with ACL lock" );
}
void server_unlock_acl( struct server *serve )
{
SERVER_UNLOCK( serve, l_acl, "Problem with ACL unlock" );
}
/** Return the actual port the server bound to. This is used because we
* are allowed to pass "0" on the command-line.
*/
int server_port( struct server * server )
{
NULLCHECK( server );
union mysockaddr addr;
socklen_t len = sizeof( addr.v4 );
if ( getsockname( server->server_fd, &addr.v4, &len ) < 0 ) {
fatal( "Failed to get the port number." );
}
return be16toh( addr.v4.sin_port );
}
/** Prepares a listening socket for the NBD server, binding etc. */
void serve_open_server_socket(struct server* params)
{
@@ -100,6 +191,8 @@ void serve_open_server_socket(struct server* params)
);
}
int tryjoin_client_thread( struct client_tbl_entry *entry, int (*joinfunc)(pthread_t, void **) )
{
@@ -192,16 +285,26 @@ int cleanup_and_find_client_slot(struct server* params)
}
/** Check whether the address client_address is allowed or not according
* to the current acl. If params->acl is NULL, the result will be 1,
* otherwise it will be the result of acl_includes().
*/
int server_acl_accepts( struct server *params, union mysockaddr * client_address )
{
NULLCHECK( params );
NULLCHECK( client_address );
if (params->acl) {
return acl_includes( params->acl, client_address );
}
struct acl * acl;
int accepted;
return 1;
server_lock_acl( params );
{
acl = params->acl;
accepted = acl ? acl_includes( acl, client_address ) : 1;
}
server_unlock_acl( params );
return accepted;
}
@@ -274,7 +377,7 @@ void accept_nbd_client(
memcpy(&params->nbd_client[slot].address, client_address,
sizeof(union mysockaddr));
if (pthread_create(&params->nbd_client[slot].thread, NULL, client_serve, client_params) < 0) {
if (pthread_create(&params->nbd_client[slot].thread, NULL, client_serve, client_params) != 0) {
debug( "Thread creation problem." );
write(client_fd, "Thread creation problem", 23);
client_destroy( client_params );
@@ -286,6 +389,30 @@ void accept_nbd_client(
}
void server_audit_clients( struct server * serve)
{
NULLCHECK( serve );
int i;
struct client_tbl_entry * entry;
/* There's an apparent race here. If the acl updates while
* we're traversing the nbd_clients array, the earlier entries
* won't have been audited against the later acl. This isn't a
* problem though, because in order to update the acl
* server_replace_acl must have been called, so the
* server_accept loop will see a second acl_updated signal as
* soon as it hits select, and a second audit will be run.
*/
for( i = 0; i < MAX_NBD_CLIENTS; i++ ) {
entry = &serve->nbd_client[i];
if ( 0 == entry->thread ) { continue; }
if ( server_acl_accepts( serve, &entry->address ) ) { continue; }
client_signal_stop( entry->client );
}
}
int server_is_closed(struct server* serve)
{
NULLCHECK( serve );
@@ -315,45 +442,79 @@ void server_close_clients( struct server *params )
}
/** Replace the current acl with a new one. The old one will be thrown
* away.
*/
void server_replace_acl( struct server *serve, struct acl * new_acl )
{
NULLCHECK(serve);
NULLCHECK(new_acl);
/* We need to lock around updates to the acl in case we try to
* destroy the old acl while checking against it.
*/
server_lock_acl( serve );
{
struct acl * old_acl = serve->acl;
serve->acl = new_acl;
/* We should always have an old_acl, but just in case... */
if ( old_acl ) { acl_destroy( old_acl ); }
}
server_unlock_acl( serve );
self_pipe_signal( serve->acl_updated_signal );
}
/** Accept either an NBD or control socket connection, dispatch appropriately */
void serve_accept_loop(struct server* params)
int server_accept( struct server * params )
{
NULLCHECK( params );
info("accept loop starting");
while (1) {
int activity_fd, client_fd;
union mysockaddr client_address;
fd_set fds;
socklen_t socklen=sizeof(client_address);
FD_ZERO(&fds);
FD_SET(params->server_fd, &fds);
self_pipe_fd_set( params->close_signal, &fds );
if (params->control_socket_name)
FD_SET(params->control_fd, &fds);
FATAL_IF_NEGATIVE(select(FD_SETSIZE, &fds,
NULL, NULL, NULL), "select() failed");
if ( self_pipe_fd_isset( params->close_signal, &fds ) ){
server_close_clients( params );
return;
}
activity_fd = FD_ISSET(params->server_fd, &fds) ? params->server_fd:
params->control_fd;
client_fd = accept(activity_fd, &client_address.generic, &socklen);
if (activity_fd == params->server_fd) {
info("Accepted nbd client socket");
accept_nbd_client(params, client_fd, &client_address);
}
if (activity_fd == params->control_fd) {
info("Accepted control client socket");
accept_control_connection(params, client_fd, &client_address);
}
int activity_fd, client_fd;
union mysockaddr client_address;
fd_set fds;
socklen_t socklen=sizeof(client_address);
FD_ZERO(&fds);
FD_SET(params->server_fd, &fds);
self_pipe_fd_set( params->close_signal, &fds );
self_pipe_fd_set( params->acl_updated_signal, &fds );
if (params->control_socket_name)
FD_SET(params->control_fd, &fds);
FATAL_IF_NEGATIVE(select(FD_SETSIZE, &fds,
NULL, NULL, NULL), "select() failed");
if ( self_pipe_fd_isset( params->close_signal, &fds ) ){
server_close_clients( params );
return 0;
}
if ( self_pipe_fd_isset( params->acl_updated_signal, &fds ) ) {
server_audit_clients( params );
}
activity_fd = FD_ISSET(params->server_fd, &fds) ? params->server_fd:
params->control_fd;
client_fd = accept(activity_fd, &client_address.generic, &socklen);
if (activity_fd == params->server_fd) {
debug("Accepted nbd client socket");
accept_nbd_client(params, client_fd, &client_address);
}
if (activity_fd == params->control_fd) {
debug("Accepted control client socket");
accept_control_connection(params, client_fd, &client_address);
}
return 1;
}
void serve_accept_loop(struct server* params)
{
while( server_accept( params ) );
}
/** Initialisation function that sets up the initial allocation map, i.e. so
@@ -370,7 +531,7 @@ void serve_init_allocation_map(struct server* params)
size = lseek64(fd, 0, SEEK_END);
params->size = size;
FATAL_IF_NEGATIVE(size, "Couldn't find size of %s",
params->filename);
params->filename);
params->allocation_map =
build_allocation_map(fd, size, block_allocation_resolution);
close(fd);
@@ -399,17 +560,14 @@ void serve_cleanup(struct server* params, int fatal)
close(params->server_fd);
if (params->control_fd)
close(params->control_fd);
if (params->acl)
free(params->acl);
if (params->control_socket_name)
if (params->control_socket_name){
;
pthread_mutex_destroy(&params->l_io);
}
if (params->proxy_fd);
close(params->proxy_fd);
if (params->close_signal)
self_pipe_destroy( params->close_signal );
if (params->allocation_map)
free(params->allocation_map);
@@ -435,13 +593,6 @@ void do_serve(struct server* params)
NULLCHECK( params );
error_set_handler((cleanup_handler*) serve_cleanup, params);
pthread_mutex_init(&params->l_io, NULL);
params->close_signal = self_pipe_create();
if ( NULL == params->close_signal) {
fatal( "close signal creation failed" );
}
serve_open_server_socket(params);
serve_open_control_socket(params);
serve_init_allocation_map(params);