Mercurial
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) |