summaryrefslogtreecommitdiffstats
path: root/src/server/protocol.h
blob: d54f44e14dee3ca8d2ba44c6effa33cc3f7b9f03 (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
#ifndef _PROTOCOL_H_
#define _PROTOCOL_H_

#include "../types.h"
#include "../serialize.h"

#define FLAGS8_SERVER 1

static inline int dnbd3_get_reply(int sock, dnbd3_reply_t *reply)
{
	if ( recv( sock, reply, sizeof(*reply), MSG_WAITALL ) != sizeof(*reply) ) {
		return FALSE;
	}
	fixup_reply( *reply );
	if ( reply->magic != dnbd3_packet_magic ) return FALSE;
	return TRUE;
}

static inline int dnbd3_select_image(int sock, char *lower_name, uint16_t rid, uint8_t flags8)
{
	serialized_buffer_t serialized;
	dnbd3_request_t request;
	struct iovec iov[2];
	serializer_reset_write( &serialized );
	serializer_put_uint16( &serialized, PROTOCOL_VERSION );
	serializer_put_string( &serialized, lower_name );
	serializer_put_uint16( &serialized, rid );
	serializer_put_uint8( &serialized, flags8 );
	const ssize_t len = serializer_get_written_length( &serialized );
	request.magic = dnbd3_packet_magic;
	request.cmd = CMD_SELECT_IMAGE;
	request.size = len;
#ifdef _DEBUG
	request.handle = 0;
	request.offset = 0;
#endif
	fixup_request( request );
	iov[0].iov_base = &request;
	iov[0].iov_len = sizeof(request);
	iov[1].iov_base = &serialized;
	iov[1].iov_len = len;
	return writev( sock, iov, 2 ) == len + sizeof(request);
}

static inline int dnbd3_get_block(int sock, uint64_t offset, uint32_t size)
{
	dnbd3_request_t request;
	request.magic = dnbd3_packet_magic;
	request.handle = 0;
	request.cmd = CMD_GET_BLOCK;
	request.offset = offset;
	request.size = size;
	fixup_request( request );
	return send( sock, &request, sizeof(request), 0 ) == sizeof(request);
}

static inline int dnbd3_get_crc32(int sock, uint32_t *master, void *buffer, size_t *bufferLen)
{
	dnbd3_request_t request;
	dnbd3_reply_t reply;
	request.magic = dnbd3_packet_magic;
	request.handle = 0;
	request.cmd = CMD_GET_CRC32;
	request.offset = 0;
	request.size = 0;
	fixup_request( request );
	if ( send( sock, &request, sizeof(request), 0 ) != sizeof(request) ) return FALSE;
	if ( !dnbd3_get_reply( sock, &reply ) ) return FALSE;
	if ( reply.size == 0 ) {
		*bufferLen = 0;
		return TRUE;
	}
	if ( reply.size < 4 ) return FALSE;
	reply.size -= 4;
	if ( reply.cmd != CMD_GET_CRC32 || reply.size > *bufferLen ) return FALSE;
	*bufferLen = reply.size;
	if ( recv( sock, master, sizeof(uint32_t), MSG_WAITALL ) != sizeof(uint32_t) ) return FALSE;
	int done = 0;
	while ( done < reply.size ) {
		const int ret = recv( sock, buffer + done, reply.size - done, 0 );
		if ( ret <= 0 ) return FALSE;
		done += ret;
	}
	return TRUE;
}

/**
 * Pass a full serialized_buffer_t and a socket fd. Parsed data will be returned in further arguments.
 * Note that all strings will point into the passed buffer, so there's no need to free them.
 */
static inline int dnbd3_select_image_reply(serialized_buffer_t *buffer, int sock, uint16_t *protocol_version, char **name, uint16_t *rid,
        uint64_t *imageSize)
{
	dnbd3_reply_t reply;
	if ( !dnbd3_get_reply( sock, &reply ) ) {
		return FALSE;
	}
	if ( reply.cmd != CMD_SELECT_IMAGE || reply.size < 3 || reply.size > MAX_PAYLOAD ) {
		return FALSE;
	}
// receive reply payload
	if ( recv( sock, buffer, reply.size, MSG_WAITALL ) != reply.size ) {
		return FALSE;
	}
// handle/check reply payload
	serializer_reset_read( buffer, reply.size );
	*protocol_version = serializer_get_uint16( buffer );
	*name = serializer_get_string( buffer );
	*rid = serializer_get_uint16( buffer );
	*imageSize = serializer_get_uint64( buffer );
	return TRUE;
}

#endif