void Socket::_handleSendError(int ret, const char* context) { #ifdef MONGO_SSL if (_ssl) { LOG(_logLevel) << "SSL Error ret: " << ret << " err: " << _sslManager->SSL_get_error(_ssl , ret) << " " << _sslManager->ERR_error_string(_sslManager->ERR_get_error(), NULL) << endl; throw SocketException(SocketException::SEND_ERROR , remoteString()); } #endif #if defined(_WIN32) const int mongo_errno = WSAGetLastError(); if ( mongo_errno == WSAETIMEDOUT && _timeout != 0 ) { #else const int mongo_errno = errno; if ( ( mongo_errno == EAGAIN || mongo_errno == EWOULDBLOCK ) && _timeout != 0 ) { #endif LOG(_logLevel) << "Socket " << context << " send() timed out " << remoteString() << endl; throw SocketException(SocketException::SEND_TIMEOUT , remoteString()); } else { LOG(_logLevel) << "Socket " << context << " send() " << errnoWithDescription(mongo_errno) << ' ' << remoteString() << endl; throw SocketException(SocketException::SEND_ERROR , remoteString()); } } void Socket::_handleRecvError(int ret, int len, int* retries) { if (ret == 0) { LOG(3) << "Socket recv() conn closed? " << remoteString() << endl; throw SocketException(SocketException::CLOSED , remoteString()); } // ret < 0 #ifdef MONGO_SSL if (_ssl) { LOG(_logLevel) << "SSL Error ret: " << ret << " err: " << _sslManager->SSL_get_error(_ssl , ret) << " " << _sslManager->ERR_error_string(_sslManager->ERR_get_error(), NULL) << endl; throw SocketException(SocketException::RECV_ERROR, remoteString()); } #endif #if defined(_WIN32) int e = WSAGetLastError(); #else int e = errno; # if defined(EINTR) if (e == EINTR) { LOG(_logLevel) << "EINTR retry " << ++*retries << endl; return; } # endif #endif #if defined(_WIN32) // Windows if ((e == EAGAIN || e == WSAETIMEDOUT) && _timeout > 0) { #else if (e == EAGAIN && _timeout > 0) { #endif // this is a timeout LOG(_logLevel) << "Socket recv() timeout " << remoteString() <<endl; throw SocketException(SocketException::RECV_TIMEOUT, remoteString()); } LOG(_logLevel) << "Socket recv() " << errnoWithDescription(e) << " " << remoteString() <<endl; throw SocketException(SocketException::RECV_ERROR , remoteString()); } void Socket::setTimeout( double secs ) { setSockTimeouts( _fd, secs ); } // TODO: allow modification? // // <positive value> : secs to wait between stillConnected checks // 0 : always check // -1 : never check const int Socket::errorPollIntervalSecs( 5 ); #if defined(NTDDI_VERSION) && ( !defined(NTDDI_VISTA) || ( NTDDI_VERSION < NTDDI_VISTA ) ) // Windows XP // pre-Vista windows doesn't have WSAPoll, so don't test connections bool Socket::isStillConnected() { return true; } #else // Not Windows XP // Patch to allow better tolerance of flaky network connections that get broken // while we aren't looking. // TODO: Remove when better async changes come. // // isStillConnected() polls the socket at max every Socket::errorPollIntervalSecs to determine // if any disconnection-type events have happened on the socket. bool Socket::isStillConnected() { if ( errorPollIntervalSecs < 0 ) return true; time_t now = time( 0 ); time_t idleTimeSecs = now - _lastValidityCheckAtSecs; // Only check once every 5 secs if ( idleTimeSecs < errorPollIntervalSecs ) return true; // Reset our timer, we're checking the connection _lastValidityCheckAtSecs = now; // It's been long enough, poll to see if our socket is still connected pollfd pollInfo; pollInfo.fd = _fd; // We only care about reading the EOF message on clean close (and errors) pollInfo.events = POLLIN; // Poll( info[], size, timeout ) - timeout == 0 => nonblocking #if defined(_WIN32) int nEvents = WSAPoll( &pollInfo, 1, 0 ); #else int nEvents = ::poll( &pollInfo, 1, 0 ); #endif LOG( 2 ) << "polling for status of connection to " << remoteString() << ", " << ( nEvents == 0 ? "no events" : nEvents == -1 ? "error detected" : "event detected" ) << endl; if ( nEvents == 0 ) { // No events incoming, return still connected AFAWK return true; } else if ( nEvents < 0 ) { // Poll itself failed, this is weird, warn and log errno warning() << "Socket poll() failed during connectivity check" << " (idle " << idleTimeSecs << " secs," << " remote host " << remoteString() << ")" << causedBy(errnoWithDescription()) << endl; // Return true since it's not clear that we're disconnected. return true; } dassert( nEvents == 1 ); dassert( pollInfo.revents > 0 ); // Return false at this point, some event happened on the socket, but log what the // actual event was. if ( pollInfo.revents & POLLIN ) { // There shouldn't really be any data to recv here, so make sure this // is a clean hangup. // Used concurrently, but we never actually read this data static char testBuf[1]; int recvd = ::recv( _fd, testBuf, 1, portRecvFlags ); if ( recvd < 0 ) { // An error occurred during recv, warn and log errno warning() << "Socket recv() failed during connectivity check" << " (idle " << idleTimeSecs << " secs," << " remote host " << remoteString() << ")" << causedBy(errnoWithDescription()) << endl; } else if ( recvd > 0 ) { // We got nonzero data from this socket, very weird? // Log and warn at runtime, log and abort at devtime // TODO: Dump the data to the log somehow? error() << "Socket found pending data during connectivity check" << " (idle " << idleTimeSecs << " secs," << " remote host " << remoteString() << ")" << endl; dassert( false ); } else { // recvd == 0, socket closed remotely, just return false LOG( 0 ) << "Socket closed remotely, no longer connected" << " (idle " << idleTimeSecs << " secs," << " remote host " << remoteString() << ")" << endl; } } else if ( pollInfo.revents & POLLHUP ) { // A hangup has occurred on this socket LOG( 0 ) << "Socket hangup detected, no longer connected" << " (idle " << idleTimeSecs << " secs," << " remote host " << remoteString() << ")" << endl; } else if ( pollInfo.revents & POLLERR ) { // An error has occurred on this socket LOG( 0 ) << "Socket error detected, no longer connected" << " (idle " << idleTimeSecs << " secs," << " remote host " << remoteString() << ")" << endl; } else if ( pollInfo.revents & POLLNVAL ) { // Socket descriptor itself is weird // Log and warn at runtime, log and abort at devtime error() << "Socket descriptor detected as invalid" << " (idle " << idleTimeSecs << " secs," << " remote host " << remoteString() << ")" << endl; dassert( false ); } else { // Don't know what poll is saying here // Log and warn at runtime, log and abort at devtime error() << "Socket had unknown event (" << static_cast<int>(pollInfo.revents) << ")" << " (idle " << idleTimeSecs << " secs," << " remote host " << remoteString() << ")" << endl; dassert( false ); } return false; } #endif // End Not Windows XP #if defined(_WIN32) struct WinsockInit { WinsockInit() { WSADATA d; if ( WSAStartup(MAKEWORD(2,2), &d) != 0 ) { out() << "ERROR: wsastartup failed " << errnoWithDescription() << endl; problem() << "ERROR: wsastartup failed " << errnoWithDescription() << endl; _exit(EXIT_NTSERVICE_ERROR); } } } winsock_init; #endif } // namespace mongo
org::esb::io::OutputStream * TcpSocket::getOutputStream() { if(!isConnected()) throw SocketException("Socket is not connected"); return _os; }
void Socket::SetNonBlockingFalg(bool isNonBlocking) { if (!SetNonBlockingFalgImpl(SockHandle, isNonBlocking)) throw SocketException("Error set non blocking flag"); }
void Web::Request::Connect() { SOCKET httpSocket; int ret; struct sockaddr_in httpAddr; struct hostent *hostinfo; char buffer[REQUESTBUFFERSIZE + 1]; int bufferSize; int timeout = REQUESTTIMEOUT; /* Choses settings for the socket to connect to */ httpAddr.sin_family = AF_INET; /* Set the port */ //httpAddr.sin_port = htons(url->getPort()); httpAddr.sin_port = htons(80); /* Do a hostname lookup on the host */ //hostinfo = gethostbyname (url->getHost()); hostinfo = gethostbyname ("localhost"); if (hostinfo == NULL) { throw HostNotFoundException(); } /* Fill the httpAddr with IP data */ httpAddr.sin_addr = *(struct in_addr *) hostinfo->h_addr; /* Creates the socket */ httpSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP) ; /* Check for errors */ if (httpSocket == INVALID_SOCKET) throw SocketException(); /* Add a timeout on all communiction*/ ret = setsockopt(httpSocket, SOL_SOCKET, SO_RCVTIMEO, (char *)&timeout, sizeof(timeout)); /* Check for errors */ if (ret == SOCKET_ERROR) { closesocket(httpSocket); throw SocketException(); } /* Connect to the server */ ret = connect(httpSocket,(LPSOCKADDR)&httpAddr, sizeof(struct sockaddr)); /* Check for errors */ if (ret == SOCKET_ERROR) { closesocket(httpSocket); throw ConnectionFailedException(WSAGetLastError()); } /* Create a request */ bufferSize = _snprintf(buffer, REQUESTBUFFERSIZE, "GET %s HTTP/1.0\r\n\r\n", url->getURL()); if (bufferSize <= 0) { closesocket(httpSocket); throw Exception("Request Buffer Too Small"); } /* Send a HTTP request */ ret = send(httpSocket, buffer, bufferSize, 0); if (ret < bufferSize) { closesocket(httpSocket); throw TransferException(); } reply.assign(""); ret = REQUESTBUFFERSIZE; /* Now wait for the return and loop while its coming */ while (ret > 0) { ret = recv(httpSocket, buffer, REQUESTBUFFERSIZE, 0); /* Append data to the buffer */ if (ret > 0) reply.append(buffer, ret); } /* Clean up the socket */ closesocket(httpSocket); /* Now if we didn't get any data throw a error */ if (reply.length()==0) { throw TransferException(); } /* Got some data let parse it */ ret = (int)reply.find("\r\n\r\n"); if (ret==-1) { throw InvalidDataException(); } header = reply.substr(0, ret); ret += 4; body = reply.substr(ret, reply.length() - ret); }
bool SSLSocket::waitWant(int ret, uint64_t millis) { #ifdef HEADER_OPENSSLV_H int err = SSL_get_error(ssl, ret); switch(err) { case SSL_ERROR_WANT_READ: return wait(millis, Socket::WAIT_READ) == WAIT_READ; case SSL_ERROR_WANT_WRITE: return wait(millis, Socket::WAIT_WRITE) == WAIT_WRITE; #else int err = ssl->last_error; switch(err) { case GNUTLS_E_INTERRUPTED: case GNUTLS_E_AGAIN: { int waitFor = wait(millis, Socket::WAIT_READ | Socket::WAIT_WRITE); return (waitFor & Socket::WAIT_READ) || (waitFor & Socket::WAIT_WRITE); } #endif // Check if this is a fatal error... default: checkSSL(ret); } dcdebug("SSL: Unexpected fallthrough"); // There was no error? return true; } int SSLSocket::read(void* aBuffer, int aBufLen) throw(SocketException) { if(!ssl) { return -1; } int len = checkSSL(SSL_read(ssl, aBuffer, aBufLen)); if(len > 0) { stats.totalDown += len; //dcdebug("In(s): %.*s\n", len, (char*)aBuffer); } return len; } int SSLSocket::write(const void* aBuffer, int aLen) throw(SocketException) { if(!ssl) { return -1; } int ret = checkSSL(SSL_write(ssl, aBuffer, aLen)); if(ret > 0) { stats.totalUp += ret; //dcdebug("Out(s): %.*s\n", ret, (char*)aBuffer); } return ret; } int SSLSocket::checkSSL(int ret) throw(SocketException) { if(!ssl) { return -1; } if(ret <= 0) { int err = SSL_get_error(ssl, ret); switch(err) { case SSL_ERROR_NONE: // Fallthrough - YaSSL doesn't for example return an openssl compatible error on recv fail case SSL_ERROR_WANT_READ: // Fallthrough case SSL_ERROR_WANT_WRITE: return -1; case SSL_ERROR_ZERO_RETURN: #ifndef HEADER_OPENSSLV_H if(ssl->last_error == GNUTLS_E_INTERRUPTED || ssl->last_error == GNUTLS_E_AGAIN) return -1; #endif throw SocketException(STRING(CONNECTION_CLOSED)); default: { ssl.reset(); // @todo replace 80 with MAX_ERROR_SZ or whatever's appropriate for yaSSL in some nice way... char errbuf[80]; /* TODO: better message for SSL_ERROR_SYSCALL * If the error queue is empty (i.e. ERR_get_error() returns 0), ret can be used to find out more about the error: * If ret == 0, an EOF was observed that violates the protocol. If ret == -1, the underlying BIO reported an I/O error * (for socket I/O on Unix systems, consult errno for details). */ int error = ERR_get_error(); sprintf(errbuf, "%s %d: %s", CSTRING(SSL_ERROR), err, (error == 0) ? CSTRING(CONNECTION_CLOSED) : ERR_reason_error_string(error)); throw SSLSocketException(errbuf); } } } return ret; } int SSLSocket::wait(uint64_t millis, int waitFor) throw(SocketException) { #ifdef HEADER_OPENSSLV_H if(ssl && (waitFor & Socket::WAIT_READ)) { /** @todo Take writing into account as well if reading is possible? */ char c; if(SSL_peek(ssl, &c, 1) > 0) return WAIT_READ; } #endif return Socket::wait(millis, waitFor); } bool SSLSocket::isTrusted() throw() { if(!ssl) { return false; } #ifdef HEADER_OPENSSLV_H if(SSL_get_verify_result(ssl) != X509_V_OK) { return false; } #else if(gnutls_certificate_verify_peers(((SSL*)ssl)->gnutls_state) != 0) { return false; } #endif X509* cert = SSL_get_peer_certificate(ssl); if(!cert) { return false; } X509_free(cert); return true; } std::string SSLSocket::getCipherName() throw() { if(!ssl) return Util::emptyString; return SSL_get_cipher_name(ssl); } std::string SSLSocket::getDigest() const throw() { #ifdef HEADER_OPENSSLV_H if(!ssl) return Util::emptyString; X509* x509 = SSL_get_peer_certificate(ssl); if(!x509) return Util::emptyString; return ssl::X509_digest(x509, EVP_sha1()); #else return Util::emptyString; #endif } void SSLSocket::shutdown() throw() { if(ssl) SSL_shutdown(ssl); } void SSLSocket::close() throw() { if(ssl) { ssl.reset(); } Socket::shutdown(); Socket::close(); } } // namespace dcpp
/** sends all data or throws an exception * @param context descriptive for logging */ void Socket::send( const vector< pair< char *, int > > &data, const char *context ) { #ifdef MONGO_SSL if ( _sslConnection.get() ) { _send( data , context ); return; } #endif #if defined(_WIN32) // TODO use scatter/gather api _send( data , context ); #else vector<struct iovec> d( data.size() ); int i = 0; for (vector< pair<char *, int> >::const_iterator j = data.begin(); j != data.end(); ++j) { if ( j->second > 0 ) { d[ i ].iov_base = j->first; d[ i ].iov_len = j->second; ++i; _bytesOut += j->second; } } struct msghdr meta; memset( &meta, 0, sizeof( meta ) ); meta.msg_iov = &d[ 0 ]; meta.msg_iovlen = d.size(); while( meta.msg_iovlen > 0 ) { int ret = -1; if (MONGO_FAIL_POINT(throwSockExcep)) { #if defined(_WIN32) WSASetLastError(WSAENETUNREACH); #else errno = ENETUNREACH; #endif } else { ret = ::sendmsg(_fd, &meta, portSendFlags); } if (ret == -1) { if ( errno != EAGAIN || _timeout == 0 ) { LOG(_logLevel) << "Socket " << context << " send() " << errnoWithDescription() << ' ' << remoteString() << endl; throw SocketException( SocketException::SEND_ERROR , remoteString() ); } else { LOG(_logLevel) << "Socket " << context << " send() remote timeout " << remoteString() << endl; throw SocketException( SocketException::SEND_TIMEOUT , remoteString() ); } } else { struct iovec *& i = meta.msg_iov; while( ret > 0 ) { if ( i->iov_len > unsigned( ret ) ) { i->iov_len -= ret; i->iov_base = (char*)(i->iov_base) + ret; ret = 0; } else { ret -= i->iov_len; ++i; --(meta.msg_iovlen); } } } } #endif }
size_t TCPClient::write(const char *msg) throw(SocketException) { if ( ::write(m_sockfd, msg, strlen(msg)) == -1 ) throw SocketException("tcp client write error"); return strlen(msg); }
void SocketIPv4::shutdown(int how) { if (::shutdown(m_socket, how) == SOCKET_ERROR) { throw SocketException(); } }
void SocketIO::Bind(Socket *s, const Anope::string &ip, int port) { s->bindaddr.pton(s->IsIPv6() ? AF_INET6 : AF_INET, ip, port); if (bind(s->GetFD(), &s->bindaddr.sa, s->bindaddr.size()) == -1) throw SocketException("Unable to bind to address: " + Anope::LastError()); }
void TCPClient::write(const void *buf, size_t count) throw(SocketException) { if ( ::write(m_sockfd, buf, count) == -1 ) throw SocketException("tcp client write error"); }
int Socket::connect(const char *hostName, in_port_t port) { int rc = -1; int sockfd, nodelay; char service[NI_MAXSERV] = {0}; struct addrinfo *host = NULL, *ressave; int count = 0; bool connected = false; while (count < connTimes) { struct addrinfo hints = {0}; ::sprintf(service, "%d", port); hints.ai_family = AF_UNSPEC; hints.ai_socktype = SOCK_STREAM; hints.ai_flags = AI_NUMERICHOST | AI_NUMERICSERV; rc = ::getaddrinfo(hostName, service, &hints, &host); if (rc == EAI_NONAME) { hints.ai_flags = 0; rc = ::getaddrinfo(hostName, service, &hints, &host); } if (!host) { throw SocketException(SocketException::NET_ERR_GETADDRINFO, errno); } ressave = host; while (host) { if ((host->ai_family == AF_INET6) && (getDisableIPv6() == 1)) { host = host->ai_next; continue; } sockfd = ::socket(host->ai_family, host->ai_socktype, host->ai_protocol); if (sockfd < 0) { ::freeaddrinfo(host); throw SocketException(SocketException::NET_ERR_SOCKET, errno); } nodelay = 1; rc = ::setsockopt(sockfd, IPPROTO_TCP, TCP_NODELAY, (char*)&nodelay, sizeof(nodelay)); rc = ::connect(sockfd, host->ai_addr, host->ai_addrlen); if (rc == 0) { connected = true; break; } host = host->ai_next; } count++; ::freeaddrinfo(ressave); if (connected) break; ::close(sockfd); ::sleep(1); } if (rc < 0) { throw SocketException(SocketException::NET_ERR_CONNECT, errno); } socket = sockfd; return sockfd; }
int Socket::listen(int &port, char *hname) { int sockfd; int yes, rc; int accCount = 0; struct addrinfo hints, *host, *ressave; char service[NI_MAXSERV] = {0}; ::memset(&hints, 0, sizeof(struct addrinfo)); hints.ai_flags = (hname == NULL) ? AI_PASSIVE : 0; hints.ai_family = AF_UNSPEC; hints.ai_socktype = SOCK_STREAM; ::sprintf(service, "%d", port); ::getaddrinfo(hname, service, &hints, &host); ressave = host; while (host && (accCount < NELEMS(accSockets))) { if ((host->ai_family != AF_INET) && (host->ai_family != AF_INET6)) { host = host->ai_next; continue; } if ((host->ai_family == AF_INET6) && (getDisableIPv6() == 1)) { host = host->ai_next; continue; } sockfd = ::socket(host->ai_family, host->ai_socktype, host->ai_protocol); if (sockfd >= 0) { yes = 1; rc = ::setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes)); if (host->ai_family == AF_INET6) { setsockopt(sockfd, IPPROTO_IPV6, IPV6_V6ONLY, &yes, sizeof(yes)); sockaddr_in6 *addr6 = (sockaddr_in6 *)host->ai_addr; if (port != 0) addr6->sin6_port = htons(port); } else { sockaddr_in *addr4 = (sockaddr_in *)host->ai_addr; if (port != 0) addr4->sin_port = htons(port); } setMode(sockfd, false); rc = ::bind(sockfd, host->ai_addr, host->ai_addrlen); if (rc == 0) { struct sockaddr_storage sockaddr; socklen_t len = sizeof(sockaddr); ::getsockname(sockfd, (struct sockaddr *)&sockaddr, &len); ::getnameinfo((struct sockaddr *)&sockaddr, len, NULL, 0, service, sizeof(service), NI_NUMERICSERV); port = ::atoi(service); rc = ::listen(sockfd, SOMAXCONN); accSockets[accCount] = sockfd; accCount++; } else { ::close(sockfd); } } host = host->ai_next; } if (accCount <= 0) { throw SocketException(SocketException::NET_ERR_BIND, errno); } ::freeaddrinfo(ressave); numListenfds = accCount; return accCount; }
/** Bind a socket * @param s The socket * @param ip The IP to bind to * @param port The optional port to bind to */ void SocketIO::Bind(Socket *s, const Flux::string &ip, int port) { s->bindaddr.pton(s->IsIPv6() ? AF_INET6 : AF_INET, ip, port); if (bind(s->GetFD(), &s->bindaddr.sa, s->bindaddr.size()) == -1) throw SocketException(printfify("Unable to bind to address: %s", strerror(errno))); }
void SocketIPv4::listen(int backlog) { if (::listen(m_socket, backlog) == SOCKET_ERROR) { throw SocketException(); } }
SocketEnvironment::SocketEnvironment() { WSADATA data; if (::WSAStartup(MAKEWORD(2, 0), &data)) { throw SocketException(__FILE__, __LINE__); } }
void SocketIPv4::getSocketOptions(int level, int name, void *value, socklen_t *len) { if (getsockopt(m_socket, level, name, (char*)value, len) == SOCKET_ERROR) { throw SocketException(); } }
void BufferedSocket::threadRead() throw(SocketException) { if(state != RUNNING) return; DownloadManager *dm = DownloadManager::getInstance(); size_t readsize = inbuf.size(); bool throttling = false; if(mode == MODE_DATA) { uint32_t getMaximum; throttling = dm->throttle(); if (throttling) { getMaximum = dm->throttleGetSlice(); readsize = (uint32_t)min((int64_t)inbuf.size(), (int64_t)getMaximum); if (readsize <= 0 || readsize > inbuf.size()) { // FIX sleep(dm->throttleCycleTime()); return; } } } int left = sock->read(&inbuf[0], (int)readsize); if(left == -1) { // EWOULDBLOCK, no data received... return; } else if(left == 0) { // This socket has been closed... throw SocketException(_("Connection closed")); } string::size_type pos = 0; // always uncompressed data string l; int bufpos = 0, total = left; while (left > 0) { switch (mode) { case MODE_ZPIPE: { const int BUF_SIZE = 1024; // Special to autodetect nmdc connections... string::size_type pos = 0; boost::scoped_array<char> buffer(new char[BUF_SIZE]); l = line; // decompress all input data and store in l. while (left) { size_t in = BUF_SIZE; size_t used = left; bool ret = (*filterIn) (&inbuf[0] + total - left, used, &buffer[0], in); left -= used; l.append (&buffer[0], in); // if the stream ends before the data runs out, keep remainder of data in inbuf if (!ret) { bufpos = total-left; setMode (MODE_LINE, rollback); break; } } // process all lines while ((pos = l.find(separator)) != string::npos) { fire(BufferedSocketListener::Line(), l.substr(0, pos)); l.erase (0, pos + 1 /* separator char */); } // store remainder line = l; break; } case MODE_LINE: // Special to autodetect nmdc connections... if(separator == 0) { if(inbuf[0] == '$') { separator = '|'; } else { separator = '\n'; } } l = line + string ((char*)&inbuf[bufpos], left); while ((pos = l.find(separator)) != string::npos) { fire(BufferedSocketListener::Line(), l.substr(0, pos)); l.erase (0, pos + 1 /* separator char */); if (l.length() < (size_t)left) left = l.length(); if (mode != MODE_LINE) { // we changed mode; remainder of l is invalid. l.clear(); bufpos = total - left; break; } } if (pos == string::npos) left = 0; line = l; break; case MODE_DATA: while(left > 0) { if(dataBytes == -1) { fire(BufferedSocketListener::Data(), &inbuf[bufpos], left); bufpos += (left - rollback); left = rollback; rollback = 0; } else { int high = (int)min(dataBytes, (int64_t)left); fire(BufferedSocketListener::Data(), &inbuf[bufpos], high); bufpos += high; left -= high; dataBytes -= high; if(dataBytes == 0) { mode = MODE_LINE; fire(BufferedSocketListener::ModeChange()); } } if (throttling) { if (left > 0 && left < (int)readsize) { dm->throttleReturnBytes(left - readsize); } uint32_t sleep_interval = dm->throttleCycleTime(); Thread::sleep(sleep_interval); } } break; } } if(mode == MODE_LINE && line.size() > static_cast<size_t>(SETTING(MAX_COMMAND_LENGTH))) { throw SocketException(_("Maximum command length exceeded")); } }
vpr::Uint32 SocketDatagramImplBSD::sendto(const void* msg, const vpr::Uint32 length, const vpr::InetAddr& to, const vpr::Interval timeout) { vpr::Uint32 bytes_sent(0); // If not writable within timeout interval throw exception. if ( ! mHandle->isWriteable(timeout) ) { std::ostringstream msg_stream; msg_stream << "Timeout occured while trying to write to " << mHandle->getName(); throw TimeoutException(msg_stream.str(), VPR_LOCATION); } ssize_t bytes; mBlockingFixed = true; bytes = ::sendto(mHandle->mFdesc, msg, length, 0, (struct sockaddr*) &to.mAddr, to.size()); if ( bytes == -1 ) { if ( errno == EAGAIN && ! isBlocking() ) { throw WouldBlockException("Would block while reading.", VPR_LOCATION); } else { std::stringstream ss; ss << "[vpr::SocketDatagramImplBSD::sendto()] ERROR: Could not send " << " to " << to << " on socket (" << mRemoteAddr << "): " << strerror(errno); throw SocketException(ss.str(), VPR_LOCATION); } } if ( ECONNRESET == errno) { throw ConnectionResetException("Connection reset.", VPR_LOCATION); } else if (EHOSTUNREACH == errno) { throw NoRouteToHostException("No route to host.", VPR_LOCATION); } else if (EHOSTDOWN == errno) { throw UnknownHostException("Unknown host.", VPR_LOCATION); } else if (ENETDOWN == errno) { throw IOException("Network is down.", VPR_LOCATION); } else { bytes_sent = bytes; } return bytes_sent; }
//============================================================================== // PlainDatagramSocketImpl::send // //============================================================================== void PlainDatagramSocketImpl::send(const DatagramPacket& p) { testSocketIsValid(); int flags = 0; struct sockaddr* to=0; struct sockaddr_in sa; if(isConnected()) { if(p.getAddress() && !(m_rpRemoteAddr->equals(*(p.getAddress())))) { throw IllegalArgumentException(QC_T("Address in datagram packet does not match connected address")); } if(p.getPort()!= -1 && p.getPort()!=m_remotePort) { throw IllegalArgumentException(QC_T("Port in datagram packet does not match connected port")); } } else { // // If the socket is not connected, then the passed datagram packet must contain // valid information. // if(!p.getAddress() || p.getPort()==-1) { throw IllegalArgumentException(QC_T("datagram packet does not contain required address/port information")); } // // Use the InetAddress and port contained in the packet to // create and initialize a sockaddr_in structure. // ::memset(&sa, 0, sizeof(sa)); sa.sin_family = AF_INET; sa.sin_port = htons(p.getPort()); // convert port to network byte order ::memcpy(&sa.sin_addr, p.getAddress()->getAddress(), p.getAddress()->getAddressLength()); to = reinterpret_cast<struct sockaddr*>(&sa); } if(Tracer::IsEnabled()) { Tracer::TraceBytes(Tracer::Net, Tracer::Low, QC_T("Datagram send:"), p.getData(), p.getLength()); } int rc = ::sendto(m_rpSocketDescriptor->getFD(), (const char*) p.getData(), p.getLength(), flags, to, to ? sizeof(struct sockaddr_in) : 0); if(rc<0) { static const String err(QC_T("error calling sendto ")); String errMsg = err + NetUtils::GetSocketErrorString(); throw SocketException(errMsg); } // // When an unbound datagram socket is used to send data, the system will allocate // it an address and ephemeral port. Let's see what weve been given! // if(!isBound()) { } }
void SocketIO::Process() { SET_SEGV_LOCATION(); timeval timeout; timeout.tv_sec = Config->SockWait; timeout.tv_usec = 0; //this timeout keeps the bot from being a CPU hog for no reason :) fd_set read = ReadFD, write = WriteFD, except = ExceptFD; FD_ZERO(&read); FD_SET(this->GetFD(), &read); int sres = select(this->GetFD() + 1, &read, &write, &except, &timeout); if(sres == -1 && errno != EINTR) { Log(LOG_DEBUG) << "Select() error: " << strerror(errno); return; } if(throwex) //throw a socket exception if we want to. mainly used for ping timeouts. throw SocketException(throwmsg); bool has_read = FD_ISSET(this->GetFD(), &read); bool has_write = FD_ISSET(this->GetFD(), &write); bool has_error = FD_ISSET(this->GetFD(), &except); if(has_error) { int optval = 0; socklen_t optlen = sizeof(optval); getsockopt(this->GetFD(), SOL_SOCKET, SO_ERROR, reinterpret_cast<char *>(&optval), &optlen); errno = optval; FOREACH_MOD(I_OnSocketError, OnSocketError(optval ? strerror(errno) : "Unknown socket error")); throw SocketException("Socket error"); } if(has_read) { char tbuf[BUFSIZE + 1] = "\0"; size_t i = recv(this->GetFD(), tbuf, BUFSIZE, 0); if(i <= 0) throw SocketException(printfify("Socket Error: %s", strerror(errno))); sepstream sep(tbuf, '\n'); Flux::string buf; while(sep.GetToken(buf)) { this->LastBuf.clear(); this->LastBuf = buf; if(!this->Read(buf)) throw SocketException("Error reading socket"); } FD_CLR(this->GetFD(), &ReadFD); } if(has_write) { Flux::string buf; while(!this->WriteBuffer.empty()) { buf = this->WriteBuffer.front(); this->WriteBuffer.pop(); int i = ::send(this->GetFD(), buf.c_str(), buf.size(), MSG_NOSIGNAL); if(i <= -1 && !quitting) throw SocketException(printfify("Error writing \"%s\" to socket: %s", buf.c_str(), strerror(errno))); Log(LOG_RAWIO) << "Sent: " << buf << " | " << buf.size() << " bytes"; this->LastBuf.clear(); this->LastBuf = buf; buf.clear(); } FD_CLR(this->GetFD(), &WriteFD); } }
//============================================================================== // PlainDatagramSocketImpl::receive // //============================================================================== void PlainDatagramSocketImpl::receive(DatagramPacket& p) { testSocketIsValid(); sockaddr_in remoteAddr; cel_socklen_t addrLen; sockaddr* pRemoteAddr = reinterpret_cast<struct sockaddr*>(&remoteAddr); int recvLength; // // The following code is placed within a while() block to attempt to unify // the behaviour on multiple platforms. If this datagram socket has been // used to send a dataram packet, an ICMP response may be received to // indicate that the send request was unsuccessful. This behaviour is not // always helpful and is not guaranteed to occur (but seems to on Windows). // There is a far greater liklihood of this behaviour occurring on all platforms // when the socket has been connected to a particular host. For this reason, // connect errors are ignored unless the socket has been connected. // while(true) { // simulate SO_TIMEOUT if(m_nTimeoutMS && !NetUtils::SelectSocket(m_rpSocketDescriptor.get(), m_nTimeoutMS,true,false)) { static const String err(QC_T("receive timed out")); throw SocketTimeoutException(err); } int flags = 0; addrLen = sizeof(remoteAddr); recvLength = recvfrom(m_rpSocketDescriptor->getFD(), (char*) p.getData(), p.getLength(), flags, pRemoteAddr, &addrLen); if(recvLength < 0) { const int errorNum = NetUtils::GetLastSocketError(); // Failure of recvfrom may be cause by the buffer length being smaller // than the message (in which case we silently ignore it, and set the // received length equal to the buffer length supplied), or due to // some other serious problem which will result in a SocketException // if(errorNum == QC_EMSGSIZE) { recvLength = p.getLength(); break; } else if(!isConnected() && (errorNum == QC_ECONNRESET || errorNum == QC_ECONNABORTED || errorNum == QC_EHOSTUNREACH)) { // See detailed comment above continue; } else { static const String err(QC_T("error calling recvfrom ")); String errMsg = err + NetUtils::GetSocketErrorString(errorNum); throw SocketException(errMsg); } } else { break; } } // // Note: this test should migrate to the InetAddress class // if(addrLen != sizeof(sockaddr_in)) { static const String err(QC_T("recvfrom() returned invalid address size")); throw SocketException(err); } // // Update the DatagramPacket with the address/length info // p.setPort(ntohs(remoteAddr.sin_port)); p.setAddress(InetAddress::FromNetworkAddress(pRemoteAddr, addrLen).get()); p.setLength(recvLength); if(Tracer::IsEnabled()) { Tracer::TraceBytes(Tracer::Net, Tracer::Low, QC_T("Datagram rcvd:"), p.getData(), recvLength); } }
void Socket::handleSendError(int ret, const char* context) { #if defined(_WIN32) const int mongo_errno = WSAGetLastError(); if ( mongo_errno == WSAETIMEDOUT && _timeout != 0 ) { #else const int mongo_errno = errno; if ( ( mongo_errno == EAGAIN || mongo_errno == EWOULDBLOCK ) && _timeout != 0 ) { #endif LOG(_logLevel) << "Socket " << context << " send() timed out " << remoteString() << endl; throw SocketException(SocketException::SEND_TIMEOUT , remoteString()); } else { LOG(_logLevel) << "Socket " << context << " send() " << errnoWithDescription(mongo_errno) << ' ' << remoteString() << endl; throw SocketException(SocketException::SEND_ERROR , remoteString()); } } void Socket::handleRecvError(int ret, int len) { if (ret == 0) { LOG(3) << "Socket recv() conn closed? " << remoteString() << endl; throw SocketException(SocketException::CLOSED , remoteString()); } // ret < 0 #if defined(_WIN32) int e = WSAGetLastError(); #else int e = errno; # if defined(EINTR) if (e == EINTR) { LOG(_logLevel) << "EINTR returned from recv(), retrying"; return; } # endif #endif #if defined(_WIN32) // Windows if ((e == EAGAIN || e == WSAETIMEDOUT) && _timeout > 0) { #else if (e == EAGAIN && _timeout > 0) { #endif // this is a timeout LOG(_logLevel) << "Socket recv() timeout " << remoteString() <<endl; throw SocketException(SocketException::RECV_TIMEOUT, remoteString()); } LOG(_logLevel) << "Socket recv() " << errnoWithDescription(e) << " " << remoteString() <<endl; throw SocketException(SocketException::RECV_ERROR , remoteString()); } void Socket::setTimeout( double secs ) { setSockTimeouts( _fd, secs ); } // TODO: allow modification? // // <positive value> : secs to wait between stillConnected checks // 0 : always check // -1 : never check const int Socket::errorPollIntervalSecs( 5 ); // Patch to allow better tolerance of flaky network connections that get broken // while we aren't looking. // TODO: Remove when better async changes come. // // isStillConnected() polls the socket at max every Socket::errorPollIntervalSecs to determine // if any disconnection-type events have happened on the socket. bool Socket::isStillConnected() { if (MONGO_FAIL_POINT(notStillConnected)) { return false; } if (_fd == -1) { // According to the man page, poll will respond with POLLVNAL for invalid or // unopened descriptors, but it doesn't seem to be properly implemented in // some platforms - it can return 0 events and 0 for revent. Hence this workaround. return false; } if ( errorPollIntervalSecs < 0 ) return true; if ( ! isPollSupported() ) return true; // nothing we can do time_t now = time( 0 ); time_t idleTimeSecs = now - _lastValidityCheckAtSecs; // Only check once every 5 secs if ( idleTimeSecs < errorPollIntervalSecs ) return true; // Reset our timer, we're checking the connection _lastValidityCheckAtSecs = now; // It's been long enough, poll to see if our socket is still connected pollfd pollInfo; pollInfo.fd = _fd; // We only care about reading the EOF message on clean close (and errors) pollInfo.events = POLLIN; // Poll( info[], size, timeout ) - timeout == 0 => nonblocking int nEvents = socketPoll( &pollInfo, 1, 0 ); LOG( 2 ) << "polling for status of connection to " << remoteString() << ", " << ( nEvents == 0 ? "no events" : nEvents == -1 ? "error detected" : "event detected" ) << endl; if ( nEvents == 0 ) { // No events incoming, return still connected AFAWK return true; } else if ( nEvents < 0 ) { // Poll itself failed, this is weird, warn and log errno warning() << "Socket poll() failed during connectivity check" << " (idle " << idleTimeSecs << " secs," << " remote host " << remoteString() << ")" << causedBy(errnoWithDescription()) << endl; // Return true since it's not clear that we're disconnected. return true; } dassert( nEvents == 1 ); dassert( pollInfo.revents > 0 ); // Return false at this point, some event happened on the socket, but log what the // actual event was. if ( pollInfo.revents & POLLIN ) { // There shouldn't really be any data to recv here, so make sure this // is a clean hangup. const int testBufLength = 1024; char testBuf[testBufLength]; int recvd = ::recv( _fd, testBuf, testBufLength, portRecvFlags ); if ( recvd < 0 ) { // An error occurred during recv, warn and log errno warning() << "Socket recv() failed during connectivity check" << " (idle " << idleTimeSecs << " secs," << " remote host " << remoteString() << ")" << causedBy(errnoWithDescription()) << endl; } else if ( recvd > 0 ) { // We got nonzero data from this socket, very weird? // Log and warn at runtime, log and abort at devtime // TODO: Dump the data to the log somehow? error() << "Socket found pending " << recvd << " bytes of data during connectivity check" << " (idle " << idleTimeSecs << " secs," << " remote host " << remoteString() << ")" << endl; dassert( false ); } else { // recvd == 0, socket closed remotely, just return false LOG( 0 ) << "Socket closed remotely, no longer connected" << " (idle " << idleTimeSecs << " secs," << " remote host " << remoteString() << ")" << endl; } } else if ( pollInfo.revents & POLLHUP ) { // A hangup has occurred on this socket LOG( 0 ) << "Socket hangup detected, no longer connected" << " (idle " << idleTimeSecs << " secs," << " remote host " << remoteString() << ")" << endl; } else if ( pollInfo.revents & POLLERR ) { // An error has occurred on this socket LOG( 0 ) << "Socket error detected, no longer connected" << " (idle " << idleTimeSecs << " secs," << " remote host " << remoteString() << ")" << endl; } else if ( pollInfo.revents & POLLNVAL ) { // Socket descriptor itself is weird // Log and warn at runtime, log and abort at devtime error() << "Socket descriptor detected as invalid" << " (idle " << idleTimeSecs << " secs," << " remote host " << remoteString() << ")" << endl; dassert( false ); } else { // Don't know what poll is saying here // Log and warn at runtime, log and abort at devtime error() << "Socket had unknown event (" << static_cast<int>(pollInfo.revents) << ")" << " (idle " << idleTimeSecs << " secs," << " remote host " << remoteString() << ")" << endl; dassert( false ); } return false; } #if defined(_WIN32) MONGO_INITIALIZER(SockWSAStartup)(InitializerContext * context) { WSADATA d; if ( WSAStartup(MAKEWORD(2,2), &d) != 0 ) { log() << "ERROR: wsastartup failed " << errnoWithDescription() << endl; abort(); } return Status::OK(); }
SocketIPv4 *SocketIPv4::accept() { SOCKET result; struct sockaddr_in addr; socklen_t addrlen = sizeof(struct sockaddr_in); SocketIPv4 *accepted; fd_set afd; timeval timeout; timeout.tv_sec = 0; timeout.tv_usec = 200; while (true) { FD_ZERO(&afd); FD_SET(m_socket, &afd); int ret = select(m_socket + 1, &afd, NULL, NULL, &timeout); if (ret == SOCKET_ERROR) { throw SocketException(); } else if (ret == 0) { continue; } else if (ret > 0) { if (FD_ISSET(m_socket, &afd)) { result = ::accept(m_socket, (struct sockaddr*)&addr, &addrlen); if (result == INVALID_SOCKET) { throw SocketException(); } break; } } } try { accepted = new SocketIPv4(); accepted->close(); } catch(...) { #ifdef _WIN32 ::closesocket(result); #else ::close(result); #endif throw SocketException(); } AutoLock l(&accepted->m_mutex); accepted->m_socket = result; accepted->m_peerAddr = new SocketAddressIPv4(*(struct sockaddr_in *)&addr); AutoLock l2(&m_mutex); if (m_localAddr) { sockaddr_in tsa = m_localAddr->getSockAddr(); accepted->m_localAddr = new SocketAddressIPv4(*(struct sockaddr_in*)&tsa); } return accepted; }
void Socket::Listen(int maxQueueLen) { if (::listen(SockHandle, maxQueueLen) == -1) throw SocketException("Error listen socket"); }
void ServerSocket::bind(uint16_t port, int32_t backlog, const sp<InetAddress>& localAddress) { if (mIsBound) { throw SocketException("Socket is already bound"); } if (mIsClosed) { throw SocketException("Socket is already closed"); } if (localAddress == nullptr) { mLocalAddress = Inet6Address::ANY; } else { mLocalAddress = localAddress; } sockaddr_storage ss; socklen_t saSize = 0; std::memset(&ss, 0, sizeof(ss)); if (Class<Inet6Address>::isInstance(mLocalAddress)) { mFd = ::socket(AF_INET6, SOCK_STREAM, 0); int32_t value = 0; ::setsockopt(mFd, SOL_SOCKET, IPV6_V6ONLY, &value, sizeof(value)); value = mReuseAddress; ::setsockopt(mFd, SOL_SOCKET, SO_REUSEADDR, (char*) &value, sizeof(value)); sockaddr_in6& sin6 = reinterpret_cast<sockaddr_in6&>(ss); sin6.sin6_family = AF_INET6; std::memcpy(&sin6.sin6_addr.s6_addr, mLocalAddress->getAddress()->c_arr(), 16); sin6.sin6_port = htons(port); saSize = sizeof(sockaddr_in6); } else { mFd = ::socket(AF_INET, SOCK_STREAM, 0); int32_t value = mReuseAddress; ::setsockopt(mFd, SOL_SOCKET, SO_REUSEADDR, (char*) &value, sizeof(value)); sockaddr_in& sin = reinterpret_cast<sockaddr_in&>(ss); sin.sin_family = AF_INET; std::memcpy(&sin.sin_addr.s_addr, mLocalAddress->getAddress()->c_arr(), 4); sin.sin_port = htons(port); saSize = sizeof(sockaddr_in); } if (::bind(mFd, (struct sockaddr*) &ss, saSize) != 0) { close(); } if (mFd != -1 && ::listen(mFd, backlog) == 0) { if (port != 0) { mLocalPort = port; } else { sockaddr_storage ss; sockaddr* sa = reinterpret_cast<sockaddr*>(&ss); socklen_t saSize = sizeof(ss); std::memset(&ss, 0, saSize); int32_t rc = ::getsockname(mFd, sa, &saSize); if (rc == 0) { switch (ss.ss_family) { case AF_INET6: { const sockaddr_in6& sin6 = *reinterpret_cast<const sockaddr_in6*>(&ss); mLocalPort = sin6.sin6_port; break; } case AF_INET: { const sockaddr_in& sin = *reinterpret_cast<const sockaddr_in*>(&ss); mLocalPort = sin.sin_port; break; } default: break; } } } mIsBound = true; } else { close(); throw SocketException(String::format("Failed to bind to port %u (errno=%d)", port, errno)); } }