summaryrefslogtreecommitdiffstats
path: root/src/bench/connection.c
blob: 129ae3ce0cc4ccf4d88ef77e8db1f1107f9ee961 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
#include "connection.h"
#include "helper.h"
#include "../config.h"
#include "../shared/protocol.h"
#include "../shared/fdsignal.h"
#include "../shared/sockhelper.h"
#include "../shared/log.h"

#include <stdlib.h>
#include <pthread.h>
#include <string.h>
#include <stdio.h>
#include <unistd.h>
#include <errno.h>

/* Constants */
static const size_t SHORTBUF = 100;
#define SOCKET_KEEPALIVE_TIMEOUT (3)
#define MAX_ALTS (8)
#define MAX_HOSTS_PER_ADDRESS (2)
// If a server wasn't reachable this many times, we slowly start skipping it on measurements
static const int FAIL_BACKOFF_START_COUNT = 8;
#define RTT_COUNT (4)

/* Module variables */

// Init guard
static bool connectionInitDone = false;
static bool keepRunning = true;

static struct {
	int sockFd;
	pthread_mutex_t sendMutex;
	dnbd3_signal_t* panicSignal;
	dnbd3_host_t currentServer;
	uint64_t startupTime;
} connection;

// Known alt servers
typedef struct _alt_server {
	dnbd3_host_t host;
	int consecutiveFails;
	int rtt;
	int rtts[RTT_COUNT];
	int rttIndex;
	int bestCount;
} alt_server_t;
alt_server_t altservers[MAX_ALTS];
dnbd3_server_entry_t newservers[MAX_ALTS];
pthread_spinlock_t altLock;

bool connection_init_n_times(
		const char *hosts,
		const char *lowerImage,
		const uint16_t rid,
		int ntimes,
		BenchCounters* counters,
		bool closeSockets
		) {
	for (int run_i = 0; run_i < ntimes; ++run_i) {
		counters->attempts++;

		printf(".");
		int sock = -1;
		char host[SHORTBUF];
		serialized_buffer_t buffer;
		uint16_t remoteVersion, remoteRid;
		char *remoteName;
		uint64_t remoteSize;

		if ( !connectionInitDone && keepRunning ) {
			dnbd3_host_t tempHosts[MAX_HOSTS_PER_ADDRESS];
			const char *current, *end;
			int altIndex = 0;
			memset( altservers, 0, sizeof altservers );
			connection.sockFd = -1;
			current = hosts;
			do {
				// Get next host from string
				while ( *current == ' ' ) current++;
				end = strchr( current, ' ' );
				size_t len = (end == NULL ? SHORTBUF : (size_t)( end - current ) + 1);
				if ( len > SHORTBUF ) len = SHORTBUF;
				snprintf( host, len, "%s", current );
				int newHosts = sock_resolveToDnbd3Host( host, tempHosts, MAX_HOSTS_PER_ADDRESS );
				for ( int i = 0; i < newHosts; ++i ) {
					if ( altIndex >= MAX_ALTS )
						break;
					altservers[altIndex].host = tempHosts[i];
					altIndex += 1;
				}
				current = end + 1;
			} while ( end != NULL && altIndex < MAX_ALTS );
			logadd( LOG_INFO, "Got %d servers from init call", altIndex );
			// Connect
			for ( int i = 0; i < altIndex; ++i ) {
				if ( altservers[i].host.type == 0 )
					continue;
				// Try to connect
				sock = sock_connect( &altservers[i].host, 500, SOCKET_KEEPALIVE_TIMEOUT * 1000 );
				if ( sock == -1 ) {
					counters->fails++;
					logadd( LOG_ERROR, "Could not connect to host" );
				} else if ( !dnbd3_select_image( sock, lowerImage, rid, 0 ) ) {
					counters->fails++;
					logadd( LOG_ERROR, "Could not send select image" );
				} else if ( !dnbd3_select_image_reply( &buffer, sock, &remoteVersion, &remoteName, &remoteRid, &remoteSize ) ) {
					counters->fails++;
					logadd( LOG_ERROR, "Could not read select image reply (%d)", errno );
				} else if ( rid != 0 && rid != remoteRid ) {
					counters->fails++;
					logadd( LOG_ERROR, "rid mismatch" );
				} else {
					counters->success++;
					break;
				}
				// Failed
				logadd( LOG_DEBUG1, "Server does not offer requested image... " );
				if ( sock != -1 ) {
					close( sock );
					sock = -1;
				}
			}
			if ( sock != -1 ) {
				// connectionInitDone = true;
				if (closeSockets) {
					close( sock );
				}
			}
		}
	}
	return true;
}