Error Handling
This commit is contained in:
@@ -11,8 +11,7 @@ namespace Socket {
|
||||
protected:
|
||||
const char * message;
|
||||
public:
|
||||
SocketException(const std::string& msg) : message(msg.c_str()) {}
|
||||
SocketException(std::string msg) : message(msg.c_str()) {}
|
||||
explicit SocketException(const std::string& msg) : message(msg.c_str()) {}
|
||||
SocketException(const char *msg) : message(msg) {}
|
||||
const char * what() const noexcept override {
|
||||
return message;
|
||||
@@ -27,16 +26,19 @@ namespace Socket {
|
||||
class SocketBindingException : public SocketException {
|
||||
public:
|
||||
SocketBindingException(char *msg) : SocketException{msg} {}
|
||||
SocketBindingException(const std::string& msg) : SocketException{msg.c_str()} {}
|
||||
};
|
||||
|
||||
class SocketConnectException : public SocketException {
|
||||
public:
|
||||
SocketConnectException(char *msg) : SocketException{msg} {}
|
||||
SocketConnectException(const std::string& msg) : SocketException{msg.c_str()} {}
|
||||
};
|
||||
|
||||
class SocketCreationException : public SocketException {
|
||||
public:
|
||||
SocketCreationException(char * msg) : SocketException{msg} {}
|
||||
SocketCreationException(const std::string& msg) : SocketException{msg.c_str()} {}
|
||||
};
|
||||
|
||||
class SocketListenException : public SocketException {
|
||||
@@ -47,20 +49,24 @@ namespace Socket {
|
||||
class SocketAcceptException : public SocketException {
|
||||
public:
|
||||
SocketAcceptException(char * msg) : SocketException{msg} {}
|
||||
};
|
||||
SocketAcceptException(const std::string& msg) : SocketException{msg.c_str()} {}
|
||||
};
|
||||
|
||||
class SocketSendException : public SocketException {
|
||||
public:
|
||||
SocketSendException(const std::string& msg) : SocketException{msg.c_str()} {}
|
||||
SocketSendException(char * msg) : SocketException{msg} {}
|
||||
};
|
||||
|
||||
class SocketReceiveException : public SocketException {
|
||||
public:
|
||||
SocketReceiveException(const std::string& msg) : SocketException{msg.c_str()} {}
|
||||
SocketReceiveException(char * msg) : SocketException{msg} {}
|
||||
};
|
||||
|
||||
class SocketCloseException : public SocketException {
|
||||
public:
|
||||
SocketCloseException(char * msg) : SocketException{msg} {}
|
||||
SocketCloseException(const std::string& msg) : SocketException{msg.c_str()} {}
|
||||
};
|
||||
}
|
||||
|
@@ -111,23 +111,23 @@ namespace Socket {
|
||||
throw error(strerror(errcode)); // No other error codes match, but something's still fucked up!
|
||||
}
|
||||
|
||||
void CheckErrors_getsockname(const std::string& errcode)
|
||||
void CheckErrors_getsockname(int errcode)
|
||||
{
|
||||
using error = SocketException;
|
||||
|
||||
if (errcode == "EBADF") throw error("The argument sockfd is not a valid file descriptor.");
|
||||
if (errcode == "EFAULT") throw error("The addr argument points to memory not in a valid part of the process address space.");
|
||||
if (errcode == "EINVAL") throw error("addrlen is invalid (e.g., is negative");
|
||||
if (errcode == "ENOBUFS") throw error("Insufficient resources were available in the system to perform the operation.");
|
||||
if (errcode == "ENOTSOCK")throw error("The file descriptor sockfd does not refer to a socket.");
|
||||
if (errcode == EBADF) throw error("The argument sockfd is not a valid file descriptor.");
|
||||
if (errcode == EFAULT) throw error("The addr argument points to memory not in a valid part of the process address space.");
|
||||
if (errcode == EINVAL) throw error("addrlen is invalid (e.g., is negative");
|
||||
if (errcode == ENOBUFS) throw error("Insufficient resources were available in the system to perform the operation.");
|
||||
if (errcode == ENOTSOCK)throw error("The file descriptor sockfd does not refer to a socket.");
|
||||
|
||||
throw error(errcode); // No other error codes match, but something's still fucked up!
|
||||
throw error(strerror(errcode)); // No other error codes match, but something's still fucked up!
|
||||
}
|
||||
|
||||
void CheckErrors_connect(const std::string& errcode)
|
||||
void CheckErrors_connect(int errcode)
|
||||
{
|
||||
using error = SocketConnectException;
|
||||
if (errcode == "EACCES") throw error(" For UNIX domain sockets, which are identified by pathname:\n"
|
||||
if (errcode == EACCES) throw error(" For UNIX domain sockets, which are identified by pathname:\n"
|
||||
"Write permission is denied on the socket file, or search\n"
|
||||
"permission is denied for one of the directories in the\n"
|
||||
"path prefix"
|
||||
@@ -136,100 +136,112 @@ namespace Socket {
|
||||
"an HTTP proxy can only connect to ports associated with\n"
|
||||
"HTTP servers, and the proxy tries to connect to a\n"
|
||||
"different port).");
|
||||
if (errcode == "EPERM") throw error("The user tried to connect to a broadcast address without\n"
|
||||
if (errcode == EPERM) throw error("The user tried to connect to a broadcast address without\n"
|
||||
" having the socket broadcast flag enabled or the connection\n"
|
||||
" request failed because of a local firewall rule.");
|
||||
if (errcode == "EADDRINUSE") throw error("Local address is already in use.");
|
||||
if (errcode == "EADDRNOTAVAIL") throw error("The socket referred to by sockfd\n"
|
||||
if (errcode == EADDRINUSE) throw error("Local address is already in use.");
|
||||
if (errcode == EADDRNOTAVAIL) throw error("The socket referred to by sockfd\n"
|
||||
" had not previously been bound to an address and, upon\n"
|
||||
" attempting to bind it to an ephemeral port, it was\n"
|
||||
" determined that all port numbers in the ephemeral port\n"
|
||||
" range are currently in use.");
|
||||
if (errcode == "EAFNOSUPPORT") throw error("The passed address didn't have the correct address family in its sa_family field.");
|
||||
if (errcode == "EAGAIN") throw error("For nonblocking UNIX domain sockets, the socket is nonblocking, and the connection cannot be completed immediately. For other socket families, there are insufficient entries in the routing cache.");
|
||||
if (errcode == "EALREADY") throw error("The socket is nonblocking and a previous connection attempt has not yet been completed.");
|
||||
if (errcode == "EBADF") throw error("sockfd is not a valid open file descriptor");
|
||||
if (errcode == "ECONNREFUSED") throw error("A connect() on a stream socket found no one listening on the remote address.");
|
||||
if (errcode == "EFAULT") throw error("The socket structure address is outside the user's address space.");
|
||||
if (errcode == "EINPROGRESS") throw error("The socket is nonblocking and the connection cannot be completed immediately.");
|
||||
if (errcode == "EINTR") throw error("The system call was interrupted by a signal call that was caught.");
|
||||
if (errcode == "EISCONN") throw error("The socket is already connected.");
|
||||
if (errcode == "ENOTSOCK") throw error("The file descriptor sockfd does not refer to a socket.");
|
||||
if (errcode == "EPROTOTYPE") throw error("The socket type does not support the requested communications protocol. This error can occur, for example, on an attempt to connect a UNIX domain datagram socket to a stream socket.");
|
||||
if (errcode == "ETIMEDOUT") throw error("Timeout while attempting connection. The server may be too busy to accept new connections. Note that for IP sockets the timeout may be very long when syncookies are enabled on this server.");
|
||||
if (errcode == EAFNOSUPPORT) throw error("The passed address didn't have the correct address family in its sa_family field.");
|
||||
if (errcode == EAGAIN) throw error("For nonblocking UNIX domain sockets, the socket is nonblocking, and the connection cannot be completed immediately. For other socket families, there are insufficient entries in the routing cache.");
|
||||
if (errcode == EALREADY) throw error("The socket is nonblocking and a previous connection attempt has not yet been completed.");
|
||||
if (errcode == EBADF) throw error("sockfd is not a valid open file descriptor");
|
||||
if (errcode == ECONNREFUSED) throw error("A connect() on a stream socket found no one listening on the remote address.");
|
||||
if (errcode == EFAULT) throw error("The socket structure address is outside the user's address space.");
|
||||
if (errcode == EINPROGRESS) throw error("The socket is nonblocking and the connection cannot be completed immediately.");
|
||||
if (errcode == EINTR) throw error("The system call was interrupted by a signal call that was caught.");
|
||||
if (errcode == EISCONN) throw error("The socket is already connected.");
|
||||
if (errcode == ENOTSOCK) throw error("The file descriptor sockfd does not refer to a socket.");
|
||||
if (errcode == EPROTOTYPE) throw error("The socket type does not support the requested communications protocol. This error can occur, for example, on an attempt to connect a UNIX domain datagram socket to a stream socket.");
|
||||
if (errcode == ETIMEDOUT) throw error("Timeout while attempting connection. The server may be too busy to accept new connections. Note that for IP sockets the timeout may be very long when syncookies are enabled on this server.");
|
||||
|
||||
throw error(errcode); // No other error codes match, but something's still fucked up!
|
||||
throw error(strerror(errcode)); // No other error codes match, but something's still fucked up!
|
||||
}
|
||||
|
||||
void CheckErrors_recvfrom(const std::string& errcode)
|
||||
void CheckErrors_recvfrom(int errcode)
|
||||
{
|
||||
using error = SocketReceiveException;
|
||||
|
||||
if (errcode == "EAGAIN" || errcode == "EWOULDBLOCK") throw error("The socket's file descriptor is marked O_NONBLOCK and no\n"
|
||||
if (errcode == EAGAIN || errcode == EWOULDBLOCK) throw error("The socket's file descriptor is marked O_NONBLOCK and no\n"
|
||||
" data is waiting to be received; or MSG_OOB is set and no\n"
|
||||
" out-of-band data is available and either the socket's file\n"
|
||||
" descriptor is marked O_NONBLOCK or the socket does not\n"
|
||||
" support blocking to await out-of-band data.");
|
||||
if (errcode == "EBADF") throw error("The socket argument is not a valid file descriptor.");
|
||||
if (errcode == "ECONNRESET") throw error("A connection was forcibly closed by a peer.");
|
||||
if (errcode == "EINTR") throw error("A signal interrupted recvfrom() before any data was available.");
|
||||
if (errcode == "EINVAL") throw error("The MSG_00B flag is set and no out-of-band data is available.");
|
||||
if (errcode == "ENOTCONN") throw error("A recieve is attempted on a connection-mode socket that is not connected.");
|
||||
if (errcode == "ENOTSOCK") throw error("The socket argument does not refer to a socket.");
|
||||
if (errcode == "EOPNOTSUPP") throw error("The specified flags are not supported for this socket type.");
|
||||
if (errcode == "ETIMEDOUT") throw error("The connection timed out during connection establishment, or due to a transmission timeout on active connection.");
|
||||
if (errcode == "EIO") throw error("An I/O error occurred while reading from or writing to the file system.");
|
||||
if (errcode == "ENOBUFS") throw error("Insufficient resources were available in the system to perform the operation.");
|
||||
if (errcode == "ENOMEM") throw error("Insufficient memory was available to fulfill the request.");
|
||||
if (errcode == EBADF) throw error("The socket argument is not a valid file descriptor.");
|
||||
if (errcode == ECONNRESET) throw error("A connection was forcibly closed by a peer.");
|
||||
if (errcode == EINTR) throw error("A signal interrupted recvfrom() before any data was available.");
|
||||
if (errcode == EINVAL) throw error("The MSG_00B flag is set and no out-of-band data is available.");
|
||||
if (errcode == ENOTCONN) throw error("A recieve is attempted on a connection-mode socket that is not connected.");
|
||||
if (errcode == ENOTSOCK) throw error("The socket argument does not refer to a socket.");
|
||||
if (errcode == EOPNOTSUPP) throw error("The specified flags are not supported for this socket type.");
|
||||
if (errcode == ETIMEDOUT) throw error("The connection timed out during connection establishment, or due to a transmission timeout on active connection.");
|
||||
if (errcode == EIO) throw error("An I/O error occurred while reading from or writing to the file system.");
|
||||
if (errcode == ENOBUFS) throw error("Insufficient resources were available in the system to perform the operation.");
|
||||
if (errcode == ENOMEM) throw error("Insufficient memory was available to fulfill the request.");
|
||||
|
||||
throw error(errcode); // No other error codes match, but something's still fucked up!
|
||||
throw error(strerror(errcode)); // No other error codes match, but something's still fucked up!
|
||||
}
|
||||
|
||||
void CheckErrors_send(const std::string& errcode)
|
||||
void CheckErrors_send(int errcode)
|
||||
{
|
||||
// Checks for and raises any errors that can occur when attempting to call ::send on a generic socket.
|
||||
using error = SocketSendException;
|
||||
|
||||
if (errcode == "EACCES") throw error("An attempt was made to send a network/broadcast address as though it were a unicast address.");
|
||||
if (errcode == "EALREADY") throw error("Another Fast Open is in progress.");
|
||||
if (errcode == "EBADF") throw error("sockfd is not a valid open file descriptor.");
|
||||
if (errcode == "ECONNRESET") throw error("Connection reset by peer.");
|
||||
if (errcode == "EDESTADDRREQ") throw error("The socket is not in connection-mode, and no peer address is set.");
|
||||
if (errcode == "EFAULT") throw error("An invalid user space address was specified for an argument.");
|
||||
if (errcode == "EINTR") throw error("A signal occured before any data was transmitted; see signal(7).");
|
||||
if (errcode == "EINVAL") throw error("Invalid argument passed.");
|
||||
if (errcode == "EISCONN") throw error("The connection-mode socket was connected already but a recipient was specified. (Now either this error is returned, or the recipient specification is ignored.");
|
||||
if (errcode == "EMSGSIZE") throw error("The socket type requires that message be sent atomically, and the size of the message to be sent made this impossible.");
|
||||
if (errcode == "ENOBUFS") throw error("The output queue for a network interface was full. This generally indicates that the interface has stopped sending, but may be caused by transient congestion. (Normally, this does not occur in Linux. Packets are just silently dropped when a device queue overflows.)");
|
||||
if (errcode == "ENOMEM") throw error("No memory available.");
|
||||
if (errcode == "ENOTCONN") throw error("The socket is not connected, and no target has been given.");
|
||||
if (errcode == "ENOTSOCK") throw error("The file descriptor sockfd does not refer to a socket.");
|
||||
if (errcode == "EOPNOTSUPP") throw error("Some bit in the flags argument is inappropriate for the socket type.");
|
||||
if (errcode == "EPIPE") throw error("The local end has been shut down on a connection oriented socket. In this case, the process will also receive a SIGPIPE unless MSG_NOSIGNAL is set.");
|
||||
if (errcode == "EAGAIN" ||
|
||||
errcode == "EWOULDBLOCK") throw error("The socket is marked nonblocking and the requested operation would block.");
|
||||
if (errcode == EACCES) throw error("An attempt was made to send a network/broadcast address as though it were a unicast address.");
|
||||
if (errcode == EALREADY) throw error("Another Fast Open is in progress.");
|
||||
if (errcode == EBADF) throw error("sockfd is not a valid open file descriptor.");
|
||||
if (errcode == ECONNRESET) throw error("Connection reset by peer.");
|
||||
if (errcode == EDESTADDRREQ) throw error("The socket is not in connection-mode, and no peer address is set.");
|
||||
if (errcode == EFAULT) throw error("An invalid user space address was specified for an argument.");
|
||||
if (errcode == EINTR) throw error("A signal occured before any data was transmitted; see signal(7).");
|
||||
if (errcode == EINVAL) throw error("Invalid argument passed.");
|
||||
if (errcode == EISCONN) throw error("The connection-mode socket was connected already but a recipient was specified. (Now either this error is returned, or the recipient specification is ignored.");
|
||||
if (errcode == EMSGSIZE) throw error("The socket type requires that message be sent atomically, and the size of the message to be sent made this impossible.");
|
||||
if (errcode == ENOBUFS) throw error("The output queue for a network interface was full. This generally indicates that the interface has stopped sending, but may be caused by transient congestion. (Normally, this does not occur in Linux. Packets are just silently dropped when a device queue overflows.)");
|
||||
if (errcode == ENOMEM) throw error("No memory available.");
|
||||
if (errcode == ENOTCONN) throw error("The socket is not connected, and no target has been given.");
|
||||
if (errcode == ENOTSOCK) throw error("The file descriptor sockfd does not refer to a socket.");
|
||||
if (errcode == EOPNOTSUPP) throw error("Some bit in the flags argument is inappropriate for the socket type.");
|
||||
if (errcode == EPIPE) throw error("The local end has been shut down on a connection oriented socket. In this case, the process will also receive a SIGPIPE unless MSG_NOSIGNAL is set.");
|
||||
if (errcode == EAGAIN ||
|
||||
errcode == EWOULDBLOCK) throw error("The socket is marked nonblocking and the requested operation would block.");
|
||||
|
||||
throw error(errcode); // No other error codes match, but something's still fucked up!
|
||||
throw error(strerror(errcode)); // No other error codes match, but something's still fucked up!
|
||||
}
|
||||
|
||||
void CheckErrors_setsockopt(const std::string& errcode)
|
||||
void CheckErrors_setsockopt(int errcode)
|
||||
{
|
||||
using error = SocketException;
|
||||
|
||||
if (errcode == "EBADF") throw error("The socket argument is not a valid file descriptor.");
|
||||
if (errcode == "EDOM") throw error("The send and receive timeout values are too big to fit into the timeout fields in the socket structure.");
|
||||
if (errcode == "EINVAL") throw error("The specified option is invalid at the specified socket level or the socket has been shut down.");
|
||||
if (errcode == "EISCONN") throw error("The socket is already connected, and a specified option cannot be set while the socket is connected.");
|
||||
if (errcode == "ENOPROTOOPT") throw error("The option is not supported by the protocol");
|
||||
if (errcode == "ENOTSOCK") throw error("The socket argument does not refer to a socket.");
|
||||
if (errcode == "ENOMEM") throw error("There was insufficient memory available for the operation to complete.");
|
||||
if (errcode == "ENOBUFS") throw error("Insufficient resources are available in the system to complete the call.");
|
||||
if (errcode == EBADF) throw error("The socket argument is not a valid file descriptor.");
|
||||
if (errcode == EDOM) throw error("The send and receive timeout values are too big to fit into the timeout fields in the socket structure.");
|
||||
if (errcode == EINVAL) throw error("The specified option is invalid at the specified socket level or the socket has been shut down.");
|
||||
if (errcode == EISCONN) throw error("The socket is already connected, and a specified option cannot be set while the socket is connected.");
|
||||
if (errcode == ENOPROTOOPT) throw error("The option is not supported by the protocol");
|
||||
if (errcode == ENOTSOCK) throw error("The socket argument does not refer to a socket.");
|
||||
if (errcode == ENOMEM) throw error("There was insufficient memory available for the operation to complete.");
|
||||
if (errcode == ENOBUFS) throw error("Insufficient resources are available in the system to complete the call.");
|
||||
|
||||
throw error(errcode); // No other error codes match, but something's still fucked up!
|
||||
throw error(strerror(errcode)); // No other error codes match, but something's still fucked up!
|
||||
}
|
||||
|
||||
void CheckErrors_getaddrinfo(const std::string& errcode)
|
||||
void CheckErrors_getaddrinfo(int errcode)
|
||||
{
|
||||
using error = SocketException;
|
||||
|
||||
if (errcode == EAI_ADDRFAMILY) throw error("The specified network host does not have any network addresses in the requested address family.");
|
||||
if (errcode == EAI_AGAIN) throw error("The name server returned a temporary failure indication. Try again later.");
|
||||
if (errcode == EAI_BADFLAGS) throw error("hints.ai_flags contains invalid flags; or hints.ai_flags included AI_CANONNAME and name was NULL.");
|
||||
if (errcode == EAI_FAIL) throw error("The name server returned a permanent failure indication.");
|
||||
if (errcode == EAI_FAMILY) throw error("The requested address family is not supported.");
|
||||
if (errcode == EAI_MEMORY) throw error("Out of memory.");
|
||||
if (errcode == EAI_NODATA) throw error("The specified network host exists ,but does not have any network addresses defined.");
|
||||
if (errcode == EAI_NONAME) throw error("The node or service is not known; or both node and service are NULL; or AI_NUMERICSERV was specified in hints.ai_flags and service was not a numeric port-number string.");
|
||||
if (errcode == EAI_SERVICE) throw error("The requested service is not available for the requested socket type. It may be available through another socket type. For example, this error could occur if service was 'shell'.");
|
||||
if (errcode == EAI_SOCKTYPE) throw error("The requested socket type is not supported. This could occur, for example, if hints.ai_socktype and hints.ai_protocol are inconsistent.");
|
||||
if (errcode == EAI_SYSTEM) throw error("Other system error; errno is set to indicate the error");
|
||||
}
|
||||
}
|
@@ -62,6 +62,8 @@ namespace Socket
|
||||
[[nodiscard]] IPAddress GetPeerIP() const {return peer_addr;}
|
||||
public:
|
||||
|
||||
/// TODO: Consider ditching templates here...
|
||||
|
||||
/// Sends a message to the bound peer only.
|
||||
template <typename T>
|
||||
int Send(const T& message) const;
|
||||
|
@@ -1,5 +1,6 @@
|
||||
#include <Sockets/Exceptions.hpp>
|
||||
#include <Sockets/TcpSocket.hpp>
|
||||
#include <Sockets/Sockets.hpp>
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netdb.h>
|
||||
@@ -39,8 +40,12 @@ namespace Socket {
|
||||
return; // Can't create socket now
|
||||
|
||||
|
||||
mSock = socket(mInfo->ai_family, mInfo->ai_socktype, 0);
|
||||
mSock = ::socket(mInfo->ai_family, mInfo->ai_socktype, 0);
|
||||
if (mSock == -1)
|
||||
{
|
||||
auto errcode = std::string(strerror(errno));
|
||||
|
||||
}
|
||||
throw SocketCreationException(strerror(errno));
|
||||
// Socket successfully "opened"
|
||||
mSockCreated = true;
|
||||
@@ -80,11 +85,11 @@ namespace Socket {
|
||||
}
|
||||
|
||||
// Socket successfully opened from here
|
||||
if (::bind(mSock, result->ai_addr, result->ai_addrlen) == 0)
|
||||
{
|
||||
mBound = true;
|
||||
return;
|
||||
}
|
||||
int ret = ::bind(mSock, result->ai_addr, result->ai_addrlen);
|
||||
if (ret < 0)
|
||||
CheckErrors_bind(errno);
|
||||
mBound = true;
|
||||
return;
|
||||
}
|
||||
// Couldn't bind, throw
|
||||
throw SocketBindingException("Can't bind to port");
|
||||
@@ -122,19 +127,21 @@ namespace Socket {
|
||||
}
|
||||
}
|
||||
// Socket successfully opened from here
|
||||
if (::connect(mSock, result->ai_addr, result->ai_addrlen) == 0)
|
||||
{
|
||||
mConnected = true;
|
||||
return;
|
||||
}
|
||||
int status = 0;
|
||||
|
||||
status = ::connect(mSock, result->ai_addr, result->ai_addrlen) == 0;
|
||||
if (status < 0)
|
||||
CheckErrors_connect(errno);
|
||||
mConnected = true;
|
||||
return;
|
||||
}
|
||||
throw SocketConnectException("Can't connect to host");
|
||||
}
|
||||
|
||||
void TcpSocket::Listen(int maxQueue)
|
||||
{
|
||||
if (::listen(mSock, maxQueue) != 0)
|
||||
throw SocketListenException(strerror(errno));
|
||||
CheckErrors_accept(errno);
|
||||
|
||||
DEBUG("Listening...");
|
||||
}
|
||||
|
||||
@@ -145,14 +152,13 @@ namespace Socket {
|
||||
const char * buff = data;
|
||||
int status = 0;
|
||||
int total_sent = 0;
|
||||
int left_to_send = length;
|
||||
unsigned int left_to_send = length;
|
||||
while(total_sent < length)
|
||||
{
|
||||
status = ::send(mSock, buff + total_sent, left_to_send, flags);
|
||||
if (status == -1)
|
||||
{
|
||||
throw SocketSendException(strerror(errno));
|
||||
} else {
|
||||
CheckErrors_send(errno);
|
||||
else {
|
||||
total_sent += status;
|
||||
left_to_send -= status;
|
||||
}
|
||||
@@ -161,10 +167,10 @@ namespace Socket {
|
||||
|
||||
bool TcpSocket::Receive(char* msg, int len, int flags)
|
||||
{
|
||||
int status;
|
||||
int status = 0;
|
||||
if ((status = ::recv(mSock, msg, len, flags)) == -1)
|
||||
throw SocketReceiveException(strerror(errno));
|
||||
else if (status == 0)
|
||||
CheckErrors_recv(errno);
|
||||
else if (status == 0)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
@@ -173,7 +179,7 @@ namespace Socket {
|
||||
void TcpSocket::Close()
|
||||
{
|
||||
if (::close(mSock) == -1)
|
||||
throw SocketCloseException(strerror(errno));
|
||||
CheckErrors_close(errno);
|
||||
else
|
||||
mClosed = true;
|
||||
}
|
||||
@@ -191,10 +197,13 @@ namespace Socket {
|
||||
charAddress = address.c_str();
|
||||
|
||||
addrinfo hints = *mInfo;
|
||||
int status;
|
||||
if ((status = getaddrinfo(charAddress, std::to_string(port).c_str(), &hints, &mInfo)) != 0)
|
||||
int status = getaddrinfo(charAddress, std::to_string(port).c_str(), &hints, &mInfo);
|
||||
if ((status) != 0)
|
||||
{
|
||||
delete charAddress;
|
||||
|
||||
CheckErrors_getaddrinfo(errno);
|
||||
|
||||
throw SocketException(
|
||||
("getaddrinfo returned non-zero: " + std::string(gai_strerror(status))).c_str()
|
||||
);
|
||||
@@ -204,11 +213,10 @@ namespace Socket {
|
||||
|
||||
void TcpSocket::openSocket(addrinfo * info)
|
||||
{
|
||||
mSock = socket(info->ai_family, info->ai_socktype, info->ai_protocol);
|
||||
mSock = ::socket(info->ai_family, info->ai_socktype, info->ai_protocol);
|
||||
if (mSock == -1)
|
||||
{
|
||||
SocketCreationException except(strerror(errno));
|
||||
throw except;
|
||||
CheckErrors_socket(errno);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -225,7 +233,7 @@ namespace Socket {
|
||||
if ((newSock = ::accept(mSock, (struct sockaddr *) 0, (unsigned int *) 0)) == -1) {
|
||||
//if ((newSock = ::accept(mSock, (sockaddr*)&address.s, &addressSize)) == -1) {
|
||||
DEBUG(strerror(errno));
|
||||
throw SocketAcceptException(strerror(errno));
|
||||
CheckErrors_accept(errno);
|
||||
}
|
||||
DEBUG("1 client accepted");
|
||||
|
||||
|
@@ -1,4 +1,5 @@
|
||||
#include "Sockets/UdpSocket.hpp"
|
||||
#include "Sockets/Sockets.hpp"
|
||||
|
||||
namespace Socket
|
||||
{
|
||||
@@ -15,9 +16,6 @@ namespace Socket
|
||||
|
||||
void UdpSocket::Open()
|
||||
{
|
||||
using error = SocketCreationException;
|
||||
|
||||
|
||||
this->Close();
|
||||
sock = (int)::socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
|
||||
if (sock < 0)
|
||||
@@ -26,25 +24,16 @@ namespace Socket
|
||||
|
||||
std::cout << "[Socket::UdpSocket::ERROR] " << errcode << std::endl;
|
||||
|
||||
if (errcode == "EACCES") throw error("Permission to create a socket of the specified type and/or protocol is denied.");
|
||||
if (errcode == "EAFNOSUPPORT") throw error("The implementation does not support the specified address family.");
|
||||
if (errcode == "EINVAL") throw error("Unknown protocol, or protocol family not available.");
|
||||
if (errcode == "EMFILE") throw error("The per-process limit on the number of open file descriptors has been reached.");
|
||||
if (errcode == "ENFILE") throw error("The system-wide limit on the total number of open files has been reached.");
|
||||
if (errcode == "EPROTONOSUPPORT") throw error("The protocol type or the specified protocol is not supported within this domain.");
|
||||
if (errcode == "ENOBUFS" || errcode == "ENOMEM") throw error("Insufficient memory is available. The socket cannot be created until sufficient resources are freed.");
|
||||
|
||||
throw error(strerror(errno));
|
||||
// This error list is not exhaustive, further errors may be generated by the underlying protocol modules.
|
||||
}
|
||||
if (this->IsClosed()) {
|
||||
throw error(strerror(errno));
|
||||
//throw error();
|
||||
}
|
||||
}
|
||||
|
||||
int UdpSocket::Close()
|
||||
{
|
||||
using error = SocketCloseException;
|
||||
|
||||
|
||||
if (!this->IsClosed()){
|
||||
#ifdef _WIN32
|
||||
@@ -53,32 +42,15 @@ namespace Socket
|
||||
int ret = ::shutdown(sock, SHUT_RDWR);
|
||||
#endif
|
||||
|
||||
if (ret < 0) {
|
||||
auto errcode = std::string(strerror(errno));
|
||||
|
||||
// TODO: implement SocketShutdownException
|
||||
if (errcode == "EBADF") throw error("sockfd is not a valid file descriptor.");
|
||||
if (errcode == "EINVAL") throw error("An invalid value was specified in how (see bugs in manpage!!!)");
|
||||
if (errcode == "ENOTCONN") throw error("The specified socket is not connected.");
|
||||
if (errcode == "ENOTSOCK") throw error("The file descriptor sockfd does not refer to a socket.");
|
||||
|
||||
throw error(strerror(errno));
|
||||
}
|
||||
if (ret < 0)
|
||||
CheckErrors_shutdown(errno);
|
||||
#ifdef _WIN32
|
||||
ret = ::closesocket(sock);
|
||||
#else
|
||||
ret = ::close(sock);
|
||||
#endif
|
||||
if (ret < 0) {
|
||||
auto errcode = std::string(strerror(errno));
|
||||
|
||||
if (errcode == "EBADF") throw error("fd isn't a valid open file descriptor.");
|
||||
if (errcode == "EINTR") throw error("The close() call was interrupted by a signal; see signal(7)");
|
||||
if (errcode == "EIO") throw error("An I/O error occured.");
|
||||
if (errcode == "ENOSPC" || errcode == "EDQUOT") throw error("NFS Specific error, consult close() manpage");
|
||||
|
||||
throw error(strerror(errno));
|
||||
}
|
||||
if (ret < 0)
|
||||
CheckErrors_close(errno);
|
||||
sock = -1;
|
||||
}
|
||||
return 0;
|
||||
@@ -95,35 +67,14 @@ namespace Socket
|
||||
self_addr_len = sizeof(self_addr);
|
||||
int opt = 1;
|
||||
int ret = ::setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (const char*)&opt, sizeof(opt));
|
||||
if (ret < 0) {
|
||||
throw SocketException(strerror(errno));
|
||||
}
|
||||
if (ret < 0)
|
||||
CheckErrors_setsockopt(errno);
|
||||
ret = ::bind(sock, (sockaddr_t*)&self_addr, self_addr_len);
|
||||
if (ret < 0) {
|
||||
using error = SocketBindingException;
|
||||
auto errcode = std::string(strerror(errno));
|
||||
if (errcode == "EACCES") throw error("The address is protected, and the user is not the superuser.");
|
||||
if (errcode == "EADDRINUSE") throw error("The given address is already in use."); // Also See Internet Domain Sockets
|
||||
if (errcode == "EBADF") throw error("sockfd is not a valid file descriptor.");
|
||||
if (errcode == "EINVAL") throw error("The socket is already bound to an address.");
|
||||
if (errcode == "ENOTSOCK") throw error("The file descriptor sockfd does not refer to a socket.");
|
||||
|
||||
throw error(strerror(errno));
|
||||
}
|
||||
if (ret < 0)
|
||||
CheckErrors_bind(errno);
|
||||
ret = ::getsockname(sock, (sockaddr_t*)&self_addr, &self_addr_len);
|
||||
if (ret < 0) {
|
||||
using error = SocketException;
|
||||
|
||||
auto errcode = std::string(strerror(errno));
|
||||
|
||||
if (errcode == "EBADF") throw error("The argument sockfd is not a valid file descriptor.");
|
||||
if (errcode == "EFAULT") throw error("The addr argument points to memory not in a valid part of the process address space.");
|
||||
if (errcode == "EINVAL") throw error("addrlen is invalid (e.g., is negative");
|
||||
if (errcode == "ENOBUFS") throw error("Insufficient resources were available in the system to perform the operation.");
|
||||
if (errcode == "ENOTSOCK")throw error("The file descriptor sockfd does not refer to a socket.");
|
||||
|
||||
throw error(strerror(errno));
|
||||
}
|
||||
if (ret < 0)
|
||||
CheckErrors_getsockname(errno);
|
||||
}
|
||||
|
||||
void UdpSocket::Bind(uint16_t portno)
|
||||
@@ -147,51 +98,8 @@ namespace Socket
|
||||
peer_addr = ipaddr;
|
||||
peer_addr_len = sizeof(peer_addr);
|
||||
int ret = ::connect(sock, (sockaddr_t*)&peer_addr, peer_addr_len);
|
||||
if (ret < 0) {
|
||||
using error = SocketConnectException;
|
||||
|
||||
|
||||
// The following are general socket errors only. There may be other domain-specific error codes.
|
||||
|
||||
// Semantically, these error codes are meant for the developer of UdpSocket (Me)
|
||||
// TODO: translate error messages to be meaningful for the API consumer
|
||||
|
||||
auto errcode = std::string(strerror(errno));
|
||||
|
||||
if (errcode == "EACCES") throw error(" For UNIX domain sockets, which are identified by pathname:\n"
|
||||
"Write permission is denied on the socket file, or search\n"
|
||||
"permission is denied for one of the directories in the\n"
|
||||
"path prefix"
|
||||
" It can also be returned if an SELinux policy denied a\n"
|
||||
"connection (for example, if there is a policy saying that\n"
|
||||
"an HTTP proxy can only connect to ports associated with\n"
|
||||
"HTTP servers, and the proxy tries to connect to a\n"
|
||||
"different port).");
|
||||
if (errcode == "EPERM") throw error("The user tried to connect to a broadcast address without\n"
|
||||
" having the socket broadcast flag enabled or the connection\n"
|
||||
" request failed because of a local firewall rule.");
|
||||
if (errcode == "EADDRINUSE") throw error("Local address is already in use.");
|
||||
if (errcode == "EADDRNOTAVAIL") throw error("The socket referred to by sockfd\n"
|
||||
" had not previously been bound to an address and, upon\n"
|
||||
" attempting to bind it to an ephemeral port, it was\n"
|
||||
" determined that all port numbers in the ephemeral port\n"
|
||||
" range are currently in use.");
|
||||
if (errcode == "EAFNOSUPPORT") throw error("The passed address didn't have the correct address family in its sa_family field.");
|
||||
|
||||
if (errcode == "EAGAIN") throw error("For nonblocking UNIX domain sockets, the socket is nonblocking, and the connection cannot be completed immediately. For other socket families, there are insufficient entries in the routing cache.");
|
||||
if (errcode == "EALREADY") throw error("The socket is nonblocking and a previous connection attempt has not yet been completed.");
|
||||
if (errcode == "EBADF") throw error("sockfd is not a valid open file descriptor");
|
||||
if (errcode == "ECONNREFUSED") throw error("A connect() on a stream socket found no one listening on the remote address.");
|
||||
if (errcode == "EFAULT") throw error("The socket structure address is outside the user's address space.");
|
||||
if (errcode == "EINPROGRESS") throw error("The socket is nonblocking and the connection cannot be completed immediately.");
|
||||
if (errcode == "EINTR") throw error("The system call was interrupted by a signal call that was caught.");
|
||||
if (errcode == "EISCONN") throw error("The socket is already connected.");
|
||||
if (errcode == "ENOTSOCK") throw error("The file descriptor sockfd does not refer to a socket.");
|
||||
if (errcode == "EPROTOTYPE") throw error("The socket type does not support the requested communications protocol. This error can occur, for example, on an attempt to connect a UNIX domain datagram socket to a stream socket.");
|
||||
if (errcode == "ETIMEDOUT") throw error("Timeout while attempting connection. The server may be too busy to accept new connections. Note that for IP sockets the timeout may be very long when syncookies are enabled on this server.");
|
||||
|
||||
throw SocketConnectException(strerror(errno));
|
||||
}
|
||||
if (ret < 0)
|
||||
CheckErrors_connect(errno);
|
||||
}
|
||||
void UdpSocket::Connect(uint16_t portno)
|
||||
{
|
||||
@@ -212,27 +120,7 @@ namespace Socket
|
||||
if (ret < 0) {
|
||||
using error = SocketReceiveException;
|
||||
|
||||
auto errcode = std::string(strerror(errno));
|
||||
|
||||
if (errcode == "EAGAIN" || errcode == "EWOULDBLOCK") throw error("The socket's file descriptor is marked O_NONBLOCK and no\n"
|
||||
" data is waiting to be received; or MSG_OOB is set and no\n"
|
||||
" out-of-band data is available and either the socket's file\n"
|
||||
" descriptor is marked O_NONBLOCK or the socket does not\n"
|
||||
" support blocking to await out-of-band data.");
|
||||
if (errcode == "EBADF") throw error("The socket argument is not a valid file descriptor.");
|
||||
if (errcode == "ECONNRESET") throw error("A connection was forcibly closed by a peer.");
|
||||
if (errcode == "EINTR") throw error("A signal interrupted recvfrom() before any data was available.");
|
||||
if (errcode == "EINVAL") throw error("The MSG_00B flag is set and no out-of-band data is available.");
|
||||
if (errcode == "ENOTCONN") throw error("A recieve is attempted on a connection-mode socket that is not connected.");
|
||||
if (errcode == "ENOTSOCK") throw error("The socket argument does not refer to a socket.");
|
||||
if (errcode == "EOPNOTSUPP") throw error("The specified flags are not supported for this socket type.");
|
||||
if (errcode == "ETIMEDOUT") throw error("The connection timed out during connection establishment, or due to a transmission timeout on active connection.");
|
||||
if (errcode == "EIO") throw error("An I/O error occurred while reading from or writing to the file system.");
|
||||
if (errcode == "ENOBUFS") throw error("Insufficient resources were available in the system to perform the operation.");
|
||||
if (errcode == "ENOMEM") throw error("Insufficient memory was available to fulfill the request.");
|
||||
|
||||
|
||||
throw SocketReceiveException(strerror(errno));
|
||||
CheckErrors_recvfrom(errno);
|
||||
}
|
||||
ipaddr = addr_in;
|
||||
message = { std::begin(buffer), std::begin(buffer)+ret};
|
||||
@@ -241,21 +129,9 @@ namespace Socket
|
||||
int UdpSocket::Broadcast(int opt) const
|
||||
{
|
||||
int ret = ::setsockopt(sock, SOL_SOCKET, SO_BROADCAST, (const char*)&opt, sizeof(opt));
|
||||
if (ret < 0) {
|
||||
using error = SocketException;
|
||||
auto errcode = std::string(strerror(errno));
|
||||
if (ret < 0)
|
||||
CheckErrors_setsockopt(errno);
|
||||
|
||||
if (errcode == "EBADF") throw error("The socket argument is not a valid file descriptor.");
|
||||
if (errcode == "EDOM") throw error("The send and receive timeout values are too big to fit into the timeout fields in the socket structure.");
|
||||
if (errcode == "EINVAL") throw error("The specified option is invalid at the specified socket level or the socket has been shut down.");
|
||||
if (errcode == "EISCONN") throw error("The socket is already connected, and a specified option cannot be set while the socket is connected.");
|
||||
if (errcode == "ENOPROTOOPT") throw error("The option is not supported by the protocol");
|
||||
if (errcode == "ENOTSOCK") throw error("The socket argument does not refer to a socket.");
|
||||
if (errcode == "ENOMEM") throw error("There was insufficient memory available for the operation to complete.");
|
||||
if (errcode == "ENOBUFS") throw error("Insufficient resources are available in the system to complete the call.");
|
||||
|
||||
throw SocketException(strerror(errno));
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -271,31 +147,7 @@ namespace Socket
|
||||
int ret = ::send(sock, (const char*)message.data(), message.size(), 0);
|
||||
|
||||
if (ret < 0)
|
||||
{
|
||||
using error = SocketSendException;
|
||||
auto errcode = std::string(strerror(errno));
|
||||
|
||||
if (errcode == "EACCES") throw error("An attempt was made to send a network/broadcast address as though it were a unicast address.");
|
||||
if (errcode == "EALREADY") throw error("Another Fast Open is in progress.");
|
||||
if (errcode == "EBADF") throw error("sockfd is not a valid open file descriptor.");
|
||||
if (errcode == "ECONNRESET") throw error("Connection reset by peer.");
|
||||
if (errcode == "EDESTADDRREQ") throw error("The socket is not in connection-mode, and no peer address is set.");
|
||||
if (errcode == "EFAULT") throw error("An invalid user space address was specified for an argument.");
|
||||
if (errcode == "EINTR") throw error("A signal occured before any data was transmitted; see signal(7).");
|
||||
if (errcode == "EINVAL") throw error("Invalid argument passed.");
|
||||
if (errcode == "EISCONN") throw error("The connection-mode socket was connected already but a recipient was specified. (Now either this error is returned, or the recipient specification is ignored.");
|
||||
if (errcode == "EMSGSIZE") throw error("The socket type requires that message be sent atomically, and the size of the message to be sent made this impossible.");
|
||||
if (errcode == "ENOBUFS") throw error("The output queue for a network interface was full. This generally indicates that the interface has stopped sending, but may be caused by transient congestion. (Normally, this does not occur in Linux. Packets are just silently dropped when a device queue overflows.)");
|
||||
if (errcode == "ENOMEM") throw error("No memory available.");
|
||||
if (errcode == "ENOTCONN") throw error("The socket is not connected, and no target has been given.");
|
||||
if (errcode == "ENOTSOCK") throw error("The file descriptor sockfd does not refer to a socket.");
|
||||
if (errcode == "EOPNOTSUPP") throw error("Some bit in the flags argument is inappropriate for the socket type.");
|
||||
if (errcode == "EPIPE") throw error("The local end has been shut down on a connection oriented socket. In this case, the process will also receive a SIGPIPE unless MSG_NOSIGNAL is set.");
|
||||
if (errcode == "EAGAIN" ||
|
||||
errcode == "EWOULDBLOCK") throw error("The socket is marked nonblocking and the requested operation would block.");
|
||||
|
||||
throw SocketException(strerror(errno));
|
||||
}
|
||||
CheckErrors_send(errno);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user