Skip to content

Commit 73b42d3

Browse files
fibonacci-matrixJonasVautherinjulianoes
committed
core: Correctly close sockets (#2357)
* core: Correctly close sockets * Update socket_holder.cpp - Fix newline style * Update socket_holder.cpp * Update src/mavsdk/core/tcp_client_connection.cpp Co-authored-by: Jonas Vautherin <[email protected]> * Update socket_holder.cpp - fix code style * Update tcp_client_connection.cpp - fix code style * Update tcp_server_connection.cpp - fix code style * Update socket_holder.h - fix code style * Update src/mavsdk/core/socket_holder.h Co-authored-by: Julian Oes <[email protected]> * Update socket_holder.h - use 64 bit descriptor type on Win64 * Update socket_holder.cpp - use 64 bit descriptor type on Win64 * Update socket_holder.cpp - minor improving of if logic * Remove default move constructor It is currently not in use, and the default implementation is not suitable because it does not change _fd to INVALID for the object being copied from --------- Co-authored-by: Jonas Vautherin <[email protected]> Co-authored-by: Julian Oes <[email protected]>
1 parent 93b91d6 commit 73b42d3

7 files changed

+114
-50
lines changed

src/mavsdk/core/CMakeLists.txt

+1
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ target_sources(mavsdk
5151
server_component_impl.cpp
5252
server_plugin_impl_base.cpp
5353
tcp_connection.cpp
54+
socket_holder.cpp
5455
timeout_handler.cpp
5556
udp_connection.cpp
5657
log.cpp

src/mavsdk/core/socket_holder.cpp

+53
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
#include "socket_holder.h"
2+
3+
#ifndef WINDOWS
4+
#include <sys/socket.h>
5+
#include <unistd.h>
6+
#endif
7+
8+
namespace mavsdk {
9+
10+
SocketHolder::SocketHolder(DescriptorType fd) noexcept : _fd{fd} {}
11+
12+
SocketHolder::~SocketHolder() noexcept
13+
{
14+
close();
15+
}
16+
17+
void SocketHolder::reset(DescriptorType fd) noexcept
18+
{
19+
if (_fd != fd) {
20+
close();
21+
_fd = fd;
22+
}
23+
}
24+
25+
void SocketHolder::close() noexcept
26+
{
27+
if (!empty()) {
28+
#if defined(WINDOWS)
29+
shutdown(_fd, SD_BOTH);
30+
closesocket(_fd);
31+
WSACleanup();
32+
#else
33+
// This should interrupt a recv/recvfrom call.
34+
shutdown(_fd, SHUT_RDWR);
35+
36+
// But on Mac, closing is also needed to stop blocking recv/recvfrom.
37+
::close(_fd);
38+
#endif
39+
_fd = invalid_socket_fd;
40+
}
41+
}
42+
43+
bool SocketHolder::empty() const noexcept
44+
{
45+
return _fd == invalid_socket_fd;
46+
}
47+
48+
SocketHolder::DescriptorType SocketHolder::get() const noexcept
49+
{
50+
return _fd;
51+
}
52+
53+
} // namespace mavsdk

src/mavsdk/core/socket_holder.h

+37
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
#pragma once
2+
3+
#if defined(WINDOWS)
4+
#include <winsock2.h>
5+
#endif
6+
7+
namespace mavsdk {
8+
9+
class SocketHolder {
10+
public:
11+
#if defined(WINDOWS)
12+
using DescriptorType = SOCKET;
13+
static constexpr DescriptorType invalid_socket_fd = INVALID_SOCKET;
14+
#else
15+
using DescriptorType = int;
16+
static constexpr DescriptorType invalid_socket_fd = -1;
17+
#endif
18+
19+
SocketHolder() noexcept = default;
20+
explicit SocketHolder(DescriptorType socket_fd) noexcept;
21+
22+
~SocketHolder() noexcept;
23+
24+
void reset(DescriptorType fd) noexcept;
25+
void close() noexcept;
26+
27+
bool empty() const noexcept;
28+
DescriptorType get() const noexcept;
29+
30+
private:
31+
SocketHolder(const SocketHolder&) = delete;
32+
SocketHolder& operator=(const SocketHolder&) = delete;
33+
34+
DescriptorType _fd = invalid_socket_fd;
35+
};
36+
37+
} // namespace mavsdk

src/mavsdk/core/tcp_connection.cpp

+10-21
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@
1111
#include <arpa/inet.h>
1212
#include <errno.h>
1313
#include <netdb.h>
14-
#include <unistd.h> // for close()
1514
#endif
1615

1716
#include <cassert>
@@ -70,9 +69,9 @@ ConnectionResult TcpConnection::setup_port()
7069
}
7170
#endif
7271

73-
_socket_fd = socket(AF_INET, SOCK_STREAM, 0);
72+
_socket_fd.reset(socket(AF_INET, SOCK_STREAM, 0));
7473

75-
if (_socket_fd < 0) {
74+
if (_socket_fd.empty()) {
7675
LogErr() << "socket error" << GET_ERROR(errno);
7776
_is_ok = false;
7877
return ConnectionResult::SocketError;
@@ -92,8 +91,10 @@ ConnectionResult TcpConnection::setup_port()
9291

9392
memcpy(&remote_addr.sin_addr, hp->h_addr, hp->h_length);
9493

95-
if (connect(_socket_fd, reinterpret_cast<sockaddr*>(&remote_addr), sizeof(struct sockaddr_in)) <
96-
0) {
94+
if (connect(
95+
_socket_fd.get(),
96+
reinterpret_cast<sockaddr*>(&remote_addr),
97+
sizeof(struct sockaddr_in)) < 0) {
9798
LogErr() << "connect error: " << GET_ERROR(errno);
9899
_is_ok = false;
99100
return ConnectionResult::SocketConnectionError;
@@ -112,19 +113,7 @@ ConnectionResult TcpConnection::stop()
112113
{
113114
_should_exit = true;
114115

115-
#ifndef WINDOWS
116-
// This should interrupt a recv/recvfrom call.
117-
shutdown(_socket_fd, SHUT_RDWR);
118-
119-
// But on Mac, closing is also needed to stop blocking recv/recvfrom.
120-
close(_socket_fd);
121-
#else
122-
shutdown(_socket_fd, SD_BOTH);
123-
124-
closesocket(_socket_fd);
125-
126-
WSACleanup();
127-
#endif
116+
_socket_fd.close();
128117

129118
if (_recv_thread) {
130119
_recv_thread->join();
@@ -174,7 +163,7 @@ bool TcpConnection::send_message(const mavlink_message_t& message)
174163
#endif
175164

176165
const auto send_len = sendto(
177-
_socket_fd,
166+
_socket_fd.get(),
178167
reinterpret_cast<char*>(buffer),
179168
buffer_len,
180169
flags,
@@ -201,7 +190,7 @@ void TcpConnection::receive()
201190
setup_port();
202191
}
203192

204-
const auto recv_len = recv(_socket_fd, buffer, sizeof(buffer), 0);
193+
const auto recv_len = recv(_socket_fd.get(), buffer, sizeof(buffer), 0);
205194

206195
if (recv_len == 0) {
207196
// This can happen when shutdown is called on the socket,
@@ -211,7 +200,7 @@ void TcpConnection::receive()
211200
}
212201

213202
if (recv_len < 0) {
214-
// This happens on desctruction when close(_socket_fd) is called,
203+
// This happens on destruction when close(_socket_fd.get()) is called,
215204
// therefore be quiet.
216205
// LogErr() << "recvfrom error: " << GET_ERROR(errno);
217206
// Something went wrong, we should try to re-connect in next iteration.

src/mavsdk/core/tcp_connection.h

+3-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
#pragma once
22

3+
#include "socket_holder.h"
4+
35
#include <atomic>
46
#include <mutex>
57
#include <memory>
@@ -43,7 +45,7 @@ class TcpConnection : public Connection {
4345
int _remote_port_number;
4446

4547
std::mutex _mutex = {};
46-
int _socket_fd = -1;
48+
SocketHolder _socket_fd;
4749

4850
std::unique_ptr<std::thread> _recv_thread{};
4951
std::atomic_bool _should_exit;

src/mavsdk/core/udp_connection.cpp

+7-27
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@
1313
#include <sys/socket.h>
1414
#include <arpa/inet.h>
1515
#include <errno.h>
16-
#include <unistd.h> // for close()
1716
#endif
1817

1918
#include <algorithm>
@@ -69,9 +68,9 @@ ConnectionResult UdpConnection::setup_port()
6968
}
7069
#endif
7170

72-
_socket_fd = socket(AF_INET, SOCK_DGRAM, 0);
71+
_socket_fd.reset(socket(AF_INET, SOCK_DGRAM, 0));
7372

74-
if (_socket_fd < 0) {
73+
if (_socket_fd.empty()) {
7574
LogErr() << "socket error" << GET_ERROR(errno);
7675
return ConnectionResult::SocketError;
7776
}
@@ -81,7 +80,7 @@ ConnectionResult UdpConnection::setup_port()
8180
inet_pton(AF_INET, _local_ip.c_str(), &(addr.sin_addr));
8281
addr.sin_port = htons(_local_port_number);
8382

84-
if (bind(_socket_fd, reinterpret_cast<sockaddr*>(&addr), sizeof(addr)) != 0) {
83+
if (bind(_socket_fd.get(), reinterpret_cast<sockaddr*>(&addr), sizeof(addr)) != 0) {
8584
LogErr() << "bind error: " << GET_ERROR(errno);
8685
return ConnectionResult::BindError;
8786
}
@@ -98,32 +97,13 @@ ConnectionResult UdpConnection::stop()
9897
{
9998
_should_exit = true;
10099

101-
#if !defined(WINDOWS)
102-
// This should interrupt a recv/recvfrom call.
103-
shutdown(_socket_fd, SHUT_RDWR);
104-
105-
#if defined(APPLE)
106-
// But on Mac, closing is also needed to stop blocking recv/recvfrom.
107-
close(_socket_fd);
108-
#endif
109-
#else
110-
shutdown(_socket_fd, SD_BOTH);
111-
112-
closesocket(_socket_fd);
113-
114-
WSACleanup();
115-
#endif
100+
_socket_fd.close();
116101

117102
if (_recv_thread) {
118103
_recv_thread->join();
119104
_recv_thread.reset();
120105
}
121106

122-
#if !defined(WINDOWS) & !defined(APPLE)
123-
// On Linux we can close later to avoid thread sanitizer from complaining.
124-
close(_socket_fd);
125-
#endif
126-
127107
// We need to stop this after stopping the receive thread, otherwise
128108
// it can happen that we interfere with the parsing of a message.
129109
stop_mavlink_receiver();
@@ -157,7 +137,7 @@ bool UdpConnection::send_message(const mavlink_message_t& message)
157137
uint16_t buffer_len = mavlink_msg_to_send_buffer(buffer, &message);
158138

159139
const auto send_len = sendto(
160-
_socket_fd,
140+
_socket_fd.get(),
161141
reinterpret_cast<char*>(buffer),
162142
buffer_len,
163143
0,
@@ -212,7 +192,7 @@ void UdpConnection::receive()
212192
struct sockaddr_in src_addr = {};
213193
socklen_t src_addr_len = sizeof(src_addr);
214194
const auto recv_len = recvfrom(
215-
_socket_fd,
195+
_socket_fd.get(),
216196
buffer,
217197
sizeof(buffer),
218198
0,
@@ -226,7 +206,7 @@ void UdpConnection::receive()
226206
}
227207

228208
if (recv_len < 0) {
229-
// This happens on destruction when close(_socket_fd) is called,
209+
// This happens on destruction when _socket_fd.close() is called,
230210
// therefore be quiet.
231211
// LogErr() << "recvfrom error: " << GET_ERROR(errno);
232212
continue;

src/mavsdk/core/udp_connection.h

+3-1
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,9 @@
77
#include <atomic>
88
#include <vector>
99
#include <cstdint>
10+
1011
#include "connection.h"
12+
#include "socket_holder.h"
1113

1214
namespace mavsdk {
1315

@@ -54,7 +56,7 @@ class UdpConnection : public Connection {
5456
};
5557
std::vector<Remote> _remotes{};
5658

57-
int _socket_fd{-1};
59+
SocketHolder _socket_fd;
5860
std::unique_ptr<std::thread> _recv_thread{};
5961
std::atomic_bool _should_exit{false};
6062
};

0 commit comments

Comments
 (0)