This is a small socket library I made to avoid complicated C boilerplate code and several #includes
for connecting sockets, bind, listening etc.
Please note that socket_create()
does not support bind
to specific IP addresses and that the IP parameter is ignored.
The only C++11 feature I am using is constexpr
. Even though it is C++11, I decided not to wrap everything in a class, but to work with standard int
.
In the future, I might add Unix domain socket in a way similar to socket_create()
and / or SSL support, but at the moment I do not need those.
sockets.h
#ifndef NET_SOCKETS_H_
#define NET_SOCKETS_H_
#include <cstdint>
namespace net{
constexpr int SOCKET_NONBLOCK = 0x01;
constexpr int SOCKET_TCPNODELAY = 0x02;
// ===========================
constexpr int SOCKET_DEFAULTOPT = SOCKET_NONBLOCK & SOCKET_TCPNODELAY;
// ===========================
int socket_create(const char *ip, uint16_t port, uint16_t backlog = 0, int options = SOCKET_DEFAULTOPT) noexcept;
bool socket_makeNonBlocking(int fd) noexcept;
bool socket_makeTCPNoDelay(int fd) noexcept;
int socket_accept(int fd) noexcept;
void socket_close(int fd) noexcept;
bool socket_check_eagain() noexcept;
}
#endif
sockets.cc
#include "sockets.h"
#include <sys/socket.h> // EAGAIN
#include <arpa/inet.h> // AF_INET
#include <netinet/tcp.h> // TCP_NODELAY
#include <fcntl.h> // fcntl
#include <unistd.h> // close
#include <errno.h> // errno
namespace net{
bool socket_check_eagain() noexcept{
return errno == EINTR || errno == EAGAIN || errno == EWOULDBLOCK;
}
bool socket_makeNonBlocking(int const fd) noexcept{
if (fd >= 0)
return fcntl(fd, F_SETFL, O_NONBLOCK) >= 0;
return false;
}
bool socket_makeTCPNoDelay(int const fd) noexcept{
int const opt = 1;
return (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, & opt, sizeof opt) >= 0);
}
void socket_close(int const fd) noexcept{
if (fd >= 0)
::close(fd);
}
int socket_accept(int const fd) noexcept{
if (fd >= 0)
return ::accept(fd, NULL, NULL);
return -1;
}
int socket_create(const char *ip, uint16_t const port, uint16_t const backlog, int const options) noexcept{
int fd = socket(AF_INET , SOCK_STREAM , 0);
if(fd < 0)
return -1;
int const opt = 1;
if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, & opt, sizeof opt) < 0){
::close(fd);
return -2;
}
if (options & SOCKET_NONBLOCK)
if (! socket_makeNonBlocking(fd) ){
::close(fd);
return -3;
}
if (options & SOCKET_TCPNODELAY)
if (! socket_makeTCPNoDelay(fd) ){
::close(fd);
return -4;
}
struct sockaddr_in address;
address.sin_family = AF_INET;
address.sin_addr.s_addr = INADDR_ANY;
address.sin_port = htons(port);
if (bind(fd, (struct sockaddr *) & address, sizeof address) < 0){
::close(fd);
return -5;
}
if (listen(fd, backlog ? backlog : SOMAXCONN) < 0){
::close(fd);
return -6;
}
return fd;
}
} // namespace