#ifdef OSF1 #define _XOPEN_SOURCE 500 #endif #include "swrapsock.h" #include "sopnamsp.h" #include #include #include #include #include #include #include #include /*! \class SOPHYA::Socket \ingroup SysTools \brief Base class for server and client sockets. The class Socket is not intended for direct use. Only the derived classes ServerSocket and ClientSocket should be used. The Close() method should be called explicitly. */ /* --Methode-- */ Socket::Socket(int s) { skt = s; tstart = tlast = (long)time(NULL); totsnd = totrcv = 0; dts = dtr = 0; nbbs = nbbr = 0; lstnbb = 0; lstdt = 0; errcnt = 0; } /* --Methode-- */ Socket::Socket(Socket const & a) { Set(a); } /* --Methode-- */ Socket::~Socket() { // Close(); } /* --Methode-- */ void Socket::Set(Socket const & a) { skt = a.skt; tstart = a.tstart; tlast = a.tlast; totsnd = a.totsnd; totrcv = a.totrcv; dts = a.dts; dtr = a.dtr; nbbs = a.nbbs; nbbr = a.nbbr; lstnbb = a.lstnbb; lstdt = a.lstdt; errcnt = a.errcnt; } /* --Methode-- */ size_t Socket::Send(const char * buff, size_t len, int flag) { ssize_t rc; rc = send(skt, buff, len, flag); if (rc > 0) { // tlast = (long)time(NULL); totsnd += rc; return(rc); } else return 0; } /* --Methode-- */ size_t Socket::Receive(char * buff, size_t len, int flag) { ssize_t rc; // int fromlen = 0; bool encore = true; while (encore) { rc = recv(skt, buff, len, flag); // rc = recvfrom(skt, buff, len, flag, NULL, &fromlen); if ((rc < 1) && (errno == EAGAIN)) usleep(20000); else encore = false; } if (rc > 0) { // tlast = (long)time(NULL); totrcv += rc; return(rc); } else return 0; } /* --Methode-- */ size_t Socket::SendAll(const char * buff, size_t len) { size_t nst = 0; int ntry = 0; while (nst < len) { size_t ns = Send(buff+nst, len-nst); ntry++; if (ns < 1) break; nst += ns; } if (nst < len) { cout << " Socket::SendAll() / ERROR ! ntry=" << ntry << " nst=" << nst << " len=" << len << endl; throw SocketException("Socket::SendAll() Error NBytesSent < len "); } return nst; } /* --Methode-- */ size_t Socket::ReceiveAll(char * buff, size_t len) { size_t nrt = 0; int ntry = 0; while (nrt < len) { size_t nr = Receive(buff+nrt, len-nrt); ntry++; if (nr < 1) break; nrt += nr; } if (nrt < len) { cout << " Socket::ReceiveAll / ERROR ! ntry=" << ntry << " nrt=" << nrt << " len=" << len << endl; throw SocketException("Socket::ReceiveAll() Error NBytesRecv < len "); } return nrt; } // extern int errno; /* --Methode-- */ int Socket::Close() { if (skt<0) return 0; int rc=-1; rc = shutdown(skt, SHUT_RDWR); if(rc < 0) cout << "Socket::Close() Erreur: Pb shutdown() ErrNo=" << errno << endl; rc = close(skt); if(rc < 0) cout << "Socket::Close() Erreur: Pb close() ErrNo=" << errno << endl; skt = -1; return(0); } /*! \class SOPHYA::ServerSocket \ingroup SysTools \brief Socket wrapper class for the server side */ /* --Methode-- */ ServerSocket::ServerSocket(int port, int nconmax) : Socket() { Initialize(NULL, port, nconmax); } /* --Methode-- */ ServerSocket::ServerSocket(const char* inadr, int port, int nconmax) : Socket() { Initialize(inadr, port, nconmax); } /* --Methode-- */ ServerSocket::ServerSocket(string const& inadr, int port, int nconmax) : Socket() { Initialize(inadr.c_str(), port, nconmax); } /* --Methode-- */ void ServerSocket::Initialize(const char* str_inadr, int port, int nconmax) { int s,rc; s = socket(AF_INET, SOCK_STREAM, 0); if (s < 0) { cout << "ServerSocket::Initialize() Pb socket ErrNo=" << errno << endl; throw SocketException("ServerSocket::Initialize() Pb socket()"); } skt = s; int soptv=1; if ( setsockopt( skt, SOL_SOCKET, SO_REUSEADDR, &soptv, sizeof(soptv) ) != 0) { cout << "ServerSocket::Initialize() Pb setsockopt(...SO_REUSEADDR...) ErrNo=" << errno << endl; throw SocketException("ServerSocket::Initialize() Pb setsockopt(...SO_REUSEADDR...)"); } if (nconmax <= 1) nconmax = 1; NConMax = nconmax; nclitot = 0; portid = port; ipskt.sin_family = AF_INET; ipskt.sin_port = htons(port); if (str_inadr==NULL) { // pas d'adresse IP specifie ipskt.sin_addr.s_addr = INADDR_ANY; } else { // adresse IP specifie sous la forme uuu.xxx.yyy.zzz. ipskt.sin_addr.s_addr = inet_addr(str_inadr); } /* Je fais un cast explicit de sockaddr_in * (Internet) en sockaddr * */ rc = bind(skt, (struct sockaddr *)(&ipskt), sizeof(ipskt)); if (rc < 0) { Close(); cout << "ServerSocket::Initialize() Pb bind() ErrNo=" << errno << endl; throw SocketException("ServerSocket::Initialize() Pb bind()"); } } /* --Methode-- */ Socket ServerSocket::WaitClientConnection() { int rc,s,len; struct sockaddr_in cli; rc = listen(skt, NConMax); if (rc < 0) { cout << "ServerSocket::WaitClientConnection() Pb listen() ErrNo=" << errno << endl; throw SocketException("ServerSocket::WaitClientConnection() Pb listen()"); } /* Je fais un cast explicit de sockaddr_in * (Internet) en sockaddr * */ socklen_t sl = sizeof(cli); s = accept(skt, (struct sockaddr *)(&cli), &sl); if(s < 0) { cout << "ServerSocket::WaitClientConnection() Pb accpet() ErrNo=" << errno << endl; throw SocketException("ServerSocket::WaitClientConnection() Pb accept()"); } nclitot++; return Socket(s); } /* --Methode-- */ int ServerSocket::Close() { if (skt<0) return 0; int rc=-1; /* il ne faut apparemment pas faire shutdown sur un socket serveur (non connected - ENOTCONN ) rc = shutdown(skt, SHUT_RDWR); if(rc < 0) cout << "Socket::Close() Erreur: Pb shutdown() ErrNo=" << errno << endl; */ rc = close(skt); if(rc < 0) cout << "ServerSocket::Close() Erreur: Pb close() ErrNo=" << errno << endl; skt = -1; return(0); } /*! \class SOPHYA::ClientSocket \ingroup SysTools \brief Socket wrapper class for the client side */ /* --Methode-- */ ClientSocket::ClientSocket(string const& srvname, int port) : Socket() { InitConnection(srvname.c_str(), port); } /* --Methode-- */ ClientSocket::ClientSocket(const char* srvname, int port) : Socket() { InitConnection(srvname, port); } /* --Methode-- */ ClientSocket::ClientSocket(ClientSocket const& a) : Socket(a) { portid=a.portid; ipskt=a.ipskt; } /* --Methode-- */ void ClientSocket::SetC(ClientSocket const& a) { Set(a); portid=a.portid; ipskt=a.ipskt; return; } /* --Methode-- */ void ClientSocket::InitConnection(const char* name, int port) { struct hostent *server; int s,rc; #if defined(Linux) || defined(linux) typedef unsigned long in_addr_t; #endif in_addr_t inad; server = NULL; /* Try to find out if this is a known machine name */ server = gethostbyname(name); if(!server) { /* Try it as an internet address a.b.c.d */ /* inad = inet_addr(name); if(inad == INADDR_NONE) { cout << "ClientSocket() Host identification failed inet_addr(" << name << ")" << endl; throw SocketException("ClientSocket() Host identification failed "); } */ server = gethostbyaddr(name, strlen(name), AF_INET); } if(!server) { cout << "ClientSocket() Host identification failed (2) for" << name << endl; throw SocketException("ClientSocket() Host identification failed (2)"); } ipskt.sin_family = AF_INET; ipskt.sin_port = htons(port); memcpy(&(ipskt.sin_addr), server->h_addr, server->h_length); s = socket(AF_INET, SOCK_STREAM, 0); if (s < 0) { cout << "ClientSocket() Erreur: Pb socket() ErrNo=" << errno << endl; throw SocketException("ClientSocket() Erreur: Pb socket()"); } skt = s; portid = port; /* Je fais un cast explicit de sockaddr_in * (Internet) en sockaddr * */ rc = connect(skt, (struct sockaddr *)(&ipskt), sizeof(struct sockaddr_in)); if (rc < 0) { cout << "ClientSocket() Erreur: Pb connect() ErrNo=" << errno << endl; Close(); throw SocketException("ClientSocket() Erreur: Pb connect()"); } }