summaryrefslogtreecommitdiffstats
path: root/src/bench/connection.c
blob: 65f175773e08f3a34efaa0ab964dbe786f1f3c90 (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
134
135
136
137
138
139
140
#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)
#define RTT_COUNT (4)

/* Module variables */
static char trash[4096];

// 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,
		uint64_t blockSize,
		BenchCounters* counters
		) {
	for (int run_i = 0; run_i < ntimes; ++run_i) {
		counters->attempts++;

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

		dnbd3_host_t tempHosts[MAX_HOSTS_PER_ADDRESS];
		const char *current, *end;
		int altIndex = 0;
		memset( altservers, 0, sizeof altservers );
		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 );
		// Connect
		for ( int i = 0; i < altIndex; ++i ) {
			if ( altservers[i].host.type == 0 )
				continue;
			// Try to connect
			dnbd3_reply_t reply;
			sock = sock_connect( &altservers[i].host, 3500, 10000 );
			if ( sock == -1 ) {
				counters->fails++;
				logadd( LOG_ERROR, "Could not connect to host (errno=%d)", errno );
			} 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 if ( !dnbd3_get_block( sock, run_i * blockSize, blockSize, 0, 0 ) ) {
			} else if ( !dnbd3_get_block( sock, (((uint64_t)rand() << 16) + rand()) % (remoteSize - blockSize), blockSize, 0, 0 ) ) {
				counters->fails++;
				logadd( LOG_ERROR, "send: get block failed" );
			} else if ( !dnbd3_get_reply( sock, &reply ) ) {
				counters->fails++;
				logadd( LOG_ERROR, "recv: get block header failed" );
			} else if ( reply.cmd != CMD_GET_BLOCK ) {
				counters->fails++;
				logadd( LOG_ERROR, "recv: get block reply is not CMD_GET_BLOCK" );
			} else {
				int rv, togo = blockSize;
				do {
					rv = recv( sock, trash, MIN( sizeof(trash), togo ), MSG_WAITALL|MSG_NOSIGNAL );
					if ( rv == -1 && errno == EINTR )
						continue;
					if ( rv <= 0 )
						break;
					togo -= rv;
				} while ( togo > 0 );
				if ( togo != 0 ) {
					counters->fails++;
					logadd( LOG_ERROR, "recv: get block payload failed (remaining %d)", togo );
				} else {
					counters->success++;
					close( sock );
					sock = -1;
					continue;
				}
			}
			// Failed
			if ( sock != -1 ) {
				close( sock );
				sock = -1;
			}
		}
		if ( sock != -1 ) {
			close( sock );
		}
	}
	return true;
}