Starshatter_Open
Open source Starshatter engine
 All Classes Files Functions Variables Typedefs Enumerations Enumerator Friends Macros
NetSock.cpp
Go to the documentation of this file.
1 /* Project nGenEx
2  Destroyer Studios LLC
3  Copyright © 1997-2004. All Rights Reserved.
4 
5  SUBSYSTEM: NetEx.lib
6  FILE: NetSock.cpp
7  AUTHOR: John DiCamillo
8 
9 
10  OVERVIEW
11  ========
12  Network (IP) Socket Wrapper Implementation
13 */
14 
15 
16 // WINSOCK2.H MUST COME FIRST!!
17 #include <winsock2.h>
18 
19 #include "MemDebug.h"
20 #include "NetSock.h"
21 #include "NetLayer.h"
22 
23 // +-------------------------------------------------------------------+
24 
29  : stream(str), closed(false), stat(0), current_timeout(9999)
30 {
31  if (stream)
32  s = ::socket(AF_INET, SOCK_STREAM, 0);
33  else
34  s = ::socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
35 }
36 
43 NetSock::NetSock(SOCKET sock, bool str)
44  : s(sock), stream(str), closed(false), stat(0), current_timeout(9999)
45 { }
46 
52 NetSock::NetSock(const NetAddr& addr, bool str)
53  : stream(str), closed(false), stat(0), current_timeout(9999)
54 {
55  if (stream)
56  s = ::socket(AF_INET, SOCK_STREAM, 0);
57  else
58  s = ::socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
59 
60  connect(addr);
61 }
62 
64 {
65  close();
66 }
67 
68 // +--------------------------------------------------------------------+
69 
70 int
71 NetSock::bind(const NetAddr& addr)
72 {
73  if (closed || s == INVALID_SOCKET) return INVALID_SOCKET;
74  return stat = ::bind(s, addr.GetSockAddr(), addr.GetSockAddrLength());
75 }
76 
77 int
79 {
80  if (closed || s == INVALID_SOCKET) return INVALID_SOCKET;
81  return stat = ::connect(s, addr.GetSockAddr(), addr.GetSockAddrLength());
82 }
83 
84 int
85 NetSock::listen(int max_connections)
86 {
87  if (closed || s == INVALID_SOCKET) return INVALID_SOCKET;
88  return stat = ::listen(s, max_connections);
89 }
90 
91 NetSock*
93 {
94  if (closed || s == INVALID_SOCKET) return 0;
95 
96  SOCKET conn = INVALID_SOCKET;
97 
98  if (addr) {
99  sockaddr a;
100  int asize = sizeof(a);
101 
102  conn = ::accept(s, &a, &asize);
103 
104  if (conn != INVALID_SOCKET && asize > 0) {
105  addr->SetSockAddr(&a, asize);
106  }
107  }
108  else {
109  conn = ::accept(s, 0, 0);
110  }
111 
112  if (conn == INVALID_SOCKET)
113  return 0;
114 
115  return new(__FILE__,__LINE__) NetSock(conn, stream);
116 }
117 
118 // +--------------------------------------------------------------------+
119 
120 int
122 {
123  if (closed || s == INVALID_SOCKET) return 0;
124 
125  DWORD nbytes = 0;
126  if (::ioctlsocket(s, FIONREAD, &nbytes) == 0)
127  return (int) nbytes;
128 
129  return 0;
130 }
131 
132 // +--------------------------------------------------------------------+
133 
134 int
136 {
137  if (closed || s == INVALID_SOCKET) return INVALID_SOCKET;
138  return stat = ::send(s, msg.data(), msg.length(), 0);
139 }
140 
141 Text
143 {
144  if (closed || s == INVALID_SOCKET) return "";
145 
146  static char rbuf[8192];
147  int rlen = -1;
148 
149  if (stream) {
150  rlen = ::recv(s, rbuf, sizeof(rbuf), 0);
151  }
152  else {
153  rlen = ::recvfrom(s, rbuf, sizeof(rbuf), 0, 0, 0);
154  }
155 
156  if (rlen < 0) {
157  stat = NetLayer::GetLastError();
158 
159  switch (stat) {
160  case WSAENETDOWN:
161  case WSAENETRESET:
162  case WSAEINTR:
163  case WSAESHUTDOWN:
164  case WSAECONNABORTED:
165  case WSAECONNRESET:
166  case WSAETIMEDOUT:
167  close();
168  break;
169 
170  case WSAEWOULDBLOCK:
171  stat = WSAEWOULDBLOCK;
172  break;
173  }
174 
175  return Text();
176  }
177 
178  else if (rlen == 0) {
179  return Text();
180  }
181 
182  return Text(rbuf, rlen);
183 }
184 
185 
186 // +--------------------------------------------------------------------+
187 
188 int
189 NetSock::sendto(Text msg, const NetAddr& dest)
190 {
191  if (closed || s == INVALID_SOCKET) return INVALID_SOCKET;
192  return stat = ::sendto(s, msg.data(), msg.length(),
193  0, dest.GetSockAddr(), dest.GetSockAddrLength());
194 }
195 
196 Text
198 {
199  if (closed || s == INVALID_SOCKET) return "";
200 
201  static char rbuf[4096];
202  int rlen = 0;
203 
204  if (a) {
205  int addrlen = a->GetSockAddrLength();
206  rlen = ::recvfrom(s, rbuf, sizeof(rbuf), 0, a->GetSockAddr(), &addrlen);
207  a->InitFromSockAddr();
208  }
209  else {
210  rlen = ::recvfrom(s, rbuf, sizeof(rbuf), 0, 0, 0);
211  }
212 
213  if (rlen < 0) {
214  stat = NetLayer::GetLastError();
215  return Text();
216  }
217 
218  else if (rlen == 0) {
219  return Text();
220  }
221 
222  return Text(rbuf, rlen);
223 }
224 
225 // +--------------------------------------------------------------------+
226 
227 int
228 NetSock::select(SELECT_TYPE t, long seconds, long microseconds)
229 {
230  if (closed || s == INVALID_SOCKET) return INVALID_SOCKET;
231 
232  FD_SET fd;
233  ZeroMemory(&fd, sizeof(fd));
234 
235  FD_SET(s, &fd);
236  TIMEVAL timeval = {seconds, microseconds};
237  TIMEVAL* timeout = &timeval;
238 
239  if (t == SELECT_READ)
240  return stat = ::select(1, &fd, 0, 0, timeout);
241 
242  else if (t == SELECT_WRITE)
243  return stat = ::select(1, 0, &fd, 0, timeout);
244 
245  else if (t == (SELECT_READ|SELECT_WRITE))
246  return stat = ::select(1, &fd, &fd, 0, timeout);
247 
248  return 0;
249 }
250 
251 // +--------------------------------------------------------------------+
252 
253 int
255 {
256  if (closed || s == INVALID_SOCKET) return 0;
257  if (msecs == current_timeout) return 1;
258 
259  // zero timeout means non-blocking
260  if (msecs == 0) {
261  u_long nonblocking = 1;
262  if (::ioctlsocket(s, FIONBIO, &nonblocking) == SOCKET_ERROR) {
263  stat = NetLayer::GetLastError();
264  return stat;
265  }
266  }
267 
268  // non-zero timeout means blocking
269  else {
270  if (current_timeout == 0) {
271  u_long nonblocking = 0; // disable non-blocking
272  if (::ioctlsocket(s, FIONBIO, &nonblocking) == SOCKET_ERROR) {
273  stat = NetLayer::GetLastError();
274  return stat;
275  }
276  }
277 
278  // max timeout means infinite wait
279  if (msecs >= NET_MAX_TIMEOUT) {
280  int maxto = 0;
281  ::setsockopt(s, SOL_SOCKET, SO_RCVTIMEO, (char*) &maxto, sizeof(maxto));
282  ::setsockopt(s, SOL_SOCKET, SO_SNDTIMEO, (char*) &maxto, sizeof(maxto));
283  }
284 
285  // otherwise, set the timeout
286  else {
287  ::setsockopt(s, SOL_SOCKET, SO_RCVTIMEO, (char*) &msecs, sizeof(msecs));
288  ::setsockopt(s, SOL_SOCKET, SO_SNDTIMEO, (char*) &msecs, sizeof(msecs));
289  }
290  }
291 
292  current_timeout = msecs;
293  return 1;
294 }
295 
296 // +--------------------------------------------------------------------+
297 
298 int
300 {
301  if (closed || s == INVALID_SOCKET) return INVALID_SOCKET;
302  ::shutdown(s, SD_RECEIVE);
303  return 0;
304 }
305 
306 // +--------------------------------------------------------------------+
307 
308 int
310 {
311  if (closed || s == INVALID_SOCKET) return INVALID_SOCKET;
312  ::shutdown(s, SD_SEND);
313  return 0;
314 }
315 
316 // +--------------------------------------------------------------------+
317 
318 int
320 {
321  if (s != INVALID_SOCKET && !closed) {
322  ::shutdown(s, SD_BOTH);
323  ::closesocket(s);
324 
325  closed = true;
326  }
327 
328  return 0;
329 }
330 
331 // +--------------------------------------------------------------------+
332 
333 DWORD
335 {
336  DWORD size = 0;
337  int len = sizeof(size);
338 
339  ::getsockopt(s, SOL_SOCKET, 0x2003, (char*) &size, &len);
340 
341  return size;
342 }