boost deadline_timer not kicking off - boost

We have written a single threaded client based on the boost asio. The client needs to implement a timeout, so that the connection is broken if the read or write from server was not completed in a stipulated time period. But the async_wait for the deadline_timer does not kick off untill I don't call run for the io_service. Now if I call run on the io_service then my reading and writing to the server is not possible.
Please see the excerpts from my current code:
typedef boost::scoped_ptr<boost::asio::ip::tcp::socket> SocketPtr;
typedef boost::shared_ptr<boost::asio::deadline_timer> DLTPtr;
SocketPtr m_SocketPtrClient;
DLPtr m_ClientTimeoutDLTPtr;
boost::asio::io_service ios;
m_SocketPtrClient.reset( new boost::asio::ip::tcp::socket( ios));
m_ClientTimeoutDLTPtr.reset( new deadline_timer( ios));
m_ClientTimeoutDLTPtr->expires_from_now( boost::posix_time::seconds( m_uiCommTimeout));
m_ClientTimeoutDLTPtr->async_wait( boost::bind( &MyClass::clientTimeoutHandler,
this,
boost::asio::placeholders::error
)
);
m_SocketPtrClient->connect
(
boost::asio::ip::tcp::endpoint
(
boost::asio::ip::address::from_string
(
m_sCommAddress == "localhost" ? "127.0.0.1" : m_sCommAddress
), m_usCommPort
), ec
);
if( !ec && m_SocketPtrClient->is_open())
{
m_ClientTimeoutDLTPtr->cancel();
}
else
{
m_ClientTimeoutDLTPtr->cancel();
m_SocketPtrClient->close();
return eStateError;
}
//install a timeout handler
m_ClientTimeoutDLTPtr->expires_from_now( boost::posix_time::seconds( m_uiCommTimeout));
m_ClientTimeoutDLTPtr->async_wait( boost::bind( &MyClass::clientTimeoutHandler,
this,
boost::asio::placeholders::error
)
);
ec = writeToServer( *m_SocketPtrClient);
if( ec)
{
// do error handling and throw an exception
}
m_ClientTimeoutDLTPtr->cancel();
//install a timeout handler
m_ClientTimeoutDLTPtr->expires_from_now( boost::posix_time::seconds( m_uiCommTimeout));
m_ClientTimeoutDLTPtr->async_wait( boost::bind( &MyClass::clientTimeoutHandler,
this,
boost::asio::placeholders::error
)
);
ec = readFromServer( *m_SocketPtrClient);
if( ec)
{
// do error handling and throw an exception
}
m_ClientTimeoutDLTPtr->cancel();
void MyClass::clientTimeoutHandler( const boost::system::error_code& ec)
{
if( ec)
{
m_ClientTimeoutDLTPtr->cancel();
m_SocketPtrClient->close();
m_ssMsg << std::endl << "break all handling because of timeout on io_service of Client!";
}
else
{
m_ClientTimeoutDLTPtr->expires_from_now( boost::posix_time::seconds( m_uiCommTimeout));
m_ClientTimeoutDLTPtr->async_wait( boost::bind( &MyClass::clientTimeoutHandler,
this,
boost::asio::placeholders::error
)
);
}
}
I need to connect, write to the server and then get response from the server and for each operation I need the timeout to kickoff. If I call the run from io_service then I can't make my these three calls.

I need to connect, write to the server and then get response from the
server and for each operation I need the timeout to kickoff. If I call
the run from io_service then I can't make my these three calls.
When using deadline_timer::async_wait() you will need to use the corresponding asynchronous socket methods such as socket::async_connect() instead of socket::connect().

Related

Koa websocket to websocket

