123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103 |
- #include <sys/socket.h>
- #include <iostream>
- #include <cstring>
- #include <netinet/in.h>
- #include <unistd.h>
- #include <poll.h>
- #include "server/network/Socket.h"
- Socket::Socket() : socketId(-1) {
- // domain - AF_INET - IPv4 Internet protocols
- // type - SOCK_STREAM - two-way, connection-based byte streams
- // protocol - 0 - use standard protocol for the given socket type
- socketId = socket(AF_INET, SOCK_STREAM, 0);
- if(socketId == -1) {
- std::cout << "cannot create socket: " << strerror(errno) << "\n";
- }
- }
- Socket::~Socket() {
- if(socketId == -1) {
- return;
- }
- if(close(socketId) == -1) {
- std::cout << "cannot close socket: " << strerror(errno) << "\n";
- }
- }
- bool Socket::hasError() const {
- return socketId == -1;
- }
- bool Socket::setNonLinger() {
- // prevents clients from blocking the port if the server exits
- // this is useful if server and client run on the same system
- struct linger sl;
- sl.l_onoff = 1; // nonzero to linger on close
- sl.l_linger = 0; // time to linger
- // sockfd - listenerSocket - modified socket
- // level - SOL_SOCKET - manipulate options at the sockets API level
- // optname - SO_LINGER - identifier of the option
- if(setsockopt(socketId, SOL_SOCKET, SO_LINGER, &sl, sizeof (struct linger)) == -1) {
- std::cout << "cannot set non lingering: " << strerror(errno) << "\n";
- return true;
- }
- return false;
- }
- bool Socket::listenOnPort(u16 port, uint queueLength) const {
- // specify binding data
- struct sockaddr_in connectSocketData;
- // clear padding
- memset(&connectSocketData, 0, sizeof (struct sockaddr_in));
- // IPv4 Internet protocols
- connectSocketData.sin_family = AF_INET;
- // port in network byte order
- connectSocketData.sin_port = htons(port);
- // address in network byte order, accept any incoming messages
- connectSocketData.sin_addr.s_addr = htons(INADDR_ANY);
- // bind the socket
- if(bind(socketId, (struct sockaddr*) &connectSocketData, sizeof (struct sockaddr_in)) == -1) {
- std::cout << "cannot bind socket: " << strerror(errno) << "\n";
- return true;
- }
- // mark the socket as handler for connection requests
- // backlog - queueLength - max queue length of pending connections
- if(listen(socketId, queueLength) == -1) {
- std::cout << "cannot start listening on socket: " << strerror(errno) << "\n";
- return true;
- }
- return false;
- }
- WaitResult Socket::waitForConnection(uint timeoutMillis) const {
- // wait until a connection arrives with timeout, this prevents being stuck in accept
- struct pollfd fds;
- fds.fd = socketId; // file descriptor for polling
- fds.events = POLLIN; // wait until data is ready to read
- fds.revents = 0; // return events - none
- // nfds_t - 1 - amount of passed in structs
- // timeout - timeoutMillis - milliseconds to wait until an event occurs
- int result = poll(&fds, 1, timeoutMillis);
- if(result > 0) {
- return WaitResult::SUCCESS;
- } else if(result == 0) {
- return WaitResult::TIMEOUT;
- }
- std::cout << "poll error: " << strerror(errno) << "\n";
- return WaitResult::ERROR;
- }
- int Socket::acceptConnection() const {
- struct sockaddr_in clientSocketData;
- // accepts an incoming client connection and stores the data in the given struct
- socklen_t addrlen = sizeof (struct sockaddr_in);
- int clientSocket = accept(socketId, (struct sockaddr*) &clientSocketData, &addrlen);
- if(clientSocket >= 0) {
- return clientSocket;
- }
- std::cout << "accept error: " << strerror(errno) << "\n";
- return -1;
- }
|