diff options
author | Adam <Adam@anope.org> | 2010-10-01 21:01:49 -0400 |
---|---|---|
committer | Adam <Adam@anope.org> | 2010-10-01 21:01:49 -0400 |
commit | d44f7971b129aa7ba80999f16f17b8c7499686e1 (patch) | |
tree | a86d08c3e641ed6b499b53b3bbb74e2a7f5b0dfb /src/sockets.cpp | |
parent | 70056dd4689eeab4f7a9b31a921e0d7e40d5ed0d (diff) |
Rewrote some of the socket code to allow m_ssl to be a service.
This allows modules (xmlrpc) to create and accept SSL connections.
Also fixed unloading m_mysql at certain times and made the threading
engine always work correctly on Windows.
Diffstat (limited to 'src/sockets.cpp')
-rw-r--r-- | src/sockets.cpp | 324 |
1 files changed, 212 insertions, 112 deletions
diff --git a/src/sockets.cpp b/src/sockets.cpp index fe712357a..f22238fcc 100644 --- a/src/sockets.cpp +++ b/src/sockets.cpp @@ -4,6 +4,8 @@ SocketEngineBase *SocketEngine = NULL; int32 TotalRead = 0; int32 TotalWritten = 0; +SocketIO normalSocketIO; + /** Trims all the \r and \ns from the begining and end of a string * @param buffer The buffer to trim */ @@ -15,6 +17,20 @@ static void TrimBuf(std::string &buffer) buffer.erase(buffer.length() - 1); } +/** Construct the object, sets everything to 0 + */ +sockaddrs::sockaddrs() +{ + this->clear(); +} + +/** Memset the object to 0 + */ +void sockaddrs::clear() +{ + memset(this, 0, sizeof(*this)); +} + /** Get the size of the sockaddr we represent * @return The size */ @@ -75,13 +91,6 @@ Anope::string sockaddrs::addr() const return address; } -/** Construct the object, sets everything to 0 - */ -sockaddrs::sockaddrs() -{ - memset(this, 0, sizeof(*this)); -} - /** Check if this sockaddr has data in it */ bool sockaddrs::operator()() const @@ -184,25 +193,96 @@ SocketEngineBase::~SocketEngineBase() #endif } +/** Receive something from the buffer + * @param s The socket + * @param buf The buf to read to + * @param sz How much to read + * @return Number of bytes received + */ +int SocketIO::Recv(Socket *s, char *buf, size_t sz) const +{ + size_t i = recv(s->GetFD(), buf, sz, 0); + TotalRead += i; + return i; +} + +/** Write something to the socket + * @param s The socket + * @param buf What to write + * @return Number of bytes written + */ +int SocketIO::Send(Socket *s, const Anope::string &buf) const +{ + size_t i = send(s->GetFD(), buf.c_str(), buf.length(), 0); + TotalWritten += i; + return i; +} + +/** Accept a connection from a socket + * @param s The socket + */ +void SocketIO::Accept(ListenSocket *s) +{ + sockaddrs conaddr; + + socklen_t size = conaddr.size(); + int newsock = accept(s->GetFD(), &conaddr.sa, &size); + +#ifndef INVALID_SOCKET +# define INVALID_SOCKET 0 +#endif + + if (newsock > 0 && newsock != INVALID_SOCKET) + s->OnAccept(newsock, conaddr); + else + throw SocketException("Unable to accept connection: " + Anope::LastError()); +} + +/** Connect the socket + * @param s THe socket + * @param target IP to connect to + * @param port to connect to + * @param bindip IP to bind to, if any + */ +void SocketIO::Connect(ConnectionSocket *s, const Anope::string &target, int port, const Anope::string &bindip) +{ + s->bindaddr.clear(); + s->conaddr.clear(); + + if (!bindip.empty()) + { + s->bindaddr.pton(s->IsIPv6() ? AF_INET6 : AF_INET, bindip, 0); + if (bind(s->GetFD(), &s->bindaddr.sa, s->bindaddr.size()) == -1) + throw SocketException(Anope::string("Unable to bind to address: ") + Anope::LastError()); + } + + s->conaddr.pton(s->IsIPv6() ? AF_INET6 : AF_INET, target, port); + if (connect(s->GetFD(), &s->conaddr.sa, s->conaddr.size()) == -1 && errno != EINPROGRESS) + throw SocketException(Anope::string("Error connecting to server: ") + Anope::LastError()); +} + /** Empty constructor, used for things such as the pipe socket */ Socket::Socket() { + this->Type = SOCKTYPE_BASE; + this->IO = &normalSocketIO; } /** Constructor - * @param nsock The socket - * @param nIPv6 IPv6? + * @param sock The socket + * @param ipv6 IPv6? * @param type The socket type, defaults to SOCK_STREAM */ -Socket::Socket(int nsock, bool nIPv6, int type) +Socket::Socket(int sock, bool ipv6, int type) { - Type = SOCKTYPE_CLIENT; - IPv6 = nIPv6; - if (nsock == 0) - Sock = socket(IPv6 ? AF_INET6 : AF_INET, type, 0); + this->Type = SOCKTYPE_BASE; + this->IO = &normalSocketIO; + this->IPv6 = ipv6; + if (sock == 0) + this->Sock = socket(this->IPv6 ? AF_INET6 : AF_INET, type, 0); else - Sock = nsock; + this->Sock = sock; SocketEngine->AddSocket(this); } @@ -212,34 +292,24 @@ Socket::~Socket() { if (SocketEngine) SocketEngine->DelSocket(this); - CloseSocket(Sock); -} - -/** Really receive something from the buffer - * @param buf The buf to read to - * @param sz How much to read - * @return Number of bytes received - */ -int Socket::RecvInternal(char *buf, size_t sz) const -{ - return recv(GetSock(), buf, sz, 0); + CloseSocket(this->Sock); + this->IO->Destroy(); } -/** Really write something to the socket - * @param buf What to write - * @return Number of bytes written +/** Get the socket FD for this socket + * @return the fd */ -int Socket::SendInternal(const Anope::string &buf) const +int Socket::GetFD() const { - return send(GetSock(), buf.c_str(), buf.length(), 0); + return Sock; } -/** Get the socket FD for this socket - * @return the fd +/** Check if this socket is IPv6 + * @return true or false */ -int Socket::GetSock() const +bool Socket::IsIPv6() const { - return Sock; + return IPv6; } /** Mark a socket as blockig @@ -249,10 +319,10 @@ bool Socket::SetBlocking() { #ifdef _WIN32 unsigned long opt = 0; - return !ioctlsocket(this->GetSock(), FIONBIO, &opt); + return !ioctlsocket(this->GetFD(), FIONBIO, &opt); #else - int flags = fcntl(this->GetSock(), F_GETFL, 0); - return !fcntl(this->GetSock(), F_SETFL, flags & ~O_NONBLOCK); + int flags = fcntl(this->GetFD(), F_GETFL, 0); + return !fcntl(this->GetFD(), F_SETFL, flags & ~O_NONBLOCK); #endif } @@ -263,45 +333,67 @@ bool Socket::SetNonBlocking() { #ifdef _WIN32 unsigned long opt = 1; - return !ioctlsocket(this->GetSock(), FIONBIO, &opt); + return !ioctlsocket(this->GetFD(), FIONBIO, &opt); #else - int flags = fcntl(this->GetSock(), F_GETFL, 0); - return !fcntl(this->GetSock(), F_SETFL, flags | O_NONBLOCK); + int flags = fcntl(this->GetFD(), F_GETFL, 0); + return !fcntl(this->GetFD(), F_SETFL, flags | O_NONBLOCK); #endif } -/** Check if this socket is IPv6 - * @return true or false +/** Called when there is something to be received for this socket + * @return true on success, false to drop this socket */ -bool Socket::IsIPv6() const +bool Socket::ProcessRead() { - return IPv6; + return true; } -/** Get the length of the read buffer - * @return The length of the read buffer +/** Called when the socket is ready to be written to + * @return true on success, false to drop this socket */ -size_t Socket::ReadBufferLen() const +bool Socket::ProcessWrite() { - return RecvLen; + return true; } -/** Get the length of the write buffer - * @return The length of the write buffer +/** Called when there is an error for this socket + * @return true on success, false to drop this socket */ -size_t Socket::WriteBufferLen() const +void Socket::ProcessError() +{ +} + +/** Constructor for pipe socket + */ +BufferedSocket::BufferedSocket() : Socket() +{ + this->Type = SOCKTYPE_BUFFERED; +} + +/** Constructor + * @param fd FD to use + * @param ipv6 true for ipv6 + * @param type socket type, defaults to SOCK_STREAM + */ +BufferedSocket::BufferedSocket(int fd, bool ipv6, int type) : Socket(fd, ipv6, type) +{ + this->Type = SOCKTYPE_BUFFERED; +} + +/** Default destructor + */ +BufferedSocket::~BufferedSocket() { - return WriteBuffer.length(); } /** Called when there is something to be received for this socket * @return true on success, false to drop this socket */ -bool Socket::ProcessRead() +bool BufferedSocket::ProcessRead() { char tbuffer[NET_BUFSIZE] = ""; - RecvLen = RecvInternal(tbuffer, sizeof(tbuffer) - 1); + RecvLen = this->IO->Recv(this, tbuffer, sizeof(tbuffer) - 1); if (RecvLen <= 0) return false; @@ -341,13 +433,13 @@ bool Socket::ProcessRead() /** Called when the socket is ready to be written to * @return true on success, false to drop this socket */ -bool Socket::ProcessWrite() +bool BufferedSocket::ProcessWrite() { if (WriteBuffer.empty()) { return true; } - if (SendInternal(WriteBuffer) == -1) + if (this->IO->Send(this, WriteBuffer) == -1) { return false; } @@ -357,18 +449,11 @@ bool Socket::ProcessWrite() return true; } -/** Called when there is an error for this socket - * @return true on success, false to drop this socket - */ -void Socket::ProcessError() -{ -} - /** Called with a line received from the socket * @param buf The line * @return true to continue reading, false to drop the socket */ -bool Socket::Read(const Anope::string &buf) +bool BufferedSocket::Read(const Anope::string &buf) { return false; } @@ -376,7 +461,7 @@ bool Socket::Read(const Anope::string &buf) /** Write to the socket * @param message The message */ -void Socket::Write(const char *message, ...) +void BufferedSocket::Write(const char *message, ...) { va_list vi; char tbuffer[BUFSIZE]; @@ -395,58 +480,36 @@ void Socket::Write(const char *message, ...) /** Write to the socket * @param message The message */ -void Socket::Write(const Anope::string &message) +void BufferedSocket::Write(const Anope::string &message) { WriteBuffer.append(message.str() + "\r\n"); SocketEngine->MarkWritable(this); } -/** Constructor - * @param TargetHost The target host to connect to - * @param Port The target port to connect to - * @param BindHost The host to bind to for connecting - * @param nIPv6 true to use IPv6 - * @param type The socket type, defaults to SOCK_STREAM - */ -ClientSocket::ClientSocket(const Anope::string &TargetHost, int Port, const Anope::string &BindHost, bool nIPv6, int type) : Socket(0, nIPv6, type) -{ - this->SetNonBlocking(); - - if (!BindHost.empty()) - { - this->bindaddrs.pton(IPv6 ? AF_INET6 : AF_INET, BindHost, 0); - if (bind(Sock, &this->bindaddrs.sa, this->bindaddrs.size()) == -1) - throw SocketException(Anope::string("Unable to bind to address: ") + Anope::LastError()); - } - - this->conaddrs.pton(IPv6 ? AF_INET6 : AF_INET, TargetHost, Port); - if (connect(Sock, &this->conaddrs.sa, this->conaddrs.size()) == -1 && errno != EINPROGRESS) - throw SocketException(Anope::string("Error connecting to server: ") + Anope::LastError()); -} - -/** Default destructor +/** Get the length of the read buffer + * @return The length of the read buffer */ -ClientSocket::~ClientSocket() +size_t BufferedSocket::ReadBufferLen() const { + return RecvLen; } -/** Called with a line received from the socket - * @param buf The line - * @return true to continue reading, false to drop the socket +/** Get the length of the write buffer + * @return The length of the write buffer */ -bool ClientSocket::Read(const Anope::string &buf) +size_t BufferedSocket::WriteBufferLen() const { - return true; + return WriteBuffer.length(); } /** Constructor * @param bindip The IP to bind to * @param port The port to listen on + * @param ipv6 true for ipv6 */ -ListenSocket::ListenSocket(const Anope::string &bindip, int port) : Socket(0, (bindip.find(':') != Anope::string::npos ? true : false)) +ListenSocket::ListenSocket(const Anope::string &bindip, int port, bool ipv6) : Socket(0, ipv6) { - Type = SOCKTYPE_LISTEN; - + this->Type = SOCKTYPE_LISTEN; this->SetNonBlocking(); this->listenaddrs.pton(IPv6 ? AF_INET6 : AF_INET, bindip, port); @@ -468,24 +531,61 @@ ListenSocket::~ListenSocket() */ bool ListenSocket::ProcessRead() { - int newsock = accept(Sock, NULL, NULL); + try + { + this->IO->Accept(this); + } + catch (const SocketException &ex) + { + Log() << ex.GetReason(); + } + return true; +} -#ifndef INVALID_SOCKET -# define INVALID_SOCKET 0 -#endif +/** Called when a connection is accepted + * @param fd The FD for the new connection + * @param addr The sockaddr for where the connection came from + * @return The new socket + */ +ClientSocket *ListenSocket::OnAccept(int fd, const sockaddrs &addr) +{ + return new ClientSocket(this, fd, addr); +} - if (newsock > 0 && newsock != INVALID_SOCKET) - return this->OnAccept(new Socket(newsock, IPv6)); +/** Constructor + * @param ipv6 true to use IPv6 + * @param type The socket type, defaults to SOCK_STREAM + */ +ConnectionSocket::ConnectionSocket(bool ipv6, int type) : BufferedSocket(0, ipv6, type) +{ + this->Type = SOCKTYPE_CONNECTION; +} - return true; +/** Connect the socket + * @param TargetHost The target host to connect to + * @param Port The target port to connect to + * @param BindHost The host to bind to for connecting + */ +void ConnectionSocket::Connect(const Anope::string &TargetHost, int Port, const Anope::string &BindHost) +{ + try + { + this->IO->Connect(this, TargetHost, Port, BindHost); + } + catch (const SocketException &) + { + delete this; + throw; + } } -/** Called when a connection is accepted - * @param s The socket for the new connection - * @return true if the listen socket should remain alive +/** Constructor + * @param ls Listen socket this connection is from + * @param fd New FD for this socket + * @param addr Address the connection came from */ -bool ListenSocket::OnAccept(Socket *s) +ClientSocket::ClientSocket(ListenSocket *ls, int fd, const sockaddrs &addr) : BufferedSocket(fd, ls->IsIPv6()), LS(ls), clientaddr(addr) { - return true; + this->Type = SOCKTYPE_CLIENT; } |