-
Notifications
You must be signed in to change notification settings - Fork 17
/
tcping.c
78 lines (73 loc) · 2.42 KB
/
tcping.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
#include "tcping.h"
int tcping_gethostinfo(char *node, char *serv, int ai_family,
struct hostinfo **hi)
{
*hi = (struct hostinfo *)calloc(1, sizeof(struct hostinfo));
/* collect all ipv4 and ipv6 address info */
struct addrinfo hints;
memset(&hints, 0, sizeof(struct addrinfo));
hints.ai_family = ai_family;
hints.ai_socktype = SOCK_STREAM;
int err;
if ((err = getaddrinfo(node, serv, &hints, &(*hi)->ai)) != 0)
return err;
if ((err = getnameinfo((*hi)->ai->ai_addr, (*hi)->ai->ai_addrlen,
(char *)&(*hi)->name, INET6_ADDRSTRLEN,
(char *)&(*hi)->serv, INET_NUMERICSERVSTRLEN,
NI_NUMERICHOST | NI_NUMERICSERV)) != 0)
return err;
return 0;
}
void tcping_freehostinfo(struct hostinfo *hi)
{
if (hi) {
if (hi->ai)
freeaddrinfo(hi->ai);
free(hi);
}
}
int tcping_socket(struct hostinfo *host)
{
int sockfd = socket(host->ai->ai_family, host->ai->ai_socktype,
host->ai->ai_protocol);
fcntl(sockfd, F_SETFL, O_NONBLOCK);
return sockfd;
}
int tcping_connect(int sockfd, struct hostinfo *host, struct timeval *timeout)
{
int ret;
if ((ret = connect(sockfd, host->ai->ai_addr, host->ai->ai_addrlen)) != 0) {
if (errno != EINPROGRESS) {
return TCPING_ERROR;
}
fd_set fdrset, fdwset;
FD_ZERO(&fdrset);
FD_SET(sockfd, &fdrset);
fdwset = fdrset;
if ((ret = select(sockfd + 1, &fdrset, &fdwset, NULL,
timeout->tv_sec + timeout->tv_usec > 0 ? timeout
: NULL)) ==
0) {
/* timeout */
return TCPING_TIMEOUT;
}
int error = 0;
if (FD_ISSET(sockfd, &fdrset) || FD_ISSET(sockfd, &fdwset)) {
socklen_t errlen = sizeof(error);
if ((ret = getsockopt(sockfd, SOL_SOCKET, SO_ERROR, &error,
&errlen)) != 0) {
/* getsockopt error */
return TCPING_ERROR;
}
if (error != 0) {
/* closed */
return TCPING_CLOSED;
}
} else {
return TCPING_ERROR;
}
}
/* connection established */
return TCPING_OPEN;
}
int tcping_close(int sockfd) { return close(sockfd); }