• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

mavlink / MAVSDK / 17995555669

25 Sep 2025 02:58AM UTC coverage: 47.616% (+0.05%) from 47.566%
17995555669

Pull #2662

github

web-flow
Merge e5c7d0ed7 into 5c85bcef8
Pull Request #2662: modify windows tcpclient reconnect bug

4 of 4 new or added lines in 1 file covered. (100.0%)

22 existing lines in 5 files now uncovered.

17039 of 35784 relevant lines covered (47.62%)

451.42 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

68.32
/src/mavsdk/core/tcp_client_connection.cpp
1
#include "tcp_client_connection.h"
2
#include "log.h"
3

4
#include <cassert>
5
#include <sstream>
6
#include <utility>
7
#include <thread>
8
#include <sstream>
9

10
#ifdef WINDOWS
11
#ifndef MINGW
12
#pragma comment(lib, "Ws2_32.lib") // Without this, Ws2_32.lib is not included in static library.
13
#endif
14
#else
15
#include <netinet/in.h>
16
#include <sys/socket.h>
17
#include <arpa/inet.h>
18
#include <errno.h>
19
#include <netdb.h>
20
#endif
21

22
#ifndef WINDOWS
23
#define GET_ERROR(_x) strerror(_x)
24
#else
25
#define GET_ERROR(_x) WSAGetLastError()
26
#endif
27

