#ifdef _WIN32 #include #endif #define _BSD_SOCKLEN_T_ int #ifndef _WIN32 #include #include #include #include #include #endif #include #include #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "BString.h" #include "Socket.h" #include "Exceptions.h" #include "Input.h" #include "Output.h" #include "gettext.h" #ifdef _WIN32 class dummy_win32_socket_class_t : public Base { public: dummy_win32_socket_class_t() throw (GeneralException) { WSADATA wsaData; if (WSAStartup(MAKEWORD(2, 0), &wsaData) != 0) throw GeneralException("WSAStartup() failed."); } } dummy_win32_socket_class; typedef int socklen_t; #endif Socket::Socket() throw (GeneralException) : Handle(socket(AF_INET, SOCK_STREAM, 0)), connected(false), listening(false), writeclosed(false), readclosed(false) { // cerr << "Socket(): connected = " << connected << "; readclosed = " << readclosed << "; writeclosed = " << writeclosed << endl; if (GetHandle() < 0) { throw GeneralException(_("Error creating socket.")); } } Socket::Socket(const Socket & s) : Handle(s), connected(s.connected), listening(s.listening), writeclosed(s.writeclosed), readclosed(s.readclosed) { // cerr << "Constructing a socket by copy...\n"; // cerr << "Socket(const Socket &): connected = " << connected << "; readclosed = " << readclosed << "; writeclosed = " << writeclosed << endl; } Socket::Socket(int h) : Handle(h), connected(true), listening(false), writeclosed(false), readclosed(false) { } String Socket::GetName(void) { return String("socket"); } bool Socket::IsConnected(void) { return connected; } bool Socket::IsListening(void) { return listening; } bool Socket::CanRead(void) { // cerr << "CanRead: connected = " << connected << "; readclosed = " << readclosed << endl; return connected && !readclosed; } bool Socket::CanWrite(void) { // cerr << "CanWrite: connected = " << connected << "; writeclosed = " << writeclosed << endl; return connected && !writeclosed; } void Socket::CloseWrite(void) { if (!writeclosed) { writeclosed = true; shutdown(GetHandle(), 1); } } void Socket::CloseRead(void) { if (!readclosed) { readclosed = true; shutdown(GetHandle(), 0); } } /***********************************************\ * Toute la suite n'est pas à décrire. Consulter * * plutôt un document décrivant les sockets. * \***********************************************/ bool Socket::SetLocal(const String & vhost, int port) { struct hostent * localhostent; struct in_addr localhostaddr; struct sockaddr_in localsocketaddr; memset((void *)&localhostaddr, 0, sizeof(localhostaddr)); if (vhost.strlen() != 0) { if ((localhostent = gethostbyname(vhost.to_charp()))) { memcpy((void *)&localhostaddr, localhostent->h_addr, sizeof(localhostaddr)); } else { return false; } } else { localhostaddr.s_addr = htonl(INADDR_ANY); } memset(&localsocketaddr, 0, sizeof(struct sockaddr_in)); localsocketaddr.sin_family = AF_INET; localsocketaddr.sin_addr = localhostaddr; localsocketaddr.sin_port = htons(port); if (bind(GetHandle(), (struct sockaddr *) &localsocketaddr, sizeof(localsocketaddr)) < 0) { return false; } else { return true; } } bool Socket::Connect(const String & host, int port) { struct hostent * remotehostent; struct sockaddr_in remotesocketaddr; if (!listening && !connected) { // cerr << " - Resolving '" << host << "'..." << endl; if (!(remotehostent = gethostbyname(host.to_charp()))) { return false; } remotesocketaddr.sin_family = AF_INET; remotesocketaddr.sin_port = htons(port); bcopy(remotehostent->h_addr, &remotesocketaddr.sin_addr, remotehostent->h_length); // cerr << " - Connecting to port " << port << " ..." << endl; if (!connect(GetHandle(), (struct sockaddr *)&remotesocketaddr, sizeof(remotesocketaddr))) { // cerr << " - Connected." << endl; connected = true; } else { // cerr << " - Error connecting: " << strerror(errno) << endl; } } return connected; } bool Socket::Listen(void) { if (!listening && !connected) { if (!listen(GetHandle(), 10)) { listening = true; } } return listening; } Socket Socket::Accept(void) throw (GeneralException) { struct sockaddr inaddr; socklen_t inlen = sizeof(inaddr); int h; if ((h = accept(GetHandle(), &inaddr, &inlen)) < 0) { throw GeneralException(_("Failed accepting.")); } else { return Socket(h); } } int Socket::GetPort() { int r; struct sockaddr_in localsocketaddr; socklen_t locallen = sizeof(localsocketaddr); if (getsockname(GetHandle(), (struct sockaddr *) &localsocketaddr, &locallen)) { return -1; } r = ntohs(localsocketaddr.sin_port); return r; } ssize_t Socket::nwrite(const void * buf, size_t count) throw (GeneralException) { return ::send(GetHandle(), (const char *) buf, count, 0); } ssize_t Socket::nread(void * buf, size_t count) throw (GeneralException) { return ::recv(GetHandle(), (char *) buf, count, 0); } int Socket::ndup() const throw (GeneralException) { #ifdef _WIN32 WSAPROTOCOL_INFO ProtocolInfo; int r, s; if (r = WSADuplicateSocket(GetHandle(), GetCurrentProcessId(), &ProtocolInfo)) { throw GeneralException("Error within WSADuplicateSocket()."); } if ((s = WSASocket(AF_INET, SOCK_STREAM, IPPROTO_TCP, &ProtocolInfo, 0, 0)) == INVALID_SOCKET) { throw GeneralException("Error within WSASocket() while dup()ing it."); } return s; #else return dup(GetHandle()); #endif } int Socket::nclose() throw (GeneralException) { return closesocket(GetHandle()); }