stream_socket.cpp
3.08 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
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
#include "socket-cpp/stream_socket.h"
#include "socket-cpp/exception.h"
#include <algorithm>
#include <memory>
using namespace std::chrono;
namespace socket-cpp {
stream_socket stream_socket::create(int domain, int protocol /*=0*/)
{
stream_socket sock(::socket(domain, COMM_TYPE, protocol));
if (!sock)
sock.clear(get_last_error());
return sock;
}
ssize_t stream_socket::read(void *buf, size_t n)
{
#if defined(_WIN32)
return check_ret(::recv(handle(), reinterpret_cast<char*>(buf),
int(n), 0));
#else
return check_ret(::recv(handle(), buf, n, 0));
#endif
}
ssize_t stream_socket::read_n(void *buf, size_t n)
{
size_t nr = 0;
ssize_t nx = 0;
uint8_t *b = reinterpret_cast<uint8_t*>(buf);
while (nr < n) {
if ((nx = read(b+nr, n-nr)) < 0 && last_error() == EINTR)
continue;
if (nx <= 0)
break;
nr += nx;
}
return (nr == 0 && nx < 0) ? nx : ssize_t(nr);
}
ssize_t stream_socket::read(const std::vector<iovec>& ranges)
{
if (ranges.empty())
return 0;
#if !defined(_WIN32)
return check_ret(::readv(handle(), ranges.data(), int(ranges.size())));
#else
std::vector<WSABUF> bufs;
for (const auto& iovec : ranges) {
bufs.push_back({
static_cast<ULONG>(iovec.iov_len),
static_cast<CHAR*>(iovec.iov_base)
});
}
DWORD flags = 0,
nread = 0,
nbuf = DWORD(bufs.size());
auto ret = check_ret(::WSARecv(handle(), bufs.data(), nbuf, &nread, &flags, nullptr, nullptr));
return ssize_t(ret == SOCKET_ERROR ? ret : nread);
#endif
}
bool stream_socket::read_timeout(const microseconds& to)
{
auto tv =
#if defined(_WIN32)
DWORD(duration_cast<milliseconds>(to).count());
#else
to_timeval(to);
#endif
return set_option(SOL_SOCKET, SO_RCVTIMEO, tv);
}
ssize_t stream_socket::write(const void *buf, size_t n)
{
#if defined(_WIN32)
return check_ret(::send(handle(), reinterpret_cast<const char*>(buf),
int(n) , 0));
#else
return check_ret(::send(handle(), buf, n , 0));
#endif
}
ssize_t stream_socket::write_n(const void *buf, size_t n)
{
size_t nw = 0;
ssize_t nx = 0;
const uint8_t *b = reinterpret_cast<const uint8_t*>(buf);
while (nw < n) {
if ((nx = write(b+nw, n-nw)) < 0 && last_error() == EINTR)
continue;
if (nx <= 0)
break;
nw += nx;
}
return (nw == 0 && nx < 0) ? nx : ssize_t(nw);
}
ssize_t stream_socket::write(const std::vector<iovec>& ranges)
{
if (ranges.empty())
return 0;
#if !defined(_WIN32)
return check_ret(::writev(handle(), ranges.data(), int(ranges.size())));
#else
std::vector<WSABUF> bufs;
for (const auto& iovec : ranges) {
bufs.push_back({
static_cast<ULONG>(iovec.iov_len),
static_cast<CHAR*>(iovec.iov_base)
});
}
DWORD nwritten = 0,
nmsg = DWORD(bufs.size());
auto ret = check_ret(::WSASend(handle(), bufs.data(), nmsg, &nwritten, 0, nullptr, nullptr));
return ssize_t(ret == SOCKET_ERROR ? ret : nwritten);
#endif
}
bool stream_socket::write_timeout(const microseconds& to)
{
auto tv =
#if defined(_WIN32)
DWORD(duration_cast<milliseconds>(to).count());
#else
to_timeval(to);
#endif
return set_option(SOL_SOCKET, SO_SNDTIMEO, tv);
}
}