28
namespace mavsdk {
29

30
inline bool notReady(int err) 
1✔
31
{
32
#ifdef WINDOWS
33
    return err == WSAEWOULDBLOCK || err == WSAETIMEDOUT;
34
#else
35
    return err == EAGAIN || err == ETIMEDOUT;
1✔
36
#endif
37
}
38

39
/* change to remote_ip and remote_port */
40
TcpClientConnection::TcpClientConnection(
1✔
41
    Connection::ReceiverCallback receiver_callback,
42
    Connection::LibmavReceiverCallback libmav_receiver_callback,
43
    MavsdkImpl& mavsdk_impl,
44
    std::string remote_ip,
45
    int remote_port,
46
    ForwardingOption forwarding_option) :
1✔
47
    Connection(
48
        std::move(receiver_callback),
1✔
49
        std::move(libmav_receiver_callback),
1✔
50
        mavsdk_impl,
51
        forwarding_option),
52
    _remote_ip(std::move(remote_ip)),
1✔
53
    _remote_port_number(remote_port),
1✔
54
    _should_exit(false)
3✔
55
{}
1✔
56

57
TcpClientConnection::~TcpClientConnection()
2✔
58
{
59
    // If no one explicitly called stop before, we should at least do it.
60
    stop();
1✔
61
}
2✔
62

63
ConnectionResult TcpClientConnection::start()
1✔
64
{
65
    if (!start_mavlink_receiver()) {
1✔
66
        return ConnectionResult::ConnectionsExhausted;
×
67
    }
68

69
    if (!start_libmav_receiver()) {
1✔
70
        return ConnectionResult::ConnectionsExhausted;
×
71
    }
72

73
    ConnectionResult ret = setup_port();
1✔
74
    if (ret != ConnectionResult::Success) {
1✔
75
        return ret;
×
76
    }
77

78
    start_recv_thread();
1✔
79

80
    return ConnectionResult::Success;
1✔
81
}
82

83
ConnectionResult TcpClientConnection::setup_port()
2✔
84
{
85
#ifdef WINDOWS
86
    WSADATA wsa;
87
    if (WSAStartup(MAKEWORD(2, 2), &wsa) != 0) {
88
        LogErr() << "Error: Winsock failed, error: %d", WSAGetLastError();
89
        return ConnectionResult::SocketError;
90
    }
91
#endif
92

93
    _socket_fd.reset(socket(AF_INET, SOCK_STREAM, 0));
2✔
94

95
    if (_socket_fd.empty()) {
2✔
96
        LogErr() << "socket error" << GET_ERROR(errno);
×
97
        return ConnectionResult::SocketError;
×
98
    }
99

100
    struct sockaddr_in remote_addr{};
2✔
101
    remote_addr.sin_family = AF_INET;
2✔
102
    remote_addr.sin_port = htons(_remote_port_number);
2✔
103

104
    struct hostent* hp;
105
    hp = gethostbyname(_remote_ip.c_str());
2✔
106
    if (hp == nullptr) {
2✔
107
        LogErr() << "Could not get host by name";
×
108
        return ConnectionResult::SocketConnectionError;
×
109
    }
110

111
    memcpy(&remote_addr.sin_addr, hp->h_addr, hp->h_length);
2✔
112

113
    if (connect(
2✔
114
            _socket_fd.get(),
115
            reinterpret_cast<sockaddr*>(&remote_addr),
116
            sizeof(struct sockaddr_in)) < 0) {
2✔
117
        LogErr() << "connect error: " << GET_ERROR(errno);
×
118
        return ConnectionResult::SocketConnectionError;
×
119
    }
120

121
    // Set receive timeout cross-platform
122
    const unsigned timeout_ms = 500;
2✔
123

124
#if defined(WINDOWS)
125
    setsockopt(
126
        _socket_fd.get(), SOL_SOCKET, SO_RCVTIMEO, (const char*)&timeout_ms, sizeof(timeout_ms));
127
#else
128
    struct timeval tv;
129
    tv.tv_sec = 0;
2✔
130
    tv.tv_usec = timeout_ms * 1000;
2✔
131
    setsockopt(_socket_fd.get(), SOL_SOCKET, SO_RCVTIMEO, (const void*)&tv, sizeof(tv));
2✔
132
#endif
133

134
    return ConnectionResult::Success;
2✔
135
}
136

137
void TcpClientConnection::start_recv_thread()
1✔
138
{
139
    _recv_thread = std::make_unique<std::thread>(&TcpClientConnection::receive, this);
1✔
140
}
1✔
141

142
ConnectionResult TcpClientConnection::stop()
1✔
143
{
144
    _should_exit = true;
1✔
145

146
    if (_recv_thread) {
1✔
147
        _recv_thread->join();
1✔
148
        _recv_thread.reset();
1✔
149
    }
150

151
    _socket_fd.close();
1✔
152

153
    // We need to stop this after stopping the receive thread, otherwise
154
    // it can happen that we interfere with the parsing of a message.
155
    stop_mavlink_receiver();
1✔
156

157
    return ConnectionResult::Success;
1✔
158
}
159

160
std::pair<bool, std::string> TcpClientConnection::send_message(const mavlink_message_t& message)
4✔
161
{
162
    // Convert message to raw bytes and use common send path
163
    uint8_t buffer[MAVLINK_MAX_PACKET_LEN];
164
    uint16_t buffer_len = mavlink_msg_to_send_buffer(buffer, &message);
4✔
165

166
    return send_raw_bytes(reinterpret_cast<const char*>(buffer), buffer_len);
4✔
167
}
168

169
std::pair<bool, std::string> TcpClientConnection::send_raw_bytes(const char* bytes, size_t length)
4✔
170
{
171
    std::pair<bool, std::string> result;
4✔
172

173
    if (_remote_ip.empty()) {
4✔
174
        result.first = false;
×
175
        result.second = "Remote IP unknown";
×
176
        LogErr() << result.second;
×
177
        return result;
×
178
    }
179

180
    if (_remote_port_number == 0) {
4✔
181
        result.first = false;
×
182
        result.second = "Remote port unknown";
×
183
        LogErr() << result.second;
×
184
        return result;
×
185
    }
186

187
#if !defined(MSG_NOSIGNAL)
188
    auto flags = 0;
189
#else
190
    auto flags = MSG_NOSIGNAL;
4✔
191
#endif
192

193
    const auto send_len = send(_socket_fd.get(), bytes, length, flags);
4✔
194

195
    if (send_len != static_cast<std::remove_cv_t<decltype(send_len)>>(length)) {
4✔
196
        std::stringstream ss;
×
197
        ss << "Send failure: " << GET_ERROR(errno);
×
198
        LogErr() << ss.str();
×
199
        result.first = false;
×
200
        result.second = ss.str();
×
201
        return result;
×
202
    }
×
203

204
    result.first = true;
4✔
205
    return result;
4✔
206
}
207

208
void TcpClientConnection::receive()
1✔
209
{
210
    // Enough for MTU 1500 bytes.
211
    char buffer[2048];
212

213
    while (!_should_exit) {
2✔
214
        const auto recv_len = recv(_socket_fd.get(), buffer, sizeof(buffer), 0);
1✔
215

216
        if (recv_len == 0 || (recv_len < 0 && notReady(recv_len))) {
1✔
217
            // Timeout, just try again.
UNCOV
218
            continue;
×
219
        }
220

221
        if (recv_len < 0) {
1✔
222
            LogErr() << "TCP receive error: " << GET_ERROR(errno) << ", trying to reconnect...";
1✔
223
            std::this_thread::sleep_for(std::chrono::seconds(1));
1✔
224
            setup_port();
1✔
225
            continue;
1✔
226
        }
227

UNCOV
228
        _mavlink_receiver->set_new_datagram(buffer, static_cast<int>(recv_len));
×
229

UNCOV
230
        while (_mavlink_receiver->parse_message()) {
×
UNCOV
231
            receive_message(_mavlink_receiver->get_last_message(), this);
×
232
        }
233

234
        // Also parse with libmav if available
UNCOV
235
        if (_libmav_receiver) {
×
UNCOV
236
            _libmav_receiver->set_new_datagram(buffer, static_cast<int>(recv_len));
×
237

UNCOV
238
            while (_libmav_receiver->parse_message()) {
×
UNCOV
239
                receive_libmav_message(_libmav_receiver->get_last_message(), this);
×
240
            }
241
        }
242
    }
243
}
1✔
244

245
} // namespace mavsdk
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc