OpenCores
URL https://opencores.org/ocsvn/riscv_vhdl/riscv_vhdl/trunk

Subversion Repositories riscv_vhdl

[/] [riscv_vhdl/] [trunk/] [debugger/] [src/] [libdbg64g/] [services/] [remote/] [tcpserver.cpp] - Rev 5

Compare with Previous | Blame | View Log

/**
 * @file
 * @copyright  Copyright 2017 GNSS Sensor Ltd. All right reserved.
 * @author     Sergey Khabarov - sergeykhbr@gmail.com
 * @brief      Remote access to debugger via TCP connection. Server side.
 */
 
#include "tcpserver.h"
 
namespace debugger {
 
/** Class registration in the Core */
REGISTER_CLASS(TcpServer)
 
TcpServer::TcpServer(const char *name) : IService(name) {
    registerInterface(static_cast<IThread *>(this));
    registerAttribute("Enable", &isEnable_);
    registerAttribute("Timeout", &timeout_);
    registerAttribute("BlockingMode", &blockmode_);
    registerAttribute("HostIP", &hostIP_);
    registerAttribute("HostPort", &hostPort_);
}
 
void TcpServer::postinitService() {
    createServerSocket();
 
    if (listen(hsock_, 1) < 0)  {
        RISCV_error("listen() failed", 0);
        return;
    }
 
    /** By default socket was created with Blocking mode */
    if (!blockmode_.to_bool()) {
        setBlockingMode(false);
    }
 
    if (isEnable_.to_bool()) {
        if (!run()) {
            RISCV_error("Can't create thread.", NULL);
            return;
        }
    }
}
 
void TcpServer::busyLoop() {
    socket_def client_sock;
    int err;
 
    fd_set readSet;
    timeval timeout;
    timeout.tv_sec = 0;
    timeout.tv_usec = 400000;   // 400 ms
 
    int idx = 0;
    char tname[64];
 
    IClass *icls;
    IService *isrv;
    while (isEnabled()) {
        FD_ZERO(&readSet);
        FD_SET(hsock_, &readSet);
        err = select(hsock_ + 1, &readSet, NULL, NULL, &timeout);
        if (err > 0) {
            client_sock = accept(hsock_, 0, 0);
            setRcvTimeout(client_sock, timeout_.to_int());
            RISCV_sprintf(tname, sizeof(tname), "client%d", idx++);
 
            icls = static_cast<IClass *>(RISCV_get_class("TcpClientClass"));
            isrv = icls->createService(tname);
            AttributeType lst, item;
            lst.make_list(0);
            item.make_list(2);
            item[0u].make_string("LogLevel");
            item[1].make_int64(4);
            lst.add_to_list(&item);
            item[0u].make_string("Enable");
            item[1].make_boolean(true);
            lst.add_to_list(&item);
 
            isrv->initService(&lst);
            IThread *ithrd =
                static_cast<IThread *>(isrv->getInterface(IFACE_THREAD));
            ithrd->setExtArgument(&client_sock);
            isrv->postinitService();
            RISCV_info("TCP %s %p started", isrv->getObjName(), client_sock);
        } else if (err == 0) {
            // timeout
        } else {
            RISCV_info("TCP server thread accept() failed", 0);
            loopEnable_.state = false;
        }
    }
    closeServerSocket();
}
 
int TcpServer::createServerSocket() {
    char hostName[256];
    if (gethostname(hostName, sizeof(hostName)) < 0) {
        return -1;
    }
 
    struct addrinfo hints;
    memset(&hints, 0, sizeof(hints));
    hints.ai_family = AF_UNSPEC;
    hints.ai_socktype = SOCK_STREAM;
    hints.ai_protocol = IPPROTO_TCP;
 
    /**
     * Check availability of IPv4 address assigned via attribute 'hostIP'.
     * If it woudn't be found use the last avaialble IP address.
     */
    int retval;
    struct addrinfo *result = NULL;
    struct addrinfo *ptr = NULL;
    retval = getaddrinfo(hostName, "0", &hints, &result);
    if (retval != 0) {
        return -1;
    }
 
    if (hostIP_.size() == 0 || hostIP_.is_equal("127.0.0.1")) {
        memset(&sockaddr_ipv4_, 0, sizeof(struct sockaddr_in));
        sockaddr_ipv4_.sin_family = AF_INET;
        sockaddr_ipv4_.sin_addr.s_addr = inet_addr("127.0.0.1");
    } else {
        for (ptr = result; ptr != NULL; ptr = ptr->ai_next) {
            // Find only IPV4 address, ignore others.
            if (ptr->ai_family != AF_INET) {
                continue;
            }
            sockaddr_ipv4_ = *((struct sockaddr_in *)ptr->ai_addr);
 
            if (hostIP_.is_equal(inet_ntoa(sockaddr_ipv4_.sin_addr))) {
                break;
            }
        }
    }
    sockaddr_ipv4_.sin_port = htons(static_cast<uint16_t>(hostPort_.to_int()));
    RISCV_info("Selected Host IPv4 %s:%d",
                inet_ntoa(sockaddr_ipv4_.sin_addr),
                hostPort_.to_uint32());
 
    hsock_ = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
    if (hsock_ < 0) {
        RISCV_error("%s", "Error: socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)");
        return -1;
    }
 
    int res = bind(hsock_,
                   reinterpret_cast<struct sockaddr *>(&sockaddr_ipv4_),
                   sizeof(sockaddr_ipv4_));
    if (res != 0) {
        RISCV_error("Error: bind(hsock_, \"%s\", ...)", hostIP_.to_string());
        return -1;
    }
 
    addr_size_t addr_sz = sizeof(sockaddr_ipv4_);
    res = getsockname(hsock_,
                      reinterpret_cast<struct sockaddr *>(&sockaddr_ipv4_),
                      &addr_sz);
 
    RISCV_info("IPv4 address %s:%d . . . opened",
                inet_ntoa(sockaddr_ipv4_.sin_addr),
                ntohs(sockaddr_ipv4_.sin_port));
 
    return 0;
}
 
void TcpServer::setRcvTimeout(socket_def skt, int timeout_ms) {
    if (!timeout_ms) {
        return;
    }
    struct timeval tv;
#if defined(_WIN32) || defined(__CYGWIN__)
    /** On windows timeout of the setsockopt() function is the DWORD
        * size variable in msec, so we use only the first field in timeval
        * struct and directly assgign argument.
        */
    tv.tv_sec = timeout_ms;
    tv.tv_usec = 0;
#else
    tv.tv_usec = (timeout_ms % 1000) * 1000;
    tv.tv_sec = timeout_ms / 1000;
#endif
    setsockopt(skt, SOL_SOCKET, SO_RCVTIMEO,
                    reinterpret_cast<char *>(&tv), sizeof(struct timeval));
}
 
bool TcpServer::setBlockingMode(bool mode) {
    int ret;
#if defined(_WIN32) || defined(__CYGWIN__)
    // 0 = disable non-blocking mode
    // 1 = enable non-blocking mode
    u_long arg = mode ? 0 : 1;
    ret = ioctlsocket(hsock_, FIONBIO, &arg);
    if (ret == SOCKET_ERROR) {
        RISCV_error("Set non-blocking socket failed", 0);
    }
#else
    int flags = fcntl(hsock_, F_GETFL, 0);
    if (flags < 0) {
        return false;
    }
    flags = mode ? (flags & ~O_NONBLOCK) : (flags | O_NONBLOCK);
    ret = fcntl(hsock_, F_SETFL, flags);
#endif
    if (ret == 0) {
        // success
        blockmode_.make_boolean(mode);
        return true;
    }
    return false;
}
 
void TcpServer::closeServerSocket() {
    if (hsock_ < 0) {
        return;
    }
 
#if defined(_WIN32) || defined(__CYGWIN__)
    closesocket(hsock_);
#else
    shutdown(hsock_, SHUT_RDWR);
    close(hsock_);
#endif
    hsock_ = -1;
}
 
 
}  // namespace debugger
 

Compare with Previous | Blame | View Log

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.