summaryrefslogtreecommitdiffstats
path: root/src/server/net.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/server/net.c')
-rw-r--r--src/server/net.c112
1 files changed, 71 insertions, 41 deletions
diff --git a/src/server/net.c b/src/server/net.c
index 9abe221..9c855e4 100644
--- a/src/server/net.c
+++ b/src/server/net.c
@@ -24,6 +24,7 @@
#include "locks.h"
#include "rpc.h"
#include "altservers.h"
+#include "reference.h"
#include "../shared/sockhelper.h"
#include "../shared/timing.h"
@@ -43,6 +44,7 @@
#include <jansson.h>
#include <inttypes.h>
#include <stdatomic.h>
+#include <signal.h>
static dnbd3_client_t *_clients[SERVER_MAX_CLIENTS];
static int _num_clients = 0;
@@ -145,13 +147,14 @@ static inline bool sendPadding( const int fd, uint32_t bytes )
void net_init()
{
- mutex_init( &_clients_lock );
+ mutex_init( &_clients_lock, LOCK_CLIENT_LIST );
}
void* net_handleNewConnection(void *clientPtr)
{
dnbd3_client_t * const client = (dnbd3_client_t *)clientPtr;
dnbd3_request_t request;
+ client->thread = pthread_self();
// Await data from client. Since this is a fresh connection, we expect data right away
sock_setTimeout( client->sock, _clientTimeout );
@@ -186,8 +189,8 @@ void* net_handleNewConnection(void *clientPtr)
}
} while (0);
// Fully init client struct
- mutex_init( &client->lock );
- mutex_init( &client->sendMutex );
+ mutex_init( &client->lock, LOCK_CLIENT );
+ mutex_init( &client->sendMutex, LOCK_CLIENT_SEND );
mutex_lock( &client->lock );
host_to_string( &client->host, client->hostName, HOSTNAMELEN );
@@ -229,7 +232,7 @@ void* net_handleNewConnection(void *clientPtr)
rid = serializer_get_uint16( &payload );
const uint8_t flags = serializer_get_uint8( &payload );
client->isServer = ( flags & FLAGS8_SERVER );
- if ( request.size < 3 || !image_name || client_version < MIN_SUPPORTED_CLIENT ) {
+ if ( unlikely( request.size < 3 || !image_name || client_version < MIN_SUPPORTED_CLIENT ) ) {
if ( client_version < MIN_SUPPORTED_CLIENT ) {
logadd( LOG_DEBUG1, "Client %s too old", client->hostName );
} else {
@@ -255,25 +258,27 @@ void* net_handleNewConnection(void *clientPtr)
// No BGR mismatch, but don't lookup if image is unknown locally
image = image_get( image_name, rid, true );
}
- mutex_lock( &client->lock );
client->image = image;
- mutex_unlock( &client->lock );
- if ( image == NULL ) {
+ atomic_thread_fence( memory_order_release );
+ if ( unlikely( image == NULL ) ) {
//logadd( LOG_DEBUG1, "Client requested non-existent image '%s' (rid:%d), rejected\n", image_name, (int)rid );
- } else if ( !image->working ) {
+ } else if ( unlikely( !image->working ) ) {
logadd( LOG_DEBUG1, "Client %s requested non-working image '%s' (rid:%d), rejected\n",
client->hostName, image_name, (int)rid );
} else {
- bool penalty;
// Image is fine so far, but occasionally drop a client if the uplink for the image is clogged or unavailable
bOk = true;
if ( image->cache_map != NULL ) {
- mutex_lock( &image->lock );
- if ( image->uplink == NULL || image->uplink->cacheFd == -1 || image->uplink->queueLen > SERVER_UPLINK_QUEUELEN_THRES ) {
+ dnbd3_uplink_t *uplink = ref_get_uplink( &image->uplinkref );
+ if ( uplink == NULL || uplink->cacheFd == -1 || uplink->queueLen > SERVER_UPLINK_QUEUELEN_THRES ) {
bOk = ( rand() % 4 ) == 1;
}
- penalty = bOk && image->uplink != NULL && image->uplink->cacheFd == -1;
- mutex_unlock( &image->lock );
+ bool penalty = bOk && ( uplink == NULL || uplink->cacheFd == -1 );
+ if ( uplink == NULL ) {
+ uplink_init( image, -1, NULL, 0 );
+ } else {
+ ref_put( &uplink->reference );
+ }
if ( penalty ) { // Wait 100ms if local caching is not working so this
usleep( 100000 ); // server gets a penalty and is less likely to be selected
}
@@ -301,7 +306,7 @@ void* net_handleNewConnection(void *clientPtr)
}
}
- if ( bOk ) {
+ if ( likely( bOk ) ) {
// add artificial delay if applicable
if ( client->isServer && _serverPenalty != 0 ) {
usleep( _serverPenalty );
@@ -315,7 +320,8 @@ void* net_handleNewConnection(void *clientPtr)
case CMD_GET_BLOCK:;
const uint64_t offset = request.offset_small; // Copy to full uint64 to prevent repeated masking
- if ( offset >= image->virtualFilesize ) {
+ reply.handle = request.handle;
+ if ( unlikely( offset >= image->virtualFilesize ) ) {
// Sanity check
logadd( LOG_WARNING, "Client %s requested non-existent block", client->hostName );
reply.size = 0;
@@ -323,7 +329,7 @@ void* net_handleNewConnection(void *clientPtr)
send_reply( client->sock, &reply, NULL );
break;
}
- if ( offset + request.size > image->virtualFilesize ) {
+ if ( unlikely( offset + request.size > image->virtualFilesize ) ) {
// Sanity check
logadd( LOG_WARNING, "Client %s requested data block that extends beyond image size", client->hostName );
reply.size = 0;
@@ -396,10 +402,9 @@ void* net_handleNewConnection(void *clientPtr)
reply.cmd = CMD_GET_BLOCK;
reply.size = request.size;
- reply.handle = request.handle;
fixup_reply( reply );
- const bool lock = image->uplink != NULL;
+ const bool lock = image->uplinkref != NULL;
if ( lock ) mutex_lock( &client->sendMutex );
// Send reply header
if ( send( client->sock, &reply, sizeof(dnbd3_reply_t), (request.size == 0 ? 0 : MSG_MORE) ) != sizeof(dnbd3_reply_t) ) {
@@ -533,16 +538,15 @@ exit_client_cleanup: ;
removeFromList( client );
totalBytesSent += client->bytesSent;
// Access time, but only if client didn't just probe
- if ( image != NULL ) {
+ if ( image != NULL && client->bytesSent > DNBD3_BLOCK_SIZE * 10 ) {
mutex_lock( &image->lock );
- if ( client->bytesSent > DNBD3_BLOCK_SIZE * 10 ) {
- timing_get( &image->atime );
- }
+ timing_get( &image->atime );
mutex_unlock( &image->lock );
}
freeClientStruct( client ); // This will also call image_release on client->image
return NULL ;
fail_preadd: ;
+ // This is before we even initialized any mutex
close( client->sock );
free( client );
return NULL;
@@ -609,6 +613,12 @@ void net_getStats(int *clientCount, int *serverCount, uint64_t *bytesSent)
}
bs += client->bytesSent;
}
+ // Do this before unlocking the list, otherwise we might
+ // account for a client twice if it would disconnect after
+ // unlocking but before we add the count here.
+ if ( bytesSent != NULL ) {
+ *bytesSent = totalBytesSent + bs;
+ }
mutex_unlock( &_clients_lock );
if ( clientCount != NULL ) {
*clientCount = cc;
@@ -616,9 +626,6 @@ void net_getStats(int *clientCount, int *serverCount, uint64_t *bytesSent)
if ( serverCount != NULL ) {
*serverCount = sc;
}
- if ( bytesSent != NULL ) {
- *bytesSent = totalBytesSent + bs;
- }
}
void net_disconnectAll()
@@ -626,11 +633,10 @@ void net_disconnectAll()
int i;
mutex_lock( &_clients_lock );
for (i = 0; i < _num_clients; ++i) {
- if ( _clients[i] == NULL ) continue;
- dnbd3_client_t * const client = _clients[i];
- mutex_lock( &client->lock );
- if ( client->sock >= 0 ) shutdown( client->sock, SHUT_RDWR );
- mutex_unlock( &client->lock );
+ if ( _clients[i] == NULL )
+ continue;
+ shutdown( _clients[i]->sock, SHUT_RDWR );
+ pthread_kill( _clients[i]->thread, SIGINT );
}
mutex_unlock( &_clients_lock );
}
@@ -668,11 +674,19 @@ static void removeFromList(dnbd3_client_t *client)
{
int i;
mutex_lock( &_clients_lock );
- for ( i = _num_clients - 1; i >= 0; --i ) {
- if ( _clients[i] == client ) {
- _clients[i] = NULL;
+ if ( _num_clients != 0 ) {
+ for ( i = _num_clients - 1; i >= 0; --i ) {
+ if ( _clients[i] == client ) {
+ _clients[i] = NULL;
+ break;
+ }
+ }
+ if ( i != 0 && i + 1 == _num_clients ) {
+ do {
+ i--;
+ } while ( _clients[i] == NULL && i > 0 );
+ _num_clients = i + 1;
}
- if ( _clients[i] == NULL && i + 1 == _num_clients ) --_num_clients;
}
mutex_unlock( &_clients_lock );
}
@@ -686,17 +700,21 @@ static void removeFromList(dnbd3_client_t *client)
static dnbd3_client_t* freeClientStruct(dnbd3_client_t *client)
{
mutex_lock( &client->lock );
+ if ( client->image != NULL ) {
+ dnbd3_uplink_t *uplink = ref_get_uplink( &client->image->uplinkref );
+ if ( uplink != NULL ) {
+ uplink_removeClient( uplink, client );
+ ref_put( &uplink->reference );
+ }
+ }
mutex_lock( &client->sendMutex );
- if ( client->sock != -1 ) close( client->sock );
+ if ( client->sock != -1 ) {
+ close( client->sock );
+ }
client->sock = -1;
mutex_unlock( &client->sendMutex );
- if ( client->image != NULL ) {
- mutex_lock( &client->image->lock );
- if ( client->image->uplink != NULL ) uplink_removeClient( client->image->uplink, client );
- mutex_unlock( &client->image->lock );
- client->image = image_release( client->image );
- }
mutex_unlock( &client->lock );
+ client->image = image_release( client->image );
mutex_destroy( &client->lock );
mutex_destroy( &client->sendMutex );
free( client );
@@ -729,3 +747,15 @@ static bool addToList(dnbd3_client_t *client)
return true;
}
+void net_sendReply(dnbd3_client_t *client, uint16_t cmd, uint64_t handle)
+{
+ dnbd3_reply_t reply;
+ reply.magic = dnbd3_packet_magic;
+ reply.cmd = cmd;
+ reply.handle = handle;
+ reply.size = 0;
+ mutex_lock( &client->sendMutex );
+ send_reply( client->sock, &reply, NULL );
+ mutex_unlock( &client->sendMutex );
+}
+