57 |
|
|
58 |
/* ------------------------------------------------------------- Definitions */ |
/* ------------------------------------------------------------- Definitions */ |
59 |
|
|
60 |
#define TYPE_LOCAL 0 |
#define TYPE_LOCAL 0 |
61 |
#define TYPE_ACCEPT 1 |
#define TYPE_ACCEPT 1 |
62 |
|
#define RBUFFER_SIZE 1024 |
63 |
|
|
64 |
struct Socket_T { |
struct Socket_T { |
65 |
int port; |
int port; |
66 |
int type; |
int type; |
67 |
int socket; |
int socket; |
68 |
char *host; |
char *host; |
69 |
Port_T Port; |
Port_T Port; |
70 |
int timeout; |
int timeout; |
71 |
int connection_type; |
int connection_type; |
72 |
ssl_connection *ssl; |
ssl_connection *ssl; |
73 |
ssl_server_connection *sslserver; |
ssl_server_connection *sslserver; |
74 |
|
int length; |
75 |
|
int offset; |
76 |
|
unsigned char buffer[RBUFFER_SIZE+1]; |
77 |
}; |
}; |
78 |
|
|
79 |
|
|
80 |
|
/* -------------------------------------------------------------- Prototypes */ |
81 |
|
|
82 |
|
|
83 |
|
static int fill(Socket_T S); |
84 |
|
|
85 |
|
|
86 |
/* ------------------------------------------------------------------ Public */ |
/* ------------------------------------------------------------------ Public */ |
87 |
|
|
88 |
|
|
101 |
* @return The connected Socket or NULL if an error occurred |
* @return The connected Socket or NULL if an error occurred |
102 |
*/ |
*/ |
103 |
Socket_T socket_new(const char *host, int port, int type, int use_ssl, |
Socket_T socket_new(const char *host, int port, int type, int use_ssl, |
104 |
int timeout) { |
int timeout) { |
105 |
|
|
106 |
Ssl_T ssl= {use_ssl, SSL_VERSION_AUTO, NULL}; |
Ssl_T ssl= {use_ssl, SSL_VERSION_AUTO, NULL}; |
107 |
|
|
108 |
return socket_create_t(host, port, type, ssl, timeout); |
return socket_create_t(host, port, type, ssl, timeout); |
109 |
|
|
110 |
} |
} |
111 |
|
|
112 |
|
|
117 |
*/ |
*/ |
118 |
Socket_T socket_create(void *port) { |
Socket_T socket_create(void *port) { |
119 |
|
|
120 |
int s; |
int s; |
121 |
Port_T p= port; |
Port_T p= port; |
122 |
|
|
123 |
ASSERT(port); |
ASSERT(port); |
124 |
|
|
125 |
if((s= create_generic_socket(p)) != -1) { |
if((s= create_generic_socket(p)) != -1) { |
126 |
|
|
127 |
Socket_T S= NULL; |
Socket_T S= NULL; |
128 |
|
|
129 |
NEW(S); |
NEW(S); |
130 |
S->socket= s; |
S->socket= s; |
131 |
S->type= p->type; |
S->length= 0; |
132 |
S->port= p->port; |
S->offset= 0; |
133 |
S->timeout= p->timeout; |
S->type= p->type; |
134 |
S->connection_type= TYPE_LOCAL; |
S->port= p->port; |
135 |
|
S->timeout= p->timeout; |
136 |
if(p->family==AF_UNIX) { |
S->connection_type= TYPE_LOCAL; |
137 |
S->host= xstrdup(LOCALHOST); |
|
138 |
} else { |
if(p->family==AF_UNIX) { |
139 |
S->host= xstrdup(p->hostname); |
S->host= xstrdup(LOCALHOST); |
140 |
} |
} else { |
141 |
|
S->host= xstrdup(p->hostname); |
142 |
if(p->SSL.use_ssl) { |
} |
143 |
if(! (S->ssl= new_ssl_connection(NULL, p->SSL.version))) { |
|
144 |
goto ssl_error; |
if(p->SSL.use_ssl) { |
145 |
} |
if(! (S->ssl= new_ssl_connection(NULL, p->SSL.version))) { |
146 |
if(! embed_ssl_socket(S->ssl, S->socket)) { |
goto ssl_error; |
147 |
goto ssl_error; |
} |
148 |
} |
if(! embed_ssl_socket(S->ssl, S->socket)) { |
149 |
if(p->SSL.certmd5) { |
goto ssl_error; |
150 |
if(! check_ssl_md5sum(S->ssl, p->SSL.certmd5)) { |
} |
151 |
goto ssl_error; |
if(p->SSL.certmd5) { |
152 |
} |
if(! check_ssl_md5sum(S->ssl, p->SSL.certmd5)) { |
153 |
} |
goto ssl_error; |
154 |
} |
} |
155 |
|
} |
156 |
S->Port= port; |
} |
157 |
|
|
158 |
return S; |
S->Port= port; |
159 |
|
|
160 |
ssl_error: |
return S; |
161 |
socket_free(&S); |
|
162 |
return NULL; |
ssl_error: |
163 |
|
socket_free(&S); |
164 |
|
return NULL; |
165 |
|
|
166 |
} |
} |
167 |
|
|
168 |
return NULL; |
return NULL; |
169 |
|
|
170 |
} |
} |
171 |
|
|
182 |
* @return The connected Socket or NULL if an error occurred |
* @return The connected Socket or NULL if an error occurred |
183 |
*/ |
*/ |
184 |
Socket_T socket_create_t(const char *host, int port, int type, Ssl_T ssl, |
Socket_T socket_create_t(const char *host, int port, int type, Ssl_T ssl, |
185 |
int timeout) { |
int timeout) { |
|
|
|
|
int s; |
|
|
int proto= type==SOCKET_UDP?SOCK_DGRAM:SOCK_STREAM; |
|
|
|
|
|
ASSERT(host); |
|
|
ASSERT((type==SOCKET_UDP)||(type==SOCKET_TCP)); |
|
|
if(ssl.use_ssl) { |
|
|
ASSERT(type==SOCKET_TCP); |
|
|
} |
|
|
ASSERT(timeout>0); |
|
186 |
|
|
187 |
if((s= create_socket(host, port, proto, timeout)) != -1) { |
int s; |
188 |
|
int proto= type==SOCKET_UDP?SOCK_DGRAM:SOCK_STREAM; |
189 |
Socket_T S= NULL; |
|
190 |
|
ASSERT(host); |
191 |
|
ASSERT((type==SOCKET_UDP)||(type==SOCKET_TCP)); |
192 |
|
if(ssl.use_ssl) { |
193 |
|
ASSERT(type==SOCKET_TCP); |
194 |
|
} |
195 |
|
ASSERT(timeout>0); |
196 |
|
|
197 |
|
if((s= create_socket(host, port, proto, timeout)) != -1) { |
198 |
|
|
199 |
|
Socket_T S= NULL; |
200 |
|
|
201 |
NEW(S); |
NEW(S); |
202 |
S->socket= s; |
S->socket= s; |
203 |
S->port= port; |
S->length= 0; |
204 |
S->type= proto; |
S->offset= 0; |
205 |
S->timeout= timeout; |
S->port= port; |
206 |
S->host= xstrdup(host); |
S->type= proto; |
207 |
S->connection_type= TYPE_LOCAL; |
S->timeout= timeout; |
208 |
|
S->host= xstrdup(host); |
209 |
if(ssl.use_ssl) { |
S->connection_type= TYPE_LOCAL; |
210 |
if(! (S->ssl= new_ssl_connection(NULL, ssl.version))) { |
|
211 |
goto ssl_error; |
if(ssl.use_ssl) { |
212 |
} |
if(! (S->ssl= new_ssl_connection(NULL, ssl.version))) { |
213 |
if(! embed_ssl_socket(S->ssl, S->socket)) { |
goto ssl_error; |
214 |
goto ssl_error; |
} |
215 |
} |
if(! embed_ssl_socket(S->ssl, S->socket)) { |
216 |
if(ssl.certmd5) { |
goto ssl_error; |
217 |
if(! check_ssl_md5sum(S->ssl, ssl.certmd5)) { |
} |
218 |
goto ssl_error; |
if(ssl.certmd5) { |
219 |
} |
if(! check_ssl_md5sum(S->ssl, ssl.certmd5)) { |
220 |
} |
goto ssl_error; |
221 |
} |
} |
222 |
|
} |
223 |
return S; |
} |
224 |
|
|
225 |
ssl_error: |
return S; |
226 |
socket_free(&S); |
|
227 |
return NULL; |
ssl_error: |
228 |
|
socket_free(&S); |
229 |
} |
return NULL; |
230 |
|
|
231 |
return NULL; |
} |
232 |
|
|
233 |
|
return NULL; |
234 |
|
|
235 |
} |
} |
236 |
|
|
249 |
* @return A Socket or NULL if an error occurred |
* @return A Socket or NULL if an error occurred |
250 |
*/ |
*/ |
251 |
Socket_T socket_create_a(int socket, const char *remote_host, |
Socket_T socket_create_a(int socket, const char *remote_host, |
252 |
int port, void *sslserver) { |
int port, void *sslserver) { |
253 |
|
|
254 |
Socket_T S; |
Socket_T S; |
255 |
|
|
256 |
ASSERT(socket>=0); |
ASSERT(socket>=0); |
257 |
ASSERT(remote_host); |
ASSERT(remote_host); |
258 |
|
|
259 |
NEW(S); |
NEW(S); |
260 |
S->port= port; |
S->length= 0; |
261 |
S->socket= socket; |
S->offset= 0; |
262 |
S->type= SOCK_STREAM; |
S->port= port; |
263 |
S->timeout= NET_TIMEOUT; |
S->socket= socket; |
264 |
S->host= xstrdup(remote_host); |
S->type= SOCK_STREAM; |
265 |
S->connection_type= TYPE_ACCEPT; |
S->timeout= NET_TIMEOUT; |
266 |
|
S->host= xstrdup(remote_host); |
267 |
if(sslserver) { |
S->connection_type= TYPE_ACCEPT; |
268 |
S->sslserver= sslserver; |
|
269 |
if(! (S->ssl= insert_accepted_ssl_socket(S->sslserver))) { |
if(sslserver) { |
270 |
goto ssl_error; |
S->sslserver= sslserver; |
271 |
} |
if(! (S->ssl= insert_accepted_ssl_socket(S->sslserver))) { |
272 |
if(! embed_accepted_ssl_socket(S->ssl, S->socket)) { |
goto ssl_error; |
273 |
goto ssl_error; |
} |
274 |
} |
if(! embed_accepted_ssl_socket(S->ssl, S->socket)) { |
275 |
} |
goto ssl_error; |
276 |
|
} |
277 |
return S; |
} |
278 |
|
|
279 |
ssl_error: |
return S; |
280 |
socket_free(&S); |
|
281 |
return NULL; |
ssl_error: |
282 |
|
socket_free(&S); |
283 |
|
return NULL; |
284 |
|
|
285 |
} |
} |
286 |
|
|
287 |
|
|
292 |
*/ |
*/ |
293 |
void socket_free(Socket_T *S) { |
void socket_free(Socket_T *S) { |
294 |
|
|
295 |
ASSERT(S && *S); |
ASSERT(S && *S); |
296 |
|
|
297 |
#ifdef HAVE_OPENSSL |
#ifdef HAVE_OPENSSL |
298 |
if((*S)->ssl && (*S)->ssl->handler) { |
if((*S)->ssl && (*S)->ssl->handler) { |
299 |
if((*S)->connection_type==TYPE_LOCAL) { |
if((*S)->connection_type==TYPE_LOCAL) { |
300 |
close_ssl_socket((*S)->ssl); |
close_ssl_socket((*S)->ssl); |
301 |
delete_ssl_socket((*S)->ssl); |
delete_ssl_socket((*S)->ssl); |
302 |
} else if((*S)->connection_type==TYPE_ACCEPT && (*S)->sslserver) { |
} else if((*S)->connection_type==TYPE_ACCEPT && (*S)->sslserver) { |
303 |
close_accepted_ssl_socket((*S)->sslserver, (*S)->ssl); |
close_accepted_ssl_socket((*S)->sslserver, (*S)->ssl); |
304 |
} |
} |
305 |
} |
} |
306 |
#endif |
#endif |
307 |
|
|
308 |
close_socket((*S)->socket); |
close_socket((*S)->socket); |
309 |
FREE((*S)->host); |
FREE((*S)->host); |
310 |
FREE(*S); |
FREE(*S); |
311 |
|
|
312 |
} |
} |
313 |
|
|
314 |
|
|
322 |
*/ |
*/ |
323 |
int socket_is_ready(Socket_T S) { |
int socket_is_ready(Socket_T S) { |
324 |
|
|
325 |
ASSERT(S); |
ASSERT(S); |
326 |
|
|
327 |
switch(S->type) { |
switch(S->type) { |
328 |
|
|
329 |
case SOCK_STREAM: |
case SOCK_STREAM: |
330 |
return check_socket(S->socket); |
return check_socket(S->socket); |
331 |
|
|
332 |
case SOCK_DGRAM: |
case SOCK_DGRAM: |
333 |
return check_udp_socket(S->socket); |
return check_udp_socket(S->socket); |
334 |
|
|
335 |
default: |
default: |
336 |
break; |
break; |
337 |
} |
} |
338 |
|
|
339 |
return FALSE; |
return FALSE; |
340 |
|
|
341 |
} |
} |
342 |
|
|
348 |
*/ |
*/ |
349 |
int socket_get_socket(Socket_T S) { |
int socket_get_socket(Socket_T S) { |
350 |
|
|
351 |
ASSERT(S); |
ASSERT(S); |
352 |
|
|
353 |
return S->socket; |
return S->socket; |
354 |
|
|
355 |
} |
} |
356 |
|
|
362 |
*/ |
*/ |
363 |
int socket_get_type(Socket_T S) { |
int socket_get_type(Socket_T S) { |
364 |
|
|
365 |
ASSERT(S); |
ASSERT(S); |
366 |
|
|
367 |
return S->type; |
return S->type; |
368 |
|
|
369 |
} |
} |
370 |
|
|
377 |
*/ |
*/ |
378 |
void *socket_get_Port(Socket_T S) { |
void *socket_get_Port(Socket_T S) { |
379 |
|
|
380 |
ASSERT(S); |
ASSERT(S); |
381 |
|
|
382 |
return S->Port; |
return S->Port; |
383 |
|
|
384 |
} |
} |
385 |
|
|
391 |
*/ |
*/ |
392 |
int socket_get_remote_port(Socket_T S) { |
int socket_get_remote_port(Socket_T S) { |
393 |
|
|
394 |
ASSERT(S); |
ASSERT(S); |
395 |
|
|
396 |
return S->port; |
return S->port; |
397 |
|
|
398 |
} |
} |
399 |
|
|
405 |
* @return The remote host |
* @return The remote host |
406 |
*/ |
*/ |
407 |
const char *socket_get_remote_host(Socket_T S) { |
const char *socket_get_remote_host(Socket_T S) { |
408 |
|
|
409 |
ASSERT(S); |
ASSERT(S); |
410 |
|
|
411 |
return S->host; |
return S->host; |
412 |
|
|
413 |
} |
} |
414 |
|
|
425 |
*/ |
*/ |
426 |
int socket_print(Socket_T S, const char *m, ...) { |
int socket_print(Socket_T S, const char *m, ...) { |
427 |
|
|
428 |
int n; |
int n; |
429 |
long l; |
long l; |
430 |
va_list ap; |
va_list ap; |
431 |
char *buf= NULL; |
char *buf= NULL; |
432 |
|
|
433 |
ASSERT(S); |
ASSERT(S); |
434 |
ASSERT(m); |
ASSERT(m); |
435 |
|
|
436 |
va_start(ap, m); |
va_start(ap, m); |
437 |
buf= Util_formatString(m, ap, &l); |
buf= Util_formatString(m, ap, &l); |
438 |
va_end(ap); |
va_end(ap); |
439 |
|
|
440 |
n= socket_write(S, buf, l); |
n= socket_write(S, buf, l); |
441 |
FREE(buf); |
FREE(buf); |
442 |
|
|
443 |
return n; |
return n; |
444 |
|
|
445 |
} |
} |
446 |
|
|
454 |
*/ |
*/ |
455 |
int socket_write(Socket_T S, void *b, int size) { |
int socket_write(Socket_T S, void *b, int size) { |
456 |
|
|
457 |
int n= 0; |
int n= 0; |
458 |
void *p= b; |
void *p= b; |
459 |
|
|
460 |
ASSERT(S); |
ASSERT(S); |
461 |
|
|
462 |
while(size > 0) { |
while(size > 0) { |
463 |
|
|
464 |
if(S->ssl) { |
if(S->ssl) { |
465 |
n= send_ssl_socket(S->ssl, p, size); |
n= send_ssl_socket(S->ssl, p, size); |
466 |
} else { |
} else { |
467 |
n= sock_write(S->socket, p, size); |
n= sock_write(S->socket, p, size); |
468 |
} |
} |
|
|
|
|
if(n <= 0) break; |
|
|
p+= n; |
|
|
size-= n; |
|
469 |
|
|
470 |
} |
if(n <= 0) break; |
471 |
|
p+= n; |
472 |
|
size-= n; |
473 |
|
|
474 |
if(n < 0) { |
} |
475 |
/* No write or a partial write is an error */ |
|
476 |
return -1; |
if(n < 0) { |
477 |
} |
/* No write or a partial write is an error */ |
478 |
|
return -1; |
479 |
return (int)(p - b); |
} |
480 |
|
|
481 |
|
return (int)(p - b); |
482 |
|
|
483 |
|
} |
484 |
|
|
485 |
|
|
486 |
|
/** |
487 |
|
* Read a single byte. The byte is returned as an int in the range 0 |
488 |
|
* to 255. |
489 |
|
* @param S A Socket_T object |
490 |
|
* @return The byte read, or -1 if the end of the stream has been reached |
491 |
|
*/ |
492 |
|
int Socket_readByte(Socket_T S) { |
493 |
|
|
494 |
|
ASSERT(S); |
495 |
|
|
496 |
|
if(S->offset >= S->length) { |
497 |
|
if(fill(S) <= 0) |
498 |
|
return -1; |
499 |
|
} |
500 |
|
|
501 |
|
return S->buffer[S->offset++]; |
502 |
|
|
503 |
} |
} |
504 |
|
|
505 |
|
|
512 |
*/ |
*/ |
513 |
int socket_read(Socket_T S, void *b, int size) { |
int socket_read(Socket_T S, void *b, int size) { |
514 |
|
|
515 |
int n= 0; |
int c; |
516 |
void *p= b; |
unsigned char *p= (unsigned char*)b; |
|
int timeout= 0; |
|
517 |
|
|
518 |
ASSERT(S); |
ASSERT(S); |
519 |
|
|
520 |
timeout= S->timeout; |
while((size-- > 0) && ((c= Socket_readByte(S)) >= 0)) { |
521 |
|
*p++= c; |
|
while(size > 0) { |
|
|
if(S->ssl) { |
|
|
n= recv_ssl_socket(S->ssl, p, size, timeout); |
|
|
} else { |
|
|
n= sock_read(S->socket, p, size, timeout); |
|
|
} |
|
|
if(n <= 0) break; |
|
|
p+= n; |
|
|
size-= n; |
|
|
/* We managed to read some bytes and we only keep on reading |
|
|
* available data, otherwise we return with what we have read |
|
|
*/ |
|
|
timeout= 0; |
|
522 |
} |
} |
523 |
|
|
524 |
|
return (int)p - (int)b; |
525 |
|
|
|
if(n < 0 && p==b) { |
|
|
return -1; |
|
|
} |
|
|
|
|
|
return (int)(p - b); |
|
|
|
|
526 |
} |
} |
527 |
|
|
528 |
|
|
530 |
* Reads in at most one less than size <code>characters</code> and |
* Reads in at most one less than size <code>characters</code> and |
531 |
* stores them into the buffer pointed to by s. Reading stops after |
* stores them into the buffer pointed to by s. Reading stops after |
532 |
* an EOF or a newline. If a newline is read, it is stored into the |
* an EOF or a newline. If a newline is read, it is stored into the |
533 |
* buffer. A '\0' is stored after the last character in the buffer. |
* buffer. A '\0' is stored after the last character in the buffer. |
534 |
* @unnecessary S A Socket_T object |
* @unnecessary S A Socket_T object |
535 |
* @unnecessary s A character buffer to store the string in |
* @unnecessary s A character buffer to store the string in |
536 |
* @param size The size of the string buffer, s |
* @param size The size of the string buffer, s |
539 |
*/ |
*/ |
540 |
char *socket_readln(Socket_T S, char *s, int size) { |
char *socket_readln(Socket_T S, char *s, int size) { |
541 |
|
|
542 |
char *p= s; |
char *p= s; |
543 |
|
|
544 |
ASSERT(S); |
ASSERT(S); |
545 |
|
|
546 |
|
while(--size && ((*s= Socket_readByte(S)) > 0)) { |
547 |
|
if(*s++ == 10) |
548 |
|
break; |
549 |
|
} |
550 |
|
|
551 |
|
*s= 0; |
552 |
|
|
553 |
|
if(*p) |
554 |
|
return p; |
555 |
|
|
556 |
|
return NULL; |
557 |
|
|
558 |
|
} |
559 |
|
|
560 |
/* |
|
561 |
* TODO: We should use an internal buffer and read a large chunk |
/* ----------------------------------------------------------------- Private */ |
562 |
* from the socket not just one by one byte. |
|
563 |
*/ |
|
564 |
while(--size && ((socket_read(S, s, 1)) > 0)) { |
/* |
565 |
if(*s++ == 10) |
* Fill the internal buffer. If an error occurs or if the read |
566 |
break; |
* operation timed out -1 is returned. |
567 |
} |
* @param S An InputStream object |
568 |
|
* @return TRUE (the length of data read) or -1 if an error occured |
569 |
*s= 0; |
*/ |
570 |
|
static int fill(Socket_T S) { |
|
if(*p) |
|
|
return p; |
|
|
|
|
|
return NULL; |
|
571 |
|
|
572 |
|
int n; |
573 |
|
int timeout= S->timeout; |
574 |
|
|
575 |
|
S->offset= 0; |
576 |
|
S->length= 0; |
577 |
|
|
578 |
|
/* Read as much as we can and only block on the first read */ |
579 |
|
while(TRUE) { |
580 |
|
|
581 |
|
if(S->ssl) { |
582 |
|
n= recv_ssl_socket(S->ssl, &S->buffer[S->length], |
583 |
|
RBUFFER_SIZE-S->length, timeout); |
584 |
|
} else { |
585 |
|
n= sock_read(S->socket, &S->buffer[S->length], |
586 |
|
RBUFFER_SIZE-S->length, timeout); |
587 |
|
} |
588 |
|
|
589 |
|
timeout= 0; |
590 |
|
|
591 |
|
if(n > 0) { |
592 |
|
S->length+= n; |
593 |
|
continue; |
594 |
|
} |
595 |
|
|
596 |
|
if(n<=0) break; |
597 |
|
|
598 |
|
} |
599 |
|
|
600 |
|
return S->length; |
601 |
|
|
602 |
} |
} |