26
26
27
27
// Helper function to resolve the port number
28
28
static int resolve_port (const char * port_str ) {
29
- return atoi (port_str );
29
+ if (!port_str || !* port_str ) return -1 ;
30
+
31
+ // Make sure the string is numeric
32
+ for (const char * p = port_str ; * p ; ++ p ) {
33
+ if (!isdigit ((unsigned char )* p )) return -1 ;
34
+ }
35
+
36
+ int port = atoi (port_str );
37
+ if (port <= 0 || port > 65535 ) return -1 ;
38
+ return port ;
30
39
}
31
40
32
41
// Initialize socket (for both client and server)
33
42
static int init_socket (const char * protocol ) {
34
- int sock = -1 ;
35
-
36
- if (strcmp (protocol , "tcp" ) == 0 ) {
37
- sock = socket (AF_INET , SOCK_STREAM , 0 );
38
- } else if (strcmp (protocol , "udp" ) == 0 ) {
39
- sock = socket (AF_INET , SOCK_DGRAM , 0 );
40
- } else if (strcmp (protocol , "raw" ) == 0 ) {
41
- sock = socket (AF_INET , SOCK_RAW , IPPROTO_RAW );
42
- } else if (strcmp (protocol , "icmp" ) == 0 ) {
43
- sock = socket (AF_INET , SOCK_RAW , IPPROTO_ICMP );
44
- } else {
45
- return -1 ; // Unsupported protocol
43
+ if (!protocol ) return -1 ;
44
+
45
+ struct {
46
+ const char * name ;
47
+ int type ;
48
+ int proto ;
49
+ } protocols [] = {
50
+ { "tcp" , SOCK_STREAM , 0 },
51
+ { "udp" , SOCK_DGRAM , 0 },
52
+ { "raw" , SOCK_RAW , IPPROTO_RAW },
53
+ { "icmp" , SOCK_RAW , IPPROTO_ICMP },
54
+ };
55
+
56
+ for (size_t i = 0 ; i < sizeof (protocols )/sizeof (protocols [0 ]); ++ i ) {
57
+ if (strcmp (protocol , protocols [i ].name ) == 0 ) {
58
+ int sock = socket (AF_INET , protocols [i ].type , protocols [i ].proto );
59
+ return sock >= 0 ? sock : -1 ;
60
+ }
46
61
}
47
62
48
- return sock ;
63
+ return -1 ; // Unsupported protocol
49
64
}
50
65
51
66
// Open a new network stream (TCP/UDP)
@@ -91,11 +106,12 @@ fossil_nstream_t *fossil_nstream_open(const char *protocol, const char *host, co
91
106
92
107
// Send data through the network stream
93
108
ssize_t fossil_nstream_send (fossil_nstream_t * ns , const void * buf , size_t len ) {
94
- if (strcmp ( ns -> protocol , "udp" ) == 0 ) {
95
- return sendto ( ns -> socket , buf , len , 0 , ( struct sockaddr * ) & ns -> addr , sizeof ( ns -> addr ));
96
- } else if (strcmp (ns -> protocol , "raw" ) == 0 || strcmp (ns -> protocol , "icmp" ) == 0 ) {
109
+ if (! ns || ns -> socket < 0 || ! buf || len == 0 ) return -1 ;
110
+
111
+ if (strcmp ( ns -> protocol , "udp" ) == 0 || strcmp (ns -> protocol , "raw" ) == 0 || strcmp (ns -> protocol , "icmp" ) == 0 ) {
97
112
return sendto (ns -> socket , buf , len , 0 , (struct sockaddr * )& ns -> addr , sizeof (ns -> addr ));
98
113
}
114
+
99
115
return send (ns -> socket , buf , len , 0 );
100
116
}
101
117
@@ -127,12 +143,14 @@ fossil_nstream_t *fossil_nstream_accept(fossil_nstream_t *ns) {
127
143
128
144
if (client_sock < 0 ) return NULL ;
129
145
130
- fossil_nstream_t * client_ns = malloc ( sizeof (fossil_nstream_t ));
146
+ fossil_nstream_t * client_ns = calloc ( 1 , sizeof (fossil_nstream_t )); // safer
131
147
if (!client_ns ) return NULL ;
132
148
133
149
client_ns -> socket = client_sock ;
134
150
client_ns -> addr = client_addr ;
135
- strcpy (client_ns -> protocol , ns -> protocol ); // Inherit protocol from server
151
+ strncpy (client_ns -> protocol , ns -> protocol , sizeof (client_ns -> protocol ) - 1 );
152
+ client_ns -> protocol [sizeof (client_ns -> protocol ) - 1 ] = '\0' ;
153
+ client_ns -> is_tls = ns -> is_tls ; // inherit TLS flag
136
154
137
155
return client_ns ;
138
156
}
@@ -145,18 +163,16 @@ void fossil_nstream_close(fossil_nstream_t *ns) {
145
163
146
164
// Set socket to non-blocking mode
147
165
int fossil_nstream_set_nonblocking (fossil_nstream_t * ns , int enable ) {
166
+ if (!ns || ns -> socket < 0 ) return -1 ;
148
167
#ifdef _WIN32
149
168
u_long mode = enable ? 1 : 0 ;
150
169
return ioctlsocket (ns -> socket , FIONBIO , & mode );
151
170
#else
152
171
int flags = fcntl (ns -> socket , F_GETFL , 0 );
153
172
if (flags == -1 ) return -1 ;
154
173
155
- if (enable ) {
156
- flags |= O_NONBLOCK ;
157
- } else {
158
- flags &= ~O_NONBLOCK ;
159
- }
174
+ if (enable ) flags |= O_NONBLOCK ;
175
+ else flags &= ~O_NONBLOCK ;
160
176
161
177
return fcntl (ns -> socket , F_SETFL , flags );
162
178
#endif
@@ -190,40 +206,59 @@ int fossil_nstream_wait_writable(fossil_nstream_t *ns, int timeout_ms) {
190
206
191
207
// Connect with timeout
192
208
int fossil_nstream_connect_timeout (fossil_nstream_t * ns , const char * host , const char * port , int timeout_ms ) {
209
+ if (!ns || ns -> socket < 0 || !host || !port ) return -1 ;
210
+
193
211
struct sockaddr_in server_addr ;
212
+ memset (& server_addr , 0 , sizeof (server_addr ));
194
213
server_addr .sin_family = AF_INET ;
195
214
server_addr .sin_port = htons (resolve_port (port ));
196
- server_addr .sin_addr .s_addr = inet_addr (host );
197
215
198
- // Set socket to non-blocking
199
- fossil_nstream_set_nonblocking ( ns , 1 );
216
+ in_addr_t addr = inet_addr ( host );
217
+ if ( addr == INADDR_NONE ) return -1 ; // Invalid address
200
218
201
- int result = connect (ns -> socket , (struct sockaddr * )& server_addr , sizeof (server_addr ));
219
+ server_addr .sin_addr .s_addr = addr ;
220
+
221
+ // Set non-blocking
222
+ if (fossil_nstream_set_nonblocking (ns , 1 ) != 0 ) return -1 ;
202
223
224
+ int result = connect (ns -> socket , (struct sockaddr * )& server_addr , sizeof (server_addr ));
203
225
if (result < 0 ) {
204
226
#ifdef _WIN32
205
- if (WSAGetLastError () == WSAEWOULDBLOCK ) {
227
+ int last_error = WSAGetLastError ();
228
+ if (last_error == WSAEWOULDBLOCK ) {
206
229
#else
207
230
if (errno == EINPROGRESS ) {
208
231
#endif
209
- struct timeval timeout ;
210
- timeout .tv_sec = timeout_ms / 1000 ;
211
- timeout .tv_usec = (timeout_ms % 1000 ) * 1000 ;
212
-
213
232
fd_set writefds ;
214
233
FD_ZERO (& writefds );
215
234
FD_SET (ns -> socket , & writefds );
216
235
236
+ struct timeval timeout ;
237
+ timeout .tv_sec = timeout_ms / 1000 ;
238
+ timeout .tv_usec = (timeout_ms % 1000 ) * 1000 ;
239
+
217
240
result = select (ns -> socket + 1 , NULL , & writefds , NULL , & timeout );
218
- if (result <= 0 ) return -1 ; // Timeout or error
241
+ if (result <= 0 ) {
242
+ fossil_nstream_set_nonblocking (ns , 0 );
243
+ return -1 ; // Timeout or select error
244
+ }
245
+
246
+ // Check if there was a socket error
247
+ int so_error = 0 ;
248
+ socklen_t len = sizeof (so_error );
249
+ getsockopt (ns -> socket , SOL_SOCKET , SO_ERROR , (char * )& so_error , & len );
250
+ if (so_error != 0 ) {
251
+ fossil_nstream_set_nonblocking (ns , 0 );
252
+ return -1 ;
253
+ }
219
254
} else {
220
- return -1 ; // Immediate error
255
+ fossil_nstream_set_nonblocking (ns , 0 );
256
+ return -1 ;
221
257
}
222
258
}
223
259
224
- // Set socket back to blocking
260
+ // Set back to blocking
225
261
fossil_nstream_set_nonblocking (ns , 0 );
226
-
227
262
return 0 ;
228
263
}
229
264
@@ -280,5 +315,11 @@ ssize_t fossil_nstream_ssl_recv(fossil_nstream_t *ns, void *buf, size_t len) {
280
315
281
316
// Get the string representation of the last error
282
317
const char * fossil_nstream_strerror (void ) {
318
+ #ifdef _WIN32
319
+ static char buf [64 ];
320
+ snprintf (buf , sizeof (buf ), "WSA Error: %d" , WSAGetLastError ());
321
+ return buf ;
322
+ #else
283
323
return strerror (errno );
324
+ #endif
284
325
}
0 commit comments