Pharos 0.7.23
Modern Web Framework & Web App Hosting Service.
Loading...
Searching...
No Matches
native_connection.c
Go to the documentation of this file.
1/**
2 * @file
3 * @brief Wraps accepted sockets with transport metadata and provides connection IO and lifecycle helpers.
4 */
5
6#include "native_connection.h"
7
8#include <stdio.h>
9#include <stdlib.h>
10#include <string.h>
11
12#ifdef _WIN32
13#include <winsock2.h>
14#include <ws2tcpip.h>
15#define native_connection_close_socket closesocket
16#define native_connection_shutdown_socket(fd) shutdown((SOCKET)(fd), SD_BOTH)
17#define native_connection_recv(fd, buffer, len) recv((SOCKET)(fd), (char *)(buffer), (int)(len), 0)
18#define native_connection_send(fd, buffer, len) send((SOCKET)(fd), (const char *)(buffer), (int)(len), 0)
19#else
20#include <arpa/inet.h>
21#include <netinet/in.h>
22#include <sys/socket.h>
23#include <sys/time.h>
24#include <sys/un.h>
25#include <unistd.h>
26#define native_connection_close_socket close
27#define native_connection_shutdown_socket(fd) shutdown((fd), SHUT_RDWR)
28#define native_connection_recv(fd, buffer, len) recv((fd), (buffer), (len), 0)
29#define native_connection_send(fd, buffer, len) send((fd), (buffer), (len), 0)
30#endif
31
32#define NATIVE_CONNECTION_IO_TIMEOUT_SECONDS 15
33
34#ifdef _WIN32
35#define native_connection_strdup _strdup
36#else
37#define native_connection_strdup strdup
38#endif
39
40static char *native_connection_format_sockaddr(const struct sockaddr *addr, socklen_t addr_len) {
41 char buffer[512];
42 if (addr == NULL) {
43 return native_connection_strdup("unknown");
44 }
45 if (addr->sa_family == AF_INET && addr_len >= (socklen_t)sizeof(struct sockaddr_in)) {
46 const struct sockaddr_in *in = (const struct sockaddr_in *)addr;
47 char ip[INET_ADDRSTRLEN];
48 if (inet_ntop(AF_INET, &in->sin_addr, ip, sizeof(ip)) == NULL) {
49 return native_connection_strdup("tcp");
50 }
51 snprintf(buffer, sizeof(buffer), "%s:%u", ip, (unsigned int)ntohs(in->sin_port));
52 return native_connection_strdup(buffer);
53 }
54#ifndef _WIN32
55 if (addr->sa_family == AF_UNIX && addr_len >= (socklen_t)sizeof(struct sockaddr_un)) {
56 const struct sockaddr_un *un = (const struct sockaddr_un *)addr;
57 if (un->sun_path[0] != '\0') {
58 return native_connection_strdup(un->sun_path);
59 }
60 return native_connection_strdup("unix");
61 }
62#endif
63 return native_connection_strdup("unknown");
64}
65
67 struct sockaddr_storage addr;
68 socklen_t addr_len = (socklen_t)sizeof(addr);
69 memset(&addr, 0, sizeof(addr));
70 if (getsockname(fd, (struct sockaddr *)&addr, &addr_len) != 0) {
72 }
73 if (addr.ss_family == AF_INET) {
75 }
76#ifndef _WIN32
77 if (addr.ss_family == AF_UNIX) {
79 }
80#endif
82}
83
85#ifdef _WIN32
86 DWORD timeout_ms = NATIVE_CONNECTION_IO_TIMEOUT_SECONDS * 1000U;
87 setsockopt((SOCKET)fd, SOL_SOCKET, SO_RCVTIMEO, (const char *)&timeout_ms, sizeof(timeout_ms));
88 setsockopt((SOCKET)fd, SOL_SOCKET, SO_SNDTIMEO, (const char *)&timeout_ms, sizeof(timeout_ms));
89#else
90 struct timeval timeout;
92 timeout.tv_usec = 0;
93 setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(timeout));
94 setsockopt(fd, SOL_SOCKET, SO_SNDTIMEO, &timeout, sizeof(timeout));
95#endif
96}
97
99 struct sockaddr_storage peer_addr;
100 struct sockaddr_storage local_addr;
101 socklen_t peer_len = (socklen_t)sizeof(peer_addr);
102 socklen_t local_len = (socklen_t)sizeof(local_addr);
103 if (connection == NULL || connection->fd < 0) {
104 return;
105 }
106 memset(&peer_addr, 0, sizeof(peer_addr));
107 memset(&local_addr, 0, sizeof(local_addr));
108 free(connection->peer_info);
109 connection->peer_info = NULL;
110 free(connection->local_info);
111 connection->local_info = NULL;
112 if (getpeername(connection->fd, (struct sockaddr *)&peer_addr, &peer_len) == 0) {
113 connection->peer_info = native_connection_format_sockaddr((const struct sockaddr *)&peer_addr, peer_len);
114 }
115 if (getsockname(connection->fd, (struct sockaddr *)&local_addr, &local_len) == 0) {
116 connection->local_info = native_connection_format_sockaddr((const struct sockaddr *)&local_addr, local_len);
117 }
118 if (connection->peer_info == NULL) {
119 connection->peer_info = native_connection_strdup("unknown");
120 }
121 if (connection->local_info == NULL) {
122 connection->local_info = native_connection_strdup("unknown");
123 }
124}
125
127 if (connection == NULL) {
128 return;
129 }
130 connection->fd = -1;
132 connection->peer_info = NULL;
133 connection->local_info = NULL;
134}
135
137 if (connection == NULL) {
138 return;
139 }
140 free(connection->peer_info);
141 free(connection->local_info);
142 connection->peer_info = NULL;
143 connection->local_info = NULL;
144 connection->fd = -1;
146}
147
148int native_connection_accept_next(int server_fd, volatile sig_atomic_t *shutdown_requested, NativeConnection *connection) {
149 int accepted = -1;
150#ifdef _WIN32
151 SOCKET socket_value = accept((SOCKET)server_fd, NULL, NULL);
152 if (socket_value == INVALID_SOCKET) {
153 if (shutdown_requested != NULL && *shutdown_requested) {
154 return 0;
155 }
156 return -1;
157 }
158 accepted = (int)socket_value;
159#else
160 accepted = accept(server_fd, NULL, NULL);
161 if (accepted == -1) {
162 if (shutdown_requested != NULL && *shutdown_requested) {
163 return 0;
164 }
165 return -1;
166 }
167#endif
168 if (connection == NULL) {
170 return -1;
171 }
172 native_connection_reset(connection);
174 connection->fd = accepted;
177 return 1;
178}
179
180int native_connection_read(NativeConnection *connection, void *buffer, size_t len) {
181 if (connection == NULL || connection->fd < 0 || buffer == NULL) {
182 return -1;
183 }
184 return (int)native_connection_recv(connection->fd, buffer, len);
185}
186
187int native_connection_write(NativeConnection *connection, const void *buffer, size_t len) {
188 size_t sent = 0;
189 if (connection == NULL || connection->fd < 0 || (buffer == NULL && len > 0)) {
190 return -1;
191 }
192 while (sent < len) {
193 int wrote = (int)native_connection_send(connection->fd, (const char *)buffer + sent, len - sent);
194 if (wrote <= 0) {
195 return -1;
196 }
197 sent += (size_t)wrote;
198 }
199 return 0;
200}
201
203 (void)connection;
204 return 0;
205}
206
208 int code = 0;
209 if (connection == NULL) {
210 return 0;
211 }
212 if (connection->fd >= 0) {
213 code = native_connection_close_socket(connection->fd) == 0 ? 0 : -1;
214 }
215 native_connection_reset(connection);
216 return code;
217}
218
220 if (connection == NULL || connection->fd < 0) {
221 return 0;
222 }
223 return native_connection_shutdown_socket(connection->fd) == 0 ? 0 : -1;
224}
225
226const char *native_connection_peer_info(const NativeConnection *connection) {
227 return connection != NULL && connection->peer_info != NULL ? connection->peer_info : "unknown";
228}
229
230const char *native_connection_local_info(const NativeConnection *connection) {
231 return connection != NULL && connection->local_info != NULL ? connection->local_info : "unknown";
232}
233
235 return connection != NULL ? connection->transport_type : NATIVE_TRANSPORT_UNKNOWN;
236}
237
239 switch (native_connection_transport_type(connection)) {
241 return "tcp";
243 return "unix";
244 default:
245 return "unknown";
246 }
247}
#define native_connection_strdup
int native_connection_flush(NativeConnection *connection)
Flushes any buffered connection output when the transport requires it.
int native_connection_close(NativeConnection *connection)
Closes a native connection and releases its owned metadata.
int native_connection_accept_next(int server_fd, volatile sig_atomic_t *shutdown_requested, NativeConnection *connection)
Accepts the next client connection and records its transport metadata.
int native_connection_shutdown(NativeConnection *connection)
Shuts down a native connection without discarding the record itself.
int native_connection_write(NativeConnection *connection, const void *buffer, size_t len)
Writes bytes to a native connection.
#define native_connection_shutdown_socket(fd)
static void native_connection_apply_timeouts(int fd)
#define native_connection_close_socket
const char * native_connection_local_info(const NativeConnection *connection)
Returns the printable local endpoint description for a connection.
void native_connection_reset(NativeConnection *connection)
Releases owned transport metadata and resets a connection record.
static char * native_connection_format_sockaddr(const struct sockaddr *addr, socklen_t addr_len)
const char * native_connection_transport_type_name(const NativeConnection *connection)
Returns a human-readable transport type name for a connection.
static void native_connection_populate_endpoint_info(NativeConnection *connection)
void native_connection_init(NativeConnection *connection)
Initializes a native connection record to an empty state.
#define NATIVE_CONNECTION_IO_TIMEOUT_SECONDS
NativeTransportType native_connection_transport_type(const NativeConnection *connection)
Returns the resolved transport type for a connection.
static NativeTransportType native_connection_detect_transport(int fd)
#define native_connection_send(fd, buffer, len)
int native_connection_read(NativeConnection *connection, void *buffer, size_t len)
Reads bytes from a native connection.
const char * native_connection_peer_info(const NativeConnection *connection)
Returns the printable remote endpoint description for a connection.
#define native_connection_recv(fd, buffer, len)
Declares the native connection abstraction and transport metadata helpers.
NativeTransportType
Transport type used by a native connection.
@ NATIVE_TRANSPORT_UNIX
@ NATIVE_TRANSPORT_UNKNOWN
@ NATIVE_TRANSPORT_TCP
Accepted client connection and its resolved transport metadata.
NativeTransportType transport_type
const char size_t len
Definition yyjson.h:8364