File: socket.c

package info (click to toggle)
uftrace 0.18.1-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 5,356 kB
  • sloc: ansic: 49,770; python: 11,181; asm: 837; makefile: 769; sh: 637; cpp: 627; javascript: 191
file content (153 lines) | stat: -rw-r--r-- 3,639 bytes parent folder | download | duplicates (2)
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
141
142
143
144
145
146
147
148
149
150
151
152
153
#include <errno.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <unistd.h>

#include "uftrace.h"
#include "utils/socket.h"
#include "utils/utils.h"

/* Unlink socket file if it exists */
void socket_unlink(struct sockaddr_un *addr)
{
	if (unlink(addr->sun_path) == -1) {
		if (errno != ENOENT)
			pr_dbg("cannot unlink socket '%s'\n", addr->sun_path);
	}
}

/* Create socket for communication between the client and the agent */
int agent_socket_create(struct sockaddr_un *addr, pid_t pid)
{
	int fd;
	char *channel = NULL;

	fd = socket(AF_UNIX, SOCK_STREAM, 0);
	if (fd == -1) {
		pr_warn("socket creation failed: %s\n", strerror(errno));
		return fd;
	}
	memset(addr, 0, sizeof(struct sockaddr_un));
	xasprintf(&channel, "%s/%d.socket", MCOUNT_AGENT_SOCKET_DIR, pid);
	addr->sun_family = AF_UNIX;
	strncpy(addr->sun_path, channel, sizeof(addr->sun_path) - 1);
	free(channel);
	return fd;
}

/* Setup socket on agent side so it can accept client connection */
int agent_listen(int fd, struct sockaddr_un *addr)
{
	if (bind(fd, (struct sockaddr *)addr, sizeof(struct sockaddr_un)) == -1) {
		pr_warn("cannot bind to socket '%s': %s\n", addr->sun_path, strerror(errno));
		return -1;
	}

	if (listen(fd, 1) == -1) {
		pr_warn("cannot listen to socket '%s': %s\n", addr->sun_path, strerror(errno));
		return -1;
	}

	return 0;
}

/* Client side: connect to an agent socket */
int agent_connect(int fd, struct sockaddr_un *addr)
{
	if (connect(fd, (struct sockaddr *)addr, sizeof(struct sockaddr_un)) == -1) {
		pr_warn("cannot connect to socket '%s': %s\n", addr->sun_path, strerror(errno));
		return -1;
	}

	return 0;
}

/* Agent side: accept incoming client connection */
int agent_accept(int fd)
{
	return accept(fd, NULL, NULL);
}

/**
 * agent_message_send - send a message through the agent socket
 * @fd     - socket file descriptor
 * @type   - type of message to send
 * @data   - data load
 * @size   - size of @data
 * @return - status code, negative for error
 */
int agent_message_send(int fd, int type, void *data, size_t size)
{
	struct uftrace_msg msg = {
		.magic = UFTRACE_MSG_MAGIC,
		.type = type,
		.len = size,
	};
	struct iovec iov[2] = {
		{
			.iov_base = &msg,
			.iov_len = sizeof(msg),
		},
		{
			.iov_base = data,
			.iov_len = size,
		},
	};

	pr_dbg4("send agent message [%d] (size=%d)\n", type, size);
	if (writev_all(fd, iov, ARRAY_SIZE(iov)) < 0) {
		pr_dbg3("error writing message to agent socket\n");
		return -1;
	}

	return 0;
}

/**
 * agent_message_read_head - read message header from the agent socket
 *
 * Fetch the message type and size so the data load can be read somewhere else.
 *
 * @fd     - socket file descriptor
 * @msg    - received message head
 * @return - status code, negative for error
 */
int agent_message_read_head(int fd, struct uftrace_msg *msg)
{
	if (read_all(fd, msg, sizeof(*msg)) < 0) {
		pr_dbg4("error reading agent message header\n");
		return -1;
	}

	if (msg->magic != UFTRACE_MSG_MAGIC) {
		pr_dbg4("invalid agent message received\n");
		return -1;
	}

	return 0;
}

/**
 * agent_message_read_response - read agent ack
 * @fd - socket file descriptor
 * @response - ack from agent
 * @return - status: data or error code, negative on error
 */
int agent_message_read_response(int fd, struct uftrace_msg *response)
{
	int status = 0;

	if (agent_message_read_head(fd, response) < 0)
		return -1;

	if (response->len > sizeof(status))
		return -1;

	if (read_all(fd, &status, response->len) < 0) {
		pr_dbg3("error reading agent socket\n");
		return -1;
	}
	pr_dbg4("read agent response [%d] (size=%d)\n", response->type, response->len);

	return status;
}