msgchannel.c 2.83 KB
Newer Older
1 2 3 4
#include "common.h"
#include "msgchannel.h"
#include "connection.h"

5 6 7
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
8
#include <sys/types.h>
9 10 11 12 13

#ifndef MINGW
#include <sys/uio.h>
#endif

14
//
15 16 17

#ifdef MINGW

18
static inline ssize_t
19 20 21
__send (struct connection * conn, void * header, const size_t header_size, void * body, const size_t body_size) {
	ssize_t sent = connection_send_full (conn, header, header_size);
	sent += connection_send_full (conn, body, body_size);
22 23 24 25 26
	return sent;
}

#else

27
static inline ssize_t
28
__send (struct connection * conn, void * header, const size_t header_size, void * body, const size_t body_size) {
29 30
	struct iovec iovs [] = {
		{ .iov_base = header, .iov_len = header_size },
31
		{ .iov_base = body, .iov_len = body_size },
32 33
	};

34
	return connection_send_iov_full (conn, &iovs [0], sizeof_array (iovs));
35 36 37 38 39 40 41 42 43 44
}

#endif /* !MINGW */


/**
 * Sends the given message to the remote instrumentation server
 * via the given connection. Returns the number of bytes sent.
 */
ssize_t
45
message_send (struct connection * conn, void * message, const size_t message_size) {
46
	assert (conn != NULL);
47
	assert (message != NULL);
48

49
	ldebug ("sending message: %lu bytes", message_size);
50 51 52

	//

53 54 55 56
	uint32_t message_size_data = htonl (message_size);
	size_t header_size = sizeof (message_size_data);
	ssize_t sent = __send (conn, &message_size_data, header_size, message, message_size);
	assert (sent == (ssize_t) (header_size + message_size));
57 58 59

	//

60
	debug (", sent %ld bytes\n", sent);
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
	return sent;
}



static inline uint8_t *
__alloc_buffer (size_t len) {
	//
	// Allocate a buffer with an extra (zeroed) byte, but only if the
	// requested buffer length is greater than zero. Return NULL otherwise.
	//
	if (len == 0) {
		return NULL;
	}

	//

	uint8_t * buf = (uint8_t *) malloc (len + 1);
	check_error (buf == NULL, "failed to allocate buffer");

	buf [len] = '\0';
	return buf;
}


/**
 * Receives a message from the remote instrumentation server.
 */
89 90
ssize_t
message_recv (struct connection * conn, void ** message_ptr) {
91
	assert (conn != NULL);
92
	assert (message_ptr != NULL);
93

94
	ldebug ("receiving message: ");
95 96

	//
97 98
	// First receive the size of the message.
	// Then receive the message itself.
99
	//
100 101 102 103
	uint32_t message_size_data;
	connection_recv_full (conn, &message_size_data, sizeof (message_size_data));
	size_t message_size = ntohl (message_size_data);
	debug ("expecting %ld bytes", message_size);
104 105

	//
106 107 108 109
	// The message body can be completely empty. In this case,
	// the buffer allocator will just return NULL and we avoid
	// reading from the socket. We will set the message pointer
	// to NULL and return zero as message size.
110
	//
111 112
	uint8_t * message = __alloc_buffer (message_size);
	connection_recv_full (conn, message, message_size);
113 114

	//
115 116 117 118 119
	// Return the message only after the whole message was read.
	//
	debug ("... done\n");
	* message_ptr = (void *) message;
	return message_size;
120
}