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

mavlink / MAVSDK / 16247473021

13 Jul 2025 09:04AM UTC coverage: 46.353% (+1.1%) from 45.212%
16247473021

Pull #2610

github

web-flow
Merge 679f9a2e4 into 6c112e71f
Pull Request #2610: Integrate parts of libmav into MAVSDK and add MavlinkDirect plugin

797 of 1029 new or added lines in 15 files covered. (77.45%)

26 existing lines in 5 files now uncovered.

16286 of 35135 relevant lines covered (46.35%)

147452.99 hits per line

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

73.64
/src/mavsdk/core/tcp_server_connection.cpp
1
#include "tcp_server_connection.h"
2
#include "log.h"
3

4
#include <cassert>
5
#include <fcntl.h>
6
#include <sstream>
7

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

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

30
namespace mavsdk {
UNCOV
31
TcpServerConnection::TcpServerConnection(
×
32
    Connection::ReceiverCallback receiver_callback,
33
    std::string local_ip,
34
    int local_port,
UNCOV
35
    ForwardingOption forwarding_option) :
×
UNCOV
36
    Connection(std::move(receiver_callback), forwarding_option),
×
UNCOV
37
    _local_ip(std::move(local_ip)),
×
UNCOV
38
    _local_port(local_port)
×
UNCOV
39
{}
×
40

41
TcpServerConnection::TcpServerConnection(
1✔
42
    Connection::ReceiverCallback receiver_callback,
43
    Connection::LibmavReceiverCallback libmav_receiver_callback,
44
    std::string local_ip,
45
    int local_port,
46
    ForwardingOption forwarding_option) :
1✔
47
    Connection(
48
        std::move(receiver_callback), std::move(libmav_receiver_callback), forwarding_option),
2✔
49
    _local_ip(std::move(local_ip)),
1✔
50
    _local_port(local_port)
4✔
51
{}
1✔
52

53
TcpServerConnection::~TcpServerConnection()
2✔
54
{
55
    stop();
1✔
56
}
2✔
57

58
ConnectionResult TcpServerConnection::start()
1✔
59
{
60
    if (!start_mavlink_receiver()) {
1✔
61
        return ConnectionResult::ConnectionsExhausted;
×
62
    }
63

64
#ifdef WINDOWS
65
    WSADATA wsa;
66
    if (WSAStartup(MAKEWORD(2, 2), &wsa) != 0) {
67
        LogErr() << "Error: Winsock failed, error: " << WSAGetLastError();
68
        return ConnectionResult::SocketError;
69
    }
70
#endif
71

72
    _server_socket_fd.reset(socket(AF_INET, SOCK_STREAM, 0));
1✔
73
    if (_server_socket_fd.empty()) {
1✔
74
        LogErr() << "socket error: " << GET_ERROR(errno);
×
75
        return ConnectionResult::SocketError;
×
76
    }
77

78
    sockaddr_in server_addr{};
1✔
79
    server_addr.sin_family = AF_INET;
1✔
80
    server_addr.sin_addr.s_addr = INADDR_ANY;
1✔
81
    server_addr.sin_port = htons(_local_port);
1✔
82

83
    if (bind(
1✔
84
            _server_socket_fd.get(),
85
            reinterpret_cast<sockaddr*>(&server_addr),
86
            sizeof(server_addr)) < 0) {
1✔
87
        LogErr() << "bind error: " << GET_ERROR(errno);
×
88
        return ConnectionResult::SocketError;
×
89
    }
90

91
    if (listen(_server_socket_fd.get(), 3) < 0) {
1✔
92
        LogErr() << "listen error: " << GET_ERROR(errno);
×
93
        return ConnectionResult::SocketError;
×
94
    }
95

96
    // Set receive timeout cross-platform
97
    const unsigned timeout_ms = 500;
1✔
98

99
#if defined(WINDOWS)
100
    setsockopt(
101
        _server_socket_fd.get(),
102
        SOL_SOCKET,
103
        SO_RCVTIMEO,
104
        (const char*)&timeout_ms,
105
        sizeof(timeout_ms));
106
    setsockopt(
107
        _client_socket_fd.get(),
108
        SOL_SOCKET,
109
        SO_RCVTIMEO,
110
        (const char*)&timeout_ms,
111
        sizeof(timeout_ms));
112
#else
113
    struct timeval tv;
1✔
114
    tv.tv_sec = 0;
1✔
115
    tv.tv_usec = timeout_ms * 1000;
1✔
116
    setsockopt(_server_socket_fd.get(), SOL_SOCKET, SO_RCVTIMEO, (const void*)&tv, sizeof(tv));
1✔
117
    setsockopt(_client_socket_fd.get(), SOL_SOCKET, SO_RCVTIMEO, (const void*)&tv, sizeof(tv));
1✔
118
#endif
119

120
    _accept_receive_thread =
1✔
121
        std::make_unique<std::thread>(&TcpServerConnection::accept_client, this);
1✔
122

123
    return ConnectionResult::Success;
1✔
124
}
125

126
ConnectionResult TcpServerConnection::stop()
1✔
127
{
128
    _should_exit = true;
1✔
129

130
    if (_accept_receive_thread && _accept_receive_thread->joinable()) {
1✔
131
        _accept_receive_thread->join();
1✔
132
        _accept_receive_thread.reset();
1✔
133
    }
134

135
    _client_socket_fd.close();
1✔
136
    _server_socket_fd.close();
1✔
137

138
    // We need to stop this after stopping the receive thread, otherwise
139
    // it can happen that we interfere with the parsing of a message.
140
    stop_mavlink_receiver();
1✔
141

142
    return ConnectionResult::Success;
1✔
143
}
144

145
std::pair<bool, std::string> TcpServerConnection::send_message(const mavlink_message_t& message)
7✔
146
{
147
    std::pair<bool, std::string> result;
7✔
148

149
    uint8_t buffer[MAVLINK_MAX_PACKET_LEN];
7✔
150
    uint16_t buffer_len = mavlink_msg_to_send_buffer(buffer, &message);
7✔
151

152
    assert(buffer_len <= MAVLINK_MAX_PACKET_LEN);
7✔
153

154
#if !defined(MSG_NOSIGNAL)
155
    auto flags = 0;
156
#else
157
    auto flags = MSG_NOSIGNAL;
7✔
158
#endif
159

160
    const auto send_len =
161
        send(_client_socket_fd.get(), reinterpret_cast<const char*>(buffer), buffer_len, flags);
7✔
162

163
    if (send_len != buffer_len) {
7✔
164
        std::stringstream ss;
×
165
        ss << "Send failure: " << GET_ERROR(errno);
×
166
        LogErr() << ss.str();
×
167
        result.first = false;
×
168
        result.second = ss.str();
×
169
        return result;
×
170
    }
×
171

172
    result.first = true;
7✔
173
    return result;
7✔
174
}
175

176
void TcpServerConnection::accept_client()
1✔
177
{
178
#ifdef WINDOWS
179
    // Set server socket to non-blocking
180
    u_long iMode = 1;
181
    int iResult = ioctlsocket(_server_socket_fd.get(), FIONBIO, &iMode);
182
    if (iResult != 0) {
183
        LogErr() << "ioctlsocket failed with error: " << WSAGetLastError();
184
    }
185
#else
186
    // Set server socket to non-blocking
187
    int flags = fcntl(_server_socket_fd.get(), F_GETFL, 0);
1✔
188
    fcntl(_server_socket_fd.get(), F_SETFL, flags | O_NONBLOCK);
1✔
189
#endif
190

191
    while (!_should_exit) {
2✔
192
        fd_set readfds;
1✔
193
        FD_ZERO(&readfds);
17✔
194
        FD_SET(_server_socket_fd.get(), &readfds);
1✔
195

196
        // Set timeout to 1 second
197
        timeval timeout;
1✔
198
        timeout.tv_sec = 1;
1✔
199
        timeout.tv_usec = 0;
1✔
200

201
        const int activity =
202
            select(_server_socket_fd.get() + 1, &readfds, nullptr, nullptr, &timeout);
1✔
203

204
        if (activity < 0 && errno != EINTR) {
1✔
205
            LogErr() << "select error: " << GET_ERROR(errno);
×
206
            continue;
×
207
        }
208

209
        if (activity == 0) {
1✔
210
            // Timeout, no incoming connection
211
            continue;
×
212
        }
213

214
        if (FD_ISSET(_server_socket_fd.get(), &readfds)) {
1✔
215
            sockaddr_in client_addr{};
1✔
216
            socklen_t client_addr_len = sizeof(client_addr);
1✔
217

218
            _client_socket_fd.reset(accept(
1✔
219
                _server_socket_fd.get(),
220
                reinterpret_cast<sockaddr*>(&client_addr),
221
                &client_addr_len));
222
            if (_client_socket_fd.empty()) {
1✔
223
                if (_should_exit) {
×
224
                    return;
×
225
                }
226
                LogErr() << "accept error: " << GET_ERROR(errno);
×
227
                continue;
×
228
            }
229

230
            receive();
1✔
231
        }
232
    }
233
}
234

235
void TcpServerConnection::receive()
1✔
236
{
237
    std::array<char, 2048> buffer{};
1✔
238

239
    bool dataReceived = false;
1✔
240
    while (!dataReceived && !_should_exit) {
10,607✔
241
        const auto recv_len = recv(_client_socket_fd.get(), buffer.data(), buffer.size(), 0);
10,606✔
242

243
#ifdef WINDOWS
244
        if (recv_len == SOCKET_ERROR) {
245
            // On Windows, on the first try, select says there is something
246
            // but recv doesn't succeed yet, and we just need to try again.
247
            if (WSAGetLastError() == WSAEWOULDBLOCK) {
248
                std::this_thread::sleep_for(std::chrono::milliseconds(10));
249
                continue;
250
            }
251
            // And at the end, we get an abort that we can silently ignore.
252
            if (WSAGetLastError() == WSAECONNABORTED) {
253
                return;
254
            }
255
        }
256
#else
257
        if (recv_len < 0) {
10,606✔
258
            // On macOS we presumably see the same thing, and have to try again.
259
            if (errno == EAGAIN) {
2✔
260
                std::this_thread::sleep_for(std::chrono::milliseconds(10));
2✔
261
                continue;
2✔
262
            }
263

264
            LogErr() << "recv failed: " << GET_ERROR(errno);
×
265
            return;
×
266
        }
267
#endif
268

269
        if (recv_len == 0) {
10,604✔
270
            continue;
10,593✔
271
        }
272

273
        _mavlink_receiver->set_new_datagram(buffer.data(), static_cast<int>(recv_len));
11✔
274

275
        // Parse all mavlink messages in one data packet. Once exhausted, we'll exit while.
276
        while (_mavlink_receiver->parse_message()) {
23✔
277
            receive_message(_mavlink_receiver->get_last_message(), this);
12✔
278
        }
279
    }
280
}
281

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