comparison seobeo/s_linux_network.c @ 18:fa2b8af609d9

[Seobeo] Fixed a bug with pathing. Support SSL.
author June Park <parkjune1995@gmail.com>
date Mon, 06 Oct 2025 08:21:34 -0700
parents d97ec3ded2ae
children 875bb6e10db7
comparison
equal deleted inserted replaced
17:d97ec3ded2ae 18:fa2b8af609d9
1 #include "seobeo/seobeo.h" 1 #include "seobeo/seobeo.h"
2 2
3 int Seobeo_CreateSocket(int32 stream, const char *host, const char* port) 3
4 { 4 Seobeo_PHandle Seobeo_Stream_Handle_Server_Create(const char *host, const char* port)
5 struct addrinfo hints = {0}, *server_infos, *free_server_info; 5 {
6 int32 sock_fd, yes = 1; // Need this for setsockopt 6 Seobeo_PHandle p_handle;
7 7 struct addrinfo hints, *server_infos, *free_server_info;
8 hints.ai_family = AF_INET; 8 int32 socket_fd, yes = 1; // Need this for setsockopt
9 hints.ai_socktype = stream ? SOCK_STREAM : SOCK_DGRAM; 9
10 hints.ai_protocol = stream ? IPPROTO_TCP : IPPROTO_UDP; 10 memset(&hints, 0, sizeof hints);
11 hints.ai_flags = stream ? AI_PASSIVE : 0; 11 hints.ai_family = AF_UNSPEC;
12 hints.ai_socktype = SOCK_STREAM;
13 hints.ai_protocol = IPPROTO_TCP;
14 hints.ai_flags = AI_PASSIVE;
12 15
13 if (getaddrinfo(host, port, &hints, &server_infos) != 0) 16 if (getaddrinfo(host, port, &hints, &server_infos) != 0)
14 { 17 { perror("getaddrinfo"); return NULL; }
15 perror("getaddrinfo");
16 return -1;
17 }
18 18
19 for 19 for
20 ( 20 (
21 free_server_info = server_infos; 21 free_server_info = server_infos;
22 free_server_info != NULL; 22 free_server_info != NULL;
23 free_server_info = free_server_info->ai_next 23 free_server_info = free_server_info->ai_next
24 ) 24 )
25 { 25 {
26 if 26 if((socket_fd = socket(free_server_info->ai_family,
27 ( 27 free_server_info->ai_socktype, free_server_info->ai_protocol)) == -1)
28 (sock_fd = socket( 28 { perror("socket"); continue; }
29 free_server_info->ai_family, free_server_info->ai_socktype, 29
30 free_server_info->ai_protocol 30 if (setsockopt(socket_fd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes)) == -1)
31 )) == -1 31 { perror("setsockopt"); continue; }
32 ) 32
33 { 33 if (bind(socket_fd, free_server_info->ai_addr, free_server_info->ai_addrlen) == -1)
34 perror("socket"); 34 { perror("v_network: Couldn't make socket non-blocking\n"); continue; }
35 continue; 35
36 }
37
38 if (setsockopt(sock_fd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes)) == -1)
39 {
40 perror("setsockopt");
41 continue;
42 }
43
44 if (host != NULL)
45 {
46 if (connect(sock_fd, free_server_info->ai_addr, free_server_info->ai_addrlen) == -1)
47 {
48 perror("connect");
49 continue;
50 }
51
52 }
53 else
54 {
55 if (bind(sock_fd, free_server_info->ai_addr, free_server_info->ai_addrlen) == -1)
56 {
57 perror("v_network: Couldn't make socket non-blocking\n");
58 continue;
59 }
60
61 // UDP should be non blocking
62 if(!stream)
63 {
64 if (fcntl(sock_fd, F_SETFL, O_NONBLOCK) != 0)
65 {
66 close(sock_fd);
67 perror("v_network: Couldn't make socket non-blocking\n");
68 return -1;
69 }
70 }
71 }
72 // binded to a open server infos;
73 break; 36 break;
74 } 37 }
75 38
76 // No longer need these values 39 if (listen(socket_fd, 16) != 0)
40 { perror("listen"); close(socket_fd); return NULL; }
41
42 if(fcntl(socket_fd, F_SETFL, O_NONBLOCK) != 0) { perror("fcntl"); return NULL; }
77 freeaddrinfo(server_infos); 43 freeaddrinfo(server_infos);
78 44
79 if (free_server_info == NULL) 45 p_handle = malloc(sizeof(*p_handle));
80 { 46 p_handle->socket = socket_fd;
81 perror("No free server"); 47 p_handle->type = SEOBEO_STREAM_TYPE_SERVER;
82 return -1; 48 p_handle->connected = FALSE;
83 } 49
84 50 p_handle->host = host != NULL ? strdup(host) : "localhost";
85 if (host == NULL) 51 p_handle->port = strdup(port);
86 { 52
87 if (listen(sock_fd, 16) != 0) 53 p_handle->ssl_ctx = NULL;
88 { 54 p_handle->ssl = NULL;
89 perror("listen"); 55
90 close(sock_fd); 56
91 return -1; 57 p_handle->read_buffer = malloc(sizeof(*p_handle->read_buffer) * INITIAL_BUFFER_CAPACITY);
92 } 58 p_handle->read_buffer_capacity = INITIAL_BUFFER_CAPACITY;
93 } 59 p_handle->read_buffer_len = 0;
94 60
95 return sock_fd; 61 p_handle->write_buffer = malloc(sizeof(*p_handle->read_buffer) * INITIAL_BUFFER_CAPACITY);
96 } 62 p_handle->write_buffer_capacity = INITIAL_BUFFER_CAPACITY;
97 63 p_handle->write_buffer_len = 0;
98 Seobeo_PHandle Seobeo_Stream_Handle_Create(const char *host, const char* port) 64
65 p_handle->file = NULL;
66 p_handle->text_copy = NULL;
67 p_handle->file_name = NULL;
68 p_handle->destroyed = false;
69
70 return p_handle;
71 }
72
73
74 Seobeo_PHandle Seobeo_Stream_Handle_Client_Create(const char *host, const char* port, boolean use_tls)
99 { 75 {
100 Seobeo_PHandle p_handle; 76 Seobeo_PHandle p_handle;
101 p_handle = malloc(sizeof(*p_handle)); 77 p_handle = malloc(sizeof(*p_handle));
102 78
103 p_handle->socket = Seobeo_CreateSocket(1, host, port); // socke fd 79 struct addrinfo hints, *server_infos, *free_server_info;
104 if (!p_handle->socket) 80 int32 socket_fd, yes = 1; // Need this for setsockopt
105 { 81
106 perror("Seobeo_CreateSocket"); 82 memset(&hints, 0, sizeof hints);
107 } 83 hints.ai_family = AF_UNSPEC;
84 hints.ai_socktype = SOCK_STREAM;
85
86 if (getaddrinfo(host, port, &hints, &server_infos) != 0)
87 { perror("getaddrinfo"); return NULL; }
88
89
90 if((socket_fd = socket(server_infos->ai_family,
91 server_infos->ai_socktype, server_infos->ai_protocol)) == -1)
92 { perror("socket"); return NULL; }
93
94 if (connect(socket_fd, server_infos->ai_addr, server_infos->ai_addrlen) != 0)
95 { perror("connect"); return NULL; }
96 freeaddrinfo(server_infos);
97
98 p_handle->socket = socket_fd;
99 p_handle->type = SEOBEO_STREAM_TYPE_CLIENT;
100 if (use_tls)
101 {
102 printf("USE SSL\n\n");
103 init_openssl();
104 p_handle->ssl_ctx = SSL_CTX_new(TLS_client_method());
105 SSL_CTX_set_default_verify_paths(p_handle->ssl_ctx);
106
107 p_handle->ssl = SSL_new(p_handle->ssl_ctx);
108 SSL_set_fd(p_handle->ssl, p_handle->socket);
109
110 SSL_set_tlsext_host_name(p_handle->ssl, host);
111 // Blocking for TSL handshake
112 fcntl(socket_fd, F_SETFL, 0);
113
114 if (SSL_connect(p_handle->ssl) != 1)
115 {
116 fprintf(stderr, "SSL_connect failed\n");
117 ERR_print_errors_fp(stderr);
118 return NULL;
119 }
120 }else
121 {
122 p_handle->ssl_ctx = NULL;
123 p_handle->ssl = NULL;
124 }
125 p_handle->connected = true;
126
108 p_handle->host = host != NULL ? strdup(host) : "localhost"; 127 p_handle->host = host != NULL ? strdup(host) : "localhost";
109 p_handle->port = strdup(port); 128 p_handle->port = strdup(port);
110 129
111 p_handle->read_buffer = malloc(sizeof(*p_handle->read_buffer) * INITIAL_BUFFER_CAPACITY); 130 p_handle->read_buffer = malloc(sizeof(*p_handle->read_buffer) * INITIAL_BUFFER_CAPACITY);
112 p_handle->read_buffer_capacity = INITIAL_BUFFER_CAPACITY; 131 p_handle->read_buffer_capacity = INITIAL_BUFFER_CAPACITY;
140 if (client_fd == -1) 159 if (client_fd == -1)
141 { 160 {
142 return NULL; 161 return NULL;
143 } 162 }
144 163
145 Seobeo_PHandle p_client_handle = malloc(sizeof *p_client_handle); 164 Seobeo_PHandle p_client_handle = malloc(sizeof *p_client_handle);
146 165
147 p_client_handle->socket = client_fd; 166 p_client_handle->socket = client_fd;
167 p_client_handle->type = SEOBEO_STREAM_TYPE_CLIENT;
168 p_client_handle->connected = true;
169
170 // TODO: support SSL in the future.
171 p_client_handle->ssl_ctx = NULL;
172 p_client_handle->ssl = NULL;
173
148 p_client_handle->host = strdup(client_inet_addr); 174 p_client_handle->host = strdup(client_inet_addr);
149 p_client_handle->port = NULL; 175 p_client_handle->port = NULL;
150 176
151 p_client_handle->read_buffer_capacity = p_server_handle->read_buffer_capacity; 177 p_client_handle->read_buffer_capacity = p_server_handle->read_buffer_capacity;
152 p_client_handle->read_buffer_len = 0; 178 p_client_handle->read_buffer_len = 0;
153 p_client_handle->read_buffer = malloc(p_client_handle->read_buffer_capacity); 179 p_client_handle->read_buffer = malloc(p_client_handle->read_buffer_capacity);
154 180
155 p_client_handle->write_buffer_capacity = p_server_handle->write_buffer_capacity; 181 p_client_handle->write_buffer_capacity = p_server_handle->write_buffer_capacity;
156 p_client_handle->write_buffer_len = 0; 182 p_client_handle->write_buffer_len = 0;
157 p_client_handle->write_buffer = malloc(p_client_handle->write_buffer_capacity); 183 p_client_handle->write_buffer = malloc(p_client_handle->write_buffer_capacity);
184
185 p_client_handle->destroyed = false;
158 186
159 return p_client_handle; 187 return p_client_handle;
160 } 188 }
161 189
162 void Seobeo_Handle_Destroy(Seobeo_PHandle p_handle) 190 void Seobeo_Handle_Destroy(Seobeo_PHandle p_handle)
179 if (p_handle->file_name) free(p_handle->file_name); 207 if (p_handle->file_name) free(p_handle->file_name);
180 208
181 free(p_handle); 209 free(p_handle);
182 } 210 }
183 211
184 int Seobeo_Handle_Flush(Seobeo_PHandle p_handle) 212
213 int32 Seobeo_Handle_Flush(Seobeo_PHandle p_handle)
185 { 214 {
186 uint32 total = p_handle->write_buffer_len; 215 uint32 total = p_handle->write_buffer_len;
187 uint32 sent = 0; 216 uint32 sent = 0;
188 217
218 printf("Total: %d\n\n", p_handle->write_buffer_len);
219
189 while (sent < total) 220 while (sent < total)
190 { 221 {
191 ssize_t n = write( 222 if (p_handle->ssl)
192 p_handle->socket, 223 {
193 p_handle->write_buffer + sent, 224 int n = SSL_write(p_handle->ssl, p_handle->write_buffer + sent, total - sent);
194 total - sent 225 if (n < 0)
195 ); 226 {
196 if (n < 0) { 227 int err = SSL_get_error(p_handle->ssl, n);
197 if (errno == EINTR) continue; 228 if (err == SSL_ERROR_WANT_READ || err == SSL_ERROR_WANT_WRITE)
198 if (errno == EAGAIN) return 1; 229 {
199 return -1; 230 // caller must wait for socket readiness and retry
200 } 231 return 0;
201 sent += (uint32)n; 232 }
233 ERR_print_errors_fp(stderr);
234 return -1;
235 }
236 sent += (uint32)n;
237 }else
238 {
239 ssize_t n = write(
240 p_handle->socket,
241 p_handle->write_buffer + sent,
242 total - sent
243 );
244 if (n < 0) {
245 if (errno == EINTR) continue;
246 if (errno == EAGAIN) return 1;
247 return -1;
248 }
249 sent += (uint32)n;
250 }
202 } 251 }
203 252
204 p_handle->write_buffer_len = 0; 253 p_handle->write_buffer_len = 0;
205 return 0; 254 return 0;
206 } 255 }
207 256
208 int Seobeo_Handle_Queue(Seobeo_PHandle p_handle, const uint8 *data, uint32 data_size) 257 int32 Seobeo_Handle_Queue(Seobeo_PHandle p_handle, const uint8 *data, uint32 data_size)
209 { 258 {
210 if (p_handle->write_buffer_len + data_size > p_handle->write_buffer_capacity) 259 if (p_handle->write_buffer_len + data_size > p_handle->write_buffer_capacity)
211 { 260 {
212 int rc = Seobeo_Handle_Flush(p_handle); 261 int32 rc = Seobeo_Handle_Flush(p_handle);
213 if (rc < 0) return -1; 262 if (rc < 0) return -1;
214 if (rc > 0) return 1; 263 if (rc > 0) return 1;
215 } 264 }
216 265
217 if (data_size > p_handle->write_buffer_capacity) 266 if (data_size > p_handle->write_buffer_capacity)
220 while (offset < data_size) 269 while (offset < data_size)
221 { 270 {
222 ssize_t n = write(p_handle->socket, 271 ssize_t n = write(p_handle->socket,
223 data + offset, 272 data + offset,
224 data_size - offset); 273 data_size - offset);
274 if (n==0)
275 {
276 // DEBUG
277 printf("NONE %d\n", offset);
278 break;
279 }
225 if (n < 0) 280 if (n < 0)
226 { 281 {
227 if (errno == EINTR) continue; 282 if (errno == EINTR || errno == EAGAIN)
283 {
284 // DEBUG
285 printf("Partial write, returning early (offset=%d)\n", offset);
286 continue;
287 }
228 if (errno == EAGAIN) return 1; 288 if (errno == EAGAIN) return 1;
229 return -1; 289 return -1;
230 } 290 }
231 offset += (uint32)n; 291 offset += (uint32)n;
232 } 292 // DEBUG
293 printf("\n\noffset: %d data_size: %d\n\n", offset, data_size);
294 }
295 // DEBUG
296 printf("\n\nTotal: %d\n", offset);
233 return 0; 297 return 0;
234 } 298 }
235 299
236 memcpy(p_handle->write_buffer + p_handle->write_buffer_len, 300 memcpy(p_handle->write_buffer + p_handle->write_buffer_len,
237 data, 301 data,
238 data_size); 302 data_size);
239 p_handle->write_buffer_len += data_size; 303 p_handle->write_buffer_len += data_size;
304 // DEBUG
305 printf("\nheader data_size: %d\n\n", data_size);
240 return 0; 306 return 0;
241 } 307 }
242 308
243 int Seobeo_Handle_Read(Seobeo_PHandle p_handle) 309 int32 Seobeo_Handle_Read(Seobeo_PHandle p_handle)
244 { 310 {
311 int32 read_size;
312 if (!p_handle) return -1;
313
245 // How many bytes we can still read into the buffer 314 // How many bytes we can still read into the buffer
246 uint32 free_space = p_handle->read_buffer_capacity - p_handle->read_buffer_len; 315 uint32 free_space = p_handle->read_buffer_capacity - p_handle->read_buffer_len;
247 if (free_space == 0) 316 if (free_space == 0)
248 return -1; 317 return -1;
249 318
250 ssize_t n = read( 319 if (p_handle->ssl)
251 p_handle->socket, 320 {
252 p_handle->read_buffer + p_handle->read_buffer_len, 321 read_size = (int32)SSL_read(p_handle->ssl, p_handle->read_buffer,
253 free_space 322 free_space);
254 ); 323 if (read_size <= 0)
255 if (n < 0) { 324 {
256 if (errno == EINTR) return Seobeo_Handle_Read(p_handle); 325 int err = SSL_get_error(p_handle->ssl, read_size);
257 if (errno == EAGAIN) return 0; // no data available right now 326 switch (err)
258 return -1; // fatal error 327 {
259 } 328 case SSL_ERROR_WANT_READ:
260 if (n == 0) { 329 case SSL_ERROR_WANT_WRITE:
261 return -2; // peer closed the connection 330 return 0;
262 } 331 case SSL_ERROR_ZERO_RETURN:
263 332 default:
264 p_handle->read_buffer_len += (uint32)n; 333 // TODO: Handle these errors
265 return (int)n; // number of bytes read 334 return -2;
335 }
336 }
337 }else
338 {
339 read_size = (int32)read(p_handle->socket,
340 p_handle->read_buffer + p_handle->read_buffer_len,
341 free_space);
342 if (read_size == 0) return -2;
343 if (read_size < 0)
344 {
345 if (errno == EAGAIN || errno == EWOULDBLOCK) return 0;
346 return -1;
347 }
348 }
349
350 p_handle->read_buffer_len += (uint32)read_size;
351 return read_size;
266 } 352 }
267 353
268 void Seobeo_Handle_Consume(Seobeo_PHandle p_handle, uint32 consumed) 354 void Seobeo_Handle_Consume(Seobeo_PHandle p_handle, uint32 consumed)
269 { 355 {
270 if (consumed >= p_handle->read_buffer_len) 356 if (consumed >= p_handle->read_buffer_len)