Blame view

src/stream_socket.cpp 3.08 KB
48b4c725   Peter M. Groen   Setting up Socket-pp
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
  #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);
  }
  
  }