2024-12-01 19:35:24 +00:00
|
|
|
//| Copyright: (C) 2020-2024 Kevin Larke <contact AT larke DOT org>
|
|
|
|
//| License: GNU GPL version 3.0 or above. See the accompanying LICENSE file.
|
2019-12-27 21:52:45 +00:00
|
|
|
#include "cwCommon.h"
|
|
|
|
#include "cwLog.h"
|
|
|
|
#include "cwCommonImpl.h"
|
|
|
|
#include "cwMem.h"
|
2024-11-30 17:19:43 +00:00
|
|
|
#include "cwTest.h"
|
|
|
|
#include "cwObject.h"
|
2019-12-27 21:52:45 +00:00
|
|
|
|
|
|
|
#include "cwThread.h"
|
|
|
|
|
|
|
|
#include "cwTcpSocket.h"
|
|
|
|
#include "cwTcpSocketSrv.h"
|
|
|
|
#include "cwTcpSocketTest.h"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
namespace cw
|
|
|
|
{
|
|
|
|
namespace net
|
|
|
|
{
|
|
|
|
namespace socket
|
|
|
|
{
|
|
|
|
typedef struct app_str
|
|
|
|
{
|
2020-01-29 16:42:41 +00:00
|
|
|
const char* remoteAddr;
|
|
|
|
unsigned remotePort;
|
2019-12-27 21:52:45 +00:00
|
|
|
unsigned recvBufByteN;
|
|
|
|
handle_t sockH;
|
|
|
|
thread::handle_t threadH;
|
|
|
|
unsigned cbN;
|
2020-01-27 22:52:53 +00:00
|
|
|
bool serverFl;
|
2019-12-27 21:52:45 +00:00
|
|
|
} app_t;
|
2020-01-27 22:52:53 +00:00
|
|
|
|
|
|
|
bool _dgramThreadFunc( void* arg )
|
2019-12-27 21:52:45 +00:00
|
|
|
{
|
|
|
|
rc_t rc;
|
|
|
|
app_t* app = static_cast<app_t*>(arg);
|
|
|
|
struct sockaddr_in fromAddr;
|
|
|
|
char addrBuf[ INET_ADDRSTRLEN ];
|
|
|
|
char buf[ app->recvBufByteN ];
|
|
|
|
unsigned recvBufByteN = 0;
|
|
|
|
|
2020-02-12 18:25:13 +00:00
|
|
|
if((rc = receive( app->sockH, buf, app->recvBufByteN, &recvBufByteN, &fromAddr )) == kOkRC )
|
2019-12-27 21:52:45 +00:00
|
|
|
{
|
|
|
|
addrToString( &fromAddr, addrBuf );
|
2024-11-30 17:19:43 +00:00
|
|
|
cwLogPrint("%i %s from %s\n", recvBufByteN, buf, addrBuf );
|
2019-12-27 21:52:45 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
app->cbN += 1;
|
|
|
|
if( app->cbN % 10 == 0)
|
|
|
|
{
|
2024-11-30 17:19:43 +00:00
|
|
|
cwLogPrint(".");
|
2019-12-27 21:52:45 +00:00
|
|
|
fflush(stdout);
|
|
|
|
}
|
|
|
|
|
2020-01-27 22:52:53 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool _tcpStreamThreadFunc( void* arg )
|
|
|
|
{
|
|
|
|
rc_t rc;
|
|
|
|
app_t* app = static_cast<app_t*>(arg);
|
|
|
|
char buf[ app->recvBufByteN ];
|
|
|
|
unsigned recvBufByteN = 0;
|
|
|
|
|
2020-01-29 16:42:41 +00:00
|
|
|
if( isConnected(app->sockH) == false )
|
2020-01-27 22:52:53 +00:00
|
|
|
{
|
2020-01-29 16:42:41 +00:00
|
|
|
if( app->serverFl )
|
2020-01-27 22:52:53 +00:00
|
|
|
{
|
|
|
|
if((rc = accept( app->sockH )) == kOkRC )
|
|
|
|
{
|
2024-11-30 17:19:43 +00:00
|
|
|
cwLogPrint("Server connected.\n");
|
2020-01-27 22:52:53 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
2020-01-29 16:42:41 +00:00
|
|
|
{
|
|
|
|
sleepMs(50);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2020-02-12 18:25:13 +00:00
|
|
|
if((rc = receive( app->sockH, buf, app->recvBufByteN, &recvBufByteN, nullptr )) == kOkRC )
|
2020-01-29 16:42:41 +00:00
|
|
|
{
|
|
|
|
// if the server disconnects then recvBufByteN
|
|
|
|
if( !isConnected( app->sockH) )
|
|
|
|
{
|
2024-11-30 17:19:43 +00:00
|
|
|
cwLogPrint("Disconnected.");
|
2020-01-29 16:42:41 +00:00
|
|
|
}
|
|
|
|
else
|
2020-01-27 22:52:53 +00:00
|
|
|
{
|
2024-11-30 17:19:43 +00:00
|
|
|
cwLogPrint("%i %s\n", recvBufByteN, buf );
|
2020-01-27 22:52:53 +00:00
|
|
|
}
|
|
|
|
}
|
2020-01-29 16:42:41 +00:00
|
|
|
}
|
2020-01-27 22:52:53 +00:00
|
|
|
|
|
|
|
// count the number of callbacks
|
|
|
|
app->cbN += 1;
|
|
|
|
if( app->cbN % 10 == 0)
|
|
|
|
{
|
|
|
|
// print '+' when the server is not connected.
|
2024-11-30 17:19:43 +00:00
|
|
|
cwLogPrint("%s", isConnected(app->sockH) == false ? "+" : ".");
|
2020-01-27 22:52:53 +00:00
|
|
|
fflush(stdout);
|
|
|
|
}
|
|
|
|
|
2019-12-27 21:52:45 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-11-30 17:19:43 +00:00
|
|
|
cw::rc_t cw::net::socket::test_udp( const object_t* cfg )
|
2019-12-27 21:52:45 +00:00
|
|
|
{
|
2024-11-30 17:19:43 +00:00
|
|
|
rc_t rc = kOkRC;
|
|
|
|
unsigned timeOutMs = 100;
|
|
|
|
const char* remoteAddr = "12.0.0.1";
|
|
|
|
portNumber_t remotePort = 5687;
|
|
|
|
portNumber_t localPort = 5688;
|
|
|
|
const unsigned sbufN = 31;
|
2019-12-27 21:52:45 +00:00
|
|
|
char sbuf[ sbufN+1 ];
|
|
|
|
app_t app;
|
|
|
|
|
|
|
|
app.cbN = 0;
|
|
|
|
app.recvBufByteN = sbufN+1;
|
2024-11-30 17:19:43 +00:00
|
|
|
|
|
|
|
if((rc = cfg->getv("localPort",localPort,
|
|
|
|
"remoteAddr",remoteAddr,
|
|
|
|
"remotePort",remotePort)) != kOkRC )
|
|
|
|
{
|
|
|
|
cwLogError(rc,"Arg. parse failed.");
|
|
|
|
goto errLabel;
|
|
|
|
}
|
2019-12-27 21:52:45 +00:00
|
|
|
|
|
|
|
if((rc = create(app.sockH,localPort, kBlockingFl,timeOutMs, NULL, kInvalidPortNumber )) != kOkRC )
|
|
|
|
return rc;
|
|
|
|
|
2024-02-18 13:37:33 +00:00
|
|
|
if((rc = thread::create( app.threadH, _dgramThreadFunc, &app, "tcp_sock_test_tcp" )) != kOkRC )
|
2019-12-27 21:52:45 +00:00
|
|
|
goto errLabel;
|
|
|
|
|
|
|
|
if((rc = thread::unpause( app.threadH )) != kOkRC )
|
|
|
|
goto errLabel;
|
|
|
|
|
2024-11-30 17:19:43 +00:00
|
|
|
cwLogPrint("Type a message to send or 'quit' to exit.\n");
|
|
|
|
|
2019-12-27 21:52:45 +00:00
|
|
|
while( true )
|
|
|
|
{
|
2024-11-30 17:19:43 +00:00
|
|
|
cwLogPrint("? ");
|
2019-12-27 21:52:45 +00:00
|
|
|
if( std::fgets(sbuf,sbufN,stdin) == sbuf )
|
|
|
|
{
|
2024-11-30 17:19:43 +00:00
|
|
|
cwLogPrint("Sending:%s",sbuf);
|
2019-12-27 21:52:45 +00:00
|
|
|
send(app.sockH, sbuf, strlen(sbuf)+1, remoteAddr, remotePort );
|
|
|
|
|
|
|
|
if( strcmp(sbuf,"quit\n") == 0)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
errLabel:
|
|
|
|
rc_t rc0 = thread::destroy(app.threadH);
|
|
|
|
|
|
|
|
rc_t rc1 = destroy(app.sockH);
|
|
|
|
|
|
|
|
return rcSelect(rc,rc0,rc1);
|
|
|
|
}
|
|
|
|
|
2020-01-27 22:52:53 +00:00
|
|
|
|
2024-11-30 17:19:43 +00:00
|
|
|
cw::rc_t cw::net::socket::test_tcp( const object_t* cfg )
|
2020-01-27 22:52:53 +00:00
|
|
|
{
|
2024-11-30 17:19:43 +00:00
|
|
|
rc_t rc = kOkRC;
|
2020-01-27 22:52:53 +00:00
|
|
|
unsigned timeOutMs = 100;
|
|
|
|
const unsigned sbufN = 31;
|
|
|
|
char sbuf[ sbufN+1 ];
|
|
|
|
app_t app;
|
2024-11-30 17:19:43 +00:00
|
|
|
bool serverFl = false;
|
|
|
|
bool dgramFl = true;
|
2020-01-27 22:52:53 +00:00
|
|
|
bool streamFl = !dgramFl;
|
|
|
|
bool clientFl = !serverFl;
|
|
|
|
unsigned flags = kTcpFl | kBlockingFl;
|
2024-11-30 17:19:43 +00:00
|
|
|
portNumber_t localPort = 5687;
|
|
|
|
const char* remoteAddr = "127.0.0.1";
|
|
|
|
portNumber_t remotePort = 5688;
|
2020-01-29 16:42:41 +00:00
|
|
|
|
|
|
|
app.remoteAddr = remoteAddr;
|
|
|
|
app.remotePort = remotePort;
|
2020-01-27 22:52:53 +00:00
|
|
|
app.cbN = 0;
|
|
|
|
app.recvBufByteN = sbufN+1;
|
|
|
|
app.serverFl = serverFl;
|
|
|
|
|
2024-11-30 17:19:43 +00:00
|
|
|
|
|
|
|
if((rc = cfg->getv("localPort",localPort,
|
|
|
|
"remoteAddr",remoteAddr,
|
|
|
|
"remotePort",remotePort,
|
|
|
|
"serverFl",serverFl,
|
|
|
|
"dgramFl",dgramFl,
|
|
|
|
"timeOutMs",timeOutMs )) != kOkRC )
|
|
|
|
{
|
|
|
|
rc = cwLogError(rc,"Arg. parse failed.");
|
|
|
|
goto errLabel;
|
|
|
|
}
|
|
|
|
|
|
|
|
streamFl = !dgramFl;
|
|
|
|
clientFl = !serverFl;
|
|
|
|
|
|
|
|
|
2020-01-27 22:52:53 +00:00
|
|
|
if( serverFl && streamFl )
|
|
|
|
flags |= kListenFl;
|
|
|
|
|
|
|
|
if( streamFl )
|
|
|
|
flags |= kStreamFl;
|
|
|
|
|
|
|
|
// create the socket
|
|
|
|
if((rc = create(app.sockH,localPort, flags,timeOutMs, NULL, kInvalidPortNumber )) != kOkRC )
|
|
|
|
return rc;
|
|
|
|
|
|
|
|
// create the listening thread (which is really only used by the server)
|
2024-02-18 13:37:33 +00:00
|
|
|
if((rc = thread::create( app.threadH, streamFl ? _tcpStreamThreadFunc : _dgramThreadFunc, &app, "tcp_sock_test" )) != kOkRC )
|
2020-01-27 22:52:53 +00:00
|
|
|
goto errLabel;
|
|
|
|
|
2020-01-29 16:42:41 +00:00
|
|
|
// if this is a streaming client then connect to the server (which must have already been started)
|
2020-01-27 22:52:53 +00:00
|
|
|
if( streamFl && clientFl )
|
|
|
|
{
|
2020-01-29 16:42:41 +00:00
|
|
|
// note that this creates a bi-directional stream
|
2020-01-27 22:52:53 +00:00
|
|
|
if((rc = connect(app.sockH,remoteAddr,remotePort)) != kOkRC )
|
2020-01-29 16:42:41 +00:00
|
|
|
goto errLabel;
|
2020-01-27 22:52:53 +00:00
|
|
|
}
|
|
|
|
|
2024-11-30 17:19:43 +00:00
|
|
|
cwLogPrint("Starting %s %s node ....\n",streamFl ? "TCP" : "UDP", serverFl ? "server" : "client");
|
|
|
|
cwLogPrint("'quit'=quit\n");
|
|
|
|
|
2020-01-27 22:52:53 +00:00
|
|
|
// start the thread
|
|
|
|
if((rc = thread::unpause( app.threadH )) != kOkRC )
|
|
|
|
goto errLabel;
|
|
|
|
|
|
|
|
|
|
|
|
while( true )
|
|
|
|
{
|
2024-11-30 17:19:43 +00:00
|
|
|
cwLogPrint("? ");
|
2020-01-27 22:52:53 +00:00
|
|
|
if( std::fgets(sbuf,sbufN,stdin) == sbuf )
|
|
|
|
{
|
|
|
|
if( strcmp(sbuf,"quit\n") == 0)
|
|
|
|
break;
|
|
|
|
|
2020-01-29 16:42:41 +00:00
|
|
|
if( streamFl )
|
2020-01-27 22:52:53 +00:00
|
|
|
{
|
2020-01-29 16:42:41 +00:00
|
|
|
// when using streams no remote address is necessary
|
2024-11-30 17:19:43 +00:00
|
|
|
cwLogPrint("Sending:%s",sbuf);
|
2020-01-27 22:52:53 +00:00
|
|
|
send(app.sockH, sbuf, strlen(sbuf)+1 );
|
|
|
|
}
|
2020-01-29 16:42:41 +00:00
|
|
|
else
|
2020-01-27 22:52:53 +00:00
|
|
|
{
|
2020-01-29 16:42:41 +00:00
|
|
|
// when using dgrams the dest. address is required
|
2024-11-30 17:19:43 +00:00
|
|
|
cwLogPrint("Sending:%s",sbuf);
|
2020-01-27 22:52:53 +00:00
|
|
|
send(app.sockH, sbuf, strlen(sbuf)+1, remoteAddr, remotePort);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
errLabel:
|
|
|
|
rc_t rc0 = thread::destroy(app.threadH);
|
|
|
|
|
|
|
|
rc_t rc1 = destroy(app.sockH);
|
|
|
|
|
|
|
|
return rcSelect(rc,rc0,rc1);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2019-12-27 21:52:45 +00:00
|
|
|
namespace cw
|
|
|
|
{
|
|
|
|
namespace net
|
|
|
|
{
|
|
|
|
namespace srv
|
|
|
|
{
|
2020-01-27 22:52:53 +00:00
|
|
|
typedef struct app_str
|
|
|
|
{
|
|
|
|
handle_t srvH;
|
|
|
|
unsigned cbN;
|
2023-07-26 00:18:55 +00:00
|
|
|
struct sockaddr_in remoteAddr;
|
2020-01-27 22:52:53 +00:00
|
|
|
} app_t;
|
2019-12-27 21:52:45 +00:00
|
|
|
|
2020-02-12 18:25:13 +00:00
|
|
|
void srvReceiveCallback( void* arg, const void* data, unsigned dataByteCnt, const struct sockaddr_in* fromAddr )
|
2020-01-27 22:52:53 +00:00
|
|
|
{
|
|
|
|
app_t* p = static_cast<app_t*>(arg);
|
2023-07-26 00:18:55 +00:00
|
|
|
|
|
|
|
send(p->srvH, data, dataByteCnt, &p->remoteAddr );
|
|
|
|
|
|
|
|
|
2020-01-27 22:52:53 +00:00
|
|
|
char addrBuf[ INET_ADDRSTRLEN ];
|
|
|
|
socket::addrToString( fromAddr, addrBuf, INET_ADDRSTRLEN );
|
|
|
|
p->cbN += 1;
|
2024-11-30 17:19:43 +00:00
|
|
|
cwLogPrint("%i %s %s\n", p->cbN, addrBuf, (const char*)data );
|
2023-07-26 00:18:55 +00:00
|
|
|
|
|
|
|
|
2020-01-27 22:52:53 +00:00
|
|
|
}
|
2019-12-27 21:52:45 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-11-30 17:19:43 +00:00
|
|
|
cw::rc_t cw::net::srv::test_udp_srv( const object_t* cfg )
|
2019-12-27 21:52:45 +00:00
|
|
|
{
|
2024-11-30 17:19:43 +00:00
|
|
|
rc_t rc = kOkRC;
|
|
|
|
unsigned recvBufByteCnt = 1024;
|
|
|
|
unsigned timeOutMs = 100;
|
|
|
|
socket::portNumber_t localPort = 5687;
|
|
|
|
const char* remoteAddr = nullptr;
|
|
|
|
socket::portNumber_t remotePort = 5688;
|
|
|
|
const unsigned sbufN = 31;
|
|
|
|
char sbuf[ sbufN+1 ];
|
|
|
|
app_t app;
|
|
|
|
|
2019-12-27 21:52:45 +00:00
|
|
|
app.cbN = 0;
|
2024-11-30 17:19:43 +00:00
|
|
|
|
|
|
|
if((rc = cfg->getv("localPort",localPort,
|
|
|
|
"remoteAddr",remoteAddr,
|
|
|
|
"remotePort",remotePort)) != kOkRC )
|
|
|
|
{
|
|
|
|
rc = cwLogError(rc,"Arg. parse failed.");
|
|
|
|
goto errLabel;
|
|
|
|
}
|
2019-12-27 21:52:45 +00:00
|
|
|
|
2020-02-12 18:25:13 +00:00
|
|
|
if((rc = srv::create(app.srvH,
|
|
|
|
localPort,
|
|
|
|
socket::kBlockingFl,
|
|
|
|
0,
|
|
|
|
srvReceiveCallback,
|
|
|
|
&app,
|
|
|
|
recvBufByteCnt,
|
|
|
|
timeOutMs,
|
|
|
|
nullptr,
|
|
|
|
socket::kInvalidPortNumber )) != kOkRC )
|
2023-07-26 00:18:55 +00:00
|
|
|
{
|
2019-12-27 21:52:45 +00:00
|
|
|
return rc;
|
2023-07-26 00:18:55 +00:00
|
|
|
}
|
2019-12-27 21:52:45 +00:00
|
|
|
|
2023-07-26 00:18:55 +00:00
|
|
|
if((rc = socket::initAddr( remoteAddr, remotePort, &app.remoteAddr )) != kOkRC )
|
|
|
|
{
|
|
|
|
cwLogError(rc,"Address initialization failed.");
|
|
|
|
goto errLabel;
|
|
|
|
}
|
|
|
|
|
2019-12-27 21:52:45 +00:00
|
|
|
if((rc = srv::start( app.srvH )) != kOkRC )
|
|
|
|
goto errLabel;
|
|
|
|
|
|
|
|
while( true )
|
|
|
|
{
|
2024-11-30 17:19:43 +00:00
|
|
|
cwLogPrint("? ");
|
2019-12-27 21:52:45 +00:00
|
|
|
if( std::fgets(sbuf,sbufN,stdin) == sbuf )
|
|
|
|
{
|
2024-11-30 17:19:43 +00:00
|
|
|
cwLogPrint("Sending:%s",sbuf);
|
2019-12-27 21:52:45 +00:00
|
|
|
send(app.srvH, sbuf, strlen(sbuf)+1, remoteAddr, remotePort );
|
|
|
|
|
|
|
|
if( strcmp(sbuf,"quit\n") == 0)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
errLabel:
|
|
|
|
rc_t rc0 = destroy(app.srvH);
|
|
|
|
|
|
|
|
return rcSelect(rc,rc0);
|
|
|
|
}
|
2020-01-27 22:52:53 +00:00
|
|
|
|
2024-11-30 17:19:43 +00:00
|
|
|
cw::rc_t cw::net::srv::test_tcp_srv( const object_t* cfg )
|
2020-02-12 18:25:13 +00:00
|
|
|
{
|
2024-11-30 17:19:43 +00:00
|
|
|
rc_t rc = kOkRC;
|
|
|
|
unsigned recvBufByteCnt = 1024;
|
|
|
|
unsigned timeOutMs = 100;
|
|
|
|
socket::portNumber_t localPort = 5687;
|
|
|
|
const char* remoteAddr = nullptr;
|
|
|
|
socket::portNumber_t remotePort = 5688;
|
|
|
|
const unsigned sbufN = 31;
|
|
|
|
char sbuf[ sbufN+1 ];
|
|
|
|
app_t app;
|
|
|
|
|
|
|
|
|
2020-02-12 18:25:13 +00:00
|
|
|
app.cbN = 0;
|
2024-11-30 17:19:43 +00:00
|
|
|
|
|
|
|
if((rc = cfg->getv("localPort",localPort,
|
|
|
|
"remoteAddr",remoteAddr,
|
|
|
|
"remotePort",remotePort)) != kOkRC )
|
|
|
|
{
|
|
|
|
rc = cwLogError(rc,"Arg. parse failed.");
|
|
|
|
goto errLabel;
|
|
|
|
}
|
2020-02-12 18:25:13 +00:00
|
|
|
|
|
|
|
if((rc = srv::create(app.srvH,
|
|
|
|
localPort,
|
|
|
|
socket::kBlockingFl | socket::kTcpFl | socket::kStreamFl,
|
|
|
|
0,
|
|
|
|
srvReceiveCallback,
|
|
|
|
&app,
|
|
|
|
recvBufByteCnt,
|
|
|
|
timeOutMs,
|
|
|
|
remoteAddr,
|
|
|
|
remotePort )) != kOkRC )
|
2024-11-30 17:19:43 +00:00
|
|
|
{
|
2020-02-12 18:25:13 +00:00
|
|
|
return rc;
|
2024-11-30 17:19:43 +00:00
|
|
|
}
|
|
|
|
|
2020-02-12 18:25:13 +00:00
|
|
|
if((rc = srv::start( app.srvH )) != kOkRC )
|
|
|
|
goto errLabel;
|
|
|
|
|
|
|
|
while( true )
|
|
|
|
{
|
2024-11-30 17:19:43 +00:00
|
|
|
cwLogPrint("? ");
|
2020-02-12 18:25:13 +00:00
|
|
|
if( std::fgets(sbuf,sbufN,stdin) == sbuf )
|
|
|
|
{
|
2024-11-30 17:19:43 +00:00
|
|
|
cwLogPrint("Sending:%s",sbuf);
|
2020-02-12 18:25:13 +00:00
|
|
|
send(app.srvH, sbuf, strlen(sbuf)+1 );
|
|
|
|
|
|
|
|
if( strcmp(sbuf,"quit\n") == 0)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
errLabel:
|
|
|
|
rc_t rc0 = destroy(app.srvH);
|
|
|
|
|
|
|
|
return rcSelect(rc,rc0);
|
|
|
|
}
|
|
|
|
|
2020-01-27 22:52:53 +00:00
|
|
|
|
|
|
|
|