#include <cstring>
#include <fcntl.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/epoll.h>
#include <sys/eventfd.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <netdb.h>
#include "socket.h"
static void addressToInaddr(const Address &address, struct sockaddr_in addr) {
memset(&addr, 0, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = address.ipUInt;
addr.sin_port = htons(address.port);
}
static bool configureTcpSocket(int sockId) {
int tcp_nodelay = 1;
return 0 == setsockopt(sockId, IPPROTO_TCP, TCP_NODELAY, &tcp_nodelay, sizeof(int))
&& 0 == fcntl(sockId, F_SETFL, fcntl(sockId, F_GETFL, 0) | O_NONBLOCK);
}
int Socket::tcpConnect(const Address &address) {
int sockId = ::socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (sockId < 0) return -1;
struct sockaddr_in addr;
addressToInaddr(address, addr);
if ( 0 != ::connect(sockId, (struct sockaddr*)&addr, sizeof(addr))
|| !configureTcpSocket(sockId) )
{ ::close(sockId); return -1; }
return sockId;
}
int Socket::tcpListen(const Address &address) {
int sockId = ::socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (sockId < 0) return -1;
struct sockaddr_in addr;
addressToInaddr(address, addr);
if ( 0 != ::bind(sockId, (struct sockaddr*)&addr, sizeof(addr))
|| 0 != ::listen(sockId, 16)
|| !configureTcpSocket(sockId) )
{ ::close(sockId); return -1; }
return sockId;
}
int Socket::tcpAccept(int sockId) {
struct sockaddr_in addr = {};
addr.sin_family = AF_INET;
socklen_t len = sizeof(addr);
int newSockId = ::accept(sockId, (struct sockaddr*)&addr, &len);
if (newSockId < 0) return -1;
if (!configureTcpSocket(newSockId))
{ ::close(newSockId); return -1; }
return newSockId;
}
int Socket::tcpSendAsync(int sockId, const void *data, int size) {
int res = ::send(sockId, data, size, MSG_DONTWAIT);
return res > 0 ? res : 0;
}
int Socket::tcpRecvAsync(int sockId, void *data, int size) {
int res = ::recv(sockId, data, size, MSG_DONTWAIT);
return res > 0 ? res : 0;
}
int Socket::udpBind(const Address &address) {
int sockId = ::socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
if (sockId < 0) return -1;
struct sockaddr_in addr;
addressToInaddr(address, addr);
if (0 != ::bind(sockId, (struct sockaddr*)&addr, sizeof(addr))) {
::close(sockId);
return -1;
}
return sockId;
}
int Socket::udpSend(int sockId, const Address &address, const void *data, int size) {
struct sockaddr_in addr;
addressToInaddr(address, addr);
int res = ::sendto(sockId, data, size, 0, (struct sockaddr*)&addr, sizeof(addr));
return res > 0 ? res : 0;
}
int Socket::udpRecvAsync(int sockId, Address &address, void *data, int size) {
address = Address();
struct sockaddr_in addr = {};
addr.sin_family = AF_INET;
socklen_t len = sizeof(addr);
int res = ::recvfrom(sockId, data, size, MSG_DONTWAIT, (struct sockaddr*)&addr, &len);
if (res <= 0) return 0;
address.ipUInt = addr.sin_addr.s_addr;
address.port = ntohs(addr.sin_port);
return res;
}
void Socket::close(int sockId)
{ ::close(sockId); }