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

mavlink / MAVSDK / 16483523487

23 Jul 2025 10:53PM UTC coverage: 46.331% (+1.2%) from 45.096%
16483523487

Pull #2610

github

web-flow
Merge fefa7691c into 743ca7d9c
Pull Request #2610: Integrate parts of libmav into MAVSDK and add MavlinkDirect plugin

764 of 986 new or added lines in 14 files covered. (77.48%)

10 existing lines in 1 file now uncovered.

16272 of 35121 relevant lines covered (46.33%)

360.85 hits per line

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

72.28
/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
/* change to remote_ip and remote_port */
31
TcpClientConnection::TcpClientConnection(
1✔
32
    Connection::ReceiverCallback receiver_callback,
33
    Connection::LibmavReceiverCallback libmav_receiver_callback,
34
    mav::MessageSet& message_set,
35
    std::string remote_ip,
36
    int remote_port,
37
    ForwardingOption forwarding_option) :
1✔
38
    Connection(
39
        std::move(receiver_callback),
1✔
40
        std::move(libmav_receiver_callback),
1✔
41
        message_set,
42
        forwarding_option),
43
    _remote_ip(std::move(remote_ip)),
1✔
44
    _remote_port_number(remote_port),
1✔
45
    _should_exit(false)
4✔
46
{}
1✔
47

48
TcpClientConnection::~TcpClientConnection()
2✔
49
{
50
    // If no one explicitly called stop before, we should at least do it.
51
    stop();
1✔
52
}
2✔
53

54
ConnectionResult TcpClientConnection::start()
1✔
55
{
56
    if (!start_mavlink_receiver()) {
1✔
57
        return ConnectionResult::ConnectionsExhausted;
×
58
    }
59

60
    if (!start_libmav_receiver()) {
1✔
NEW
61
        return ConnectionResult::ConnectionsExhausted;
×
62
    }
63

64
    ConnectionResult ret = setup_port();
1✔
65
    if (ret != ConnectionResult::Success) {
1✔
66
        return ret;
×
67
    }
68

69
    start_recv_thread();
1✔
70

71
    return ConnectionResult::Success;
1✔
72
}
73

74
ConnectionResult TcpClientConnection::setup_port()
1✔
75
{
76
#ifdef WINDOWS
77
    WSADATA wsa;
78
    if (WSAStartup(MAKEWORD(2, 2), &wsa) != 0) {
79
        LogErr() << "Error: Winsock failed, error: %d", WSAGetLastError();
80
        return ConnectionResult::SocketError;
81
    }
82
#endif
83

84
    _socket_fd.reset(socket(AF_INET, SOCK_STREAM, 0));
1✔
85

86
    if (_socket_fd.empty()) {
1✔
87
        LogErr() << "socket error" << GET_ERROR(errno);
×
88
        return ConnectionResult::SocketError;
×
89
    }
90

91
    struct sockaddr_in remote_addr {};
1✔
92
    remote_addr.sin_family = AF_INET;
1✔
93
    remote_addr.sin_port = htons(_remote_port_number);
1✔
94

95
    struct hostent* hp;
96
    hp = gethostbyname(_remote_ip.c_str());
1✔
97
    if (hp == nullptr) {
1✔
98
        LogErr() << "Could not get host by name";
×
99
        return ConnectionResult::SocketConnectionError;
×
100
    }
101

102
    memcpy(&remote_addr.sin_addr, hp->h_addr, hp->h_length);
1✔
103

104
    if (connect(
1✔
105
            _socket_fd.get(),
106
            reinterpret_cast<sockaddr*>(&remote_addr),
107
            sizeof(struct sockaddr_in)) < 0) {
1✔
108
        LogErr() << "connect error: " << GET_ERROR(errno);
×
109
        return ConnectionResult::SocketConnectionError;
×
110
    }
111

112
    // Set receive timeout cross-platform
113
    const unsigned timeout_ms = 500;
1✔
114

115
#if defined(WINDOWS)
116
    setsockopt(
117
        _socket_fd.get(), SOL_SOCKET, SO_RCVTIMEO, (const char*)&timeout_ms, sizeof(timeout_ms));
118
#else
119
    struct timeval tv;
1✔
120
    tv.tv_sec = 0;
1✔
121
    tv.tv_usec = timeout_ms * 1000;
1✔
122
    setsockopt(_socket_fd.get(), SOL_SOCKET, SO_RCVTIMEO, (const void*)&tv, sizeof(tv));
1✔
123
#endif
124

125
    return ConnectionResult::Success;
1✔
126
}
127