I have a node.js server that takes data from a "sleepy" client over a websocket, then tries to push that data to the web client via its websocket. Sleepy means that it sleeps for a few minutes then wakes up to take a measurement and push the data, then back to sleep. See below:
sleepy client --> websocket--> node.js server --> websocket --> web clients
There is only one sleepy client but there can be multiple web clients. So when new data arrives, I need to push it to all web client web sockets. To keep track of this, I have an array that track web clients and stores their ctx info for later.
But, and this is the problem, when I try to push data to the web client websocket, I get a context error and node.js crashes.
Here is my code:
var globalCtx = [];
app.ws.use( function( ctx, next ) {
ctx.websocket.on('message', function ( message )
{
if( "telemetry" in jsonMsg )
{
console.log( "Got Telemetry: " );
console.log( message.toString() );
// we just got a telemetry message,
// so push it to the all the web client websockets
globalCtx.forEach( (myCtx, next) => {
console.log( "DEBUG: ", util.inspect(myCtx) ); <<<-----crashes here
myCtx.send( jsonMsg ); <<<----- or crashes here when not debugging
});
}
else
if( "webClient" in jsonMsg )
{
console.log( "Got WS Client: " );
console.log( message.toString() );
// we just got a web client connection message
// so store its context for pushing to later
if( Array.isArray( globalCtx ) && globalCtx.length )
{
// search for an existing entry
for( let idx = 0; idx < globalCtx.length; idx++ )
{
if( globalCtx[ idx ].ip == ctx.ip )
{
// we already have this IP stored, do nothing
console.log("IP already found: ", ctx.ip );
//return next( ctx );
return;
}
}
// we made it here, this means that the IP wasn't found
console.log("not found, adding IP: ", ctx.ip );
globalCtx.push( ctx );
}
else
{
// the array is empty, so just add it
console.log("empty array adding IP: ", ctx.ip );
globalCtx.push( ctx );
}
}
});
return next(ctx);
});
Here is the error:
/home/pi/node_modules/koa/lib/response.js:73
return this.res.statusCode;
^
TypeError: Cannot read property 'statusCode' of undefined
at Object.get status [as status] (/home/pi/node_modules/koa/lib/response.js:73:21)
at /home/pi/node_modules/only/index.js:6:20
at Array.reduce (<anonymous>)
at module.exports (/home/pi/node_modules/only/index.js:5:15)
at Object.toJSON (/home/pi/node_modules/koa/lib/response.js: 562:12)
at Object.toJSON (/home/pi/node_modules/koa/lib/context.js:5 1:31)
at Object.inspect (/home/pi/node_modules/koa/lib/context.js: 33:17)
at formatValue (internal/util/inspect.js:745:19)
at Object.inspect (internal/util/inspect.js:319:10)
at /home/pi/koaThermostat/index2.js:46:46
Here is the error from the myCtx.send( jsonMsg ); line
/home/pi/koaThermostat/index2.js:47
myCtx.send( jsonMsg );
^
TypeError: myCtx.send is not a function
at /home/pi/koaThermostat/index2.js:47:23
Well I feel silly! When using the Koa context with websockets, you have to use the websocket object. So in my case it should have been myCtx.websocket.send() not myCtx.send().
Now I'm on to my next bug....

Poco c++ Websocket server connection reset by peer

