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

mavlink / MAVSDK / 14793244879

02 May 2025 10:11AM UTC coverage: 44.318% (+0.1%) from 44.223%
14793244879

Pull #2542

github

web-flow
Merge fe276f187 into 2cf24f244
Pull Request #2542: Fixing thread sanitizer issues

254 of 364 new or added lines in 18 files covered. (69.78%)

77 existing lines in 8 files now uncovered.

14756 of 33296 relevant lines covered (44.32%)

291.36 hits per line

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

72.45
/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
    std::string remote_ip,
34
    int remote_port,
35
    ForwardingOption forwarding_option) :
1✔
36
    Connection(std::move(receiver_callback), forwarding_option),
1✔
37
    _remote_ip(std::move(remote_ip)),
1✔
38
    _remote_port_number(remote_port),
1✔
39
    _should_exit(false)
3✔
40
{}
1✔
41

42
TcpClientConnection::~TcpClientConnection()
2✔
43
{
44
    // If no one explicitly called stop before, we should at least do it.
45
    stop();
1✔
46
}
2✔
47

48
ConnectionResult TcpClientConnection::start()
1✔
49
{
50
    if (!start_mavlink_receiver()) {
1✔
51
        return ConnectionResult::ConnectionsExhausted;
×
52
    }
53

54
    ConnectionResult ret = setup_port();
1✔
55
    if (ret != ConnectionResult::Success) {
1✔
56
        return ret;
×
57
    }
58

59
    start_recv_thread();
1✔
60

61
    return ConnectionResult::Success;
1✔
62
}
63

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

74
    _socket_fd.reset(socket(AF_INET, SOCK_STREAM, 0));
1✔
75

76
    if (_socket_fd.empty()) {
1✔
77
        LogErr() << "socket error" << GET_ERROR(errno);
×
78
        return ConnectionResult::SocketError;
×
79
    }
80

81
    struct sockaddr_in remote_addr {};
1✔
82
    remote_addr.sin_family = AF_INET;
1✔
83
    remote_addr.sin_port = htons(_remote_port_number);
1✔
84

85
    struct hostent* hp;
86
    hp = gethostbyname(_remote_ip.c_str());
1✔
87
    if (hp == nullptr) {
1✔
88
        LogErr() << "Could not get host by name";
×
89
        return ConnectionResult::SocketConnectionError;
×
90
    }
91

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

94
    if (connect(
1✔
95
            _socket_fd.get(),
96
            reinterpret_cast<sockaddr*>(&remote_addr),
97
            sizeof(struct sockaddr_in)) < 0) {
1✔
98
        LogErr() << "connect error: " << GET_ERROR(errno);
×
99
        return ConnectionResult::SocketConnectionError;
×
100
    }
101

102
    // Set receive timeout cross-platform
103
    const unsigned timeout_ms = 500;
1✔
104

105
#if defined(WINDOWS)
106
    setsockopt(
107
        _socket_fd.get(), SOL_SOCKET, SO_RCVTIMEO, (const char*)&timeout_ms, sizeof(timeout_ms));
108
#else
109
    struct timeval tv;
1✔
110
    tv.tv_sec = 0;
1✔
111
    tv.tv_usec = timeout_ms * 1000;
1✔
112
    setsockopt(_socket_fd.get(), SOL_SOCKET, SO_RCVTIMEO, (const void*)&tv, sizeof(tv));
1✔
113
#endif
114

115
    return ConnectionResult::Success;
1✔
116
}
117

118
void TcpClientConnection::start_recv_thread()
1✔
119
{
120
    _recv_thread = std::make_unique<std::thread>(&TcpClientConnection::receive, this);
1✔
121
}
1✔
122

123
ConnectionResult TcpClientConnection::stop()
1✔
124
{
125
    _should_exit = true;
1✔
126

127
    if (_recv_thread) {
1✔
128
        _recv_thread->join();
1✔
129
        _recv_thread.reset();
1✔
130
    }
131

132
    _socket_fd.close();
1✔
133

134
    // We need to stop this after stopping the receive thread, otherwise
135
    // it can happen that we interfere with the parsing of a message.
136
    stop_mavlink_receiver();
1✔
137

138
    return ConnectionResult::Success;
1✔
139
}
140

141
std::pair<bool, std::string> TcpClientConnection::send_message(const mavlink_message_t& message)
7✔
142
{
143
    std::pair<bool, std::string> result;
7✔
144

145
    if (_remote_ip.empty()) {
7✔
UNCOV
146
        result.first = false;
×
147
        result.second = "Remote IP unknown";
×
148
        LogErr() << result.second;
×
149
        return result;
×
150
    }
151

152
    if (_remote_port_number == 0) {
7✔
153
        result.first = false;
×
154
        result.second = "Remote port unknown";
×
155
        LogErr() << result.second;
×
156
        return result;
×
157
    }
158

159
    struct sockaddr_in dest_addr {};
7✔
160
    dest_addr.sin_family = AF_INET;
7✔
161

162
    inet_pton(AF_INET, _remote_ip.c_str(), &dest_addr.sin_addr.s_addr);
7✔
163

164
    dest_addr.sin_port = htons(_remote_port_number);
7✔
165

166
    uint8_t buffer[MAVLINK_MAX_PACKET_LEN];
7✔
167
    uint16_t buffer_len = mavlink_msg_to_send_buffer(buffer, &message);
7✔
168

169
    // TODO: remove this assert again
170
    assert(buffer_len <= MAVLINK_MAX_PACKET_LEN);
7✔
171

172
#if !defined(MSG_NOSIGNAL)
173
    auto flags = 0;
174
#else
175
    auto flags = MSG_NOSIGNAL;
7✔
176
#endif
177

178
    const auto send_len =
179
        send(_socket_fd.get(), reinterpret_cast<const char*>(buffer), buffer_len, flags);
7✔
180

181
    if (send_len != buffer_len) {
7✔
182
        std::stringstream ss;
×
183
        ss << "Send failure: " << GET_ERROR(errno);
×
184
        LogErr() << ss.str();
×
185
        result.first = false;
×
186
        result.second = ss.str();
×
187
        return result;
×
188
    }
×
189

190
    result.first = true;
7✔
191
    return result;
7✔
192
}
193

194
void TcpClientConnection::receive()
1✔
195
{
196
    // Enough for MTU 1500 bytes.
197
    char buffer[2048];
1✔
198

199
    while (!_should_exit) {
7✔
200
        const auto recv_len = recv(_socket_fd.get(), buffer, sizeof(buffer), 0);
6✔
201

202
        if (recv_len == 0 || (recv_len < 0 && (errno == EAGAIN || errno == ETIMEDOUT))) {
6✔
203
            // Timeout, just try again.
204
            continue;
3✔
205
        }
206

207
        if (recv_len < 0) {
3✔
NEW
208
            LogErr() << "TCP receive error: " << GET_ERROR(errno) << ", trying to reeconnect...";
×
NEW
209
            std::this_thread::sleep_for(std::chrono::seconds(1));
×
NEW
210
            setup_port();
×
UNCOV
211
            continue;
×
212
        }
213

214
        _mavlink_receiver->set_new_datagram(buffer, static_cast<int>(recv_len));
3✔
215

216
        while (_mavlink_receiver->parse_message()) {
6✔
217
            receive_message(_mavlink_receiver->get_last_message(), this);
3✔
218
        }
219
    }
220
}
1✔
221

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