/******************************************************************************
|
* FILE: TcpTransport.cpp
|
* Description:
|
* Implementation of the CTcpTransport class.
|
*
|
* Modified Code History
|
* Mark Date By Modification Reason
|
*******************************************************************************
|
* 01 2007-10-8 songxw Initial creation.
|
******************************************************************************/
|
|
#include <stdio.h>
|
#include <sys/types.h>
|
#include <sys/socket.h>
|
#include <string.h>
|
#include <netinet/in.h>
|
#include <arpa/inet.h>
|
#include <unistd.h>
|
#include <fcntl.h>
|
#include <errno.h>
|
#include <poll.h>
|
|
#include "TcpTransport.h"
|
|
CTcpTransport::CTcpTransport() : SockFd(-1)
|
{
|
memset(sTcpClientIpAddr, '\0', sizeof(sTcpClientIpAddr));
|
uTcpClientPort = 0;
|
}
|
|
CTcpTransport::CTcpTransport(char *pIpAddr, UINT16 port) : SockFd(-1)
|
{
|
strncpy2(sIpAddr, pIpAddr, 32);
|
uPort = port;
|
|
memset(sTcpClientIpAddr, '\0', sizeof(sTcpClientIpAddr));
|
uTcpClientPort = 0;
|
}
|
|
CTcpTransport::~CTcpTransport()
|
{
|
Close();
|
}
|
|
int CTcpTransport::Create(TcpServiceType_E eType, char *pAddr, UINT16 port)
|
{
|
if((pAddr!= NULL) && (strlen(pAddr) > 0) && (port > 0))
|
{
|
strncpy2(sIpAddr, pAddr, 32);
|
uPort = port;
|
}
|
sType = eType;
|
|
//Create the TCP socket
|
SockFd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
|
if (-1 == SockFd)
|
{
|
perror("CTcpTransport socket");
|
return -1;
|
}
|
|
//Set Non-Blocking model
|
//fcntl(SockFd, F_SETFL, O_NDELAY); // O_NONBLOCK
|
|
//Create Tcp server or client
|
if (TCP_SERVER == sType)
|
{
|
return Listen();
|
}
|
else
|
{
|
if((strlen(sTcpClientIpAddr) > 0) && (uTcpClientPort > 0))
|
{
|
//----------------------------------°ó¶¨Ô´IPºÍ¶Ë¿Ú---------------
|
struct sockaddr_in MyAddr;
|
bzero(&MyAddr, sizeof(struct sockaddr_in) );
|
MyAddr.sin_family = AF_INET;
|
MyAddr.sin_addr.s_addr = inet_addr(sTcpClientIpAddr);
|
MyAddr.sin_port = htons(uTcpClientPort);
|
|
if (bind(SockFd,(struct sockaddr *)&MyAddr, sizeof(struct sockaddr_in) ) == -1)
|
{
|
printf("%s socket bind %s %d\r\n",__FUNCTION__,sTcpClientIpAddr,uTcpClientPort);
|
perror("bind");
|
}
|
//--------------------------------------------------------------------
|
}
|
return Connect();
|
}
|
|
return 0;
|
}
|
|
int CTcpTransport::Close()
|
{
|
if (SockFd != -1)
|
{
|
close(SockFd);
|
SockFd = -1;
|
}
|
|
return 0;
|
}
|
|
int CTcpTransport::Listen(void)
|
{
|
struct sockaddr_in MyAddr;
|
struct linger linger;
|
int optval;
|
|
bzero(&MyAddr, sizeof(struct sockaddr_in) );
|
MyAddr.sin_family = AF_INET;
|
//MyAddr.sin_addr.s_addr = inet_addr(sIpAddr);
|
MyAddr.sin_addr.s_addr = htonl(INADDR_ANY);
|
MyAddr.sin_port = htons(uPort);
|
|
linger.l_onoff = 1;
|
linger.l_linger = 0;
|
if (setsockopt(SockFd, SOL_SOCKET, SO_LINGER, (char *)&linger, sizeof(struct linger) ) == -1)
|
{
|
close(SockFd);
|
perror("CTcpTransport set tcp sockopt linger error");
|
return -1;
|
}
|
|
optval = 1;
|
if (setsockopt(SockFd, SOL_SOCKET, SO_REUSEADDR, (char *)&optval, sizeof(optval) ) == -1)
|
{
|
close(SockFd);
|
perror("CTcpTransport set tcp sockopt reuse address error");
|
return -1;
|
}
|
|
if (bind(SockFd, (struct sockaddr *)&MyAddr, sizeof(struct sockaddr_in) ) == -1)
|
{
|
close(SockFd);
|
perror("CTcpTransport tcp bind error");
|
return -1;
|
}
|
|
if (listen(SockFd, 20) == -1)
|
{
|
close(SockFd);
|
return -1;
|
}
|
|
return 0;
|
}
|
|
int CTcpTransport::Connect(void)
|
{
|
struct sockaddr_in SvrAddr;
|
|
bzero(&SvrAddr, sizeof(struct sockaddr_in) );
|
SvrAddr.sin_family = AF_INET;
|
SvrAddr.sin_addr.s_addr = inet_addr(sIpAddr);
|
SvrAddr.sin_port = htons(uPort);
|
#if 0
|
//------------set O_NONBLOCK------------------------------
|
int nFlags = fcntl(SockFd, F_GETFL, 0);
|
if(nFlags < 0)
|
{
|
perror("fcntl F_GETFL");
|
close(SockFd);
|
return -1;
|
}
|
if(fcntl(SockFd, F_SETFL, nFlags | O_NONBLOCK) < 0)
|
{
|
perror("setting O_NONBLOCK");
|
close(SockFd);
|
return -1;
|
}
|
//----------------------------------------------------------
|
#endif
|
if (connect(SockFd, (struct sockaddr *)&SvrAddr, sizeof(struct sockaddr_in) ) < 0)
|
{
|
if(errno != EINPROGRESS)
|
{
|
perror("connect");
|
close(SockFd);
|
return -1;
|
}
|
else
|
{
|
if(!ReadSelect(100*1000))
|
{
|
perror("connect");
|
close(SockFd);
|
return -1;
|
}
|
}
|
}
|
|
return 0;
|
}
|
|
bool CTcpTransport::ReadSelect(UINT32 timeout)
|
{
|
int res;
|
struct timeval tv;
|
fd_set wrset;
|
int valopt;
|
socklen_t sock_len;
|
|
if (timeout == 0)
|
{
|
tv.tv_sec=tv.tv_usec=0;
|
}
|
else
|
{
|
tv.tv_sec = timeout / 1000000;
|
tv.tv_usec = timeout % 1000000;
|
}
|
|
FD_ZERO(&wrset);
|
FD_SET(SockFd, &wrset);
|
|
res = select(SockFd + 1, NULL, &wrset, NULL, &tv);
|
if (res > 0)
|
{
|
sock_len = sizeof(int);
|
if(getsockopt(SockFd, SOL_SOCKET, SO_ERROR, (void *) (&valopt), &sock_len) == 0)
|
{
|
if(!valopt)
|
return true;
|
}
|
}
|
return false;
|
}
|
|
bool CTcpTransport::IsReadSelect(UINT32 timeout)
|
{
|
int res;
|
struct timeval tv;
|
fd_set rdset;
|
|
if (timeout == 0)
|
{
|
tv.tv_sec=tv.tv_usec=0;
|
}
|
else
|
{
|
tv.tv_sec = timeout / 1000000;
|
tv.tv_usec = timeout % 1000000;
|
}
|
|
FD_ZERO(&rdset);
|
FD_SET(SockFd, &rdset);
|
|
res = select(SockFd + 1, &rdset, NULL, NULL, &tv);
|
if (res > 0)
|
{
|
if(FD_ISSET(SockFd,&rdset))
|
{
|
return true;
|
}
|
|
}
|
return false;
|
}
|
|
|
int CTcpTransport::Send(UINT8 *pBuf, int len)
|
{
|
#if defined(TCP_SUPPORT_TPKT)
|
//TPKT 4 bytes
|
pBuf[0] = 0x03;
|
pBuf[1] = 0x00;
|
*(UINT16 *)(pBuf+2) = htons( (UINT16)(len - TPKT_MAX_LEN) );
|
#endif
|
|
UINT8* p = pBuf;
|
int iRet = 0, WLen = 0;
|
do {
|
iRet = send(SockFd, p+WLen, (len - WLen), 0);
|
if (iRet <= 0) //(-1 == ret) && (errno != EINTR)
|
{
|
perror("send falid");
|
return iRet;
|
}
|
WLen += iRet;
|
} while (len > WLen);
|
|
return WLen;
|
}
|
|
int CTcpTransport::Read(UINT8 *pBuf, int BufLen, int param)
|
{
|
int iRet = recv(SockFd, pBuf, BufLen, param);
|
if (iRet <= 0)
|
{
|
return -1;
|
}
|
|
return iRet;
|
}
|
|
|
int CTcpTransport::ServerRead(UINT8 *pBuf, int BufLen, int param)
|
{
|
struct sockaddr_in pin;
|
socklen_t address_size = sizeof(pin);
|
int ConnFd = accept(SockFd, (struct sockaddr *)&pin, &address_size);
|
int iRet = recv(ConnFd, pBuf, BufLen, param);
|
if (iRet <= 0)
|
{
|
return -1;
|
}
|
|
close(ConnFd);
|
|
return iRet;
|
}
|
|
|
|
int CTcpTransport::GetSockName(char *pIpAddr, UINT16 &port)
|
{
|
struct sockaddr_in addr;
|
socklen_t len = sizeof(sockaddr_in);
|
|
//get socket addr and port info
|
if (getsockname(SockFd, (struct sockaddr *)&addr, &len) == -1)
|
{
|
perror("getsockname");
|
return -1;
|
}
|
|
//strncpy2(pIpAddr, (char *)inet_ntoa(addr.sin_addr), IPSTR_MAX_LEN);
|
inet_ntop(AF_INET, (struct in_addr *)&addr.sin_addr, pIpAddr, 32); //ʹÓÃḬ̈߳²È«º¯Êý
|
port = ntohs(addr.sin_port);
|
|
return 0;
|
}
|