mirror of
https://github.com/electronicarts/CnC_Renegade.git
synced 2025-12-16 23:51:41 -05:00
Initial commit of Command & Conquer Renegade source code.
This commit is contained in:
332
Code/Tools/RenegadeGR/tcpcon.cpp
Normal file
332
Code/Tools/RenegadeGR/tcpcon.cpp
Normal file
@@ -0,0 +1,332 @@
|
||||
/*
|
||||
** Command & Conquer Renegade(tm)
|
||||
** Copyright 2025 Electronic Arts Inc.
|
||||
**
|
||||
** This program is free software: you can redistribute it and/or modify
|
||||
** it under the terms of the GNU General Public License as published by
|
||||
** the Free Software Foundation, either version 3 of the License, or
|
||||
** (at your option) any later version.
|
||||
**
|
||||
** This program is distributed in the hope that it will be useful,
|
||||
** but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
** GNU General Public License for more details.
|
||||
**
|
||||
** You should have received a copy of the GNU General Public License
|
||||
** along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "tcpcon.h"
|
||||
#include <time.h>
|
||||
|
||||
#define DEFAULT_TCP_DELAY 15
|
||||
|
||||
TCPCon::TCPCon(SOCKET sock) :
|
||||
BufferedWrites_(false),
|
||||
TCPMgrPtr_(NULL)
|
||||
{
|
||||
Socket_=sock;
|
||||
isConnected(); // This will set the internal connect status
|
||||
setInputDelay(DEFAULT_TCP_DELAY);
|
||||
setOutputDelay(DEFAULT_TCP_DELAY);
|
||||
}
|
||||
|
||||
TCPCon::~TCPCon()
|
||||
{
|
||||
close(); // will try and flush the write queue
|
||||
ReadQueue_.clear();
|
||||
WriteQueue_.clear();
|
||||
|
||||
if ((BufferedWrites_) && (TCPMgrPtr_))
|
||||
TCPMgrPtr_->setBufferedWrites(this, FALSE);
|
||||
}
|
||||
|
||||
SOCKET TCPCon::getFD(void)
|
||||
{ return(Socket_); }
|
||||
|
||||
|
||||
void TCPCon::close(void)
|
||||
{
|
||||
if (BufferedWrites_)
|
||||
{
|
||||
while(WriteQueue_.length())
|
||||
pumpWrites();
|
||||
}
|
||||
::closesocket(Socket_);
|
||||
State_=TCPMgr::CLOSED;
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// Write data
|
||||
//
|
||||
// Returns 'n' bytes written, 0 if closed, or -1 for error.
|
||||
//
|
||||
sint32 TCPCon::write(IN uint8 *msg,uint32 len, sint32 wait_secs)
|
||||
{
|
||||
if (State_==TCPMgr::CLOSED)
|
||||
return(0);
|
||||
|
||||
if (BufferedWrites_)
|
||||
{
|
||||
WriteQueue_.addMany(msg, WriteQueue_.length(), len); // add to tail
|
||||
pumpWrites(); // send what I can
|
||||
return(len);
|
||||
}
|
||||
else
|
||||
{
|
||||
return (normalWrite(msg, len, wait_secs));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// set buffered status
|
||||
//
|
||||
void TCPCon::setBufferedWrites(TCPMgr *mgrptr, bit8 enabled)
|
||||
{
|
||||
if (enabled)
|
||||
BufferedWrites_=TRUE;
|
||||
else
|
||||
{
|
||||
while(WriteQueue_.length())
|
||||
pumpWrites();
|
||||
BufferedWrites_=FALSE;
|
||||
}
|
||||
TCPMgrPtr_=mgrptr;
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// Try and send queued data (PRIVATE)
|
||||
//
|
||||
void TCPCon::pumpWrites(void)
|
||||
{
|
||||
if (State_==TCPMgr::CLOSED)
|
||||
WriteQueue_.clear();
|
||||
|
||||
if (WriteQueue_.length()==0)
|
||||
return;
|
||||
|
||||
int sendlen;
|
||||
int retval;
|
||||
uint8 *bufptr=NULL;
|
||||
|
||||
while(1)
|
||||
{
|
||||
sendlen=WriteQueue_.length();
|
||||
if (sendlen == 0)
|
||||
break;
|
||||
|
||||
WriteQueue_.getPointer(&bufptr,0); // pointer to first byte
|
||||
|
||||
retval=normalWrite((uint8 *)bufptr, sendlen, 0);
|
||||
if (retval <= 0)
|
||||
break;
|
||||
|
||||
WriteQueue_.removeMany(NULL, 0, retval); // successful send
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// Non-buffered write (PRIVATE METHOD)
|
||||
//
|
||||
// Returns 'n' bytes written, 0 if closed, or -1 for error.
|
||||
//
|
||||
sint32 TCPCon::normalWrite(IN uint8 *msg,uint32 len, sint32 wait_secs)
|
||||
{
|
||||
if (State_==TCPMgr::CLOSED)
|
||||
return(0);
|
||||
|
||||
if (wait_secs < 0)
|
||||
wait_secs=OutputDelay_;
|
||||
|
||||
sint32 retval=0;
|
||||
sint32 sendCount=0;
|
||||
time_t start=time(NULL);
|
||||
|
||||
TCPMgr::STATUS status;
|
||||
|
||||
while(1)
|
||||
{
|
||||
retval=send(Socket_,(const char *)(msg+sendCount),(len-sendCount),0);
|
||||
if ((retval > 0) && (retval+sendCount)==int(len))
|
||||
break;
|
||||
if (retval==SOCKET_ERROR)
|
||||
{
|
||||
status=TCPMgr::getStatus();
|
||||
if ((status != TCPMgr::INTR) && (status != TCPMgr::WOULDBLOCK) && (status != TCPMgr::INPROGRESS))
|
||||
{
|
||||
if (sendCount)
|
||||
return(sendCount);
|
||||
else
|
||||
return(-1);
|
||||
}
|
||||
}
|
||||
else if (retval > 0)
|
||||
sendCount+=retval;
|
||||
|
||||
sint32 remaining_wait=wait_secs - (time(NULL)-start);
|
||||
if ((remaining_wait > 0) && (TCPMgr::wait(remaining_wait,0,&Socket_,1,FALSE) > 0))
|
||||
continue; // I can write now....
|
||||
|
||||
if (remaining_wait <= 0)
|
||||
break;
|
||||
}
|
||||
return(retval);
|
||||
}
|
||||
|
||||
//
|
||||
// Read data
|
||||
//
|
||||
// Returns 'n' bytes read, 0 for close, or -1 for error.
|
||||
// This may return less than we asked for
|
||||
//
|
||||
sint32 TCPCon::read(OUT uint8 *msg,uint32 maxlen, sint32 wait_secs)
|
||||
{
|
||||
sint32 retval=0;
|
||||
sint32 recvCount=0;
|
||||
time_t start=time(NULL);
|
||||
char readBuffer[257];
|
||||
|
||||
if (wait_secs < 0)
|
||||
wait_secs=InputDelay_;
|
||||
|
||||
if (State_==TCPMgr::CLOSED)
|
||||
return(0);
|
||||
|
||||
TCPMgr::STATUS status;
|
||||
|
||||
while(1)
|
||||
{
|
||||
// Do we even nead to read from the net?
|
||||
if (ReadQueue_.length() >= int(maxlen))
|
||||
{
|
||||
ReadQueue_.removeMany(msg, 0, maxlen);
|
||||
return(maxlen);
|
||||
}
|
||||
|
||||
do
|
||||
{
|
||||
retval=recv(Socket_,readBuffer, 256,0);
|
||||
if (retval > 0) // add to the tail of the list
|
||||
{
|
||||
readBuffer[retval]=0;
|
||||
DBGMSG("RECV: "<<readBuffer);
|
||||
|
||||
// Add to tail
|
||||
ReadQueue_.addMany((uint8 *)readBuffer, ReadQueue_.length(), retval);
|
||||
}
|
||||
} while ((retval > 0)&&(ReadQueue_.length() < int(maxlen)));
|
||||
|
||||
if (ReadQueue_.length()) // OK, we'll take what we've got
|
||||
{
|
||||
uint8 *cptr;
|
||||
ReadQueue_.getPointer(&cptr,0);
|
||||
|
||||
/*******
|
||||
fprintf(stderr,"ReadQueue(%d): '",ReadQueue_.length());
|
||||
for (int i=0; i<ReadQueue_.length(); i++)
|
||||
fprintf(stderr,"%c",cptr[i]);
|
||||
fprintf(stderr,"'\n");
|
||||
********/
|
||||
|
||||
int retcount=MIN(ReadQueue_.length(), int(maxlen));
|
||||
ReadQueue_.removeMany(msg, 0, retcount);
|
||||
return(retcount);
|
||||
}
|
||||
else if (retval==0)
|
||||
{
|
||||
close();
|
||||
return(0);
|
||||
}
|
||||
else if (retval==SOCKET_ERROR)
|
||||
{
|
||||
status=TCPMgr::getStatus();
|
||||
if ((status != TCPMgr::INTR) && (status != TCPMgr::WOULDBLOCK) &&
|
||||
(status != TCPMgr::INPROGRESS))
|
||||
return(-1);
|
||||
}
|
||||
|
||||
sint32 remaining_wait=wait_secs - (time(NULL)-start);
|
||||
if ((remaining_wait > 0) && (TCPMgr::wait(remaining_wait,0,&Socket_,1,TRUE) > 0))
|
||||
continue; // I can read now....
|
||||
|
||||
if (remaining_wait <= 0)
|
||||
break;
|
||||
}
|
||||
return(retval);
|
||||
}
|
||||
|
||||
// Push data back onto the read queue
|
||||
bit8 TCPCon::unread(uint8 *data, int length)
|
||||
{
|
||||
ReadQueue_.addMany(data, 0, length);
|
||||
return(TRUE);
|
||||
}
|
||||
|
||||
|
||||
// Returns 0 on failure
|
||||
// Returns IP in host byte order!
|
||||
bit8 TCPCon::getRemoteAddr(uint32 *ip, uint16 *port)
|
||||
{
|
||||
struct sockaddr_in sin;
|
||||
int sinSize=sizeof(sin);
|
||||
|
||||
if(getpeername(Socket_,(sockaddr *)&sin,&sinSize)==0)
|
||||
{
|
||||
if (ip)
|
||||
*ip=ntohl(sin.sin_addr.s_addr);
|
||||
if (port)
|
||||
*port=ntohs(sin.sin_port);
|
||||
return(TRUE);
|
||||
}
|
||||
return(FALSE);
|
||||
}
|
||||
|
||||
//
|
||||
// only use for strings up to 4096 chars!
|
||||
//
|
||||
sint32 TCPCon::printf(const char *format, ...)
|
||||
{
|
||||
va_list arg;
|
||||
char string[4097];
|
||||
sint32 retval;
|
||||
va_start(arg,format);
|
||||
vsprintf(string,format,arg);
|
||||
va_end(arg);
|
||||
string[4096]=0;
|
||||
|
||||
retval=write((IN uint8 *)string,strlen(string), OutputDelay_);
|
||||
return(retval);
|
||||
}
|
||||
|
||||
|
||||
bit8 TCPCon::isConnected(void)
|
||||
{
|
||||
uint32 remoteIp;
|
||||
uint16 remotePort;
|
||||
|
||||
if (getRemoteAddr(&remoteIp,&remotePort)==TRUE)
|
||||
{
|
||||
State_=TCPMgr::CONNECTED;
|
||||
return(TRUE);
|
||||
}
|
||||
else
|
||||
{
|
||||
State_=TCPMgr::CLOSED;
|
||||
return(FALSE);
|
||||
}
|
||||
}
|
||||
|
||||
/*********
|
||||
// For the OutputDevice interface
|
||||
int TCPCon::print(IN char *str, int len)
|
||||
{
|
||||
return(write((IN uint8 *)str,len,0));
|
||||
}
|
||||
********/
|
||||
|
||||
|
||||
Reference in New Issue
Block a user