PageRenderTime 70ms CodeModel.GetById 12ms app.highlight 53ms RepoModel.GetById 1ms app.codeStats 0ms

/ghost-legacy/socket.cpp

http://ghostcb.googlecode.com/
C++ | 797 lines | 564 code | 161 blank | 72 comment | 130 complexity | 623ab957816fa85c6c7c982534ca044e MD5 | raw file
  1/*
  2
  3   Copyright [2008] [Trevor Hogan]
  4
  5   Licensed under the Apache License, Version 2.0 (the "License");
  6   you may not use this file except in compliance with the License.
  7   You may obtain a copy of the License at
  8
  9       http://www.apache.org/licenses/LICENSE-2.0
 10
 11   Unless required by applicable law or agreed to in writing, software
 12   distributed under the License is distributed on an "AS IS" BASIS,
 13   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 14   See the License for the specific language governing permissions and
 15   limitations under the License.
 16
 17   CODE PORTED FROM THE ORIGINAL GHOST PROJECT: http://ghost.pwner.org/
 18
 19*/
 20
 21#include "ghost.h"
 22#include "util.h"
 23#include "socket.h"
 24
 25#include <string.h>
 26
 27#ifndef WIN32
 28 int GetLastError( ) { return errno; }
 29#endif
 30
 31//
 32// CSocket
 33//
 34
 35CSocket :: CSocket( )
 36{
 37	m_Socket = INVALID_SOCKET;
 38	memset( &m_SIN, 0, sizeof( m_SIN ) );
 39	m_HasError = false;
 40	m_Error = 0;
 41}
 42
 43CSocket :: CSocket( SOCKET nSocket, struct sockaddr_in nSIN )
 44{
 45	m_Socket = nSocket;
 46	m_SIN = nSIN;
 47	m_HasError = false;
 48	m_Error = 0;
 49}
 50
 51CSocket :: ~CSocket( )
 52{
 53	if( m_Socket != INVALID_SOCKET )
 54		closesocket( m_Socket );
 55}
 56
 57BYTEARRAY CSocket :: GetPort( )
 58{
 59	return UTIL_CreateByteArray( m_SIN.sin_port, false );
 60}
 61
 62BYTEARRAY CSocket :: GetIP( )
 63{
 64	return UTIL_CreateByteArray( (uint32_t)m_SIN.sin_addr.s_addr, false );
 65}
 66
 67string CSocket :: GetIPString( )
 68{
 69	return inet_ntoa( m_SIN.sin_addr );
 70}
 71
 72string CSocket :: GetErrorString( )
 73{
 74	if( !m_HasError )
 75		return "NO ERROR";
 76
 77	switch( m_Error )
 78	{
 79	case EWOULDBLOCK: return "EWOULDBLOCK";
 80	case EINPROGRESS: return "EINPROGRESS";
 81	case EALREADY: return "EALREADY";
 82	case ENOTSOCK: return "ENOTSOCK";
 83	case EDESTADDRREQ: return "EDESTADDRREQ";
 84	case EMSGSIZE: return "EMSGSIZE";
 85	case EPROTOTYPE: return "EPROTOTYPE";
 86	case ENOPROTOOPT: return "ENOPROTOOPT";
 87	case EPROTONOSUPPORT: return "EPROTONOSUPPORT";
 88	case ESOCKTNOSUPPORT: return "ESOCKTNOSUPPORT";
 89	case EOPNOTSUPP: return "EOPNOTSUPP";
 90	case EPFNOSUPPORT: return "EPFNOSUPPORT";
 91	case EAFNOSUPPORT: return "EAFNOSUPPORT";
 92	case EADDRINUSE: return "EADDRINUSE";
 93	case EADDRNOTAVAIL: return "EADDRNOTAVAIL";
 94	case ENETDOWN: return "ENETDOWN";
 95	case ENETUNREACH: return "ENETUNREACH";
 96	case ENETRESET: return "ENETRESET";
 97	case ECONNABORTED: return "ECONNABORTED";
 98	case ECONNRESET: return "ECONNRESET";
 99	case ENOBUFS: return "ENOBUFS";
100	case EISCONN: return "EISCONN";
101	case ENOTCONN: return "ENOTCONN";
102	case ESHUTDOWN: return "ESHUTDOWN";
103	case ETOOMANYREFS: return "ETOOMANYREFS";
104	case ETIMEDOUT: return "ETIMEDOUT";
105	case ECONNREFUSED: return "ECONNREFUSED";
106	case ELOOP: return "ELOOP";
107	case ENAMETOOLONG: return "ENAMETOOLONG";
108	case EHOSTDOWN: return "EHOSTDOWN";
109	case EHOSTUNREACH: return "EHOSTUNREACH";
110	case ENOTEMPTY: return "ENOTEMPTY";
111	case EUSERS: return "EUSERS";
112	case EDQUOT: return "EDQUOT";
113	case ESTALE: return "ESTALE";
114	case EREMOTE: return "EREMOTE";
115	}
116
117	return "UNKNOWN ERROR (" + UTIL_ToString( m_Error ) + ")";
118}
119
120void CSocket :: SetFD( fd_set *fd, fd_set *send_fd, int *nfds )
121{
122	if( m_Socket == INVALID_SOCKET )
123		return;
124
125	FD_SET( m_Socket, fd );
126	FD_SET( m_Socket, send_fd );
127
128#ifndef WIN32
129	if( m_Socket > *nfds )
130		*nfds = m_Socket;
131#endif
132}
133
134void CSocket :: Allocate( int type )
135{
136	m_Socket = socket( AF_INET, type, 0 );
137
138	if( m_Socket == INVALID_SOCKET )
139	{
140		m_HasError = true;
141		m_Error = GetLastError( );
142		CONSOLE_Print( "[SOCKET] error (socket) - " + GetErrorString( ) );
143		return;
144	}
145}
146
147void CSocket :: Reset( )
148{
149	if( m_Socket != INVALID_SOCKET )
150		closesocket( m_Socket );
151
152	m_Socket = INVALID_SOCKET;
153	memset( &m_SIN, 0, sizeof( m_SIN ) );
154	m_HasError = false;
155	m_Error = 0;
156}
157
158//
159// CTCPSocket
160//
161
162CTCPSocket :: CTCPSocket( ) : CSocket( )
163{
164	Allocate( SOCK_STREAM );
165	m_Connected = false;
166	m_LastRecv = GetTime( );
167	m_LastSend = GetTime( );
168
169	// make socket non blocking
170
171#ifdef WIN32
172	int iMode = 1;
173	ioctlsocket( m_Socket, FIONBIO, (u_long FAR *)&iMode );
174#else
175	fcntl( m_Socket, F_SETFL, fcntl( m_Socket, F_GETFL ) | O_NONBLOCK );
176#endif
177}
178
179CTCPSocket :: CTCPSocket( SOCKET nSocket, struct sockaddr_in nSIN ) : CSocket( nSocket, nSIN )
180{
181	m_Connected = true;
182	m_LastRecv = GetTime( );
183	m_LastSend = GetTime( );
184
185	// make socket non blocking
186
187#ifdef WIN32
188	int iMode = 1;
189	ioctlsocket( m_Socket, FIONBIO, (u_long FAR *)&iMode );
190#else
191	fcntl( m_Socket, F_SETFL, fcntl( m_Socket, F_GETFL ) | O_NONBLOCK );
192#endif
193}
194
195CTCPSocket :: ~CTCPSocket( )
196{
197
198}
199
200void CTCPSocket :: Reset( )
201{
202	CSocket :: Reset( );
203
204	Allocate( SOCK_STREAM );
205	m_Connected = false;
206	m_RecvBuffer.clear( );
207	m_SendBuffer.clear( );
208	m_LastRecv = GetTime( );
209	m_LastSend = GetTime( );
210
211	// make socket non blocking
212
213#ifdef WIN32
214	int iMode = 1;
215	ioctlsocket( m_Socket, FIONBIO, (u_long FAR *)&iMode );
216#else
217	fcntl( m_Socket, F_SETFL, fcntl( m_Socket, F_GETFL ) | O_NONBLOCK );
218#endif
219
220	if( !m_LogFile.empty( ) )
221	{
222		ofstream Log;
223		Log.open( m_LogFile.c_str( ), ios :: app );
224
225		if( !Log.fail( ) )
226		{
227			Log << "----------RESET----------" << endl;
228			Log.close( );
229		}
230	}
231}
232
233void CTCPSocket :: PutBytes( string bytes )
234{
235	m_SendBuffer += bytes;
236}
237
238void CTCPSocket :: PutBytes( BYTEARRAY bytes )
239{
240	m_SendBuffer += string( bytes.begin( ), bytes.end( ) );
241}
242
243void CTCPSocket :: DoRecv( fd_set *fd )
244{
245	if( m_Socket == INVALID_SOCKET || m_HasError || !m_Connected )
246		return;
247
248	if( FD_ISSET( m_Socket, fd ) )
249	{
250		// data is waiting, receive it
251
252		char buffer[1024];
253		int c = recv( m_Socket, buffer, 1024, 0 );
254
255		if( c == SOCKET_ERROR && GetLastError( ) != EWOULDBLOCK )
256		{
257			// receive error
258
259			m_HasError = true;
260			m_Error = GetLastError( );
261			CONSOLE_Print( "[TCPSOCKET] error (recv) - " + GetErrorString( ) );
262			return;
263		}
264		else if( c == 0 )
265		{
266			// the other end closed the connection
267
268			CONSOLE_Print( "[TCPSOCKET] closed by remote host" );
269			m_Connected = false;
270		}
271		else if( c > 0 )
272		{
273			// success! add the received data to the buffer
274
275			if( !m_LogFile.empty( ) )
276			{
277				ofstream Log;
278				Log.open( m_LogFile.c_str( ), ios :: app );
279
280				if( !Log.fail( ) )
281				{
282					Log << "					RECEIVE <<< " << UTIL_ByteArrayToHexString( UTIL_CreateByteArray( (unsigned char *)buffer, c ) ) << endl;
283					Log.close( );
284				}
285			}
286
287			m_RecvBuffer += string( buffer, c );
288			m_LastRecv = GetTime( );
289		}
290	}
291}
292
293void CTCPSocket :: DoSend( fd_set *send_fd )
294{
295	if( m_Socket == INVALID_SOCKET || m_HasError || !m_Connected || m_SendBuffer.empty( ) )
296		return;
297
298	if( FD_ISSET( m_Socket, send_fd ) )
299	{
300		// socket is ready, send it
301
302		int s = send( m_Socket, m_SendBuffer.c_str( ), (int)m_SendBuffer.size( ), MSG_NOSIGNAL );
303
304		if( s == SOCKET_ERROR && GetLastError( ) != EWOULDBLOCK )
305		{
306			// send error
307
308			m_HasError = true;
309			m_Error = GetLastError( );
310			CONSOLE_Print( "[TCPSOCKET] error (send) - " + GetErrorString( ) );
311			return;
312		}
313		else if( s > 0 )
314		{
315			// success! only some of the data may have been sent, remove it from the buffer
316
317			if( !m_LogFile.empty( ) )
318			{
319				ofstream Log;
320				Log.open( m_LogFile.c_str( ), ios :: app );
321
322				if( !Log.fail( ) )
323				{
324					Log << "SEND >>> " << UTIL_ByteArrayToHexString( BYTEARRAY( m_SendBuffer.begin( ), m_SendBuffer.begin( ) + s ) ) << endl;
325					Log.close( );
326				}
327			}
328
329			m_SendBuffer = m_SendBuffer.substr( s );
330			m_LastSend = GetTime( );
331		}
332	}
333}
334
335void CTCPSocket :: Disconnect( )
336{
337	if( m_Socket != INVALID_SOCKET )
338		shutdown( m_Socket, SHUT_RDWR );
339
340	m_Connected = false;
341}
342
343void CTCPSocket :: SetNoDelay( bool noDelay )
344{
345	int OptVal = 0;
346
347	if( noDelay )
348		OptVal = 1;
349
350	setsockopt( m_Socket, IPPROTO_TCP, TCP_NODELAY, (const char *)&OptVal, sizeof( int ) );
351}
352
353//
354// CTCPClient
355//
356
357CTCPClient :: CTCPClient( ) : CTCPSocket( )
358{
359	m_Connecting = false;
360}
361
362CTCPClient :: ~CTCPClient( )
363{
364
365}
366
367void CTCPClient :: Reset( )
368{
369	CTCPSocket :: Reset( );
370	m_Connecting = false;
371}
372
373void CTCPClient :: Disconnect( )
374{
375	CTCPSocket :: Disconnect( );
376	m_Connecting = false;
377}
378
379void CTCPClient :: Connect( string localaddress, string address, uint16_t port )
380{
381	if( m_Socket == INVALID_SOCKET || m_HasError || m_Connecting || m_Connected )
382		return;
383
384	if( !localaddress.empty( ) )
385	{
386		struct sockaddr_in LocalSIN;
387		memset( &LocalSIN, 0, sizeof( LocalSIN ) );
388		LocalSIN.sin_family = AF_INET;
389
390		if( ( LocalSIN.sin_addr.s_addr = inet_addr( localaddress.c_str( ) ) ) == INADDR_NONE )
391			LocalSIN.sin_addr.s_addr = INADDR_ANY;
392
393		LocalSIN.sin_port = htons( 0 );
394
395		if( bind( m_Socket, (struct sockaddr *)&LocalSIN, sizeof( LocalSIN ) ) == SOCKET_ERROR )
396		{
397			m_HasError = true;
398			m_Error = GetLastError( );
399			CONSOLE_Print( "[TCPCLIENT] error (bind) - " + GetErrorString( ) );
400			return;
401		}
402	}
403
404	// get IP address
405
406	struct hostent *HostInfo;
407	uint32_t HostAddress;
408	HostInfo = gethostbyname( address.c_str( ) );
409
410	if( !HostInfo )
411	{
412		m_HasError = true;
413		// m_Error = h_error;
414		CONSOLE_Print( "[TCPCLIENT] error (gethostbyname)" );
415		return;
416	}
417
418	memcpy( &HostAddress, HostInfo->h_addr, HostInfo->h_length );
419
420	// connect
421
422	m_SIN.sin_family = AF_INET;
423	m_SIN.sin_addr.s_addr = HostAddress;
424	m_SIN.sin_port = htons( port );
425
426	if( connect( m_Socket, (struct sockaddr *)&m_SIN, sizeof( m_SIN ) ) == SOCKET_ERROR )
427	{
428		if( GetLastError( ) != EINPROGRESS && GetLastError( ) != EWOULDBLOCK )
429		{
430			// connect error
431
432			m_HasError = true;
433			m_Error = GetLastError( );
434			CONSOLE_Print( "[TCPCLIENT] error (connect) - " + GetErrorString( ) );
435			return;
436		}
437	}
438
439	m_Connecting = true;
440}
441
442bool CTCPClient :: CheckConnect( )
443{
444	if( m_Socket == INVALID_SOCKET || m_HasError || !m_Connecting )
445		return false;
446
447	fd_set fd;
448	FD_ZERO( &fd );
449	FD_SET( m_Socket, &fd );
450
451	struct timeval tv;
452	tv.tv_sec = 0;
453	tv.tv_usec = 0;
454
455	// check if the socket is connected
456
457#ifdef WIN32
458	if( select( 1, NULL, &fd, NULL, &tv ) == SOCKET_ERROR )
459#else
460	if( select( m_Socket + 1, NULL, &fd, NULL, &tv ) == SOCKET_ERROR )
461#endif
462	{
463		m_HasError = true;
464		m_Error = GetLastError( );
465		return false;
466	}
467
468	if( FD_ISSET( m_Socket, &fd ) )
469	{
470		m_Connecting = false;
471		m_Connected = true;
472		return true;
473	}
474
475	return false;
476}
477
478//
479// CTCPServer
480//
481
482CTCPServer :: CTCPServer( ) : CTCPSocket( )
483{
484	// set the socket to reuse the address in case it hasn't been released yet
485
486	int optval = 1;
487
488#ifdef WIN32
489	setsockopt( m_Socket, SOL_SOCKET, SO_REUSEADDR, (const char *)&optval, sizeof( int ) );
490#else
491	setsockopt( m_Socket, SOL_SOCKET, SO_REUSEADDR, (const void *)&optval, sizeof( int ) );
492#endif
493}
494
495CTCPServer :: ~CTCPServer( )
496{
497
498}
499
500bool CTCPServer :: Listen( string address, uint16_t port )
501{
502	if( m_Socket == INVALID_SOCKET || m_HasError )
503		return false;
504
505	m_SIN.sin_family = AF_INET;
506
507	if( !address.empty( ) )
508	{
509		if( ( m_SIN.sin_addr.s_addr = inet_addr( address.c_str( ) ) ) == INADDR_NONE )
510			m_SIN.sin_addr.s_addr = INADDR_ANY;
511	}
512	else
513		m_SIN.sin_addr.s_addr = INADDR_ANY;
514
515	m_SIN.sin_port = htons( port );
516
517	if( bind( m_Socket, (struct sockaddr *)&m_SIN, sizeof( m_SIN ) ) == SOCKET_ERROR )
518	{
519		m_HasError = true;
520		m_Error = GetLastError( );
521		CONSOLE_Print( "[TCPSERVER] error (bind) - " + GetErrorString( ) );
522		return false;
523	}
524
525	// listen, queue length 8
526
527	if( listen( m_Socket, 8 ) == SOCKET_ERROR )
528	{
529		m_HasError = true;
530		m_Error = GetLastError( );
531		CONSOLE_Print( "[TCPSERVER] error (listen) - " + GetErrorString( ) );
532		return false;
533	}
534
535	return true;
536}
537
538CTCPSocket *CTCPServer :: Accept( fd_set *fd )
539{
540	if( m_Socket == INVALID_SOCKET || m_HasError )
541		return NULL;
542
543	if( FD_ISSET( m_Socket, fd ) )
544	{
545		// a connection is waiting, accept it
546
547		struct sockaddr_in Addr;
548		int AddrLen = sizeof( Addr );
549		SOCKET NewSocket;
550
551#ifdef WIN32
552		if( ( NewSocket = accept( m_Socket, (struct sockaddr *)&Addr, &AddrLen ) ) == INVALID_SOCKET )
553#else
554		if( ( NewSocket = accept( m_Socket, (struct sockaddr *)&Addr, (socklen_t *)&AddrLen ) ) == INVALID_SOCKET )
555#endif
556		{
557			// accept error, ignore it
558		}
559		else
560		{
561			// success! return the new socket
562
563			return new CTCPSocket( NewSocket, Addr );
564		}
565	}
566
567	return NULL;
568}
569
570//
571// CUDPSocket
572//
573
574CUDPSocket :: CUDPSocket( ) : CSocket( )
575{
576	Allocate( SOCK_DGRAM );
577
578	// enable broadcast support
579
580	int OptVal = 1;
581	setsockopt( m_Socket, SOL_SOCKET, SO_BROADCAST, (const char *)&OptVal, sizeof( int ) );
582	
583	// set default broadcast target
584	m_BroadcastTarget.s_addr = INADDR_BROADCAST;
585}
586
587CUDPSocket :: ~CUDPSocket( )
588{
589
590}
591
592bool CUDPSocket :: SendTo( struct sockaddr_in sin, BYTEARRAY message )
593{
594	if( m_Socket == INVALID_SOCKET || m_HasError )
595		return false;
596
597	string MessageString = string( message.begin( ), message.end( ) );
598
599	if( sendto( m_Socket, MessageString.c_str( ), MessageString.size( ), 0, (struct sockaddr *)&sin, sizeof( sin ) ) == -1 )
600		return false;
601
602	return true;
603}
604
605bool CUDPSocket :: SendTo( string address, uint16_t port, BYTEARRAY message )
606{
607	if( m_Socket == INVALID_SOCKET || m_HasError )
608		return false;
609
610	// get IP address
611
612	struct hostent *HostInfo;
613	uint32_t HostAddress;
614	HostInfo = gethostbyname( address.c_str( ) );
615
616	if( !HostInfo )
617	{
618		m_HasError = true;
619		// m_Error = h_error;
620		CONSOLE_Print( "[UDPSOCKET] error (gethostbyname)" );
621		return false;
622	}
623
624	memcpy( &HostAddress, HostInfo->h_addr, HostInfo->h_length );
625	struct sockaddr_in sin;
626	sin.sin_family = AF_INET;
627	sin.sin_addr.s_addr = HostAddress;
628	sin.sin_port = htons( port );
629
630	return SendTo( sin, message );
631}
632
633bool CUDPSocket :: Broadcast( uint16_t port, BYTEARRAY message )
634{
635	if( m_Socket == INVALID_SOCKET || m_HasError )
636		return false;
637
638	struct sockaddr_in sin;
639	sin.sin_family = AF_INET;
640	sin.sin_addr.s_addr = m_BroadcastTarget.s_addr;
641	sin.sin_port = htons( port );
642
643	string MessageString = string( message.begin( ), message.end( ) );
644
645	if( sendto( m_Socket, MessageString.c_str( ), MessageString.size( ), 0, (struct sockaddr *)&sin, sizeof( sin ) ) == -1 )
646	{
647		CONSOLE_Print( "[UDPSOCKET] failed to broadcast packet (port " + UTIL_ToString( port ) + ", size " + UTIL_ToString( MessageString.size( ) ) + " bytes)" );
648		return false;
649	}
650
651	return true;
652}
653
654void CUDPSocket :: SetBroadcastTarget( string subnet )
655{
656	if( subnet.empty( ) )
657	{
658		CONSOLE_Print( "[UDPSOCKET] using default broadcast target" );
659		m_BroadcastTarget.s_addr = INADDR_BROADCAST;
660	}
661	else
662	{
663		// this function does not check whether the given subnet is a valid subnet the user is on
664		// convert string representation of ip/subnet to in_addr
665
666		CONSOLE_Print( "[UDPSOCKET] using broadcast target [" + subnet + "]" );
667		m_BroadcastTarget.s_addr = inet_addr( subnet.c_str( ) );
668
669		// if conversion fails, inet_addr( ) returns INADDR_NONE
670
671		if( m_BroadcastTarget.s_addr == INADDR_NONE )
672		{
673			CONSOLE_Print( "[UDPSOCKET] invalid broadcast target, using default broadcast target" );
674			m_BroadcastTarget.s_addr = INADDR_BROADCAST;
675		}
676	}
677}
678
679void CUDPSocket :: SetDontRoute( bool dontRoute )
680{
681	int OptVal = 0;
682
683	if( dontRoute )
684		OptVal = 1;
685
686	// don't route packets; make them ignore routes set by routing table and send them to the interface
687	// belonging to the target address directly
688
689	setsockopt( m_Socket, SOL_SOCKET, SO_DONTROUTE, (const char *)&OptVal, sizeof( int ) );
690}
691
692//
693// CUDPServer
694//
695
696CUDPServer :: CUDPServer( ) : CUDPSocket( )
697{
698	// make socket non blocking
699
700#ifdef WIN32
701	int iMode = 1;
702	ioctlsocket( m_Socket, FIONBIO, (u_long FAR *)&iMode );
703#else
704	fcntl( m_Socket, F_SETFL, fcntl( m_Socket, F_GETFL ) | O_NONBLOCK );
705#endif
706
707	// set the socket to reuse the address
708	// with UDP sockets this allows more than one program to listen on the same port
709
710	int optval = 1;
711
712#ifdef WIN32
713	setsockopt( m_Socket, SOL_SOCKET, SO_REUSEADDR, (const char *)&optval, sizeof( int ) );
714#else
715	setsockopt( m_Socket, SOL_SOCKET, SO_REUSEADDR, (const void *)&optval, sizeof( int ) );
716#endif
717}
718
719CUDPServer :: ~CUDPServer( )
720{
721
722}
723
724bool CUDPServer :: Bind( struct sockaddr_in sin )
725{
726	if( m_Socket == INVALID_SOCKET || m_HasError )
727		return false;
728
729	m_SIN = sin;
730
731	if( bind( m_Socket, (struct sockaddr *)&m_SIN, sizeof( m_SIN ) ) == SOCKET_ERROR )
732	{
733		m_HasError = true;
734		m_Error = GetLastError( );
735		CONSOLE_Print( "[UDPSERVER] error (bind) - " + GetErrorString( ) );
736		return false;
737	}
738
739	return true;
740}
741
742bool CUDPServer :: Bind( string address, uint16_t port )
743{
744	if( m_Socket == INVALID_SOCKET || m_HasError )
745		return false;
746
747	struct sockaddr_in sin;
748	sin.sin_family = AF_INET;
749
750	if( !address.empty( ) )
751	{
752		if( ( sin.sin_addr.s_addr = inet_addr( address.c_str( ) ) ) == INADDR_NONE )
753			sin.sin_addr.s_addr = INADDR_ANY;
754	}
755	else
756		sin.sin_addr.s_addr = INADDR_ANY;
757
758	sin.sin_port = htons( port );
759
760	return Bind( sin );
761}
762
763void CUDPServer :: RecvFrom( fd_set *fd, struct sockaddr_in *sin, string *message )
764{
765	if( m_Socket == INVALID_SOCKET || m_HasError || !sin || !message )
766		return;
767
768	int AddrLen = sizeof( *sin );
769
770	if( FD_ISSET( m_Socket, fd ) )
771	{
772		// data is waiting, receive it
773
774		char buffer[1024];
775
776#ifdef WIN32
777		int c = recvfrom( m_Socket, buffer, 1024, 0, (struct sockaddr *)sin, &AddrLen );
778#else
779		int c = recvfrom( m_Socket, buffer, 1024, 0, (struct sockaddr *)sin, (socklen_t *)&AddrLen );
780#endif
781
782		if( c == SOCKET_ERROR && GetLastError( ) != EWOULDBLOCK )
783		{
784			// receive error
785
786			m_HasError = true;
787			m_Error = GetLastError( );
788			CONSOLE_Print( "[UDPSERVER] error (recvfrom) - " + GetErrorString( ) );
789		}
790		else if( c > 0 )
791		{
792			// success!
793
794			*message = string( buffer, c );
795		}
796	}
797}