forked from andreasbuhr/cppcoro
-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathsocket_send_to_operation.cpp
More file actions
102 lines (91 loc) · 3.12 KB
/
Copy pathsocket_send_to_operation.cpp
File metadata and controls
102 lines (91 loc) · 3.12 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
///////////////////////////////////////////////////////////////////////////////
// Copyright (c) Lewis Baker
// Licenced under MIT license. See LICENSE.txt for details.
///////////////////////////////////////////////////////////////////////////////
#include <cppcoro/net/socket_send_to_operation.hpp>
#include <cppcoro/net/socket.hpp>
#include "socket_helpers.hpp"
#if CPPCORO_OS_WINNT
# include <winsock2.h>
# include <ws2tcpip.h>
# include <mswsock.h>
# include <windows.h>
bool cppcoro::net::socket_send_to_operation_impl::try_start(
cppcoro::detail::win32_overlapped_operation_base& operation) noexcept
{
// Need to read this flag before starting the operation, otherwise
// it may be possible that the operation will complete immediately
// on another thread and then destroy the socket before we get a
// chance to read it.
const bool skipCompletionOnSuccess = m_socket.skip_completion_on_success();
SOCKADDR_STORAGE destinationAddress;
const int destinationLength = detail::ip_endpoint_to_sockaddr(
m_destination, std::ref(destinationAddress));
DWORD numberOfBytesSent = 0;
int result = ::WSASendTo(
m_socket.native_handle(),
reinterpret_cast<WSABUF*>(&m_buffer),
1, // buffer count
&numberOfBytesSent,
0, // flags
reinterpret_cast<const SOCKADDR*>(&destinationAddress),
destinationLength,
operation.get_overlapped(),
nullptr);
if (result == SOCKET_ERROR)
{
int errorCode = ::WSAGetLastError();
if (errorCode != WSA_IO_PENDING)
{
// Failed synchronously.
operation.m_errorCode = static_cast<DWORD>(errorCode);
operation.m_numberOfBytesTransferred = numberOfBytesSent;
return false;
}
}
else if (skipCompletionOnSuccess)
{
// Completed synchronously, no completion event will be posted to the IOCP.
operation.m_errorCode = ERROR_SUCCESS;
operation.m_numberOfBytesTransferred = numberOfBytesSent;
return false;
}
// Operation will complete asynchronously.
return true;
}
void cppcoro::net::socket_send_to_operation_impl::cancel(
cppcoro::detail::win32_overlapped_operation_base& operation) noexcept
{
(void)::CancelIoEx(
reinterpret_cast<HANDLE>(m_socket.native_handle()),
operation.get_overlapped());
}
#elif CPPCORO_OS_LINUX
# include <sys/socket.h>
# include <netinet/in.h>
# include <netinet/tcp.h>
# include <netinet/udp.h>
bool cppcoro::net::socket_send_to_operation_impl::try_start(
cppcoro::detail::linux_async_operation_base& operation) noexcept
{
sockaddr_storage destinationAddress = {0};
const socklen_t destinationLength = detail::ip_endpoint_to_sockaddr(
m_destination, std::ref(destinationAddress));
operation.m_completeFunc = [=]() {
int res = sendto(
m_socket.native_handle(), m_buffer, m_byteCount, 0,
reinterpret_cast<const sockaddr*>(&destinationAddress),
destinationLength
);
operation.m_mq->remove_fd_watch(m_socket.native_handle());
return res;
};
operation.m_mq->add_fd_watch(m_socket.native_handle(), reinterpret_cast<void*>(&operation), EPOLLOUT);
return true;
}
void cppcoro::net::socket_send_to_operation_impl::cancel(
cppcoro::detail::linux_async_operation_base& operation) noexcept
{
operation.m_mq->remove_fd_watch(m_socket.native_handle());
}
#endif