| 1 |
#include "tcplib.h" |
#include "tcplib.h" |
| 2 |
|
#include "common.h" |
|
void MsToTimeval(const int ms, struct timeval *tv) |
|
|
{ |
|
|
tv->tv_sec = ms / TIME_CNV_RATIO; |
|
|
tv->tv_usec = (ms - tv->tv_sec * TIME_CNV_RATIO) * TIME_CNV_RATIO; |
|
|
} |
|
|
|
|
|
int TimevalToMs(const struct timeval *tv) |
|
|
{ |
|
|
return (tv->tv_sec * TIME_CNV_RATIO + tv->tv_usec / TIME_CNV_RATIO); |
|
|
} |
|
|
|
|
|
void TimevalSubtract(struct timeval *ltv, const struct timeval *rtv) |
|
|
{ |
|
|
if (ltv->tv_usec < rtv->tv_usec) |
|
|
{ |
|
|
ltv->tv_sec--; |
|
|
ltv->tv_usec += TIME_CNV_RATIO * TIME_CNV_RATIO; |
|
|
} |
|
|
ltv->tv_sec -= rtv->tv_sec; |
|
|
ltv->tv_usec -= rtv->tv_usec; |
|
|
} |
|
|
|
|
|
int NonBlockConnect(int sockfd, const struct sockaddr *saptr, socklen_t salen, |
|
|
const int msec) |
|
|
{ |
|
|
int flags, n, error; |
|
|
socklen_t len; |
|
|
fd_set rset, wset; |
|
|
struct timeval tval; |
|
|
|
|
|
/* |
|
|
* 设置为非阻塞的 socket |
|
|
*/ |
|
|
flags = fcntl(sockfd, F_GETFL, 0); |
|
|
fcntl(sockfd, F_SETFL, flags | O_NONBLOCK); |
|
|
|
|
|
error = 0; |
|
|
if ((n = connect(sockfd, saptr, salen)) < 0) |
|
|
{ |
|
|
if (errno != EINPROGRESS) |
|
|
return ERR_TCPLIB_CONNECT; /* 连接失败 */ |
|
|
} |
|
|
|
|
|
/* |
|
|
* Do whatever we want while the connect is taking place. |
|
|
*/ |
|
|
|
|
|
if (n == 0) |
|
|
goto done; /* connect completed immediately */ |
|
|
|
|
|
FD_ZERO(&rset); |
|
|
FD_SET(sockfd, &rset); |
|
|
wset = rset; /* structure assignment */ |
|
|
MsToTimeval(msec, &tval); |
|
|
|
|
|
n = SignalSafeSelect(sockfd + 1, &rset, &wset, NULL, msec ? &tval : NULL); |
|
|
if (n == 0) |
|
|
{ |
|
|
errno = ETIMEDOUT; |
|
|
return ERR_TCPLIB_TIMEOUT; /* 连接服务器超时 */ |
|
|
} |
|
|
else if (n < 0) |
|
|
return ERR_TCPLIB_OTHERS; /* select()出错 */ |
|
|
if (FD_ISSET(sockfd, &rset) || FD_ISSET(sockfd, &wset)) |
|
|
{ |
|
|
len = sizeof(error); |
|
|
if (getsockopt(sockfd, SOL_SOCKET, SO_ERROR, &error, &len) < 0) |
|
|
return ERR_TCPLIB_OTHERS; /* Solaris pending error */ |
|
|
} |
|
|
|
|
|
done: |
|
|
fcntl(sockfd, F_SETFL, flags); /* restore file status flags */ |
|
|
|
|
|
if (error) |
|
|
{ |
|
|
errno = error; |
|
|
return ERR_TCPLIB_CONNECT; /* 连接服务器失败 */ |
|
|
} |
|
|
return 0; /* 连接服务器成功 */ |
|
|
} |
|
| 3 |
|
|
| 4 |
int NonBlockConnectEx(int sockfd, const struct sockaddr *saptr, socklen_t salen, |
int NonBlockConnectEx(int sockfd, const struct sockaddr *saptr, socklen_t salen, |
| 5 |
const int msec, const int conn) |
const int msec, const int conn) |
| 6 |
{ |
{ |
| 7 |
int flags, n, error; |
int flags, ret, error; |
| 8 |
socklen_t len; |
socklen_t len; |
| 9 |
fd_set rset, wset; |
fd_set rset, wset; |
| 10 |
struct timeval tval; |
struct timeval tval; |
| 18 |
error = 0; |
error = 0; |
| 19 |
if (conn == 1) |
if (conn == 1) |
| 20 |
{ |
{ |
| 21 |
if ((n = connect(sockfd, saptr, salen)) < 0) |
if ((ret = connect(sockfd, saptr, salen)) < 0) |
| 22 |
{ |
{ |
| 23 |
if (errno != EINPROGRESS) |
if (errno != EINPROGRESS) |
| 24 |
|
{ |
| 25 |
return ERR_TCPLIB_CONNECT; /* 连接失败 */ |
return ERR_TCPLIB_CONNECT; /* 连接失败 */ |
| 26 |
|
} |
| 27 |
} |
} |
| 28 |
|
|
| 29 |
/* |
/* |
| 30 |
* Do whatever we want while the connect is taking place. |
* Do whatever we want while the connect is taking place. |
| 31 |
*/ |
*/ |
| 32 |
|
if (ret == 0) |
| 33 |
if (n == 0) |
{ |
| 34 |
goto done; /* connect completed immediately */ |
goto done; /* connect completed immediately */ |
| 35 |
|
} |
| 36 |
} |
} |
| 37 |
|
|
| 38 |
FD_ZERO(&rset); |
tval.tv_sec = msec / 1000; |
| 39 |
FD_SET(sockfd, &rset); |
tval.tv_usec = msec % 1000 * 1000; |
|
wset = rset; /* structure assignment */ |
|
|
MsToTimeval(msec, &tval); |
|
|
|
|
|
n = SignalSafeSelect(sockfd + 1, &rset, &wset, NULL, msec ? &tval : NULL); |
|
|
if (n == 0) |
|
|
{ |
|
|
errno = ETIMEDOUT; |
|
|
return ERR_TCPLIB_TIMEOUT; /* 连接服务器超时 */ |
|
|
} |
|
|
else if (n < 0) |
|
|
return ERR_TCPLIB_OTHERS; /* select()出错 */ |
|
|
if (FD_ISSET(sockfd, &rset) || FD_ISSET(sockfd, &wset)) |
|
|
{ |
|
|
len = sizeof(error); |
|
|
if (getsockopt(sockfd, SOL_SOCKET, SO_ERROR, &error, &len) < 0) |
|
|
return ERR_TCPLIB_OTHERS; /* Solaris pending error */ |
|
|
} |
|
|
|
|
|
done: |
|
|
fcntl(sockfd, F_SETFL, flags); /* restore file status flags */ |
|
|
|
|
|
if (error) |
|
|
{ |
|
|
errno = error; |
|
|
return ERR_TCPLIB_CONNECT; /* 连接服务器失败 */ |
|
|
} |
|
|
return 0; /* 连接服务器成功 */ |
|
|
} |
|
|
|
|
|
int DoConnect(const char *ip, const int port, const int msec) |
|
|
{ |
|
|
struct sockaddr_in sa; |
|
|
int conn_fd; |
|
|
int rv; |
|
|
|
|
|
/* |
|
|
* assert(ip != NULL && port != 0); |
|
|
*/ |
|
| 40 |
|
|
| 41 |
/* |
while (!SYS_server_exit) |
|
* 创建 socket |
|
|
*/ |
|
|
if ((conn_fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) |
|
|
return ERR_TCPLIB_OTHERS; /* 创建 socket 失败 */ |
|
|
/* |
|
|
* 设置 sockaddr_in 结构 |
|
|
*/ |
|
|
bzero(&sa, sizeof(sa)); |
|
|
sa.sin_family = AF_INET; |
|
|
#ifdef HAVE_INET_ATON |
|
|
if (inet_aton(ip, &sa.sin_addr) <= 0) |
|
|
#else |
|
|
if (inet_pton(AF_INET, ip, &sa.sin_addr) <= 0) |
|
|
#endif |
|
|
return ERR_TCPLIB_OTHERS; /* 获取服务器地址失败 */ |
|
|
sa.sin_port = htons(port); |
|
|
/* |
|
|
* 创建连接 |
|
|
*/ |
|
|
rv = NonBlockConnect(conn_fd, (struct sockaddr *)&sa, sizeof(sa), msec); |
|
|
if (rv < 0) |
|
| 42 |
{ |
{ |
| 43 |
/* |
FD_ZERO(&rset); |
| 44 |
* 创建连接失败,关掉 socket |
FD_SET(sockfd, &rset); |
|
*/ |
|
|
close(conn_fd); |
|
|
return rv; |
|
|
} |
|
| 45 |
|
|
| 46 |
return conn_fd; |
FD_ZERO(&wset); |
| 47 |
} |
FD_SET(sockfd, &wset); |
| 48 |
|
|
| 49 |
void DoDisconnect(int conn_fd) |
ret = select(sockfd + 1, &rset, &wset, NULL, &tval); |
|
{ |
|
|
close(conn_fd); |
|
|
} |
|
|
|
|
|
int SignalSafeSelect(int nfds, fd_set *rs, fd_set *ws, fd_set *es, |
|
|
struct timeval *tv) |
|
|
{ |
|
|
int rv; |
|
| 50 |
|
|
| 51 |
while ((rv = select(nfds, rs, ws, es, tv)) < 0) |
if (ret == 0) |
| 52 |
{ |
{ |
| 53 |
if (errno != EINTR) |
return ERR_TCPLIB_TIMEOUT; /* 连接服务器超时 */ |
| 54 |
break; |
} |
| 55 |
} |
else if (ret < 0) |
| 56 |
return rv; |
{ |
| 57 |
} |
if (errno != EINTR) |
| 58 |
|
{ |
| 59 |
|
return ERR_TCPLIB_OTHERS; /* select()出错 */ |
| 60 |
|
} |
| 61 |
|
continue; |
| 62 |
|
} |
| 63 |
|
|
| 64 |
int SafeAccept(int sockfd, struct sockaddr *cliaddr, socklen_t *addrlen) |
if (FD_ISSET(sockfd, &rset) || FD_ISSET(sockfd, &wset)) |
|
{ |
|
|
int flags, n; |
|
|
fd_set rset; |
|
|
int conn_fd = ERR_TCPLIB_OTHERS; |
|
|
|
|
|
FD_ZERO(&rset); |
|
|
FD_SET(sockfd, &rset); |
|
|
n = SignalSafeSelect(sockfd + 1, &rset, NULL, NULL, NULL); |
|
|
if (n < 0) |
|
|
return ERR_TCPLIB_OTHERS; |
|
|
if (FD_ISSET(sockfd, &rset)) |
|
|
{ |
|
|
/* |
|
|
* 设置为非阻塞的 socket |
|
|
*/ |
|
|
flags = fcntl(sockfd, F_GETFL, 0); |
|
|
fcntl(sockfd, F_SETFL, flags | O_NONBLOCK); |
|
|
/* |
|
|
* 然后调用 accept() 接受连接请求 |
|
|
*/ |
|
|
while ((conn_fd = accept(sockfd, cliaddr, addrlen)) < 0) |
|
| 65 |
{ |
{ |
| 66 |
/* |
len = sizeof(error); |
| 67 |
* from UNPv1 Page 424 |
if (getsockopt(sockfd, SOL_SOCKET, SO_ERROR, &error, &len) < 0) |
| 68 |
*/ |
{ |
| 69 |
if (errno != EWOULDBLOCK && errno != ECONNABORTED && errno != EINTR) |
return ERR_TCPLIB_OTHERS; /* Solaris pending error */ |
| 70 |
break; |
} |
| 71 |
} |
} |
|
/* |
|
|
* 使 socket 复原 |
|
|
*/ |
|
|
fcntl(sockfd, F_SETFL, flags); |
|
|
} |
|
|
return conn_fd; |
|
|
} |
|
| 72 |
|
|
| 73 |
int DoSendData(int sockfd, const void *buf, const size_t len, int msec) |
break; |
|
{ |
|
|
struct timeval tv; |
|
|
fd_set wset; |
|
|
int rv; |
|
|
int wc; |
|
|
|
|
|
MsToTimeval(msec, &tv); |
|
|
FD_ZERO(&wset); |
|
|
FD_SET(sockfd, &wset); |
|
|
rv = SignalSafeSelect(sockfd + 1, NULL, &wset, NULL, &tv); |
|
|
if (rv < 0) |
|
|
return ERR_TCPLIB_OTHERS; /* some error occured */ |
|
|
if (rv == 0) |
|
|
return ERR_TCPLIB_TIMEOUT; /* timed out */ |
|
|
if (FD_ISSET(sockfd, &wset)) |
|
|
{ |
|
|
/* |
|
|
* 一次发送所有数据 |
|
|
*/ |
|
|
wc = send(sockfd, buf, len, 0); |
|
|
return wc; /* return bytes had sent */ |
|
| 74 |
} |
} |
|
return 0; /* nothing had sent */ |
|
|
} |
|
| 75 |
|
|
| 76 |
int DoRecvData(int sockfd, void *buf, const size_t len, int msec) |
done: |
| 77 |
{ |
fcntl(sockfd, F_SETFL, flags); /* restore file status flags */ |
| 78 |
struct timeval tv; |
|
| 79 |
fd_set rset; |
if (error) |
|
int rv; |
|
|
int rc; |
|
|
|
|
|
MsToTimeval(msec, &tv); |
|
|
FD_ZERO(&rset); |
|
|
FD_SET(sockfd, &rset); |
|
|
rv = SignalSafeSelect(sockfd + 1, &rset, NULL, NULL, msec ? &tv : NULL); |
|
|
if (rv < 0) |
|
|
return ERR_TCPLIB_OTHERS; /* some error occured */ |
|
|
if (rv == 0) |
|
|
return ERR_TCPLIB_TIMEOUT; /* timed out */ |
|
|
if (FD_ISSET(sockfd, &rset)) |
|
| 80 |
{ |
{ |
| 81 |
/* |
errno = error; |
| 82 |
* 一次接收所有数据 |
return ERR_TCPLIB_CONNECT; /* 连接服务器失败 */ |
|
*/ |
|
|
rc = recv(sockfd, buf, len, 0); |
|
|
return rc; /* return bytes had received */ |
|
| 83 |
} |
} |
| 84 |
return 0; /* nothing had received */ |
|
| 85 |
|
return 0; /* 连接服务器成功 */ |
| 86 |
} |
} |