-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathconnect_nonb.c
More file actions
120 lines (104 loc) · 2.82 KB
/
Copy pathconnect_nonb.c
File metadata and controls
120 lines (104 loc) · 2.82 KB
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
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
#include "common.h"
#ifdef CONNB_BLOCK
int connect_nonb(int sockfd, const struct sockaddr *saptr, socklen_t salen, int nsec, int nusec)
{
if (connect(sockfd, saptr, salen) == -1)
return -1;
return 0;
}
#elif CONNB_SELECT
int connect_nonb(int sockfd, const struct sockaddr *saptr, socklen_t salen, int nsec, int nusec)
{
int flags, n, error;
socklen_t len;
fd_set wset;
struct timeval tval;
error = 0;
if ((flags = fcntl(sockfd, F_GETFL, 0)) == -1)
return -1;
if (fcntl(sockfd, F_SETFL, flags | O_NONBLOCK))
return -1;
if ( (n = connect(sockfd, saptr, salen)) < 0)
if (errno != EINPROGRESS)
return(-1);
if (n == 0) {
SILK_LOG(INFO, "connect(%d) completed immediately", sockfd);
goto done;
}
FD_ZERO(&wset);
FD_SET(sockfd, &wset);
tval.tv_sec = nsec;
tval.tv_usec = nusec;
/* on Linux select() modifies timeout to reflect the amount of time not slept */
again:
if ( (n = select(sockfd+1, NULL, &wset, NULL,
nsec ? &tval : NULL)) == 0) {
SILK_LOG(INFO, "select(%d), timeout expired", sockfd);
close(sockfd);
errno = ETIMEDOUT;
return(-1);
} else if (n == -1) {
if (errno == EINTR)
goto again;
error = errno;
err_ret("connect_nonb(%d): select error", sockfd);
goto done;
}
if (FD_ISSET(sockfd, &wset)) {
len = sizeof(error);
if (getsockopt(sockfd, SOL_SOCKET, SO_ERROR, &error, &len) < 0)
return(-1);
SILK_LOG(INFO"connect(%d) success", sockfd);
} else {
if (errno == EINPROGRESS)
goto again;
err_ret("connect_nonb(%d): select error, sockfd not set", sockfd);
close(sockfd);
return -1;
}
done:
if (fcntl(sockfd, F_SETFL, flags) == -1)
return -1;
if (error) {
close(sockfd);
errno = error;
return(-1);
}
return(0);
}
#else
int connect_nonb(int sockfd, const struct sockaddr *saptr, socklen_t salen, int nsec, int nusec)
{
struct pollfd fds[1];
int flags;
int n;
if ((flags = fcntl(sockfd, F_GETFL, 0)) == -1)
return -1;
if (fcntl(sockfd, F_SETFL, flags | O_NONBLOCK))
return -1;
if(connect(sockfd, saptr, salen) < 0)
if(errno != EAGAIN && errno != EINPROGRESS) {
SILK_LOG_ERRNO(NOTICE, "connect error");
return -1;
}
memset(fds, 0, sizeof(fds));
fds[0].fd = sockfd;
fds[0].events = POLLOUT;
again:
n = poll(fds, 1, nsec * 1000);
if (n == -1) {
if (errno == EINTR || errno == EAGAIN) {
usleep(SLEEPTIME);
goto again;
}
SILK_LOG_ERRNO(NOTICE, "poll error");
return -1;
}
if (n == 0) {
SILK_LOG(NOTICE, "poll error, timeout expired");
return -1;
}
fcntl(sockfd, F_SETFL, flags);
return 0;
}
#endif