GCC Code Coverage Report


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