I am writing a kind of chat server app where a message received from one websocket client is sent out to all other websocket clients. To do this, I keep the connected clients in a list. When a client disconnects, I need to remove it from the list (so that future "sends" do not fail).
However, sometimes when a client disconnects, the server just gets an exception "connection reset by peer", and the code does not get chance to remove from the client list. Is there a way to guarantee a "nice" notification that the connection has been reset?
My code is:
void WsRequestHandler::handleRequest(HTTPServerRequest &req, HTTPServerResponse &resp)
{
int n;
Poco::Timespan timeOut(5,0);
try
{
req.set("Connection","Upgrade"); // knock out any extra tokens firefox may send such as "keep-alive"
ws = new WebSocket(req, resp);
ws->setKeepAlive(false);
connectedSockets->push_back(this);
do
{
flags = 0;
if (!ws->poll(timeOut,Poco::Net::Socket::SELECT_READ || Poco::Net::Socket::SELECT_ERROR))
{
// cout << ".";
}
else
{
n = ws->receiveFrame(buffer, sizeof(buffer), flags);
if (n > 0)
{
if ((flags & WebSocket::FRAME_OP_BITMASK) == WebSocket::FRAME_OP_BINARY)
{
// process and send out to all other clients
DoReceived(ws, buffer, n);
}
}
}
}
while ((flags & WebSocket::FRAME_OP_BITMASK) != WebSocket::FRAME_OP_CLOSE);
// client has closed, so remove from list
for (vector<WsRequestHandler *>::iterator it = connectedSockets->begin() ; it != connectedSockets->end(); ++it)
{
if (*it == this)
{
connectedSockets->erase(it);
logger->information("Connection closed %s", ws->peerAddress().toString());
break;
}
}
delete(ws);
ws = NULL;
}
catch (WebSocketException& exc)
{
//never gets called
}
}
See receiveFrame() documentation:
Returns the number of bytes received. A return value of 0 means that the peer has shut down or closed the connection.
So if receiveFrame() call returns zero, you can act acordingly.
I do not know if this is an answer to the question, but the implementation you have done does not deal with PING frames. This is currently (as of my POCO version: 1.7.5) not done automatically by the POCO framework. I put up a question about that recently. According to the RFC (6465), the ping and pong frames are used (among others) as a keep-alive function. This may therefore be critical to get right in order to get your connection stable over time. Much of this is guess-work from my side as I am experimenting with this now myself.
#Alex, you are a main developer of POCO I believe, a comment on my answer would be much appreciated.
I extended the catch, to do some exception handling for "Connection reset by peer".
catch (Poco::Net::WebSocketException& exc)
{
// Do something
}
catch (Poco::Exception& e)
{
// This is where the "Connection reset by peer" lands
}
A bit late to the party here... but I am using Poco and Websockets as well - and properly handling disconnects was tricky.
I ended up implementing a simple ping functionality myself where the client side sends an ACK message for every WS Frame it receives. A separate thread on the server side tries to read the ACK messages - and it will now detect when the client has disconnected by looking at flags | WebSocket::FRAME_OP_CLOSE.
//Serverside - POCO. Start thread for receiving ACK packages. Needed in order to detect when websocket is closed!
thread t0([&]()->void{
while((!KillFlag && ws!= nullptr && flags & WebSocket::FRAME_OP_BITMASK) != WebSocket::FRAME_OP_CLOSE && machineConnection != nullptr){
try{
if(ws == nullptr){
return;
}
if(ws->available() > 0){
int len = ws->receiveFrame(buffer, sizeof(buffer), flags);
}
else{
Util::Sleep(10);
}
}
catch(Poco::Exception &pex){
flags = flags | WebSocket::FRAME_OP_CLOSE;
return;
}
catch(...){
//log::info(string("Unknown exception in ACK Thread drained"));
return;
}
}
log::debug("OperatorWebHandler::HttpRequestHandler() Websocket Acking thread DONE");
});
on the client side I just send a dummy "ACK" message back to the server (JS) every time I receive a WS frame from the server (POCO).
websocket.onmessage = (evt) => {
_this.receivedData = JSON.parse(evt.data);
websocket.send("ACK");
};
It is not about disconnect handling, rather about the stability of the connection.
Had some issues with POCO Websocket server in StreamSocket mode and C# client. Sometimes the client sends Pong messages with zero length payload and disconnect occurs so I added Ping and Pong handling code.
int WebSocketImpl::receiveBytes(void* buffer, int length, int)
{
char mask[4];
bool useMask;
_frameFlags = 0;
for (;;) {
int payloadLength = receiveHeader(mask, useMask);
int frameOp = _frameFlags & WebSocket::FRAME_OP_BITMASK;
if (frameOp == WebSocket::FRAME_OP_PONG || frameOp ==
WebSocket::FRAME_OP_PING) {
std::vector<char> tmp(payloadLength);
if (payloadLength != 0) {
receivePayload(tmp.data(), payloadLength, mask, useMask);
}
if (frameOp == WebSocket::FRAME_OP_PING) {
sendBytes(tmp.data(), payloadLength, WebSocket::FRAME_OP_PONG);
}
continue;
}
if (payloadLength <= 0)
return payloadLength;
if (payloadLength > length)
throw WebSocketException(Poco::format("Insufficient buffer for
payload size %d", payloadLength),
WebSocket::WS_ERR_PAYLOAD_TOO_BIG);
return receivePayload(reinterpret_cast<char*>(buffer), payloadLength,
mask, useMask);
}
}

call async_resolve.cancel(),but the callback handler of async_resolve doesn't return boost::asio::error::operation_aborted

i used boost asio to process http request and answer,to avoid async_resolve doesn't invoke its callback handler,i set a timeout,just like this:
void resolve()
{
resolver_.async_resolve(query,strand_.wrap(boost::bind(&connection::handle_resolve,
shared_from_this(),
boost::asio::placeholders::error,
boost::asio::placeholders::iterator)));
int cancel_num = timer_.expires_from_now(boost::posix_time::seconds(resolve_timeout_));
timer_.async_wait(strand_.wrap(boost::bind(&connection::handle_resolve_timeout,
shared_from_this(),
boost::asio::placeholders::error)));
}
void connection::handle_resolve_timeout(const boost::system::error_code& err)
{
if (err != boost::asio::error::operation_aborted)
{
resolver_.cancel();
}
}
void connection::handle_resolve(const boost::system::error_code& err,
boost::asio::ip::tcp::resolver::iterator endpoint_iterator)
{
timer_.cancel();
if(!err)
{
boost::asio::ip::tcp::endpoint endpoint = *endpoint_iterator;
socket_.async_connect(endpoint,strand_.wrap(boost::bind(&connection::handle_connect,
shared_from_this(),
boost::asio::placeholders::error,
++endpoint_iterator)));
//to distinct the type of timeout ,0:connect timeout,1:read timeout
int flag = 0;
int cancel_num = timer_.expires_from_now(boost::posix_time::seconds(connect_timeout_));
timer_.async_wait(strand_.wrap(boost::bind(&connection::handle_timeout,
shared_from_this(),
boost::asio::placeholders::error,
flag)));
}
else if(err != boost::asio::error::operation_aborted)
{
status_ = resolve_error;
check_.do_finish(shared_from_this());
}
else
{
FASTCHECK_INFO("resolve is canceled\n");
}
}
when resolve timeout ,i found the handle_resolve_timeout is invoked,but the handle_resolve doesn't return boost::asio::error::operation_aborted,why,i am puzzled,can someone can explain it for me?
According to the discussion on boost-users mailing list, resolver::cancel() is only able to cancel pending, queued resolve requests, not the one that's currently executing.
As a delayed follow up to #Cubbi's answer, this bug was also raised on the Boost issue tracker a few months after this question's thread. The Asio resolver API is slightly confusing because it suggests that any async_resolve() operation can be cancelled on demand. I had the same problem myself. It also turns out that in the Asio implementation, calls to async_resolve() makes a synchronous system call to getaddrinfo() behind the scenes. I discuss this interesting behavior in a recent codecast.

Multithreaded IOCP Client Issue

I am writing a multithreaded client that uses an IO Completion Port.
I create and connect the socket that has the WSA_FLAG_OVERLAPPED attribute set.
if ((m_socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == INVALID_SOCKET)
{
throw std::exception("Failed to create socket.");
}
if (WSAConnectByName(m_socket, L"server.com", L"80", &localAddressLength, reinterpret_cast<sockaddr*>(&localAddress), &remoteAddressLength, &remoteAddress, NULL, NULL) == FALSE)
{
throw std::exception("Failed to connect.");
}
I associate the IO Completion Port with the socket.
if ((m_hIOCP = CreateIoCompletionPort(reinterpret_cast<HANDLE>(m_socket), m_hIOCP, NULL, 8)) == NULL)
{
throw std::exception("Failed to create IOCP object.");
}
All appears to go well until I try to send some data over the socket.
SocketData* socketData = new SocketData;
socketData->hEvent = 0;
DWORD bytesSent = 0;
if (WSASend(m_socket, socketData->SetBuffer(socketData->GenerateLoginRequestHeader()), 1, &bytesSent, NULL, reinterpret_cast<OVERLAPPED*>(socketData), NULL) == SOCKET_ERROR && WSAGetLastError() != WSA_IO_PENDING)
{
throw std::exception("Failed to send data.");
}
Instead of returning SOCKET_ERROR with the last error set to WSA_IO_PENDING, WSASend returns immediately.
I need the IO to pend and for it's completion to be handled in my thread function which is also my worker thread.
unsigned int __stdcall MyClass::WorkerThread(void* lpThis)
{
}
I've done this before but I don't know what is going wrong in this case, I'd greatly appreciate any efforts in helping me fix this problem.
It's not a problem unless you make it so.
As long as you're not calling SetFileCompletionNotificationModes() and setting the flag to skip completion port processing on success then even if WSARecv (or whatever) returns SUCCESS an IO Completion Packet is queued to the IOCP the same as if ERROR_IO_PENDING was returned. Thus you need no special handling for the non error return case.
See http://support.microsoft.com/default.aspx?scid=kb;en-us;Q192800 for details.
First of all break the call into more clear logic:
int nRet = WSASend(m_socket, socketData->SetBuffer(socketData->GenerateLoginRequestHeader()), 1, NULL, NULL, reinterpret_cast<OVERLAPPED*>(socketData), NULL);
if (nRet == SOCKET_ERROR)
{
if ((WSAGetLastError()) == WSA_IO_PENDING)
nRet = 0; // ok
else
throw std::exception("Failed to send data."); // failed
}
Also, as you can see in my code, you should NOT pass the "&bytesSent" parameter according to WSASend:
Use NULL for this parameter if the
lpOverlapped parameter is not NULL to
avoid potentially erroneous results.
Besides that your call to WSASend() looks fine.

Windows service shut down

I use VS6 and ATL with CServiceModule to implement a custom windows service. In case of a fatal error service should shut itself down. Since CServiceModule is available via _Module variable in all files I thought of something like this to cause CServiceModule::Run to stop pumping messages and shut itself down
PostThreadMessage(_Module.dwThreadID, WM_QUIT, 0, 0);
Is this correct or you have better idea ?
For self shutdown you send command to Service Manager. Try this sample :
BOOL StopServiceCmd ( const char * szServiceName )
{
SC_HANDLE schService;
SC_HANDLE schSCManager;
SERVICE_STATUS ssStatus; // current status of the service
BOOL bRet;
int iCont=0;
schSCManager = OpenSCManager(
NULL, // machine (NULL == local)
NULL, // database (NULL == default)
SC_MANAGER_ALL_ACCESS // access required
);
if ( schSCManager )
{
schService = OpenService(schSCManager, szServiceName, SERVICE_ALL_ACCESS);
if (schService)
{
// try to stop the service
if ( ControlService( schService, SERVICE_CONTROL_STOP, &ssStatus ) )
{
Sleep( 1000 );
while( QueryServiceStatus( schService, &ssStatus ) )
{
iCont++;
if ( ssStatus.dwCurrentState == SERVICE_STOP_PENDING )
{
Sleep( 1000 );
if ( iCont > 4 ) break;
}
else
break;
}
if ( ssStatus.dwCurrentState == SERVICE_STOPPED )
bRet = TRUE;
else
bRet = FALSE;
}
CloseServiceHandle(schService);
}
else
bRet = FALSE;
CloseServiceHandle(schSCManager);
}
else
bRet = FALSE;
return bRet;
}
I believe that if you do this, then the service manager will think that your service has crashed and if the user ever sets it up to auto-restart, it will.
In .NET, you use the ServiceController to signal your service to shut down. I expect it is similar in Win32 since most of this stuff in .NET is just wrappers. Sorry, I don't have C++ code handy to shut down the service, but here is the .NET code. This will hopefully help you Google the info you need, or find the docs in MSDN.
This is from some test suite code, thus the style of error checking ;) You will need to put this code in a thread so that the shutdown message gets handled.
private void stopPLService( bool close )
{
if ( m_serviceController == null )
{
m_serviceController = new ServiceController( "PLService" );
}
WriteLine( "StopPLService" );
if ( m_serviceController != null )
{
try
{
m_serviceController.Stop();
}
catch
{
// Probably just means that it wasn't running or installed, ignore
}
// Wait up to 30 seconds for the service to stop
try
{
m_serviceController.WaitForStatus( ServiceControllerStatus.Stopped, new TimeSpan( 0, 0, 30 ) );
}
catch ( System.ServiceProcess.TimeoutException )
{
Assert.Fail( "Timeout waiting for PLService to stop" );
}
catch
{
// Not installed, we only care in the start
}
if ( close )
{
m_serviceController.Close();
m_serviceController = null;
}
}
}
You probably want to use the ControlService or ControlServiceEx methods to shutdown your service. You should be able to get the required handle from the CServiceModule.

Resources