GCC Code Coverage Report


Directory: src/
File: src/net.c
Date: 2024-04-25 03:45:42
Exec Total Coverage
Lines: 87 139 62.6%
Branches: 30 92 32.6%

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