Important Update:

- SelectableCore:
  - Finish UDP implementation
    - Change UDPsock to UDPserver/client/remote
    - Add OpenUDPserver/client/remote methods
    - Add ReadFrom/WriteToUDP() methods (cannot write to FD)
    - ReadFrom/WriteToFD():
      - return negative bytes on error
      - small delay between consecutive reads/writes
  - Set address correctly on resolve (for UDP or TCP)
  - Improve ReadFrom/WriteToFD() methods (improved timing & error)
  - Improve error reporting on Input/OutputHandle() methods
- CharBufferCore:
  - Standardise ReadFrom/WriteToFD() method
  - Bug fix: Peek/PeekCopy error if Data param not passed
- FileCore
  - Standardise ReadFrom/WriteToFD() method
This commit is contained in:
Charl Wentzel
2018-11-19 19:52:39 +02:00
parent 1e74b9cd60
commit 278198171d
4 changed files with 420 additions and 129 deletions

View File

@@ -170,7 +170,7 @@ bool CSelectableCore::LoadConfigData()
}
SetUnixHandle( Handle, ctUNIXclient, Address );
}
else if (!strcasecmp( Type, "UDP" ))
else if (!strcasecmp( Type, "UDPserver" ))
{
if ((Name = (char*)TempMember->GetMemStr( "Socket/Name", NULL ))) {
sprintf( Path, "Address/%s/Address", Name );
@@ -183,7 +183,22 @@ bool CSelectableCore::LoadConfigData()
Port = (char*)TempMember->GetMemStr( "Socket/Port", "0", true ); // Get default Port value
}
Delay = TempMember->GetMemInt( "Socket/ResolveDelay", 0, true );
SetSocketHandle( Handle, ctUDPsock, Address, strlcase(Port), Delay );
SetSocketHandle( Handle, ctUDPserver, Address, strlcase(Port), Delay );
}
else if (!strcasecmp( Type, "UDPclient" ))
{
if ((Name = (char*)TempMember->GetMemStr( "Socket/Name", NULL ))) {
sprintf( Path, "Address/%s/Address", Name );
Address = (char*)DataTree->GetMemStr( Path, NULL, true ); // Get AddressList Address value
sprintf( Path, "Address/%s/Port", Name );
Port = (char*)DataTree->GetMemStr( Path, "0", true ); // Get AddressList Port value
}
else {
Address = (char*)TempMember->GetMemStr( "Socket/Address", NULL, true ); // Get default Address value
Port = (char*)TempMember->GetMemStr( "Socket/Port", "0", true ); // Get default Port value
}
Delay = TempMember->GetMemInt( "Socket/ResolveDelay", 0, true );
SetSocketHandle( Handle, ctUDPclient, Address, strlcase(Port), Delay );
}
else if (!strcasecmp( Type, "TCPserver" ))
{
@@ -465,7 +480,7 @@ bool CSelectableCore::SetSocketHandle( THandle * Handle, EConnectType Type, con
{
// Validate
if (!Handle || !HostName || !PortName ||
!((Type == ctUDPsock) || (Type == ctTCPserver) || (Type == ctTCPclient) || (Type == ctTCPremote)) ||
!((Type == ctUDPserver) || (Type == ctUDPclient) || (Type == ctUDPremote) || (Type == ctTCPserver) || (Type == ctTCPclient) || (Type == ctTCPremote)) ||
!((Handle->Type == ctNone) || (Handle->Type == Type)) ) {
return false;
}
@@ -1098,8 +1113,13 @@ bool CSelectableCore::ResolveAddress( THandle * Handle, bool DelayResolve )
// Set address specification
memset( &hints, 0, sizeof hints );
hints.ai_family = AF_UNSPEC; // use AF_INET6 to force IPv6
hints.ai_socktype = SOCK_STREAM;
if ((Handle->Type == ctTCPserver) || (Handle->Type == ctTCPclient)) {
hints.ai_family = AF_UNSPEC; // use AF_INET6 to force IPv6
hints.ai_socktype = SOCK_STREAM;
} else {
hints.ai_family = AF_UNSPEC; // use AF_INET6 to force IPv6
hints.ai_socktype = SOCK_DGRAM;
}
if (Log) Log->Message( LogLevel, dlMedium, "%s: Handle '%s' - Resolving Host name [%s:%s]...",
Name, Handle->Name, Handle->HostName, Handle->PortName );
@@ -1145,18 +1165,10 @@ bool CSelectableCore::ResolveAddress( THandle * Handle, bool DelayResolve )
}
//---------------------------------------------------------------------------
int CSelectableCore::OpenUDPsocket( THandle * Handle, bool DelayResolve )
int CSelectableCore::OpenUDPserverSocket( THandle * Handle, bool DelayResolve )
{
// Socket options
struct linger ServerLinger_opt;
ServerLinger_opt.l_onoff = 1;
ServerLinger_opt.l_linger = 5;
int Reuse_opt = 1;
int KeepAlive_opt = 1;
// Validate Handle
if (Handle->Type != ctUDPsock) {
if (Handle->Type != ctUDPserver) {
return false;
}
@@ -1168,25 +1180,13 @@ int CSelectableCore::OpenUDPsocket( THandle * Handle, bool DelayResolve )
if ((Handle->FD = socket( Handle->AddressInfo->ai_family, Handle->AddressInfo->ai_socktype, Handle->AddressInfo->ai_protocol )) < 0)
{
// Log Event
if (Log) Log->Message( LogLevel, dlMedium, "%s: Handle '%s' - Failed to create UDP Server socket [%s:%s] (%s)", Name, Handle->Name, Handle->HostName, Handle->PortName, strerror(errno) );
if (Log) Log->Message( LogLevel, dlMedium, "%s: Handle '%s' - Failed to create UDP socket [%s:%s] (%s)", Name, Handle->Name, Handle->HostName, Handle->PortName, strerror(errno) );
// Set state
ChangeState( Handle, csFailed );
return -1;
};
// Configure connection
if ((setsockopt( Handle->FD, SOL_SOCKET, SO_LINGER, &ServerLinger_opt, sizeof(ServerLinger_opt)) == -1) ||
(setsockopt( Handle->FD, SOL_SOCKET, SO_REUSEADDR, &Reuse_opt, sizeof(Reuse_opt)) == -1))
{
// Log Event
if (Log) Log->Message( LogLevel, dlMedium, "%s: Handle '%s' - Could not set socket options [%s:%s] (%s)", Name, Handle->Name, Handle->HostName, Handle->PortName, strerror(errno) );
// Set state
ChangeState( Handle, csFailed );
return -1;
}
// Set non-blocking flag
int flags = fcntl( Handle->FD, F_GETFL, 0 );
fcntl( Handle->FD, F_SETFL, flags | O_NONBLOCK );
@@ -1195,21 +1195,7 @@ int CSelectableCore::OpenUDPsocket( THandle * Handle, bool DelayResolve )
if (bind( Handle->FD, Handle->AddressInfo->ai_addr, Handle->AddressInfo->ai_addrlen ) < 0)
{
// Log Event
if (Log) Log->Message( LogLevel, dlMedium, "%s: Handle '%s' - Failed to bind UDP Server socket [%s:%s] (%s)", Name, Handle->Name, Handle->HostName, Handle->PortName, strerror(errno) );
// Set state
close( Handle->FD );
Handle->FD = -1;
ChangeState( Handle, csFailed );
Handle->AddressFailed = true;
return -1;
};
// Create que for 5 connections
if (listen( Handle->FD, 5 ) < 0)
{
// Log Event
if (Log) Log->Message( LogLevel, dlMedium, "%s: Handle '%s' - Failed to listen on UDP Server socket [%s:%s] (%s)", Name, Handle->Name, Handle->HostName, Handle->PortName, strerror(errno) );
if (Log) Log->Message( LogLevel, dlMedium, "%s: Handle '%s' - Failed to bind UDP socket [%s:%s] (%s)", Name, Handle->Name, Handle->HostName, Handle->PortName, strerror(errno) );
// Set state
close( Handle->FD );
@@ -1220,7 +1206,7 @@ int CSelectableCore::OpenUDPsocket( THandle * Handle, bool DelayResolve )
};
// Log Event
if (Log) Log->Message( LogLevel, dlMedium, "%s: Handle '%s' - UDP Server binded and listening [%s:%s]", Name, Handle->Name, Handle->HostName, Handle->PortName );
if (Log) Log->Message( LogLevel, dlMedium, "%s: Handle '%s' - UDP socket binded and listening [%s:%s]", Name, Handle->Name, Handle->HostName, Handle->PortName );
// Add to Select Lists
if (Selector) {
@@ -1233,6 +1219,101 @@ int CSelectableCore::OpenUDPsocket( THandle * Handle, bool DelayResolve )
}
//---------------------------------------------------------------------------
int CSelectableCore::OpenUDPremoteSocket( THandle * Handle, char * ClientAddress, char * ClientPort )
{
THandle ** RemoteClient;
int ClientCount;
char ClientName[100];
// Validate
if (!Handle || (Handle->Type != ctUDPserver)) {
return -1;
}
// Check if Remote client already exists
ClientCount = 1;
RemoteClient = &FirstHandle;
while (*RemoteClient && (strcmp((*RemoteClient)->HostName, ClientAddress) || strcmp((*RemoteClient)->PortName, ClientPort))) {
RemoteClient = &((*RemoteClient)->Next);
ClientCount++;
}
if (*RemoteClient) {
return (*RemoteClient)->FD;
}
// Create Remote Client Handle
sprintf( ClientName, "%s-%d", Handle->Name, ClientCount );
*RemoteClient = CreateHandle( ClientName, false );
if (!SetSocketHandle( *RemoteClient, ctUDPremote, ClientAddress, ClientPort, 0 )) {
if (Log) Log->Message( LogLevel, dlMedium, "%s: Handle '%s' - UDP Server failed to configure Remote UDP Client connection (%s)", Name, Handle->Name, strerror(errno) );
return -1;
}
// Copy Parent Buffer setup
SetInBuffer( *RemoteClient, ((Handle->InBuffer)? Handle->InBuffer->Size() : 0),
Handle->InTimeout, Handle->InMarker, Handle->InMarkerLen );
SetOutBuffer( *RemoteClient, ((Handle->OutBuffer)? Handle->OutBuffer->Size() : 0) );
// Set Key parameters
(*RemoteClient)->FD = Handle->FD;
(*RemoteClient)->Parent = Handle;
(*RemoteClient)->State = csOpen;
// Reset Timer
SetStartTime( &((*RemoteClient)->LastAction) );
// Log Event
if (Log) Log->Message( LogLevel, dlMedium, "%s: Handle '%s' - UDP Server accepted Remote UDP Client connection [%s:%s]", Name, Handle->Name, ClientAddress, ClientPort );
// Add to Select Lists
if (Selector) {
Selector->Add( (*RemoteClient)->FD, true, true, *RemoteClient, this );
}
return (*RemoteClient)->FD;
}
//---------------------------------------------------------------------------
int CSelectableCore::OpenUDPclientSocket( THandle * Handle, bool DelayResolve )
{
// Check state
if (Handle->State == csOpen) {
// Already open
return Handle->FD;
}
// Resolve IP Address
if (!ResolveAddress( Handle, DelayResolve ))
return -1;
// Create File descriptor
if ((Handle->FD = socket( Handle->AddressInfo->ai_family, Handle->AddressInfo->ai_socktype, Handle->AddressInfo->ai_protocol )) < 0)
{
// Log Event
if (Log) Log->Message( LogLevel, dlMedium, "%s: Handle '%s' - Failed to create UDP Client socket [%s:%s] (%s)", Name, Handle->Name, Handle->HostName, Handle->PortName, strerror(errno) );
// Set Status
ChangeState( Handle, csFailed );
return -1;
};
// Set Non blocking open
int flags = fcntl( Handle->FD, F_GETFL, 0 );
fcntl( Handle->FD, F_SETFL, O_NONBLOCK|flags );
if (Log) Log->Message( LogLevel, dlMedium, "%s: Handle '%s' - UDP Client ready [%s:%s]", Name, Handle->Name, Handle->HostName, Handle->PortName );
// Add to Select Lists
if (Selector) {
Selector->Add( Handle->FD, true, true, Handle, this );
}
// Set status
ChangeState( Handle, csOpen );
return Handle->FD;
}
//---------------------------------------------------------------------------
int CSelectableCore::OpenTCPserverSocket( THandle * Handle, bool DelayResolve )
{
// Socket options
@@ -1567,11 +1648,11 @@ int CSelectableCore::Open( THandle * Handle, bool DelayResolve )
case ctUNIXclient :
FD = OpenUNIXclientSocket( Handle );
break;
case ctUNIXremote :
FD = OpenUNIXremoteSocket( Handle );
case ctUDPserver :
FD = OpenUDPserverSocket( Handle, DelayResolve );
break;
case ctUDPsock :
FD = OpenUDPsocket( Handle, DelayResolve );
case ctUDPclient :
FD = OpenUDPclientSocket( Handle, DelayResolve );
break;
case ctTCPserver :
FD = OpenTCPserverSocket( Handle, DelayResolve );
@@ -1579,9 +1660,6 @@ int CSelectableCore::Open( THandle * Handle, bool DelayResolve )
case ctTCPclient :
FD = OpenTCPclientSocket( Handle, DelayResolve );
break;
case ctTCPremote :
FD = OpenTCPremoteSocket( Handle );
break;
default:
FD = -1;
}
@@ -1604,7 +1682,7 @@ bool CSelectableCore::Close( THandle * Handle, bool QuickReopen )
return false;
// Close Children
if ((Handle->Type == ctTCPserver) || (Handle->Type == ctUNIXserver))
if ((Handle->Type == ctTCPserver) || (Handle->Type == ctUDPserver) || (Handle->Type == ctUNIXserver))
{
ChildHandle = FirstHandle;
while (ChildHandle)
@@ -1625,7 +1703,11 @@ bool CSelectableCore::Close( THandle * Handle, bool QuickReopen )
}
// Close Handle
Fail = (close( Handle->FD ))? true : false;
if (Handle->Type == ctUDPremote) {
Fail = false;
} else {
Fail = (close( Handle->FD ))? true : false;
}
ChangeState( Handle, ((Fail)? csFailed : csClosed) );
// Start timer (for re-open)
@@ -1657,15 +1739,23 @@ bool CSelectableCore::Close( THandle * Handle, bool QuickReopen )
break;
case ctUNIXclient:
if (Log) Log->Message( LogLevel, dlMedium, "%s: Handle '%s' - UNIX Client connection %s [%s]", Name, Handle->Name, ((Fail)? "failed" : "closed"), Handle->Path );
if (Log) Log->Message( LogLevel, dlMedium, "%s: Handle '%s' - UNIX Client %s [%s]", Name, Handle->Name, ((Fail)? "failed" : "closed"), Handle->Path );
break;
case ctUNIXremote:
if (Log) Log->Message( LogLevel, dlMedium, "%s: Handle '%s' - UNIX Remote Client connection %s [%s]", Name, Handle->Name, ((Fail)? "failed" : "closed"), Handle->Path );
if (Log) Log->Message( LogLevel, dlMedium, "%s: Handle '%s' - UNIX Remote Client %s [%s]", Name, Handle->Name, ((Fail)? "failed" : "closed"), Handle->Path );
break;
case ctUDPsock:
if (Log) Log->Message( LogLevel, dlMedium, "%s: Handle '%s' - UDP Socket connection %s [%s:%s]", Name, Handle->Name, ((Fail)? "failed" : "closed"), Handle->HostName, Handle->PortName );
case ctUDPserver:
if (Log) Log->Message( LogLevel, dlMedium, "%s: Handle '%s' - UDP Server %s [%s:%s]", Name, Handle->Name, ((Fail)? "failed" : "closed"), Handle->HostName, Handle->PortName );
break;
case ctUDPclient:
if (Log) Log->Message( LogLevel, dlMedium, "%s: Handle '%s' - UDP Client %s [%s:%s]", Name, Handle->Name, ((Fail)? "failed" : "closed"), Handle->HostName, Handle->PortName );
break;
case ctUDPremote:
if (Log) Log->Message( LogLevel, dlMedium, "%s: Handle '%s' - UDP Remote Client %s [%s:%s]", Name, Handle->Name, ((Fail)? "failed" : "closed"), Handle->HostName, Handle->PortName );
break;
case ctTCPserver:
@@ -1673,11 +1763,11 @@ bool CSelectableCore::Close( THandle * Handle, bool QuickReopen )
break;
case ctTCPremote:
if (Log) Log->Message( LogLevel, dlMedium, "%s: Handle '%s' - TCP Remote Client connection %s [%s]", Name, Handle->Name, ((Fail)? "failed" : "closed"), Handle->HostName );
if (Log) Log->Message( LogLevel, dlMedium, "%s: Handle '%s' - TCP Remote Client %s [%s]", Name, Handle->Name, ((Fail)? "failed" : "closed"), Handle->HostName );
break;
case ctTCPclient:
if (Log) Log->Message( LogLevel, dlMedium, "%s: Handle '%s' - TCP Client connection %s [%s:%s]", Name, Handle->Name, ((Fail)? "failed" : "closed"), Handle->HostName, Handle->PortName );
if (Log) Log->Message( LogLevel, dlMedium, "%s: Handle '%s' - TCP Client %s [%s:%s]", Name, Handle->Name, ((Fail)? "failed" : "closed"), Handle->HostName, Handle->PortName );
break;
case ctNone:
@@ -1704,6 +1794,10 @@ bool CSelectableCore::Read( THandle * Handle )
int BytesRead = 0;
int BytesWaiting = -1;
char * UDPbuffer = NULL;
char UDPaddress[50] = "";
char UDPport[20] = "";
// Validate
if (!Handle || (Handle->State == csNone) || (Handle->State == csFailed) || (Handle->State == csClosed)) {
return false;
@@ -1774,6 +1868,37 @@ bool CSelectableCore::Read( THandle * Handle )
return false;
}
}
else if ((Handle->Type == ctUDPserver) || (Handle->Type == ctUDPclient) || (Handle->Type == ctUDPremote))
{
// Check if anything to read
ioctl( Handle->FD, FIONREAD, &BytesWaiting );
if (BytesWaiting < 0)
{
if (Log) Log->Message( LogLevel, dlMedium, "%s: Handle '%s' - Data waiting error (%s)", Name, Handle->Name, strerror(errno) );
// Close Handle
Close( Handle, false );
return false;
}
// Read incoming message and address
errno = 0;
UDPbuffer = (char*)malloc( BytesWaiting+1 );
BytesRead = ReadFromUDP( Handle, (char*)UDPaddress, (char*)UDPport, UDPbuffer, BytesWaiting );
if (!errno && (Handle->Type == ctUDPserver))
{
// Create/Find Incoming client
ClientFD = OpenUDPremoteSocket( Handle, UDPaddress, UDPport );
if (ClientFD == -1) {
return false;
}
}
// Reset Timer
SetStartTime( &(Handle->LastAction) );
}
else if (Handle->Type == ctSerial)
{
// Check if anything to read
@@ -1811,10 +1936,31 @@ bool CSelectableCore::Read( THandle * Handle )
}
// Read File directly into buffer
if (Handle->InBuffer && (BytesRead = Handle->InBuffer->ReadFromFD( Handle->FD, BytesWaiting )))
if (Handle->InBuffer)
{
// Process Buffer
ProcessInputBuffer( Handle, false );
if ((Handle->Type == ctUDPserver) || (Handle->Type == ctUDPclient) || (Handle->Type == ctUDPremote)) {
if (BytesRead) {
Handle->InBuffer->Push( true, UDPbuffer, abs(BytesRead) );
}
if (UDPbuffer) free( UDPbuffer );
}
else {
errno = 0;
BytesRead = Handle->InBuffer->ReadFromFD( Handle->FD, BytesWaiting );
}
// Report failure
if (errno) {
if (Log) Log->Message( LogLevel, dlHigh, "%s: Handle '%s' - Error reading data [%d/%d] (%s)", Name, Handle->Name, -BytesRead, BytesWaiting, strerror(errno) );
}
else if (BytesRead < BytesWaiting) {
if (Log) Log->Message( LogLevel, dlHigh, "%s: Handle '%s' - Incomplete data read [%d/%d]", Name, Handle->Name, BytesRead, BytesWaiting );
}
if (BytesRead != 0) {
// Process Buffer
ProcessInputBuffer( Handle, false );
}
}
// Reset timer
@@ -1878,28 +2024,41 @@ bool CSelectableCore::Write( THandle * Handle )
{
if (Handle->OutBuffer)
{
// Write to FD directly from output buffer
if ((BytesWritten = Handle->OutBuffer->WriteToFD( Handle->FD )))
{
if (LogLevel >= dlHigh) {
// Show event
Len = Handle->OutBuffer->Peek( &Data );
if (Log) Log->Output( LogLevel, dlHigh, LogOutput, Data, Len, "%s: Handle '%s' - OUT:", Name, Handle->Name );
}
// Update Buffer
Handle->OutBuffer->Clear( BytesWritten );
// Reset Timer
SetStartTime( &(Handle->LastAction) );
// Write directly to handle / socket
errno = 0;
if ((Handle->Type == ctUDPclient)|| (Handle->Type == ctUDPremote)) {
Len = Handle->OutBuffer->Peek( &Data );
BytesWritten = WriteToUDP( Handle, Data, Len, true );
}
else {
BytesWritten = Handle->OutBuffer->WriteToFD( Handle->FD );
}
// Check if Buffer emtpy
if (!Handle->OutBuffer->Len()) {
// Add to Select Write list
if (Selector) {
Selector->Remove( Handle->FD, false, true );
if (Log) Log->Output( LogLevel, dlHigh, LogOutput, Data, Len, "%s: Handle '%s' - OUT:", Name, Handle->Name );
// Report failure
if (errno) {
if (Log) Log->Message( LogLevel, dlHigh, "%s: Handle '%s' - Error sending data [%d/%d] (%s)", Name, Handle->Name, -BytesWritten, Len, strerror(errno) );
}
else if (BytesWritten < Len) {
if (Log) Log->Message( LogLevel, dlHigh, "%s: Handle '%s' - Incomplete data sent [%d/%d]", Name, Handle->Name, BytesWritten, Len );
}
if (BytesWritten != 0)
{
// Update Buffer
Handle->OutBuffer->Clear( (BytesWritten > 0)? BytesWritten : -BytesWritten ); // negative value reported if error occurred
// Check if Buffer empty
if (!Handle->OutBuffer->Len()) {
// Add to Select Write list
if (Selector) {
Selector->Remove( Handle->FD, false, true );
}
}
// Reset timeout
SetStartTime( &(Handle->LastAction) );
}
}
else
@@ -1972,28 +2131,34 @@ int CSelectableCore::ReadFromFD( int FD, char * Data, int MaxLen )
{
int BytesRead = 0;
int TotalRead = 0;
int DataRemain = 0;
int DataRemain = MaxLen;
bool Error = false;
// Check if buffer created
if ((FD == -1) || !Data) {
if ((FD == -1) || (MaxLen < 1)) {
return 0;
}
// Read Data into buffer
DataRemain = (MaxLen == -1)? strlen(Data) : MaxLen;
while (DataRemain)
{
// Read from file descriptor
BytesRead = read( FD, &Data[TotalRead], DataRemain );
if ((BytesRead <= 0)) {
if ((BytesRead < 0)) {
Error = true;
errno = (!BytesRead)? 0 : errno; // No error if no bytes written
break;
}
// Update Data Pointers
TotalRead += BytesRead;
DataRemain -= BytesRead;
if (DataRemain) {
usleep( 500 );
}
}
return TotalRead;
return (Error)? -TotalRead : TotalRead; // Report negative total on error
}
//---------------------------------------------------------------------------
@@ -2001,28 +2166,81 @@ int CSelectableCore::WriteToFD( int FD, const char * Data, int Len, bool Force )
{
int BytesWritten = 0;
int TotalWritten = 0;
int DataRemain = 0;
int DataRemain = (Len != -1)? Len : (Data)? strlen(Data) : 0;
bool Error = false;
// Check if buffer created
if ((FD == -1) || !Data) {
if ((FD == -1) || !DataRemain) {
return 0;
}
// Read Data into buffer
DataRemain = (Len == -1)? strlen(Data) : Len;
while (DataRemain)
{
// Read from file descriptor
BytesWritten = write( FD, &Data[TotalWritten], DataRemain );
if ((BytesWritten <= 0) && (!Force || (errno != EAGAIN))) {
Error = true;
errno = (!BytesWritten)? 0 : errno; // No error if no bytes written
break;
}
// Update Data Pointers
TotalWritten += BytesWritten;
DataRemain -= BytesWritten;
if (DataRemain) {
usleep( 500 );
}
}
return TotalWritten;
return (Error)? -TotalWritten : TotalWritten; // Report negative total on error
}
//---------------------------------------------------------------------------
int CSelectableCore::ReadFromUDP( THandle * Handle, char * RemoteAddr, char * RemotePort, char * Data, int MaxLen )
{
int BytesRead = 0;
struct sockaddr_in Addr;
socklen_t AddrLen = sizeof(Addr);
// Check if buffer created
if (!Handle || (Handle->FD == -1) || !RemoteAddr || !RemotePort || (MaxLen < 1)) {
return 0;
}
// Get datagram
Addr.sin_family = AF_UNSPEC; // use AF_INET6 to force IPv6
Addr.sin_port = ((struct sockaddr_in *)Handle->AddressInfo->ai_addr)->sin_port;
Addr.sin_addr.s_addr = ((struct sockaddr_in *)Handle->AddressInfo->ai_addr)->sin_addr.s_addr;
BytesRead = recvfrom( Handle->FD, Data, MaxLen, 0, (struct sockaddr *)&Addr, &AddrLen );
if (BytesRead >= 0) {
// Decode address
strcpy( RemoteAddr, inet_ntoa(Addr.sin_addr) );
sprintf( RemotePort, "%d", ntohs(Addr.sin_port) );
}
return (BytesRead < 0)? 0 : BytesRead; // Report zero on error
}
//---------------------------------------------------------------------------
int CSelectableCore::WriteToUDP( THandle * Handle, const char * Data, int Len, bool Force )
{
int BytesWritten = 0;
int DataLen = (Len != -1)? Len : (Data)? strlen(Data) : 0;
// Check if buffer created
if (!Handle || (Handle->FD == -1) || !DataLen) {
return 0;
}
// Set Options
BytesWritten = sendto( Handle->FD, Data, DataLen, MSG_NOSIGNAL /*| ((!Force)? MSG_DONTWAIT : 0)*/,
Handle->AddressInfo->ai_addr, Handle->AddressInfo->ai_addrlen );
return (BytesWritten < 0)? 0 : BytesWritten; // Report zero on error
}
//---------------------------------------------------------------------------
@@ -2082,6 +2300,7 @@ int CSelectableCore::OutputHandle( THandle * Handle, const char * Data, int Len
{
THandle * ChildHandle = NULL;
int BytesWritten = 0;
int DataLen = (Len != -1)? Len : (Data)? strlen(Data) : 0;
if ((Handle->State != csOpen))
{
@@ -2146,14 +2365,29 @@ int CSelectableCore::OutputHandle( THandle * Handle, const char * Data, int Len
}
else
{
// Show event
// Write directly to handle / socket
errno = 0;
if ((Handle->Type == ctUDPclient)|| (Handle->Type == ctUDPremote)) {
BytesWritten = WriteToUDP( ChildHandle, Data, Len, true );
}
else {
BytesWritten = WriteToFD( ChildHandle->FD, Data, Len, true );
}
if (Log) Log->Output( LogLevel, dlHigh, LogOutput, Data, Len, "%s: Handle '%s' - OUT:", Name, ChildHandle->Name );
// Write directly to handle
BytesWritten = WriteToFD( ChildHandle->FD, Data, Len, true );
// Report failure
if (errno) {
if (Log) Log->Message( LogLevel, dlHigh, "%s: Handle '%s' - Error sending data [%d/%d] (%s)", Name, ChildHandle->Name, -BytesWritten, DataLen, strerror(errno) );
}
else if (BytesWritten < DataLen) {
if (Log) Log->Message( LogLevel, dlHigh, "%s: Handle '%s' - Incomplete data sent [%d/%d]", Name, ChildHandle->Name, BytesWritten, DataLen );
}
// Reset Timer
SetStartTime( &(Handle->LastAction) );
if (BytesWritten != 0) {
// Reset timeout
SetStartTime( &(ChildHandle->LastAction) );
}
}
}
// Next
@@ -2178,13 +2412,27 @@ int CSelectableCore::OutputHandle( THandle * Handle, const char * Data, int Len
}
else
{
// Show event
// Write directly to handle / socket
errno = 0;
if ((Handle->Type == ctUDPclient)|| (Handle->Type == ctUDPremote)) {
BytesWritten = WriteToUDP( Handle, Data, Len, true );
}
else {
BytesWritten = WriteToFD( Handle->FD, Data, Len, true );
}
if (Log) Log->Output( LogLevel, dlHigh, LogOutput, Data, Len, "%s: Handle '%s' - OUT:", Name, Handle->Name );
// Write directly to handle
if ((BytesWritten = WriteToFD( Handle->FD, Data, Len, true )))
{
// Reset Timer
// Report failure
if (errno) {
if (Log) Log->Message( LogLevel, dlHigh, "%s: Handle '%s' - Error sending data [%d/%d] (%s)", Name, Handle->Name, -BytesWritten, DataLen, strerror(errno) );
}
else if (BytesWritten < DataLen) {
if (Log) Log->Message( LogLevel, dlHigh, "%s: Handle '%s' - Incomplete data sent [%d/%d]", Name, Handle->Name, BytesWritten, DataLen );
}
if (BytesWritten != 0) {
// Reset timeout
SetStartTime( &(Handle->LastAction) );
}
}