1 #pragma comment(lib, "WS2_32.lib")
4 int TcpSocket::_wsaReferenceCount
= 0;
5 WSAData
TcpSocket::_wsaData
;
7 TcpSocket::TcpSocket(SOCKET socket
) :
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
30 TcpSocket::TcpSocket(const TcpSocket
& other
) :
31 _socket(other
._socket
),
37 TcpSocket::~TcpSocket()
39 if (--_wsaReferenceCount
== 0)
41 // the last instance of a socket has been deleted, winsock needs to be shut down
46 bool TcpSocket::Connect(const char* name
, short port
)
50 if (Resolve(name
, &address
) && Create())
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;
63 bool TcpSocket::Connect(long address
, short port
, bool translated
)
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;
78 bool TcpSocket::Bind(short port
)
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;
93 bool TcpSocket::Listen(int backlog
)
97 return listen(_socket
, backlog
) == 0;
103 bool TcpSocket::Accept(TcpSocket
* other
)
107 *other
= TcpSocket(accept(_socket
, 0, 0));
114 int TcpSocket::GetPendingReadLength() const
118 if (!IsValid() || ioctlsocket(_socket
, FIONREAD
, reinterpret_cast<u_long
*>(&size
)) == SOCKET_ERROR
)
126 int TcpSocket::Receive(void* buffer
, int size
)
130 return recv(_socket
, static_cast<char*>(buffer
), size
, 0);
136 int TcpSocket::Send(const void* buffer
, int size
)
140 return send(_socket
, static_cast<const char*>(buffer
), size
, 0);
146 bool TcpSocket::EnableDelay()
151 return setsockopt(GetDescriptor(), IPPROTO_TCP
, TCP_NODELAY
, reinterpret_cast<const char*>(&data
), sizeof(data
)) == 0;
157 bool TcpSocket::DisableDelay()
162 return setsockopt(GetDescriptor(), IPPROTO_TCP
, TCP_NODELAY
, reinterpret_cast<const char*>(&data
), sizeof(data
)) == 0;
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
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
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
;
201 // current event is valid, close and invalidate it
202 WSACloseEvent(_event
);
207 bool TcpSocket::QueryEventState(int eventId
, EventState
* state
) const
209 // set default event state values
213 // bail out if the socket is not valid (can't check events)
219 WSANETWORKEVENTS events
;
221 // determine which events are set for this socket; bail if operation fails
222 if (WSAEnumNetworkEvents(_socket
, _event
, &events
) != 0)
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))
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
];
247 SOCKET
TcpSocket::GetDescriptor()
252 bool TcpSocket::IsReadable(int timeout
) const
261 FD_SET(_socket
, &rs
);
265 delay
.tv_usec
= timeout
* 1000;
267 return select(0, &rs
, 0, 0, &delay
) > 0;
270 bool TcpSocket::IsWriteable(int timeout
) const
279 FD_SET(_socket
, &ws
);
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
);
310 // host name cannot be resolved
315 // store off the first address associated with this name
316 *address
= *reinterpret_cast<long*>(host
->h_addr_list
[0]);
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
;