← index
cplusplus11.Examples/UNIX/network/socket.cpp
Source: cplusplus11.Examples/UNIX/network/socket.cpp
#include "socket.hpp"


namespace net {
    
    Socket::Socket() : sockfd(0), addrlen(0), blocking(true) {
        
    }
    
    Socket::Socket(int fd) : sockfd(fd), addrlen(0), blocking(true) {
        
    }
    
    Socket::Socket(const Socket &s) {
        setSocket(s);
    }
    
    Socket::Socket(Socket &&s) {
        setSocket(s);
    }
    
    Socket &Socket::operator=(const Socket &s) {
        setSocket(s);
        return *this;
    }
    
    Socket &Socket::operator=(const Socket &&s) {
        setSocket(s);
        return *this;
    }
    
    void Socket::setSocket(const Socket &s) {
        sockfd = s.sockfd;
        addrlen = s.addrlen;
        blocking = s.blocking;
    }
    
    int Socket::connectToHost(const std::string &host, const std::string &port, SocketType type) {
        addrinfo hints;
        addrinfo *rt, *rp;
        int sfd, s;
        memset(&hints, 0, sizeof(addrinfo));
        hints.ai_canonname = NULL;
        hints.ai_addr = NULL;
        hints.ai_next = NULL;
        hints.ai_family = AF_UNSPEC;
        hints.ai_socktype = (type == SocketType::STREAM) ? SOCK_STREAM : SOCK_DGRAM;
        s = getaddrinfo(host.c_str(), port.c_str(), &hints, &rt);
        if(s != 0) {
            errno = ENOSYS;
            return -1;
        }
        for(rp = rt; rp != NULL; rp = rp->ai_next) {
            sfd = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol);
            if(sfd == -1)
                continue;
            
            if(connect(sfd, rp->ai_addr, rp->ai_addrlen) != -1)
                break;
            
            close(sfd);
        }
        
        if(rp != NULL) {
            this->sockfd = sfd;
            this->addrlen = rp->ai_addrlen;
        }
        
        freeaddrinfo(rt);
        
        return (rp == NULL) ? -1 : sfd;
    }
    
    int Socket::listenAt(const std::string &port, SocketType type, int backlog) {
        addrinfo hints;
        addrinfo *rt, *rp;
        int sfd, optval, s;
        
        memset(&hints, 0, sizeof(addrinfo));
        hints.ai_canonname = NULL;
        hints.ai_addr = NULL;
        hints.ai_next = NULL;
        hints.ai_socktype = (type == SocketType::STREAM) ? SOCK_STREAM : SOCK_DGRAM;
        hints.ai_family = AF_UNSPEC;
        hints.ai_flags = AI_PASSIVE;
        
        s = getaddrinfo(NULL, port.c_str(), &hints, &rt);
        if(s != 0)
            return -1;
        
        optval = 1;
        
        for(rp = rt; rp != NULL; rp = rp->ai_next) {
            sfd = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol);
            if(sfd == -1)
                continue;
            
            if(setsockopt(sfd, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval)) == -1) {
                close(sfd);
                freeaddrinfo(rt);
                return -1;
            }
            
            if(bind(sfd, rp->ai_addr, rp->ai_addrlen) == 0)
                break;
            
            close(sfd);
        }
        
        
        
        if(rp != NULL) {
            if(listen(sfd, backlog) == -1) {
                freeaddrinfo(rt);
                return -1;
            }
            this->sockfd = sfd;
            this->addrlen = rp->ai_addrlen;
        }
        freeaddrinfo(rt);
        return (rp == NULL) ? -1 : sfd;
    }
    
    ssize_t Socket::readLine(std::string &buf) {
        if(!valid()) return -1;
        ssize_t bytesRead = 0;
        while(1) {
            char c;
            ssize_t readVal = read(sockfd, &c, 1);
            if(readVal == 0 || readVal == -1) break;
            if(c == '\n') break;
            buf += c;
            bytesRead++;
        }
        return bytesRead;
    }
    
    std::string Socket::readLine(ssize_t &bytesRead) {
        bytesRead = 0;
        std::ostringstream stream;
        while(1) {
            char c;
            ssize_t readVal = read(sockfd, &c, 1);
            if(readVal == 0 || readVal == -1) break;
            if(c == '\n') break;
            stream << c;
            bytesRead++;
            
        }
        return stream.str();
    }
    
    ssize_t Socket::receive(void *buf, size_t len) {
        return read(sockfd, buf, len);
    }
    
    ssize_t Socket::sendString(const std::string &text) {
        return sendData((const void*)text.c_str(), text.length());
    }
    
    ssize_t Socket::sendData(const void *buf, size_t len) {
        return write(sockfd, buf, len);
    }
    
    int Socket::closeSocket() {
        return close(sockfd);
    }
    
    int Socket::acceptSocket(Socket &s) {
        int newsock = accept(sockfd, 0, 0);
        if(newsock == -1) return -1;
        std::cout << "Socket: " << newsock << " accepted..\n";
        Socket sa(newsock);
        s = sa;
        return newsock;
    }
    
    void Socket::setBlocking(bool state) {
        
        if(sockfd >= 0) {
            int flags = fcntl(sockfd, F_GETFL);
            if(flags == -1) {
                std::cerr << "Error getting flags for: " << sockfd << "\n";
                return;
            }
            
            if(state == true) flags &= ~O_NONBLOCK;
            else flags |= O_NONBLOCK;
            
            blocking = state;
            if(fcntl(sockfd, F_SETFL, flags) == -1)
                std::cerr << "Error settings flags on: " << sockfd << "\n";
        }
    }
    
    void ignorePipeSignal() {
        if(signal(SIGPIPE, SIG_IGN) == SIG_ERR) {
            std::cerr << "Error ignoring signal..\n";
        }
    }
    
    
}