#include
#include
#include
#include
#include
#define SELMAXSOCK (16)
#define SELTIMEO (10)
int get_connected_sock(char *target, char *service);
int connect_select(struct addrinfo* addr);
int main(int argc, char **argv) {
int sockd;
sockd = get_connected_sock("www.google.com", "1234");
/*
* do something using connected socket descriptor.
*
* ...
* ...
* close(sockd);
*
*/
return 0;
}
int get_connected_sock(char *target, char *service) {
int sockd;
struct addrinfo hints;
struct addrinfo *addrlist;
memset(&hints, 0, sizeof(struct addrinfo));
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
hints.ai_flags = 0;
hints.ai_protocol = 0;
if (getaddrinfo(target, service, &hints, &addrlist) == -1)
return -1;
sockd = connect_select(addrlist);
freeaddrinfo(addrlist);
return sockd;
}
int connect_select(struct addrinfo* addr) {
int active_sock_cnt, err, rtn, i, j;
int sock_fd[SELMAXSOCK];
uint sock_flags[SELMAXSOCK];
socklen_t sock_len;
fd_set rset, wset;
struct timeval tv;
FD_ZERO(&rset);
for (i = 0; addr != NULL && i < SELMAXSOCK; addr = addr->ai_next) {
if ((sock_fd[i] = socket(addr->ai_family, addr->ai_socktype, addr->ai_protocol)) == -1) {
// socket creating failed
continue;
}
sock_flags[i] = fcntl(sock_fd[i], F_GETFL, 0);
fcntl(sock_fd[i], F_SETFL, sock_flags[i] | O_NONBLOCK); // set non-nonblocking option to socket
if (connect(sock_fd[i], addr->ai_addr, addr->ai_addrlen) == 0) {
// connect success immediately
for (j = 0; j < i; j++) {
rtn = close(sock_fd[j]);
// close already created sockets
}
fcntl(sock_fd[i], F_SETFL, sock_flags[i]);
return sock_fd[i];
} else {
if (errno != EINPROGRESS) {
// connect failed, close socket
rtn = close(sock_fd[i]);
continue;
}
// connecting in progress. this is target to select()
FD_SET(sock_fd[i], &rset);
i++;
}
}
active_sock_cnt = i;
wset = rset;
tv.tv_sec = SELTIMEO;
tv.tv_usec = 0;
if (select(sock_fd[active_sock_cnt - 1] + 1, &rset, &wset, NULL, &tv) == 0) {
// select timeout
for (i = 0; i < active_sock_cnt; i++) {
rtn = close(sock_fd[i]);
// close already created sockets
}
return -1;
}
for (i = 0; i < active_sock_cnt; i++) {
if (FD_ISSET(sock_fd[i], &rset) || FD_ISSET(sock_fd[i], &wset)) {
sock_len = sizeof(err);
err = 0;
if (getsockopt(sock_fd[i], SOL_SOCKET, SO_ERROR, &err, &sock_len) < 0) {
// getsockopt function error. close socket
rtn = close(sock_fd[i]);
continue;
}
if (err) {
// socket error. close socket
rtn = close(sock_fd[i]);
continue;
}
} else {
// read/write descriptor is not set
rtn = close(sock_fd[i]);
continue;
}
// now, we get successful connected socket
for (j = i + 1; j < active_sock_cnt; j++) {
// close already created sockets
rtn = close(sock_fd[j]);
}
fcntl(sock_fd[i], F_SETFL, sock_flags[i]);
return sock_fd[i];
}
return -1;
}
댓글 없음:
댓글 쓰기