128
void TcpClientConnection::start_recv_thread()
1✔
129
{
130
    _recv_thread = std::make_unique<std::thread>(&TcpClientConnection::receive, this);
1✔
131
}
1✔
132

133
ConnectionResult TcpClientConnection::stop()
1✔
134
{
135
    _should_exit = true;
1✔
136

137
    if (_recv_thread) {
1✔
138
        _recv_thread->join();
1✔
139
        _recv_thread.reset();
1✔
140
    }
141

142
    _socket_fd.close();
1✔
143

144
    // We need to stop this after stopping the receive thread, otherwise
145
    // it can happen that we interfere with the parsing of a message.
146
    stop_mavlink_receiver();
1✔
147

148
    return ConnectionResult::Success;
1✔
149
}
150

151
std::pair<bool, std::string> TcpClientConnection::send_message(const mavlink_message_t& message)
12✔
152
{
153
    std::pair<bool, std::string> result;
12✔
154

155
    if (_remote_ip.empty()) {
12✔
156
        result.first = false;
×
157
        result.second = "Remote IP unknown";
×
158
        LogErr() << result.second;
×
159
        return result;
×
160
    }
161

162
    if (_remote_port_number == 0) {
12✔
163
        result.first = false;
×
164
        result.second = "Remote port unknown";
×
165
        LogErr() << result.second;
×
166
        return result;
×
167
    }
168

169
    struct sockaddr_in dest_addr {};
12✔
170
    dest_addr.sin_family = AF_INET;
12✔
171

172
    inet_pton(AF_INET, _remote_ip.c_str(), &dest_addr.sin_addr.s_addr);
12✔
173

174
    dest_addr.sin_port = htons(_remote_port_number);
12✔
175

176
    uint8_t buffer[MAVLINK_MAX_PACKET_LEN];
12✔
177
    uint16_t buffer_len = mavlink_msg_to_send_buffer(buffer, &message);
12✔
178

179
    // TODO: remove this assert again
180
    assert(buffer_len <= MAVLINK_MAX_PACKET_LEN);
12✔
181

182
#if !defined(MSG_NOSIGNAL)
183
    auto flags = 0;
184
#else
185
    auto flags = MSG_NOSIGNAL;
12✔
186
#endif
187

188
    const auto send_len =
189
        send(_socket_fd.get(), reinterpret_cast<const char*>(buffer), buffer_len, flags);
12✔
190

191
    if (send_len != buffer_len) {
12✔
192
        std::stringstream ss;
×
193
        ss << "Send failure: " << GET_ERROR(errno);
×
194
        LogErr() << ss.str();
×
195
        result.first = false;
×
196
        result.second = ss.str();
×
197
        return result;
×
198
    }
×
199

200
    result.first = true;
12✔
201
    return result;
12✔
202
}
203

204
void TcpClientConnection::receive()
1✔
205
{
206
    // Enough for MTU 1500 bytes.
207
    char buffer[2048];
1✔
208

209
    while (!_should_exit) {
10✔
210
        const auto recv_len = recv(_socket_fd.get(), buffer, sizeof(buffer), 0);
9✔
211

212
        if (recv_len == 0 || (recv_len < 0 && (errno == EAGAIN || errno == ETIMEDOUT))) {
9✔
213
            // Timeout, just try again.
214
            continue;
2✔
215
        }
216

217
        if (recv_len < 0) {
7✔
218
            LogErr() << "TCP receive error: " << GET_ERROR(errno) << ", trying to reeconnect...";
×
219
            std::this_thread::sleep_for(std::chrono::seconds(1));
×
220
            setup_port();
×
221
            continue;
×
222
        }
223

224
        _mavlink_receiver->set_new_datagram(buffer, static_cast<int>(recv_len));
7✔
225

226
        while (_mavlink_receiver->parse_message()) {
14✔
227
            receive_message(_mavlink_receiver->get_last_message(), this);
7✔
228
        }
229
    }
230
}
1✔
231

232
} // 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