OLD | NEW |
| (Empty) |
1 /***************************************************************************** | |
2 Copyright (c) 2001 - 2011, The Board of Trustees of the University of Illinois. | |
3 All rights reserved. | |
4 | |
5 Redistribution and use in source and binary forms, with or without | |
6 modification, are permitted provided that the following conditions are | |
7 met: | |
8 | |
9 * Redistributions of source code must retain the above | |
10 copyright notice, this list of conditions and the | |
11 following disclaimer. | |
12 | |
13 * Redistributions in binary form must reproduce the | |
14 above copyright notice, this list of conditions | |
15 and the following disclaimer in the documentation | |
16 and/or other materials provided with the distribution. | |
17 | |
18 * Neither the name of the University of Illinois | |
19 nor the names of its contributors may be used to | |
20 endorse or promote products derived from this | |
21 software without specific prior written permission. | |
22 | |
23 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS | |
24 IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, | |
25 THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR | |
26 PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR | |
27 CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, | |
28 EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, | |
29 PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR | |
30 PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF | |
31 LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING | |
32 NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | |
33 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
34 ****************************************************************************/ | |
35 | |
36 /**************************************************************************** | |
37 written by | |
38 Yunhong Gu, last updated 01/27/2011 | |
39 *****************************************************************************/ | |
40 | |
41 #ifndef WIN32 | |
42 #include <netdb.h> | |
43 #include <arpa/inet.h> | |
44 #include <unistd.h> | |
45 #include <fcntl.h> | |
46 #include <cstring> | |
47 #include <cstdio> | |
48 #include <cerrno> | |
49 #else | |
50 #include <winsock2.h> | |
51 #include <ws2tcpip.h> | |
52 #ifdef LEGACY_WIN32 | |
53 #include <wspiapi.h> | |
54 #endif | |
55 #endif | |
56 #include "channel.h" | |
57 #include "packet.h" | |
58 | |
59 #ifdef WIN32 | |
60 #define socklen_t int | |
61 #endif | |
62 | |
63 #ifndef WIN32 | |
64 #define NET_ERROR errno | |
65 #else | |
66 #define NET_ERROR WSAGetLastError() | |
67 #endif | |
68 | |
69 | |
70 CChannel::CChannel(): | |
71 m_iIPversion(AF_INET), | |
72 m_iSockAddrSize(sizeof(sockaddr_in)), | |
73 m_iSocket(), | |
74 m_iSndBufSize(65536), | |
75 m_iRcvBufSize(65536) | |
76 { | |
77 } | |
78 | |
79 CChannel::CChannel(const int& version): | |
80 m_iIPversion(version), | |
81 m_iSocket(), | |
82 m_iSndBufSize(65536), | |
83 m_iRcvBufSize(65536) | |
84 { | |
85 m_iSockAddrSize = (AF_INET == m_iIPversion) ? sizeof(sockaddr_in) : sizeof(so
ckaddr_in6); | |
86 } | |
87 | |
88 CChannel::~CChannel() | |
89 { | |
90 } | |
91 | |
92 void CChannel::open(const sockaddr* addr) | |
93 { | |
94 // construct an socket | |
95 m_iSocket = socket(m_iIPversion, SOCK_DGRAM, 0); | |
96 | |
97 #ifdef WIN32 | |
98 if (INVALID_SOCKET == m_iSocket) | |
99 #else | |
100 if (m_iSocket < 0) | |
101 #endif | |
102 throw CUDTException(1, 0, NET_ERROR); | |
103 | |
104 if (NULL != addr) | |
105 { | |
106 socklen_t namelen = m_iSockAddrSize; | |
107 | |
108 if (0 != bind(m_iSocket, addr, namelen)) | |
109 throw CUDTException(1, 3, NET_ERROR); | |
110 } | |
111 else | |
112 { | |
113 //sendto or WSASendTo will also automatically bind the socket | |
114 addrinfo hints; | |
115 addrinfo* res; | |
116 | |
117 memset(&hints, 0, sizeof(struct addrinfo)); | |
118 | |
119 hints.ai_flags = AI_PASSIVE; | |
120 hints.ai_family = m_iIPversion; | |
121 hints.ai_socktype = SOCK_DGRAM; | |
122 | |
123 if (0 != getaddrinfo(NULL, "0", &hints, &res)) | |
124 throw CUDTException(1, 3, NET_ERROR); | |
125 | |
126 if (0 != bind(m_iSocket, res->ai_addr, res->ai_addrlen)) | |
127 throw CUDTException(1, 3, NET_ERROR); | |
128 | |
129 freeaddrinfo(res); | |
130 } | |
131 | |
132 setUDPSockOpt(); | |
133 } | |
134 | |
135 void CChannel::open(UDPSOCKET udpsock) | |
136 { | |
137 m_iSocket = udpsock; | |
138 setUDPSockOpt(); | |
139 } | |
140 | |
141 void CChannel::setUDPSockOpt() | |
142 { | |
143 #if defined(BSD) || defined(OSX) | |
144 // BSD system will fail setsockopt if the requested buffer size exceeds sy
stem maximum value | |
145 int maxsize = 64000; | |
146 if (0 != setsockopt(m_iSocket, SOL_SOCKET, SO_RCVBUF, (char*)&m_iRcvBufSiz
e, sizeof(int))) | |
147 setsockopt(m_iSocket, SOL_SOCKET, SO_RCVBUF, (char*)&maxsize, sizeof(in
t)); | |
148 if (0 != setsockopt(m_iSocket, SOL_SOCKET, SO_SNDBUF, (char*)&m_iSndBufSiz
e, sizeof(int))) | |
149 setsockopt(m_iSocket, SOL_SOCKET, SO_SNDBUF, (char*)&maxsize, sizeof(in
t)); | |
150 #else | |
151 // for other systems, if requested is greated than maximum, the maximum va
lue will be automactally used | |
152 if ((0 != setsockopt(m_iSocket, SOL_SOCKET, SO_RCVBUF, (char*)&m_iRcvBufSi
ze, sizeof(int))) || | |
153 (0 != setsockopt(m_iSocket, SOL_SOCKET, SO_SNDBUF, (char*)&m_iSndBufSi
ze, sizeof(int)))) | |
154 throw CUDTException(1, 3, NET_ERROR); | |
155 #endif | |
156 | |
157 timeval tv; | |
158 tv.tv_sec = 0; | |
159 #if defined (BSD) || defined (OSX) | |
160 // Known BSD bug as the day I wrote this code. | |
161 // A small time out value will cause the socket to block forever. | |
162 tv.tv_usec = 10000; | |
163 #else | |
164 tv.tv_usec = 100; | |
165 #endif | |
166 | |
167 #ifdef UNIX | |
168 // Set non-blocking I/O | |
169 // UNIX does not support SO_RCVTIMEO | |
170 int opts = fcntl(m_iSocket, F_GETFL); | |
171 if (-1 == fcntl(m_iSocket, F_SETFL, opts | O_NONBLOCK)) | |
172 throw CUDTException(1, 3, NET_ERROR); | |
173 #elif WIN32 | |
174 DWORD ot = 1; //milliseconds | |
175 if (0 != setsockopt(m_iSocket, SOL_SOCKET, SO_RCVTIMEO, (char *)&ot, sizeo
f(DWORD))) | |
176 throw CUDTException(1, 3, NET_ERROR); | |
177 #else | |
178 // Set receiving time-out value | |
179 if (0 != setsockopt(m_iSocket, SOL_SOCKET, SO_RCVTIMEO, (char *)&tv, sizeo
f(timeval))) | |
180 throw CUDTException(1, 3, NET_ERROR); | |
181 #endif | |
182 } | |
183 | |
184 void CChannel::close() const | |
185 { | |
186 #ifndef WIN32 | |
187 ::close(m_iSocket); | |
188 #else | |
189 closesocket(m_iSocket); | |
190 #endif | |
191 } | |
192 | |
193 int CChannel::getSndBufSize() | |
194 { | |
195 socklen_t size = sizeof(socklen_t); | |
196 | |
197 getsockopt(m_iSocket, SOL_SOCKET, SO_SNDBUF, (char *)&m_iSndBufSize, &size); | |
198 | |
199 return m_iSndBufSize; | |
200 } | |
201 | |
202 int CChannel::getRcvBufSize() | |
203 { | |
204 socklen_t size = sizeof(socklen_t); | |
205 | |
206 getsockopt(m_iSocket, SOL_SOCKET, SO_RCVBUF, (char *)&m_iRcvBufSize, &size); | |
207 | |
208 return m_iRcvBufSize; | |
209 } | |
210 | |
211 void CChannel::setSndBufSize(const int& size) | |
212 { | |
213 m_iSndBufSize = size; | |
214 } | |
215 | |
216 void CChannel::setRcvBufSize(const int& size) | |
217 { | |
218 m_iRcvBufSize = size; | |
219 } | |
220 | |
221 void CChannel::getSockAddr(sockaddr* addr) const | |
222 { | |
223 socklen_t namelen = m_iSockAddrSize; | |
224 | |
225 getsockname(m_iSocket, addr, &namelen); | |
226 } | |
227 | |
228 void CChannel::getPeerAddr(sockaddr* addr) const | |
229 { | |
230 socklen_t namelen = m_iSockAddrSize; | |
231 | |
232 getpeername(m_iSocket, addr, &namelen); | |
233 } | |
234 | |
235 int CChannel::sendto(const sockaddr* addr, CPacket& packet) const | |
236 { | |
237 // convert control information into network order | |
238 if (packet.getFlag()) | |
239 for (int i = 0, n = packet.getLength() / 4; i < n; ++ i) | |
240 *((uint32_t *)packet.m_pcData + i) = htonl(*((uint32_t *)packet.m_pcDat
a + i)); | |
241 | |
242 // convert packet header into network order | |
243 //for (int j = 0; j < 4; ++ j) | |
244 // packet.m_nHeader[j] = htonl(packet.m_nHeader[j]); | |
245 uint32_t* p = packet.m_nHeader; | |
246 for (int j = 0; j < 4; ++ j) | |
247 { | |
248 *p = htonl(*p); | |
249 ++ p; | |
250 } | |
251 | |
252 #ifndef WIN32 | |
253 msghdr mh; | |
254 mh.msg_name = (sockaddr*)addr; | |
255 mh.msg_namelen = m_iSockAddrSize; | |
256 mh.msg_iov = (iovec*)packet.m_PacketVector; | |
257 mh.msg_iovlen = 2; | |
258 mh.msg_control = NULL; | |
259 mh.msg_controllen = 0; | |
260 mh.msg_flags = 0; | |
261 | |
262 int res = sendmsg(m_iSocket, &mh, 0); | |
263 #else | |
264 DWORD size = CPacket::m_iPktHdrSize + packet.getLength(); | |
265 int addrsize = m_iSockAddrSize; | |
266 int res = WSASendTo(m_iSocket, (LPWSABUF)packet.m_PacketVector, 2, &size,
0, addr, addrsize, NULL, NULL); | |
267 res = (0 == res) ? size : -1; | |
268 #endif | |
269 | |
270 // convert back into local host order | |
271 //for (int k = 0; k < 4; ++ k) | |
272 // packet.m_nHeader[k] = ntohl(packet.m_nHeader[k]); | |
273 p = packet.m_nHeader; | |
274 for (int k = 0; k < 4; ++ k) | |
275 { | |
276 *p = ntohl(*p); | |
277 ++ p; | |
278 } | |
279 | |
280 if (packet.getFlag()) | |
281 { | |
282 for (int l = 0, n = packet.getLength() / 4; l < n; ++ l) | |
283 *((uint32_t *)packet.m_pcData + l) = ntohl(*((uint32_t *)packet.m_pcDat
a + l)); | |
284 } | |
285 | |
286 return res; | |
287 } | |
288 | |
289 int CChannel::recvfrom(sockaddr* addr, CPacket& packet) const | |
290 { | |
291 #ifndef WIN32 | |
292 msghdr mh; | |
293 mh.msg_name = addr; | |
294 mh.msg_namelen = m_iSockAddrSize; | |
295 mh.msg_iov = packet.m_PacketVector; | |
296 mh.msg_iovlen = 2; | |
297 mh.msg_control = NULL; | |
298 mh.msg_controllen = 0; | |
299 mh.msg_flags = 0; | |
300 | |
301 #ifdef UNIX | |
302 fd_set set; | |
303 timeval tv; | |
304 FD_ZERO(&set); | |
305 FD_SET(m_iSocket, &set); | |
306 tv.tv_sec = 0; | |
307 tv.tv_usec = 10000; | |
308 select(m_iSocket+1, &set, NULL, &set, &tv); | |
309 #endif | |
310 | |
311 int res = recvmsg(m_iSocket, &mh, 0); | |
312 #else | |
313 DWORD size = CPacket::m_iPktHdrSize + packet.getLength(); | |
314 DWORD flag = 0; | |
315 int addrsize = m_iSockAddrSize; | |
316 | |
317 int res = WSARecvFrom(m_iSocket, (LPWSABUF)packet.m_PacketVector, 2, &size
, &flag, addr, &addrsize, NULL, NULL); | |
318 res = (0 == res) ? size : -1; | |
319 #endif | |
320 | |
321 if (res <= 0) | |
322 { | |
323 packet.setLength(-1); | |
324 return -1; | |
325 } | |
326 | |
327 packet.setLength(res - CPacket::m_iPktHdrSize); | |
328 | |
329 // convert back into local host order | |
330 //for (int i = 0; i < 4; ++ i) | |
331 // packet.m_nHeader[i] = ntohl(packet.m_nHeader[i]); | |
332 uint32_t* p = packet.m_nHeader; | |
333 for (int i = 0; i < 4; ++ i) | |
334 { | |
335 *p = ntohl(*p); | |
336 ++ p; | |
337 } | |
338 | |
339 if (packet.getFlag()) | |
340 { | |
341 for (int j = 0, n = packet.getLength() / 4; j < n; ++ j) | |
342 *((uint32_t *)packet.m_pcData + j) = ntohl(*((uint32_t *)packet.m_pcDat
a + j)); | |
343 } | |
344 | |
345 return packet.getLength(); | |
346 } | |
OLD | NEW |