Directory: | src/ |
---|---|
File: | src/net.c |
Date: | 2023-08-28 07:33:56 |
Exec | Total | Coverage | |
---|---|---|---|
Lines: | 101 | 157 | 64.3% |
Branches: | 31 | 96 | 32.3% |
Line | Branch | Exec | Source |
---|---|---|---|
1 | /* | ||
2 | * Copyright (c) 2022 Egor Tensin <Egor.Tensin@gmail.com> | ||
3 | * This file is part of the "cimple" project. | ||
4 | * For details, see https://github.com/egor-tensin/cimple. | ||
5 | * Distributed under the MIT License. | ||
6 | */ | ||
7 | |||
8 | #include "net.h" | ||
9 | #include "file.h" | ||
10 | #include "log.h" | ||
11 | |||
12 | #include <netdb.h> | ||
13 | #include <stdint.h> | ||
14 | #include <stdlib.h> | ||
15 | #include <string.h> | ||
16 | #include <sys/socket.h> | ||
17 | #include <sys/types.h> | ||
18 | #include <unistd.h> | ||
19 | |||
20 | #define gai_log_errno(ec) log_err("getaddrinfo: %s\n", gai_strerror(ec)) | ||
21 | |||
22 | 29 | int net_bind(const char *port) | |
23 | { | ||
24 | static const int flags = SOCK_CLOEXEC; | ||
25 | 29 | struct addrinfo *result = NULL, *it = NULL; | |
26 | struct addrinfo hints; | ||
27 | 29 | int socket_fd = -1, ret = 0; | |
28 | |||
29 | 29 | memset(&hints, 0, sizeof(hints)); | |
30 | 29 | hints.ai_family = AF_INET6; | |
31 | 29 | hints.ai_socktype = SOCK_STREAM; | |
32 | 29 | hints.ai_flags = AI_PASSIVE; | |
33 | |||
34 | 29 | ret = getaddrinfo(NULL, port, &hints, &result); | |
35 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 29 times.
|
29 | if (ret) { |
36 | ✗ | gai_log_errno(ret); | |
37 | ✗ | return -1; | |
38 | } | ||
39 | |||
40 |
1/2✓ Branch 0 taken 29 times.
✗ Branch 1 not taken.
|
29 | for (it = result; it; it = it->ai_next) { |
41 | 29 | socket_fd = socket(it->ai_family, it->ai_socktype | flags, it->ai_protocol); | |
42 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 29 times.
|
29 | if (socket_fd < 0) { |
43 | ✗ | log_errno("socket"); | |
44 | ✗ | continue; | |
45 | } | ||
46 | |||
47 | static const int yes = 1; | ||
48 | static const int no = 0; | ||
49 | |||
50 |
1/2✓ Branch 0 taken 29 times.
✗ Branch 1 not taken.
|
29 | if (it->ai_family == AF_INET6) { |
51 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 29 times.
|
29 | if (setsockopt(socket_fd, IPPROTO_IPV6, IPV6_V6ONLY, &no, sizeof(no)) < 0) { |
52 | ✗ | log_errno("setsockopt"); | |
53 | ✗ | goto close_socket; | |
54 | } | ||
55 | } | ||
56 | |||
57 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 29 times.
|
29 | if (setsockopt(socket_fd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes)) < 0) { |
58 | ✗ | log_errno("setsockopt"); | |
59 | ✗ | goto close_socket; | |
60 | } | ||
61 | |||
62 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 29 times.
|
29 | if (bind(socket_fd, it->ai_addr, it->ai_addrlen) < 0) { |
63 | ✗ | log_errno("bind"); | |
64 | ✗ | goto close_socket; | |
65 | } | ||
66 | |||
67 | 29 | break; | |
68 | |||
69 | ✗ | close_socket: | |
70 | ✗ | net_close(socket_fd); | |
71 | } | ||
72 | |||
73 | 29 | freeaddrinfo(result); | |
74 | |||
75 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 29 times.
|
29 | if (!it) { |
76 | ✗ | log_err("Couldn't bind to port %s\n", port); | |
77 | ✗ | return -1; | |
78 | } | ||
79 | |||
80 | 29 | ret = listen(socket_fd, 4096); | |
81 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 29 times.
|
29 | if (ret < 0) { |
82 | ✗ | log_errno("listen"); | |
83 | ✗ | goto fail; | |
84 | } | ||
85 | |||
86 | 29 | return socket_fd; | |
87 | |||
88 | ✗ | fail: | |
89 | ✗ | net_close(socket_fd); | |
90 | |||
91 | ✗ | return ret; | |
92 | } | ||
93 | |||
94 | 27594 | int net_accept(int fd) | |
95 | { | ||
96 | static const int flags = SOCK_CLOEXEC; | ||
97 | 27594 | int ret = 0; | |
98 | |||
99 | 27594 | ret = accept4(fd, NULL, NULL, flags); | |
100 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 27594 times.
|
27594 | if (ret < 0) { |
101 | ✗ | log_errno("accept4"); | |
102 | ✗ | return ret; | |
103 | } | ||
104 | |||
105 | 27594 | return ret; | |
106 | } | ||
107 | |||
108 | 27594 | int net_connect(const char *host, const char *port) | |
109 | { | ||
110 | static const int flags = SOCK_CLOEXEC; | ||
111 | 27594 | struct addrinfo *result = NULL, *it = NULL; | |
112 | struct addrinfo hints; | ||
113 | 27594 | int socket_fd = -1, ret = 0; | |
114 | |||
115 | 27594 | memset(&hints, 0, sizeof(hints)); | |
116 | 27594 | hints.ai_family = AF_UNSPEC; | |
117 | 27594 | hints.ai_socktype = SOCK_STREAM; | |
118 | |||
119 | 27594 | ret = getaddrinfo(host, port, &hints, &result); | |
120 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 27594 times.
|
27594 | if (ret) { |
121 | ✗ | gai_log_errno(ret); | |
122 | ✗ | return -1; | |
123 | } | ||
124 | |||
125 |
1/2✓ Branch 0 taken 27594 times.
✗ Branch 1 not taken.
|
27594 | for (it = result; it; it = it->ai_next) { |
126 | 27594 | socket_fd = socket(it->ai_family, it->ai_socktype | flags, it->ai_protocol); | |
127 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 27594 times.
|
27594 | if (socket_fd < 0) { |
128 | ✗ | log_errno("socket"); | |
129 | ✗ | continue; | |
130 | } | ||
131 | |||
132 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 27594 times.
|
27594 | if (connect(socket_fd, it->ai_addr, it->ai_addrlen) < 0) { |
133 | ✗ | log_errno("connect"); | |
134 | ✗ | goto close_socket; | |
135 | } | ||
136 | |||
137 | 27594 | break; | |
138 | |||
139 | ✗ | close_socket: | |
140 | ✗ | net_close(socket_fd); | |
141 | } | ||
142 | |||
143 | 27594 | freeaddrinfo(result); | |
144 | |||
145 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 27594 times.
|
27594 | if (!it) { |
146 | ✗ | log_err("Couldn't connect to host %s, port %s\n", host, port); | |
147 | ✗ | return -1; | |
148 | } | ||
149 | |||
150 | 27594 | return socket_fd; | |
151 | } | ||
152 | |||
153 | 64451 | void net_close(int fd) | |
154 | { | ||
155 | 64451 | file_close(fd); | |
156 | 64451 | } | |
157 | |||
158 | 91908 | static ssize_t net_send_part(int fd, const void *buf, size_t size) | |
159 | { | ||
160 | static const int flags = MSG_NOSIGNAL; | ||
161 | |||
162 | 91908 | ssize_t ret = send(fd, buf, size, flags); | |
163 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 91908 times.
|
91908 | if (ret < 0) { |
164 | ✗ | log_errno("send"); | |
165 | ✗ | return -1; | |
166 | } | ||
167 | |||
168 | 91908 | return ret; | |
169 | } | ||
170 | |||
171 | 91908 | int net_send(int fd, const void *buf, size_t size) | |
172 | { | ||
173 | 91908 | size_t sent_total = 0; | |
174 | |||
175 |
2/2✓ Branch 0 taken 91908 times.
✓ Branch 1 taken 91908 times.
|
183816 | while (sent_total < size) { |
176 | ssize_t sent_now = | ||
177 | 91908 | net_send_part(fd, (const char *)buf + sent_total, size - sent_total); | |
178 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 91908 times.
|
91908 | if (sent_now < 0) |
179 | ✗ | return -1; | |
180 | 91908 | sent_total += sent_now; | |
181 | } | ||
182 | |||
183 | 91908 | return 0; | |
184 | } | ||
185 | |||
186 | 91908 | int net_recv(int fd, void *buf, size_t size) | |
187 | { | ||
188 | 91908 | ssize_t read_total = 0; | |
189 | |||
190 |
2/2✓ Branch 0 taken 104687 times.
✓ Branch 1 taken 91908 times.
|
196595 | while ((size_t)read_total < size) { |
191 | 104687 | ssize_t read_now = read(fd, (unsigned char *)buf + read_total, size - read_total); | |
192 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 104687 times.
|
104687 | if (!read_now) |
193 | ✗ | break; | |
194 | |||
195 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 104687 times.
|
104687 | if (read_now < 0) { |
196 | ✗ | log_errno("read"); | |
197 | ✗ | return -1; | |
198 | } | ||
199 | |||
200 | 104687 | read_total += read_now; | |
201 | } | ||
202 | |||
203 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 91908 times.
|
91908 | if ((size_t)read_total < size) { |
204 | ✗ | log_err("Received only %zd bytes out of %zu\n", read_total, size); | |
205 | ✗ | return -1; | |
206 | } | ||
207 | |||
208 | 91908 | return 0; | |
209 | } | ||
210 | |||
211 | struct buf { | ||
212 | uint32_t size; | ||
213 | const void *data; | ||
214 | }; | ||
215 | |||
216 | 91908 | int buf_create(struct buf **_buf, const void *data, uint32_t size) | |
217 | { | ||
218 | 91908 | struct buf *buf = malloc(sizeof(struct buf)); | |
219 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 91908 times.
|
91908 | if (!buf) { |
220 | ✗ | log_errno("malloc"); | |
221 | ✗ | return -1; | |
222 | } | ||
223 | |||
224 | 91908 | buf->data = data; | |
225 | 91908 | buf->size = size; | |
226 | |||
227 | 91908 | *_buf = buf; | |
228 | 91908 | return 0; | |
229 | } | ||
230 | |||
231 | 45954 | int buf_create_from_string(struct buf **buf, const char *str) | |
232 | { | ||
233 | 45954 | return buf_create(buf, str, strlen(str) + 1); | |
234 | } | ||
235 | |||
236 | 91908 | void buf_destroy(struct buf *buf) | |
237 | { | ||
238 | 91908 | free(buf); | |
239 | 91908 | } | |
240 | |||
241 | ✗ | uint32_t buf_get_size(const struct buf *buf) | |
242 | { | ||
243 | ✗ | return buf->size; | |
244 | } | ||
245 | |||
246 | 91908 | const void *buf_get_data(const struct buf *buf) | |
247 | { | ||
248 | 91908 | return buf->data; | |
249 | } | ||
250 | |||
251 | 45954 | int net_send_buf(int fd, const struct buf *buf) | |
252 | { | ||
253 | 45954 | int ret = 0; | |
254 | |||
255 | 45954 | uint32_t size = htonl(buf->size); | |
256 | 45954 | ret = net_send(fd, &size, sizeof(size)); | |
257 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 45954 times.
|
45954 | if (ret < 0) |
258 | ✗ | return ret; | |
259 | |||
260 | 45954 | ret = net_send(fd, buf->data, buf->size); | |
261 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 45954 times.
|
45954 | if (ret < 0) |
262 | ✗ | return ret; | |
263 | |||
264 | 45954 | return ret; | |
265 | } | ||
266 | |||
267 | 45954 | int net_recv_buf(int fd, struct buf **buf) | |
268 | { | ||
269 | 45954 | uint32_t size = 0; | |
270 | 45954 | int ret = 0; | |
271 | |||
272 | 45954 | ret = net_recv(fd, &size, sizeof(size)); | |
273 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 45954 times.
|
45954 | if (ret < 0) { |
274 | ✗ | log_err("Couldn't read buffer size\n"); | |
275 | ✗ | goto fail; | |
276 | } | ||
277 | 45954 | size = ntohl(size); | |
278 | |||
279 | 45954 | void *data = malloc(size); | |
280 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 45954 times.
|
45954 | if (!data) { |
281 | ✗ | log_errno("malloc"); | |
282 | ✗ | goto fail; | |
283 | } | ||
284 | |||
285 | 45954 | ret = net_recv(fd, data, size); | |
286 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 45954 times.
|
45954 | if (ret < 0) { |
287 | ✗ | log_err("Couldn't read buffer\n"); | |
288 | ✗ | goto free_data; | |
289 | } | ||
290 | |||
291 | 45954 | ret = buf_create(buf, data, size); | |
292 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 45954 times.
|
45954 | if (ret < 0) |
293 | ✗ | goto free_data; | |
294 | |||
295 | 45954 | return ret; | |
296 | |||
297 | ✗ | free_data: | |
298 | ✗ | free(data); | |
299 | |||
300 | ✗ | fail: | |
301 | ✗ | return -1; | |
302 | } | ||
303 |