void Socket::SetNonBlocking(bool enabled) { if (_socket == NET_INVALID_SOCKET) /* throw invalid socket */ throw InvalidSocketException{ LOGIC_EXCEPT("Invalid socket") }; #if defined(OS_WINDOWS) u_long isEnabled = enabled ? 1 : 0; if (NET_SOCKET_ERROR == ioctlsocket(_socket, FIONBIO, &isEnabled)) OnSocketError(); #else auto rc = ::fcntl(_socket, F_GETFL); if (rc == -1) OnSocketError(); if (enabled) { rc |= O_NONBLOCK; } else { rc &= ~O_NONBLOCK; } (void)fcntl(F_SETFL, rc); #endif }
std::uint32_t UDPSocket::ReceiveFrom(SocketAddress& address, std::uint8_t* buffer, std::uint32_t length, std::uint32_t flags) { if (!_socket.IsValid()) throw InvalidSocketException{ LOGIC_EXCEPT("Invalid socket") }; auto rc = 0; /* raw address */ SocketAddress::RawAddresss rawAddr; net_socketlen_t len = sizeof(rawAddr); do { rc = ::recvfrom(_socket, reinterpret_cast<char*>(buffer), length, flags, reinterpret_cast<struct sockaddr *>(&rawAddr), &len); } while (rc < 0 && Socket::LastError() == NETERRNO(EINTR)); if (rc < 0) { OnSocketError(); rc = 0; } else { address = rawAddr; } return static_cast<std::uint32_t>(rc); }
void Socket::Shutdown() { if (_socket == NET_INVALID_SOCKET) return; auto rc = ::shutdown(_socket, 2); if (rc == NET_SOCKET_ERROR) OnSocketError(); }
void Socket::GetOption(std::int32_t level, std::int32_t option, std::int8_t * optval, std::int32_t *optlen) const { if (_socket == NET_INVALID_SOCKET) /* throw invalid socket */ throw InvalidSocketException{ LOGIC_EXCEPT("Invalid socket") }; auto rc = ::getsockopt(_socket, level, option, reinterpret_cast<char*>(optval), optlen); if (rc == NET_SOCKET_ERROR) OnSocketError(); }
/** * \fn bool SocketIO::Read(const Flux::string &buf) const * \brief Read from a socket for the IRC processor * \param buffer Raw socket buffer */ bool SocketIO::Read(const Flux::string &buf) const { if(buf.search_ci("ERROR :Closing link:")) { FOREACH_MOD(I_OnSocketError, OnSocketError(buf)); return false; } Log(LOG_RAWIO) << "Received: " << Flux::Sanitize(buf); process(buf); /* Process the buffer for navn */ return true; }
SocketAddress Socket::Address() const { if (_socket == NET_INVALID_SOCKET) /* throw invalid socket */ throw InvalidSocketException{ LOGIC_EXCEPT("Invalid socket") }; SocketAddress::RawAddresss rawAddr; net_socketlen_t len = sizeof(rawAddr); auto rc = ::getsockname(_socket, reinterpret_cast<struct sockaddr *>(&rawAddr), &len); if (rc == NET_SOCKET_ERROR) OnSocketError(); return rawAddr; }
void TCPSocket::Connect(const SocketAddress& address) { if (!_socket.IsValid()) /* throw invalid socket */ throw InvalidSocketException{ LOGIC_EXCEPT("Invalid socket") }; auto rc = 0; do { rc = ::connect(_socket, address.GetRawAddress(), address.RawLength()); } while (rc == NET_SOCKET_ERROR && Socket::LastError() == NETERRNO(EINTR)); if (rc == NET_SOCKET_ERROR) OnSocketError(); }
std::uint32_t Socket::Available() const { if (_socket == NET_INVALID_SOCKET) /* throw invalid socket */ throw InvalidSocketException{ LOGIC_EXCEPT("Invalid socket") }; #if defined(OS_WINDOWS) u_long avail = 0; auto rc = ioctlsocket(_socket, FIONREAD, reinterpret_cast<u_long*>(&avail)); #else std::int32_t avail = 0; auto rc = ::ioctl(_socket, FIONREAD, &avail); #endif if (rc == NET_SOCKET_ERROR) OnSocketError(); return static_cast<std::uint32_t>(avail); }
std::uint32_t TCPSocket::Receive(std::uint8_t* buffer, std::uint32_t length, std::uint32_t flags) { if (!_socket.IsValid()) throw InvalidSocketException{ LOGIC_EXCEPT("Invalid socket") }; auto rc = 0; do { rc = ::recv(_socket, reinterpret_cast<char *>(buffer), length, flags); } while (rc < 0 && Socket::LastError() == NETERRNO(EINTR)); if (rc < 0) { OnSocketError(); rc = 0; } return static_cast<std::uint32_t>(rc); }
std::uint32_t UDPSocket::SendTo(const SocketAddress& address, const std::uint8_t*buffer, std::uint32_t length, std::uint32_t flags) { if (!_socket.IsValid()) throw InvalidSocketException{ LOGIC_EXCEPT("Invalid socket") }; auto rc = 0; do { rc = ::sendto(_socket, reinterpret_cast<const char*>(buffer), length, flags, address.GetRawAddress(), address.RawLength()); } while (rc < 0 && Socket::LastError() == NETERRNO(EINTR)); if (rc < 0) { OnSocketError(); rc = 0; } return static_cast<std::uint32_t>(rc); }
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); } }