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] - Blame information for rev 5

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 5 sergeykhbr
/**
2
 * @file
3
 * @copyright  Copyright 2017 GNSS Sensor Ltd. All right reserved.
4
 * @author     Sergey Khabarov - sergeykhbr@gmail.com
5
 * @brief      Remote access to debugger via TCP connection. Server side.
6
 */
7
 
8
#include "tcpserver.h"
9
 
10
namespace debugger {
11
 
12
/** Class registration in the Core */
13
REGISTER_CLASS(TcpServer)
14
 
15
TcpServer::TcpServer(const char *name) : IService(name) {
16
    registerInterface(static_cast<IThread *>(this));
17
    registerAttribute("Enable", &isEnable_);
18
    registerAttribute("Timeout", &timeout_);
19
    registerAttribute("BlockingMode", &blockmode_);
20
    registerAttribute("HostIP", &hostIP_);
21
    registerAttribute("HostPort", &hostPort_);
22
}
23
 
24
void TcpServer::postinitService() {
25
    createServerSocket();
26
 
27
    if (listen(hsock_, 1) < 0)  {
28
        RISCV_error("listen() failed", 0);
29
        return;
30
    }
31
 
32
    /** By default socket was created with Blocking mode */
33
    if (!blockmode_.to_bool()) {
34
        setBlockingMode(false);
35
    }
36
 
37
    if (isEnable_.to_bool()) {
38
        if (!run()) {
39
            RISCV_error("Can't create thread.", NULL);
40
            return;
41
        }
42
    }
43
}
44
 
45
void TcpServer::busyLoop() {
46
    socket_def client_sock;
47
    int err;
48
 
49
    fd_set readSet;
50
    timeval timeout;
51
    timeout.tv_sec = 0;
52
    timeout.tv_usec = 400000;   // 400 ms
53
 
54
    int idx = 0;
55
    char tname[64];
56
 
57
    IClass *icls;
58
    IService *isrv;
59
    while (isEnabled()) {
60
        FD_ZERO(&readSet);
61
        FD_SET(hsock_, &readSet);
62
        err = select(hsock_ + 1, &readSet, NULL, NULL, &timeout);
63
        if (err > 0) {
64
            client_sock = accept(hsock_, 0, 0);
65
            setRcvTimeout(client_sock, timeout_.to_int());
66
            RISCV_sprintf(tname, sizeof(tname), "client%d", idx++);
67
 
68
            icls = static_cast<IClass *>(RISCV_get_class("TcpClientClass"));
69
            isrv = icls->createService(tname);
70
            AttributeType lst, item;
71
            lst.make_list(0);
72
            item.make_list(2);
73
            item[0u].make_string("LogLevel");
74
            item[1].make_int64(4);
75
            lst.add_to_list(&item);
76
            item[0u].make_string("Enable");
77
            item[1].make_boolean(true);
78
            lst.add_to_list(&item);
79
 
80
            isrv->initService(&lst);
81
            IThread *ithrd =
82
                static_cast<IThread *>(isrv->getInterface(IFACE_THREAD));
83
            ithrd->setExtArgument(&client_sock);
84
            isrv->postinitService();
85
            RISCV_info("TCP %s %p started", isrv->getObjName(), client_sock);
86
        } else if (err == 0) {
87
            // timeout
88
        } else {
89
            RISCV_info("TCP server thread accept() failed", 0);
90
            loopEnable_.state = false;
91
        }
92
    }
93
    closeServerSocket();
94
}
95
 
96
int TcpServer::createServerSocket() {
97
    char hostName[256];
98
    if (gethostname(hostName, sizeof(hostName)) < 0) {
99
        return -1;
100
    }
101
 
102
    struct addrinfo hints;
103
    memset(&hints, 0, sizeof(hints));
104
    hints.ai_family = AF_UNSPEC;
105
    hints.ai_socktype = SOCK_STREAM;
106
    hints.ai_protocol = IPPROTO_TCP;
107
 
108
    /**
109
     * Check availability of IPv4 address assigned via attribute 'hostIP'.
110
     * If it woudn't be found use the last avaialble IP address.
111
     */
112
    int retval;
113
    struct addrinfo *result = NULL;
114
    struct addrinfo *ptr = NULL;
115
    retval = getaddrinfo(hostName, "0", &hints, &result);
116
    if (retval != 0) {
117
        return -1;
118
    }
119
 
120
    if (hostIP_.size() == 0 || hostIP_.is_equal("127.0.0.1")) {
121
        memset(&sockaddr_ipv4_, 0, sizeof(struct sockaddr_in));
122
        sockaddr_ipv4_.sin_family = AF_INET;
123
        sockaddr_ipv4_.sin_addr.s_addr = inet_addr("127.0.0.1");
124
    } else {
125
        for (ptr = result; ptr != NULL; ptr = ptr->ai_next) {
126
            // Find only IPV4 address, ignore others.
127
            if (ptr->ai_family != AF_INET) {
128
                continue;
129
            }
130
            sockaddr_ipv4_ = *((struct sockaddr_in *)ptr->ai_addr);
131
 
132
            if (hostIP_.is_equal(inet_ntoa(sockaddr_ipv4_.sin_addr))) {
133
                break;
134
            }
135
        }
136
    }
137
    sockaddr_ipv4_.sin_port = htons(static_cast<uint16_t>(hostPort_.to_int()));
138
    RISCV_info("Selected Host IPv4 %s:%d",
139
                inet_ntoa(sockaddr_ipv4_.sin_addr),
140
                hostPort_.to_uint32());
141
 
142
    hsock_ = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
143
    if (hsock_ < 0) {
144
        RISCV_error("%s", "Error: socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)");
145
        return -1;
146
    }
147
 
148
    int res = bind(hsock_,
149
                   reinterpret_cast<struct sockaddr *>(&sockaddr_ipv4_),
150
                   sizeof(sockaddr_ipv4_));
151
    if (res != 0) {
152
        RISCV_error("Error: bind(hsock_, \"%s\", ...)", hostIP_.to_string());
153
        return -1;
154
    }
155
 
156
    addr_size_t addr_sz = sizeof(sockaddr_ipv4_);
157
    res = getsockname(hsock_,
158
                      reinterpret_cast<struct sockaddr *>(&sockaddr_ipv4_),
159
                      &addr_sz);
160
 
161
    RISCV_info("IPv4 address %s:%d . . . opened",
162
                inet_ntoa(sockaddr_ipv4_.sin_addr),
163
                ntohs(sockaddr_ipv4_.sin_port));
164
 
165
    return 0;
166
}
167
 
168
void TcpServer::setRcvTimeout(socket_def skt, int timeout_ms) {
169
    if (!timeout_ms) {
170
        return;
171
    }
172
    struct timeval tv;
173
#if defined(_WIN32) || defined(__CYGWIN__)
174
    /** On windows timeout of the setsockopt() function is the DWORD
175
        * size variable in msec, so we use only the first field in timeval
176
        * struct and directly assgign argument.
177
        */
178
    tv.tv_sec = timeout_ms;
179
    tv.tv_usec = 0;
180
#else
181
    tv.tv_usec = (timeout_ms % 1000) * 1000;
182
    tv.tv_sec = timeout_ms / 1000;
183
#endif
184
    setsockopt(skt, SOL_SOCKET, SO_RCVTIMEO,
185
                    reinterpret_cast<char *>(&tv), sizeof(struct timeval));
186
}
187
 
188
bool TcpServer::setBlockingMode(bool mode) {
189
    int ret;
190
#if defined(_WIN32) || defined(__CYGWIN__)
191
    // 0 = disable non-blocking mode
192
    // 1 = enable non-blocking mode
193
    u_long arg = mode ? 0 : 1;
194
    ret = ioctlsocket(hsock_, FIONBIO, &arg);
195
    if (ret == SOCKET_ERROR) {
196
        RISCV_error("Set non-blocking socket failed", 0);
197
    }
198
#else
199
    int flags = fcntl(hsock_, F_GETFL, 0);
200
    if (flags < 0) {
201
        return false;
202
    }
203
    flags = mode ? (flags & ~O_NONBLOCK) : (flags | O_NONBLOCK);
204
    ret = fcntl(hsock_, F_SETFL, flags);
205
#endif
206
    if (ret == 0) {
207
        // success
208
        blockmode_.make_boolean(mode);
209
        return true;
210
    }
211
    return false;
212
}
213
 
214
void TcpServer::closeServerSocket() {
215
    if (hsock_ < 0) {
216
        return;
217
    }
218
 
219
#if defined(_WIN32) || defined(__CYGWIN__)
220
    closesocket(hsock_);
221
#else
222
    shutdown(hsock_, SHUT_RDWR);
223
    close(hsock_);
224
#endif
225
    hsock_ = -1;
226
}
227
 
228
 
229
}  // namespace debugger

powered by: WebSVN 2.1.0

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