Added a test build
[RedVex.git] / core / TcpSocket.cpp
blob77ad1f90f797dce60cc5894d5ae8a0b55765583d
1 #pragma comment(lib, "WS2_32.lib")
2 #include "TcpSocket.h"
4 int TcpSocket::_wsaReferenceCount = 0;
5 WSAData TcpSocket::_wsaData;
7 TcpSocket::TcpSocket(SOCKET socket) :
8 _socket(socket),
9 _event(0)
11 if (_wsaReferenceCount++ == 0)
13 // the first instance of a socket has been created, sockets need to be initialized
14 Startup(WinSockMajorVersion, WinSockMinorVersion);
17 if (_socket != INVALID_SOCKET)
19 // a valid socket socket was passed in, create an event and bind desired conditions to it
20 _event = WSACreateEvent();
22 if (_event == 0 || WSAEventSelect(_socket, _event, MonitoredEvents) != 0)
24 // there is some sort of error with the socket or the event associated with it, close everything
25 Close();
30 TcpSocket::TcpSocket(const TcpSocket& other) :
31 _socket(other._socket),
32 _event(other._event)
34 _wsaReferenceCount++;
37 TcpSocket::~TcpSocket()
39 if (--_wsaReferenceCount == 0)
41 // the last instance of a socket has been deleted, winsock needs to be shut down
42 Cleanup();
46 bool TcpSocket::Connect(const char* name, short port)
48 long address;
50 if (Resolve(name, &address) && Create())
52 sockaddr_in host;
53 host.sin_port = htons(port);
54 host.sin_family = Family;
55 host.sin_addr.s_addr = address;
57 return connect(_socket, reinterpret_cast<const sockaddr*>(&host), sizeof(host)) == 0;
60 return false;
63 bool TcpSocket::Connect(long address, short port, bool translated)
65 if (Create())
67 sockaddr_in host;
68 host.sin_port = htons(port);
69 host.sin_family = Family;
70 host.sin_addr.s_addr = translated ? address : htonl(address);
72 return connect(_socket, reinterpret_cast<const sockaddr*>(&host), sizeof(host)) == 0;
75 return false;
78 bool TcpSocket::Bind(short port)
80 if (Create())
82 sockaddr_in address;
83 address.sin_family = Family;
84 address.sin_port = htons(port);
85 address.sin_addr.s_addr = htonl(INADDR_ANY);
87 return bind(_socket, reinterpret_cast<const sockaddr*>(&address), sizeof(address)) == 0;
90 return false;
93 bool TcpSocket::Listen(int backlog)
95 if (IsValid())
97 return listen(_socket, backlog) == 0;
100 return false;
103 bool TcpSocket::Accept(TcpSocket* other)
105 if (IsValid())
107 *other = TcpSocket(accept(_socket, 0, 0));
108 return true;
111 return false;
114 int TcpSocket::GetPendingReadLength() const
116 int size;
118 if (!IsValid() || ioctlsocket(_socket, FIONREAD, reinterpret_cast<u_long*>(&size)) == SOCKET_ERROR)
120 return -1;
123 return size;
126 int TcpSocket::Receive(void* buffer, int size)
128 if (IsValid())
130 return recv(_socket, static_cast<char*>(buffer), size, 0);
133 return -1;
136 int TcpSocket::Send(const void* buffer, int size)
138 if (IsValid())
140 return send(_socket, static_cast<const char*>(buffer), size, 0);
143 return -1;
146 bool TcpSocket::EnableDelay()
148 if (IsValid())
150 int data = 0;
151 return setsockopt(GetDescriptor(), IPPROTO_TCP, TCP_NODELAY, reinterpret_cast<const char*>(&data), sizeof(data)) == 0;
154 return false;
157 bool TcpSocket::DisableDelay()
159 if (IsValid())
161 int data = 1;
162 return setsockopt(GetDescriptor(), IPPROTO_TCP, TCP_NODELAY, reinterpret_cast<const char*>(&data), sizeof(data)) == 0;
165 return false;
168 bool TcpSocket::Create()
170 // close the existing event and socket if they have already been created
171 // so as to not leak any networking resources when the new socket is created
172 if (IsValid())
174 Close();
177 if ((_socket = socket(Family, Type, Protocol)) == INVALID_SOCKET ||
178 (_event = WSACreateEvent()) == 0 || (WSAEventSelect(_socket, _event, MonitoredEvents)) != 0)
180 // socket and/or event creation has failed; close free whatever
181 // resources were allocated and bail out because this socket
182 // is unusable in the current state
183 Close();
184 return false;
187 return true;
190 void TcpSocket::Close()
192 if (_socket != INVALID_SOCKET)
194 // current socket is valid, close and invalidate it
195 closesocket(_socket);
196 _socket = INVALID_SOCKET;
199 if (_event != 0)
201 // current event is valid, close and invalidate it
202 WSACloseEvent(_event);
203 _event = 0;
207 bool TcpSocket::QueryEventState(int eventId, EventState* state) const
209 // set default event state values
210 state->error = 0;
211 state->set = false;
213 // bail out if the socket is not valid (can't check events)
214 if (!IsValid())
216 return false;
219 WSANETWORKEVENTS events;
221 // determine which events are set for this socket; bail if operation fails
222 if (WSAEnumNetworkEvents(_socket, _event, &events) != 0)
224 return false;
227 // store off whether or not the given even is set; return out immediately
228 // if the event is not set (because there aren't any error codes for it)
229 if (state->set = ((events.lNetworkEvents & eventId) != 0))
231 return true;
234 // find and store off the applicable error code for this eventId if one exists
235 for (int i = 0, flag = 1; i < FD_MAX_EVENTS; i++, flag <<= 1)
237 if ((flag & eventId) == eventId)
239 state->error = events.iErrorCode[i];
240 break;
244 return true;
247 SOCKET TcpSocket::GetDescriptor()
249 return _socket;
252 bool TcpSocket::IsReadable(int timeout) const
254 if (!IsValid())
256 return false;
259 fd_set rs;
260 FD_ZERO(&rs);
261 FD_SET(_socket, &rs);
263 timeval delay;
264 delay.tv_sec = 0;
265 delay.tv_usec = timeout * 1000;
267 return select(0, &rs, 0, 0, &delay) > 0;
270 bool TcpSocket::IsWriteable(int timeout) const
272 if (!IsValid())
274 return false;
277 fd_set ws;
278 FD_ZERO(&ws);
279 FD_SET(_socket, &ws);
281 timeval delay;
282 delay.tv_sec = 0;
283 delay.tv_usec = timeout * 1000;
285 return select(0, 0, &ws, 0, &delay) > 0;
288 bool TcpSocket::IsValid() const
290 return _socket != INVALID_SOCKET && _event != 0;
293 int TcpSocket::GetLastError()
295 return WSAGetLastError();
298 bool TcpSocket::Resolve(const char* name, long* address)
300 // attempt to parse the host name as an ip string
301 *address = inet_addr(name);
303 if (*address == INADDR_NONE)
305 // host name is not an ip string, attempt to resolve it
306 hostent* host = gethostbyname(name);
308 if (host == 0)
310 // host name cannot be resolved
311 *address = 0;
312 return false;
315 // store off the first address associated with this name
316 *address = *reinterpret_cast<long*>(host->h_addr_list[0]);
319 return true;
322 bool TcpSocket::Startup(int majorVersion, int minorVersion)
324 return WSAStartup(MAKEWORD(majorVersion, minorVersion), &_wsaData) == 0;
327 bool TcpSocket::Cleanup()
329 return WSACleanup() != SOCKET_ERROR;