A simple class to do line-based TCP communication. To be used with the NetServicesMin library-.
Diff: tcplinestream.cpp
- Revision:
- 0:f2727a16072f
- Child:
- 1:28416a5a4ec5
diff -r 000000000000 -r f2727a16072f tcplinestream.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tcplinestream.cpp Sat Jan 29 22:42:14 2011 +0000 @@ -0,0 +1,169 @@ +#include "Timer.h" + +#include "tcplinestream.h" + +#include "dnsresolve.h" + +void TCPLineStream::onTCPSocketEvent(TCPSocketEvent e) { +// printf("New TCPSocketEvent: %d\n",e); + switch (e) { + case TCPSOCKET_CONNECTED: + _connected = true; + _connecting=false; + break; + + case TCPSOCKET_READABLE: + break; + case TCPSOCKET_WRITEABLE: + break; + + case TCPSOCKET_CONTIMEOUT: + case TCPSOCKET_CONRST: + case TCPSOCKET_CONABRT: + case TCPSOCKET_ERROR: + case TCPSOCKET_DISCONNECTED: { + // don't close the real socket here, as this may skip the already received data + _connected = false; + _connecting=false; + } + break; + } +} + +TCPLineStream::TCPLineStream(const char *server, int port, const char* term) { + _server=server; + _port=port; + _term=term; +} + +bool TCPLineStream::open() { + _closed=false; + _readpos=0; + _readlen=0; + + _socket=new TCPSocket(); + _socket->setOnEvent(this,&TCPLineStream::onTCPSocketEvent); + + IpAddr addr; + // ignore IP adress - is !null even if it is 0.0.0.0 + // so do DNS if a name is given + if (NULL!=_server) { +// printf("do DNS request for %s\n",_server); + DNSResolver dr; + addr=dr.resolveName(_server); + } +// printf("server=%i.%i.%i.%i/%i\n",addr[0],addr[1],addr[2],addr[3],_port); + + Host host(addr, _port); + +// printf("connect\n"); + TCPSocketErr bindErr = _socket->connect(host); + + if (bindErr != 0) { + printf("connection bind error %i\n", bindErr); + return false; + } +// printf("connecting\n"); + // wait for connection established + _connecting=true; + mbed::Timer tmr; + tmr.start(); + tmr.reset(); + + while (_connecting) { + Net::poll(); + wait_us(100); + if (tmr.read()>20) { + printf("error: reached timeout\n"); + break; + } + } + if (!_connected) { + printf("error - could not connect (timeout)\n"); + return false; + } +// printf("connected\n"); + return true; +} + +void TCPLineStream::sendLine(string line) { +// printf("send request[%s]\n",line.c_str()); + _socket->send(line.append(_term).c_str(),line.length()+strlen(_term)); + Net::poll(); +} + +void TCPLineStream::close() { + if (_closed) + return; + + while (_connected) { + Net::poll(); + // read remaining data + int err=_socket->recv(_readbuf,BUFSIZE-1); + if (err<=0) + break; + } + + while (true) { + Net::poll(); + // read remaining data + int err=_socket->recv(_readbuf,BUFSIZE-1); + if (err<=0) + break; + } + + _socket->resetOnEvent(); + _socket->close(); + delete _socket; + _closed=true; +} + +string TCPLineStream::readLine(int strLen) { + string r; + r.reserve(strLen); + + int emptyCount=0; + int lineendPos=0; + while (true) { + Net::poll(); + if (_readlen>_readpos) { + while (_readbuf[_readpos]!=0 && _readpos<_readlen) { + char c=_readbuf[_readpos++]; + //if the current char is the right one of the line terminator sequence + if (c==_term[lineendPos]) { + lineendPos++; + if (0==_term[lineendPos]) { // last char of term sequence -> finished + return r; + } + } else { // other characters + int i=0; + while (i<lineendPos) // add missed characters from term to string, if there are any + r.push_back(_term[i++]); + lineendPos=0; + r.push_back(c); + } + } + } else { + int err=_socket->recv(_readbuf,BUFSIZE-1); + if (err < 0) { + printf("error while receiving data: %i!\n",err); + break; + } else if (err>0) { + emptyCount=0; + _readbuf[err]=0; + _readlen=err; + _readpos=0; +// printf("r=%s\n",_readbuf); + } else { + // when we don't receive any data, and are not connected + // we stop because there isn't anything left + if (emptyCount++>2) + if (!_connected) + break; + } + } + wait_us(100); + } + return r; +} +