📄 ecossocket.cpp
字号:
//####COPYRIGHTBEGIN####
//
// ----------------------------------------------------------------------------
// Copyright (C) 1998, 1999, 2000 Red Hat, Inc.
//
// This program is part of the eCos host tools.
//
// This program is free software; you can redistribute it and/or modify it
// under the terms of the GNU General Public License as published by the Free
// Software Foundation; either version 2 of the License, or (at your option)
// any later version.
//
// This program is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
// more details.
//
// You should have received a copy of the GNU General Public License along with
// this program; if not, write to the Free Software Foundation, Inc.,
// 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
//
// ----------------------------------------------------------------------------
//
//####COPYRIGHTEND####
//=================================================================
//
// eCosSocket.cpp
//
// Socket test class
//
//=================================================================
//=================================================================
//#####DESCRIPTIONBEGIN####
//
// Author(s): sdf
// Contributors: sdf
// Date: 1999-04-01
// Description: This class abstracts tcp/ip sockets for use in the testing infrastructure
// Usage:
//
//####DESCRIPTIONEND####
#include "eCosStd.h"
#include "eCosSocket.h"
#include "eCosSerial.h"
#include "eCosThreadUtils.h"
#include "eCosTrace.h"
#include <map>
enum {ERR_TIMEOUT=20000, ERR_READ_AFTER_CLOSE=20001};
// Blocking read on one or other of the data sources:
// Result: -1 - socket error occurred
// 1 - data read from socket
// -2 - serial error occurred
// 2 - data read from serial
CeCosSocket::SSReadResult CeCosSocket::SSRead (CeCosSerial &serial,CeCosSocket &socket,void *pBuf,unsigned int nSize,unsigned int &nRead,bool *pbStop)
{
SSReadResult rc=SS_STOPPED;
bool bBlocking=serial.GetBlockingReads();
bool bBlockingModified=false;
while(0==pbStop || !(*pbStop)){
if(!socket.Peek(nRead)){
rc=SS_SOCKET_ERROR;
break;
} else if(nRead){
nRead=MIN(nRead,nSize);
rc=socket.recv(pBuf,nRead)?SS_SOCKET_READ:SS_SOCKET_ERROR;
break;
} else {
if(bBlocking){
serial.SetBlockingReads(false);
bBlockingModified=true;
bBlocking=false;
}
if(serial.Read(pBuf,nSize,nRead)){
if(nRead>0){
rc=SS_SERIAL_READ;
break;
}
} else {
rc=SS_SERIAL_ERROR;
break;
}
}
CeCosThreadUtils::Sleep(10);
}
if(bBlockingModified){
serial.SetBlockingReads(true);
}
return rc;
}
// ctors and dtors
CeCosSocket::CeCosSocket ():
m_nDefaultTimeout(10*1000),
m_nSock(-1),
m_nClient(0)
{
VTRACE(_T("Create socket instance %08x\n"),(unsigned int)this);
}
CeCosSocket::CeCosSocket (int sock /*result of previous call of Listen*/, bool *pbStop):
m_nDefaultTimeout(10*1000),
m_nSock(-1),
m_nClient(0)
{
VTRACE(_T("Create socket instance %08x\n"),(unsigned int)this);
Accept(sock,pbStop);
}
CeCosSocket::CeCosSocket (LPCTSTR pszHostPort,Duration dTimeout):
m_nDefaultTimeout(10*1000),
m_nSock(-1),
m_nClient(0)
{
VTRACE(_T("Create socket instance %08x\n"),(unsigned int)this);
Connect(pszHostPort,dTimeout);
}
bool CeCosSocket::Accept(int sock /*result of previous call of Listen*/, bool *pbStop)
{
m_nSock=-1;
while(0==pbStop||!*pbStop){
struct sockaddr cli_addr;
#ifndef _WIN32
unsigned
#endif
int clilen=sizeof(struct sockaddr);
m_nSock=::accept(sock, (struct sockaddr *) &cli_addr, &clilen);
SaveError();
if(-1==m_nSock){
if(WOULDBLOCK==SocketError()){
CeCosThreadUtils::Sleep(100);
continue;
}
} else {
memcpy(&m_nClient,cli_addr.sa_data+2,4);
TRACE(_T("Connection accepted from %s - socket %d\n"),(LPCTSTR )ClientName(m_nClient),m_nSock);
SetSocketOptions();
break;
}
}
return -1!=m_nSock;
}
int CeCosSocket::Listen(int nTcpPort)
{
// Create socket
int sock=::socket(AF_INET, SOCK_STREAM, 0);
if (sock == -1) {
ERROR(_T("Couldn't create socket\n"));
} else {
VTRACE(_T("Created socket %d listening on port %d\n"),sock,nTcpPort);
// Bind socket to address
struct sockaddr_in serv_addr;
memset(&serv_addr, 0, sizeof serv_addr);
serv_addr.sin_family = AF_INET;
serv_addr.sin_port=htons((short)nTcpPort);
serv_addr.sin_addr.s_addr = INADDR_ANY;
if (::bind(sock, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) == -1) {
TRACE(_T("Couldn't bind socket on port %d\n"),nTcpPort);
CloseSocket(sock);
} else if (-1==::listen(sock, SOMAXCONN)){
CloseSocket(sock);
TRACE(_T("socket error on listen - port %d\n"),nTcpPort);
} else {
#ifdef _WIN32
int nTrue=1;
bool rc=(0==::ioctlsocket(sock, FIONBIO, (unsigned long *)&nTrue));
#else //UNIX
int flags=::fcntl(sock,F_GETFL);
flags|=O_NONBLOCK;
bool rc=(0==::fcntl (sock, F_SETFL, flags));
#endif
if(!rc){
TRACE(_T("Failed to set socket options on socket %d\n"),sock);
}
}
}
return sock;
}
bool CeCosSocket::Connect(LPCTSTR pszHostPort,Duration dTimeout)
{
dTimeout=TimeoutDuration(dTimeout);
struct sockaddr_in serv_addr;
VTRACE(_T("Connect: %s timeout=%d\n"),pszHostPort,dTimeout);
// Get the target host address
String strHost;
int nPort;
CeCosSocket::ParseHostPort(pszHostPort,strHost,nPort);
String strErr;
char *ip=GetHostByName(strHost).GetCString();
memset(&serv_addr, 0, sizeof serv_addr);
// Create socket
m_nSock = ::socket(AF_INET, SOCK_STREAM, 0);
if (-1 == m_nSock) {
TRACE(_T("Could not create socket [%s]\n"),pszHostPort);
} else {
#ifdef _WIN32
SetSocketOptions();
#endif
VTRACE(_T("Created socket %d connected to %s\n"),m_nSock,pszHostPort);
// Bind socket to address
serv_addr.sin_family = AF_INET;
serv_addr.sin_port=htons((short)nPort);
SaveError();
serv_addr.sin_addr.s_addr = inet_addr(ip);
// Connect to server
VTRACE(_T("Connect() : connecting to server\n"));
int cc=::connect(m_nSock, (struct sockaddr *) &serv_addr, sizeof(serv_addr));
SaveError();
String strMsg;
if(-1==cc){
if(
#ifdef _WIN32
WOULDBLOCK==SocketError()
#else // UNIX
EINPROGRESS==SocketError()
#endif
){
// Allow dTimeout milliseconds for connect to complete
fd_set set;
FD_ZERO(&set);
#ifdef _WIN32
#pragma warning( push )
#pragma warning( disable : 4127 ) // conditional expression is constant
#endif
FD_SET((unsigned)m_nSock, &set);
#ifdef _WIN32
#pragma warning( pop )
#endif
struct timeval tv;
tv.tv_sec = dTimeout/1000;
tv.tv_usec = 1000*(dTimeout % 1000);
switch(::select(m_nSock, NULL, &set , NULL, &tv)){
case 0:
m_nErr=ERR_TIMEOUT;
strMsg.Format(_T("attempt timed out after %d seconds"),dTimeout/1000);
break;
case -1:
SaveError();
strMsg=SocketErrString();
break;
default:
cc=0;
}
} else {
strMsg=SocketErrString();
}
}
if(-1==cc){
TRACE(_T("Could not connect to %s - %s\n"),pszHostPort,(LPCTSTR)strMsg);
CloseSocket(m_nSock);
} else {
#ifndef _WIN32
SetSocketOptions();
#endif
}
}
delete [] ip;
return -1!=m_nSock;
}
bool CeCosSocket::sendrecv(bool bSend,const void *pData,unsigned int nLength,
LPCTSTR pszMsg,Duration dTimeout,CeCosSocket::StopFunc pFnStop,void *pParam)
{
dTimeout=TimeoutDuration(dTimeout);
LPCTSTR pszSR=(bSend?_T("sending"):_T("receiving"));
LPTSTR c=(LPTSTR )pData;
Time ft0=Now();
int nTodo=nLength;
while((nTodo>0) && ((0==pFnStop) || (!pFnStop(pParam)))){
int s=bSend?::send(m_nSock, (const char *)c, nTodo, 0): ::recv(m_nSock, (char *)c, nTodo, 0);
if(0==s && !bSend){
m_nErr=ERR_READ_AFTER_CLOSE;
} else {
SaveError();
}
if(-1==s && WOULDBLOCK==SocketError()){
Duration d=Duration(Now()-ft0);
if(d>dTimeout){
TRACE(_T("%d/%d mSec timeout on socket %d %s %s - processed %d/%d bytes\n") ,
d,dTimeout,m_nSock,pszSR,pszMsg,
nLength-nTodo,nLength);
m_nErr=ERR_TIMEOUT;
break;
}
CeCosThreadUtils::Sleep(100);
} else if (s>0) {
c+=s;
nTodo-=s;
ft0=Now();
} else {
TRACE(_T("Error on socket %d %s %s - %s\n") ,m_nSock, pszSR, pszMsg, (LPCTSTR )SocketErrString());
break;
}
}
return 0==nTodo;
}
// Graceful socket closedown
CeCosSocket::~CeCosSocket()
{
Close();
VTRACE(_T("Delete socket instance %08x\n"),(unsigned int)this);
}
bool CeCosSocket::CloseSocket(int &sock)
{
bool rc=false;
if(-1!=sock){
VTRACE(_T("Closing socket %d\n"),sock);
try{
shutdown(sock,0);// SD_BOTH
#ifdef _WIN32
rc=(0==closesocket(sock));
#else // UNIX
rc=(0==close(sock));
#endif
}
catch(...) {
TRACE(_T("!!! Exception caught in CeCosSocket::CloseSocket!!!\n"));
}
sock=-1;
}
return rc;
}
bool CeCosSocket::SetSocketOptions()
{
bool rc;
#ifdef _WIN32
int nTrue=1;
rc=(0==::ioctlsocket(m_nSock, FIONBIO, (unsigned long *)&nTrue));
SaveError();
#else // UNIX
int flags=::fcntl(m_nSock,F_GETFL);
SaveError();
flags|=O_NONBLOCK;
rc=(0==::fcntl (m_nSock, F_SETFL, flags));
SaveError();
#endif
int bLinger=0;
setsockopt(m_nSock,SOL_SOCKET,SO_LINGER,(const char *)&bLinger, sizeof(bLinger));
if(!rc){
TRACE(_T("Failed to set socket options socket %d - %s\n"),m_nSock,(LPCTSTR )SocketErrString());
}
return rc;
}
String CeCosSocket::SocketErrString(int nErr)
{
String str;
#ifdef _WIN32
switch(nErr){
case ERR_TIMEOUT: str=_T("Read operation timed out");break;
case ERR_READ_AFTER_CLOSE: str=_T("Read operation after socket closed");break;
case WSAEACCES: str=_T("Permission denied");break;
case WSAEADDRINUSE: str=_T("Address already in use");break;
case WSAEADDRNOTAVAIL: str=_T("Cannot assign requested address");break;
case WSAEAFNOSUPPORT: str=_T("Address family not supported by protocol family");break;
case WSAEALREADY: str=_T("Operation already in progress");break;
case WSAECONNABORTED: str=_T("Software caused connection abort");break;
case WSAECONNREFUSED: str=_T("Connection refused");break;
case WSAECONNRESET: str=_T("Connection reset by peer");break;
case WSAEDESTADDRREQ: str=_T("Destination address required");break;
case WSAEFAULT: str=_T("Bad address");break;
case WSAEHOSTDOWN: str=_T("Host is down");break;
case WSAEHOSTUNREACH: str=_T("No route to host");break;
case WSAEINPROGRESS: str=_T("Operation now in progress");break;
case WSAEINTR: str=_T("Interrupted function call");break;
case WSAEINVAL: str=_T("Invalid argument");break;
case WSAEISCONN: str=_T("Socket is already connected");break;
case WSAEMFILE: str=_T("Too many open files");break;
case WSAEMSGSIZE: str=_T("Message too long");break;
case WSAENETDOWN: str=_T("Network is down");break;
case WSAENETRESET: str=_T("Network dropped connection on reset");break;
case WSAENETUNREACH: str=_T("Network is unreachable");break;
case WSAENOBUFS: str=_T("No buffer space available");break;
case WSAENOPROTOOPT: str=_T("Bad protocol option");break;
case WSAENOTCONN: str=_T("Socket is not connected");break;
case WSAENOTSOCK: str=_T("Socket operation on non-socket");break;
case WSAEOPNOTSUPP: str=_T("Operation not supported");break;
case WSAEPFNOSUPPORT: str=_T("Protocol family not supported");break;
case WSAEPROCLIM: str=_T("Too many processes");break;
case WSAEPROTONOSUPPORT: str=_T("Protocol not supported");break;
case WSAEPROTOTYPE: str=_T("Protocol wrong type for socket");break;
case WSAESHUTDOWN: str=_T("Cannot send after socket shutdown");break;
case WSAESOCKTNOSUPPORT: str=_T("Socket type not supported");break;
case WSAETIMEDOUT: str=_T("Connection timed out");break;
case WSATYPE_NOT_FOUND: str=_T("Class type not found");break;
case WSAEWOULDBLOCK: str=_T("Resource temporarily unavailable");break;
case WSAHOST_NOT_FOUND: str=_T("Host not found");break;
case WSA_INVALID_HANDLE: str=_T("Specified event object handle is invalid");break;
case WSA_INVALID_PARAMETER: str=_T("One or more parameters are invalid");break;
//case WSAINVALIDPROCTABLE: str=_T("Invalid procedure table from service provider");break;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -