97 |
*/ |
*/ |
98 |
|
|
99 |
|
|
100 |
|
/* -------------------------------------------------------------- Prototypes */ |
101 |
|
|
102 |
|
|
103 |
|
static int do_connect(int s, const struct sockaddr *addr, socklen_t addrlen); |
104 |
|
|
105 |
|
|
106 |
/* ------------------------------------------------------------------ Public */ |
/* ------------------------------------------------------------------ Public */ |
107 |
|
|
108 |
|
|
122 |
|
|
123 |
ASSERT(hostname); |
ASSERT(hostname); |
124 |
|
|
125 |
if ((socket= create_socket(hostname, port, protocol)) < 0) { |
if((socket= create_socket(hostname, port, protocol)) < 0) { |
|
|
|
126 |
rv= FALSE; |
rv= FALSE; |
127 |
|
} else if(! check_socket(socket)) { |
|
} else if (! check_socket(socket)) { |
|
|
|
|
128 |
rv= FALSE; |
rv= FALSE; |
|
|
|
129 |
} |
} |
130 |
|
|
131 |
close_socket(socket); |
close_socket(socket); |
146 |
|
|
147 |
ASSERT(hostname); |
ASSERT(hostname); |
148 |
|
|
149 |
if ((hp = gethostbyname(hostname)) == NULL) { |
if((hp = gethostbyname(hostname)) == NULL) { |
|
|
|
150 |
return FALSE; |
return FALSE; |
|
|
|
151 |
} |
} |
152 |
|
|
153 |
return TRUE; |
return TRUE; |
171 |
FD_SET(socket, &wset); |
FD_SET(socket, &wset); |
172 |
tv.tv_sec= SELECT_TIMEOUT; |
tv.tv_sec= SELECT_TIMEOUT; |
173 |
tv.tv_usec= 0; |
tv.tv_usec= 0; |
174 |
|
|
175 |
return (select(socket+1, &rset, &wset, NULL, &tv) > 0); |
return (select(socket+1, &rset, &wset, NULL, &tv) > 0); |
176 |
|
|
177 |
} |
} |
178 |
|
|
179 |
|
|
197 |
* R/W is asynchronous and we should probably loop and wait longer |
* R/W is asynchronous and we should probably loop and wait longer |
198 |
* for a possible ICMP error. |
* for a possible ICMP error. |
199 |
*/ |
*/ |
|
set_noblock(socket); |
|
200 |
write(socket, buf, 1); |
write(socket, buf, 1); |
201 |
sleep(2); |
sleep(2); |
202 |
r= read(socket, buf, 1); |
r= read(socket, buf, 1); |
|
set_block(socket); |
|
203 |
if(0>r) { |
if(0>r) { |
204 |
switch(errno) { |
switch(errno) { |
205 |
case ECONNREFUSED: return FALSE; |
case ECONNREFUSED: return FALSE; |
213 |
|
|
214 |
|
|
215 |
/** |
/** |
216 |
* Open a socket against hostname:port with the given protocol. |
* Create a non-blocking socket against hostname:port with the given |
217 |
* The protocol is normaly either SOCK_STREAM or SOCK_DGRAM. |
* protocol. The protocol is normaly either SOCK_STREAM or |
218 |
|
* SOCK_DGRAM. |
219 |
* @param hostname The host to open a socket at |
* @param hostname The host to open a socket at |
220 |
* @param port The port number to connect to |
* @param port The port number to connect to |
221 |
* @param protocol Socket protocol to use (SOCK_STREAM|SOCK_DGRAM) |
* @param protocol Socket protocol to use (SOCK_STREAM|SOCK_DGRAM) |
230 |
ASSERT(hostname); |
ASSERT(hostname); |
231 |
|
|
232 |
if((hp= gethostbyname(hostname)) == NULL) { |
if((hp= gethostbyname(hostname)) == NULL) { |
|
|
|
233 |
return -1; |
return -1; |
|
|
|
234 |
} |
} |
235 |
|
|
236 |
if((s= socket(AF_INET, protocol, 0)) < 0) { |
if((s= socket(AF_INET, protocol, 0)) < 0) { |
|
|
|
237 |
return -1; |
return -1; |
|
|
|
238 |
} |
} |
239 |
|
|
240 |
sin.sin_family= AF_INET; |
sin.sin_family= AF_INET; |
241 |
sin.sin_port= htons(port); |
sin.sin_port= htons(port); |
242 |
memcpy(&sin.sin_addr, hp->h_addr, hp->h_length); |
memcpy(&sin.sin_addr, hp->h_addr, hp->h_length); |
243 |
|
|
244 |
|
if(do_connect(s, (struct sockaddr *)&sin, sizeof(sin)) < 0) { |
245 |
|
goto error; |
246 |
|
} |
247 |
|
|
248 |
if(connect(s, (struct sockaddr *)&sin, sizeof(sin)) < 0) { |
if(set_noblock(s) < 0) { |
249 |
|
goto error; |
|
close_socket(s); |
|
|
return -1; |
|
|
|
|
250 |
} |
} |
251 |
|
|
252 |
return s; |
return s; |
253 |
|
|
254 |
|
error: |
255 |
|
close_socket(s); |
256 |
|
return -1; |
257 |
|
|
258 |
} |
} |
259 |
|
|
260 |
|
|
270 |
|
|
271 |
ASSERT(p); |
ASSERT(p); |
272 |
|
|
273 |
if(p->family == AF_INET) { |
switch(p->family) { |
274 |
|
case AF_UNIX: |
275 |
socket_fd= create_socket(p->hostname, p->port, p->type); |
socket_fd= create_unix_socket(p->pathname); |
276 |
|
break; |
277 |
} else if(p->family == AF_UNIX) { |
case AF_INET: |
278 |
|
socket_fd= create_socket(p->hostname, p->port, p->type); |
279 |
socket_fd= create_unix_socket(p->pathname, p->type); |
break; |
280 |
|
default: |
281 |
|
socket_fd= -1; |
282 |
} |
} |
283 |
|
|
284 |
return socket_fd; |
return socket_fd; |
285 |
|
|
286 |
} |
} |
287 |
|
|
288 |
|
|
289 |
/** |
/** |
290 |
* Open a socket against pathname with the given protocol. |
* Create a non-blocking socket against pathname with the given |
291 |
* The protocol is normaly either SOCK_STREAM or SOCK_DGRAM. |
* protocol. |
292 |
* @param pathname The unix socket to connect to |
* @param pathname The unix socket to connect to |
293 |
* @param protocol Socket protocol to use (SOCK_STREAM|SOCK_DGRAM) |
* @param protocol Socket protocol to use (SOCK_STREAM|SOCK_DGRAM) |
294 |
* @return The socket or -1 if an error occured. |
* @return The socket or -1 if an error occured. |
295 |
*/ |
*/ |
296 |
int create_unix_socket(char *pathname, int protocol) { |
int create_unix_socket(char *pathname) { |
297 |
|
|
298 |
int s; |
int s; |
299 |
struct sockaddr_un unixsocket; |
struct sockaddr_un unixsocket; |
300 |
|
|
301 |
ASSERT(pathname); |
ASSERT(pathname); |
302 |
|
|
303 |
if ((s= socket(PF_UNIX, protocol, 0)) < 0) { |
if((s= socket(PF_UNIX, SOCK_STREAM, 0)) < 0) { |
|
|
|
304 |
return -1; |
return -1; |
|
|
|
305 |
} |
} |
306 |
|
|
307 |
unixsocket.sun_family= AF_UNIX; |
unixsocket.sun_family= AF_UNIX; |
308 |
snprintf(unixsocket.sun_path, sizeof(unixsocket.sun_path), "%s", pathname); |
snprintf(unixsocket.sun_path, sizeof(unixsocket.sun_path), "%s", pathname); |
309 |
|
|
310 |
if (connect(s, (struct sockaddr *)&unixsocket, sizeof(unixsocket)) < 0) { |
if (do_connect(s, (struct sockaddr *)&unixsocket, sizeof(unixsocket)) < 0) { |
311 |
|
goto error; |
|
close_socket(s); |
|
|
return -1; |
|
|
|
|
312 |
} |
} |
313 |
|
|
314 |
|
if(set_noblock(s) < 0) { |
315 |
|
goto error; |
316 |
|
} |
317 |
|
|
318 |
return s; |
return s; |
319 |
|
|
320 |
|
error: |
321 |
|
close_socket(s); |
322 |
|
return -1; |
323 |
|
|
324 |
} |
} |
325 |
|
|
326 |
|
|
327 |
/** |
/** |
328 |
* Creates a server socket (SOCK_STREAM type) and binds it to the |
* Creates a blocking server socket (SOCK_STREAM type) and binds it to |
329 |
* specified local port number, with the specified backlog. Set a |
* the specified local port number, with the specified backlog. Set a |
330 |
* socket option to make the port reusable again. This is useful if |
* socket option to make the port reusable again. This is useful if |
331 |
* the server has been shut down, and then restarted right away while |
* the server has been shut down, and then restarted right away while |
332 |
* sockets are still active on its port. If a bind address is given |
* sockets are still active on its port. If a bind address is given |
363 |
myaddr.sin_addr.s_addr= htonl(INADDR_ANY); |
myaddr.sin_addr.s_addr= htonl(INADDR_ANY); |
364 |
} |
} |
365 |
|
|
366 |
if (setsockopt(s, SOL_SOCKET, |
if(setsockopt(s, SOL_SOCKET, |
367 |
SO_REUSEADDR, (char *)&flag, sizeof(int)) < 0) |
SO_REUSEADDR, (char *)&flag, sizeof(int)) < 0) |
368 |
goto error; |
goto error; |
369 |
|
|
370 |
if (bind(s, (struct sockaddr *)&myaddr, sizeof(struct sockaddr_in)) < 0) |
if(bind(s, (struct sockaddr *)&myaddr, sizeof(struct sockaddr_in)) < 0) |
371 |
goto error; |
goto error; |
372 |
|
|
373 |
if (listen(s, backlog) < 0) |
if(listen(s, backlog) < 0) |
374 |
goto error; |
goto error; |
375 |
|
|
376 |
if (fcntl(s, F_SETFD, FD_CLOEXEC) == -1) |
if(fcntl(s, F_SETFD, FD_CLOEXEC) == -1) |
377 |
goto error; |
goto error; |
378 |
|
|
379 |
return s; |
return s; |
395 |
|
|
396 |
int rv= TRUE; |
int rv= TRUE; |
397 |
|
|
398 |
if ((shutdown(socket, 2) < 0)) { |
if((shutdown(socket, 2) < 0)) { |
|
|
|
399 |
rv= FALSE; |
rv= FALSE; |
|
|
|
400 |
} |
} |
401 |
|
|
402 |
if (close(socket) < 0) { |
if(close(socket) < 0) { |
|
|
|
403 |
rv= FALSE; |
rv= FALSE; |
|
|
|
404 |
} |
} |
405 |
|
|
406 |
return rv; |
return rv; |
407 |
|
|
408 |
} |
} |
409 |
|
|
410 |
|
|
411 |
/** |
/** |
|
* Set a so_timeout (read/write) for the given socket with the |
|
|
* specified timeout in seconds. |
|
|
* @param socket A socket |
|
|
* @param timeout Read/Write timeout in seconds |
|
|
* @return TRUE if success otherwise FALSE |
|
|
*/ |
|
|
int set_sotimeout(int socket, int timeout) { |
|
|
|
|
|
struct timeval tv= {timeout, 0}; |
|
|
|
|
|
return ((setsockopt(socket, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv))==0) && |
|
|
(setsockopt(socket, SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof(tv))==0)); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
/** |
|
412 |
* Enable nonblocking i|o on the given socket. |
* Enable nonblocking i|o on the given socket. |
413 |
* @param socket A socket |
* @param socket A socket |
414 |
* @return TRUE if success, otherwise FALSE |
* @return TRUE if success, otherwise FALSE |
415 |
*/ |
*/ |
416 |
int set_noblock(int socket) { |
int set_noblock(int socket) { |
417 |
|
|
418 |
int flag= 1; |
int flags; |
419 |
|
|
420 |
return (! ioctl(socket, FIONBIO, &flag)); |
flags= fcntl(socket, F_GETFL, 0); |
421 |
|
flags |= O_NONBLOCK; |
422 |
|
|
423 |
|
return (fcntl(socket, F_SETFL, flags) == 0); |
424 |
|
|
425 |
} |
} |
426 |
|
|
432 |
*/ |
*/ |
433 |
int set_block(int socket) { |
int set_block(int socket) { |
434 |
|
|
435 |
int flag= 0; |
int flags; |
436 |
|
|
437 |
|
flags= fcntl(socket, F_GETFL, 0); |
438 |
|
flags &= ~O_NONBLOCK; |
439 |
|
|
440 |
return (! ioctl(socket, FIONBIO, &flag)); |
return (fcntl(socket, F_SETFL, flags) == 0); |
441 |
|
|
442 |
} |
} |
443 |
|
|
444 |
|
|
445 |
/** |
/** |
446 |
* Send the message 'msg' down the socket in non-blocking mode and |
* Check if data is available, if not, wait timeout seconds for data |
447 |
* with failover. Inspired by code from the Apache web server. |
* to be present. |
448 |
* @param sock A socket |
* @param socket A socket |
449 |
* @param msg The message to send |
* @param timeout How long to wait before timeout (value in seconds) |
450 |
* @param len The length of the message in bytes |
* @return Return TRUE if the event occured, otherwise FALSE. |
|
* @param flags Optional send flags |
|
|
* @return The bytes sent or -1 if an error occured |
|
451 |
*/ |
*/ |
452 |
int sock_send(int sock, const char *msg, int len, int flags) { |
int can_read(int socket, int timeout) { |
453 |
|
|
454 |
int rv; |
fd_set rset; |
455 |
fd_set fdset; |
struct timeval tv; |
456 |
struct timeval t; |
|
457 |
int retry; |
FD_ZERO(&rset); |
458 |
|
FD_SET(socket, &rset); |
459 |
|
tv.tv_sec= timeout; |
460 |
|
tv.tv_usec= 0; |
461 |
|
|
462 |
|
return (select(socket+1, &rset, NULL, NULL, &tv) > 0); |
463 |
|
|
464 |
|
} |
465 |
|
|
|
ASSERT(msg); |
|
466 |
|
|
467 |
if (! set_noblock(sock)) { |
/** |
468 |
|
* Check if data can be sent to the socket, if not, wait timeout |
469 |
return -1; |
* seconds for the socket to be ready. |
470 |
|
* @param socket A socket |
471 |
} |
* @param timeout How long to wait before timeout (value in seconds) |
472 |
|
* @return Return TRUE if the event occured, otherwise FALSE. |
473 |
|
*/ |
474 |
|
int can_write(int socket, int timeout) { |
475 |
|
|
476 |
rv= send(sock, msg, len, flags); |
fd_set wset; |
477 |
if (rv <= 0) { |
struct timeval tv; |
|
|
|
|
if (errno == EWOULDBLOCK) |
|
|
do { |
|
|
|
|
|
retry= FALSE; |
|
|
FD_ZERO(&fdset); |
|
|
FD_SET(sock, &fdset); |
|
|
t.tv_sec= SELECT_TIMEOUT; |
|
|
t.tv_usec= 0; |
|
|
rv = select(sock+1, NULL, &fdset, NULL, &t); |
|
|
if (rv <= 0) { |
|
|
|
|
|
rv= -1; |
|
|
|
|
|
} |
|
|
else { |
|
|
|
|
|
rv = send(sock, msg, len, flags); |
|
|
if (rv <= 0) { |
|
|
|
|
|
if(errno == EWOULDBLOCK) { |
|
|
|
|
|
retry= TRUE; |
|
|
sleep(1); |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
} while(retry); |
|
|
|
|
|
} |
|
|
|
|
|
set_block(sock); |
|
478 |
|
|
479 |
return rv; |
FD_ZERO(&wset); |
480 |
|
FD_SET(socket, &wset); |
481 |
|
tv.tv_sec= timeout; |
482 |
|
tv.tv_usec= 0; |
483 |
|
|
484 |
|
return (select(socket+1, NULL, &wset, NULL, &tv) > 0); |
485 |
|
|
486 |
} |
} |
487 |
|
|
488 |
|
|
489 |
/** |
/** |
490 |
* Read a message from the socket in non-blocking mode and |
* Write <code>size</code> bytes from the <code>buffer</code> to the |
491 |
* with failover. Inspired by code from the Apache web server. |
* <code>socket</code> |
492 |
* @param sock A socket |
* @param socket the socket to write to |
493 |
* @param buf The buffer to read a message into |
* @param buffer The buffer to write |
494 |
* @param len The length of the buffer |
* @param size Number of bytes to send |
495 |
* @param flags Optional recv flags |
* @return The number of bytes sent or -1 if an error |
496 |
* @return Returns the bytes read or -1 if an error occured |
* occured. Returning 0 means EOF |
497 |
*/ |
*/ |
498 |
int sock_recv(int sock, char *buf, int len, int flags) { |
int sock_write(int socket, void *buffer, int size) { |
|
|
|
|
int rv; |
|
|
fd_set fdset; |
|
|
struct timeval t; |
|
|
|
|
|
ASSERT(buf); |
|
499 |
|
|
500 |
if (! set_noblock(sock)) { |
ssize_t n= 0; |
501 |
|
|
502 |
|
if(size<=0) |
503 |
|
return 0; |
504 |
|
|
505 |
|
errno= 0; |
506 |
|
do { |
507 |
|
n= write(socket, buffer, size); |
508 |
|
} while(n == -1 && errno == EINTR); |
509 |
|
|
510 |
|
if(n == -1 && (errno == EAGAIN || errno == EWOULDBLOCK)) { |
511 |
|
if(can_write(socket, 5) <= 0) { |
512 |
|
return -1; |
513 |
|
} |
514 |
|
do { |
515 |
|
n= write(socket, buffer, size); |
516 |
|
} while(n == -1 && errno == EINTR); |
517 |
|
} |
518 |
|
|
519 |
|
if(n < 0) { |
520 |
return -1; |
return -1; |
|
|
|
521 |
} |
} |
522 |
|
|
523 |
|
return n; |
524 |
|
|
525 |
|
} |
526 |
|
|
527 |
|
|
528 |
|
/** |
529 |
|
* Read up to size bytes from the <code>socket</code> into the |
530 |
|
* <code>buffer</code>. If data is not available wait for |
531 |
|
* <code>timeout</code> seconds. |
532 |
|
* @param socket the Socket to read data from |
533 |
|
* @param buffer The buffer to write the data to |
534 |
|
* @param size Number of bytes to read from the socket |
535 |
|
* @param timeout Seconds to wait for data to be available |
536 |
|
* @return The number of bytes read or -1 if an error |
537 |
|
* occured. Returning 0 means EOF |
538 |
|
*/ |
539 |
|
int sock_read(int socket, void *buffer, int size, int timeout) { |
540 |
|
|
541 |
rv= recv(sock, buf, len, flags); |
ssize_t n; |
542 |
if (rv <= 0) { |
|
543 |
|
errno= 0; |
544 |
if (errno == EWOULDBLOCK) { |
do { |
545 |
|
n= read(socket, buffer, size); |
546 |
FD_ZERO(&fdset); |
} while(n == -1 && errno == EINTR); |
547 |
FD_SET(sock, &fdset); |
|
548 |
t.tv_sec= SELECT_TIMEOUT; |
if(n == -1 && (errno == EAGAIN || errno == EWOULDBLOCK)) { |
549 |
t.tv_usec = 0; |
if(can_read(socket, timeout) <= 0) { |
550 |
rv = select(sock+1, &fdset, NULL, NULL, &t); |
return -1; |
|
if (rv <= 0) { |
|
|
|
|
|
rv= -1; |
|
|
|
|
|
} |
|
|
else { |
|
|
|
|
|
rv= recv(sock, buf, len, flags); |
|
|
|
|
|
} |
|
|
|
|
551 |
} |
} |
552 |
|
do { |
553 |
|
n= read(socket, buffer, size); |
554 |
|
} while(n == -1 && errno == EINTR); |
555 |
} |
} |
556 |
|
|
557 |
set_block(sock); |
return n; |
|
|
|
|
return rv; |
|
558 |
|
|
559 |
} |
} |
560 |
|
|
579 |
} |
} |
580 |
|
|
581 |
|
|
582 |
/** |
/* ----------------------------------------------------------------- Private */ |
583 |
* Get the remote host name from the originating host. |
|
584 |
* @param socket A socket |
|
585 |
* @return the (official) name (A-Record) of the peer |
/* |
586 |
* or NULL if lookup failed. |
* Do a non blocking connect, timeout of not connected within 5 seconds |
587 |
*/ |
*/ |
588 |
char *get_remote_host(int socket) { |
static int do_connect(int s, const struct sockaddr *addr, socklen_t addrlen) { |
589 |
|
|
590 |
struct hostent *h; |
int n, error; |
591 |
struct sockaddr_in r; |
fd_set wset, rset; |
592 |
int l= sizeof(struct sockaddr_in); |
struct timeval tv; |
593 |
|
|
594 |
if (getpeername(socket, (struct sockaddr*)&r, &l) < 0) { |
errno= 0; |
595 |
|
error= 0; |
596 |
return NULL; |
|
597 |
|
if(0 > (n= connect(s, addr, addrlen))) |
598 |
} else { |
if(errno != EINPROGRESS) |
599 |
|
return -1; |
600 |
h=gethostbyaddr((char *)&r.sin_addr, sizeof(struct in_addr), AF_INET); |
|
601 |
if (h) { |
FD_ZERO(&rset); |
602 |
|
FD_SET(s, &rset); |
603 |
return strdup(h->h_name); |
wset= rset; |
604 |
|
tv.tv_sec= 5; |
605 |
} |
tv.tv_usec= 0; |
606 |
|
|
607 |
|
if(select(s+1, NULL, &rset, &wset, &tv)==0) { |
608 |
|
close(s); |
609 |
|
errno= ETIMEDOUT; |
610 |
|
return -1; |
611 |
} |
} |
612 |
|
|
613 |
return NULL; |
if(FD_ISSET(s, &rset) || FD_ISSET(s, &wset)) { |
614 |
|
int len= sizeof(error); |
615 |
|
if(getsockopt(s, SOL_SOCKET, SO_ERROR, &error, &len) < 0) |
616 |
|
return -1; |
617 |
|
} else |
618 |
|
return -1; |
619 |
|
|
620 |
|
if(error) { |
621 |
|
close(s); |
622 |
|
errno= error; |
623 |
|
return -1; |
624 |
|
} |
625 |
|
|
626 |
|
return 0; |
627 |
|
|
628 |
} |
} |
629 |
|
|