A simple class to do line-based TCP communication. To be used with the NetServicesMin library-.
tcplinestream.cpp@0:f2727a16072f, 2011-01-29 (annotated)
- Committer:
- hlipka
- Date:
- Sat Jan 29 22:42:14 2011 +0000
- Revision:
- 0:f2727a16072f
- Child:
- 1:28416a5a4ec5
initial version
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
hlipka | 0:f2727a16072f | 1 | #include "Timer.h" |
hlipka | 0:f2727a16072f | 2 | |
hlipka | 0:f2727a16072f | 3 | #include "tcplinestream.h" |
hlipka | 0:f2727a16072f | 4 | |
hlipka | 0:f2727a16072f | 5 | #include "dnsresolve.h" |
hlipka | 0:f2727a16072f | 6 | |
hlipka | 0:f2727a16072f | 7 | void TCPLineStream::onTCPSocketEvent(TCPSocketEvent e) { |
hlipka | 0:f2727a16072f | 8 | // printf("New TCPSocketEvent: %d\n",e); |
hlipka | 0:f2727a16072f | 9 | switch (e) { |
hlipka | 0:f2727a16072f | 10 | case TCPSOCKET_CONNECTED: |
hlipka | 0:f2727a16072f | 11 | _connected = true; |
hlipka | 0:f2727a16072f | 12 | _connecting=false; |
hlipka | 0:f2727a16072f | 13 | break; |
hlipka | 0:f2727a16072f | 14 | |
hlipka | 0:f2727a16072f | 15 | case TCPSOCKET_READABLE: |
hlipka | 0:f2727a16072f | 16 | break; |
hlipka | 0:f2727a16072f | 17 | case TCPSOCKET_WRITEABLE: |
hlipka | 0:f2727a16072f | 18 | break; |
hlipka | 0:f2727a16072f | 19 | |
hlipka | 0:f2727a16072f | 20 | case TCPSOCKET_CONTIMEOUT: |
hlipka | 0:f2727a16072f | 21 | case TCPSOCKET_CONRST: |
hlipka | 0:f2727a16072f | 22 | case TCPSOCKET_CONABRT: |
hlipka | 0:f2727a16072f | 23 | case TCPSOCKET_ERROR: |
hlipka | 0:f2727a16072f | 24 | case TCPSOCKET_DISCONNECTED: { |
hlipka | 0:f2727a16072f | 25 | // don't close the real socket here, as this may skip the already received data |
hlipka | 0:f2727a16072f | 26 | _connected = false; |
hlipka | 0:f2727a16072f | 27 | _connecting=false; |
hlipka | 0:f2727a16072f | 28 | } |
hlipka | 0:f2727a16072f | 29 | break; |
hlipka | 0:f2727a16072f | 30 | } |
hlipka | 0:f2727a16072f | 31 | } |
hlipka | 0:f2727a16072f | 32 | |
hlipka | 0:f2727a16072f | 33 | TCPLineStream::TCPLineStream(const char *server, int port, const char* term) { |
hlipka | 0:f2727a16072f | 34 | _server=server; |
hlipka | 0:f2727a16072f | 35 | _port=port; |
hlipka | 0:f2727a16072f | 36 | _term=term; |
hlipka | 0:f2727a16072f | 37 | } |
hlipka | 0:f2727a16072f | 38 | |
hlipka | 0:f2727a16072f | 39 | bool TCPLineStream::open() { |
hlipka | 0:f2727a16072f | 40 | _closed=false; |
hlipka | 0:f2727a16072f | 41 | _readpos=0; |
hlipka | 0:f2727a16072f | 42 | _readlen=0; |
hlipka | 0:f2727a16072f | 43 | |
hlipka | 0:f2727a16072f | 44 | _socket=new TCPSocket(); |
hlipka | 0:f2727a16072f | 45 | _socket->setOnEvent(this,&TCPLineStream::onTCPSocketEvent); |
hlipka | 0:f2727a16072f | 46 | |
hlipka | 0:f2727a16072f | 47 | IpAddr addr; |
hlipka | 0:f2727a16072f | 48 | // ignore IP adress - is !null even if it is 0.0.0.0 |
hlipka | 0:f2727a16072f | 49 | // so do DNS if a name is given |
hlipka | 0:f2727a16072f | 50 | if (NULL!=_server) { |
hlipka | 0:f2727a16072f | 51 | // printf("do DNS request for %s\n",_server); |
hlipka | 0:f2727a16072f | 52 | DNSResolver dr; |
hlipka | 0:f2727a16072f | 53 | addr=dr.resolveName(_server); |
hlipka | 0:f2727a16072f | 54 | } |
hlipka | 0:f2727a16072f | 55 | // printf("server=%i.%i.%i.%i/%i\n",addr[0],addr[1],addr[2],addr[3],_port); |
hlipka | 0:f2727a16072f | 56 | |
hlipka | 0:f2727a16072f | 57 | Host host(addr, _port); |
hlipka | 0:f2727a16072f | 58 | |
hlipka | 0:f2727a16072f | 59 | // printf("connect\n"); |
hlipka | 0:f2727a16072f | 60 | TCPSocketErr bindErr = _socket->connect(host); |
hlipka | 0:f2727a16072f | 61 | |
hlipka | 0:f2727a16072f | 62 | if (bindErr != 0) { |
hlipka | 0:f2727a16072f | 63 | printf("connection bind error %i\n", bindErr); |
hlipka | 0:f2727a16072f | 64 | return false; |
hlipka | 0:f2727a16072f | 65 | } |
hlipka | 0:f2727a16072f | 66 | // printf("connecting\n"); |
hlipka | 0:f2727a16072f | 67 | // wait for connection established |
hlipka | 0:f2727a16072f | 68 | _connecting=true; |
hlipka | 0:f2727a16072f | 69 | mbed::Timer tmr; |
hlipka | 0:f2727a16072f | 70 | tmr.start(); |
hlipka | 0:f2727a16072f | 71 | tmr.reset(); |
hlipka | 0:f2727a16072f | 72 | |
hlipka | 0:f2727a16072f | 73 | while (_connecting) { |
hlipka | 0:f2727a16072f | 74 | Net::poll(); |
hlipka | 0:f2727a16072f | 75 | wait_us(100); |
hlipka | 0:f2727a16072f | 76 | if (tmr.read()>20) { |
hlipka | 0:f2727a16072f | 77 | printf("error: reached timeout\n"); |
hlipka | 0:f2727a16072f | 78 | break; |
hlipka | 0:f2727a16072f | 79 | } |
hlipka | 0:f2727a16072f | 80 | } |
hlipka | 0:f2727a16072f | 81 | if (!_connected) { |
hlipka | 0:f2727a16072f | 82 | printf("error - could not connect (timeout)\n"); |
hlipka | 0:f2727a16072f | 83 | return false; |
hlipka | 0:f2727a16072f | 84 | } |
hlipka | 0:f2727a16072f | 85 | // printf("connected\n"); |
hlipka | 0:f2727a16072f | 86 | return true; |
hlipka | 0:f2727a16072f | 87 | } |
hlipka | 0:f2727a16072f | 88 | |
hlipka | 0:f2727a16072f | 89 | void TCPLineStream::sendLine(string line) { |
hlipka | 0:f2727a16072f | 90 | // printf("send request[%s]\n",line.c_str()); |
hlipka | 0:f2727a16072f | 91 | _socket->send(line.append(_term).c_str(),line.length()+strlen(_term)); |
hlipka | 0:f2727a16072f | 92 | Net::poll(); |
hlipka | 0:f2727a16072f | 93 | } |
hlipka | 0:f2727a16072f | 94 | |
hlipka | 0:f2727a16072f | 95 | void TCPLineStream::close() { |
hlipka | 0:f2727a16072f | 96 | if (_closed) |
hlipka | 0:f2727a16072f | 97 | return; |
hlipka | 0:f2727a16072f | 98 | |
hlipka | 0:f2727a16072f | 99 | while (_connected) { |
hlipka | 0:f2727a16072f | 100 | Net::poll(); |
hlipka | 0:f2727a16072f | 101 | // read remaining data |
hlipka | 0:f2727a16072f | 102 | int err=_socket->recv(_readbuf,BUFSIZE-1); |
hlipka | 0:f2727a16072f | 103 | if (err<=0) |
hlipka | 0:f2727a16072f | 104 | break; |
hlipka | 0:f2727a16072f | 105 | } |
hlipka | 0:f2727a16072f | 106 | |
hlipka | 0:f2727a16072f | 107 | while (true) { |
hlipka | 0:f2727a16072f | 108 | Net::poll(); |
hlipka | 0:f2727a16072f | 109 | // read remaining data |
hlipka | 0:f2727a16072f | 110 | int err=_socket->recv(_readbuf,BUFSIZE-1); |
hlipka | 0:f2727a16072f | 111 | if (err<=0) |
hlipka | 0:f2727a16072f | 112 | break; |
hlipka | 0:f2727a16072f | 113 | } |
hlipka | 0:f2727a16072f | 114 | |
hlipka | 0:f2727a16072f | 115 | _socket->resetOnEvent(); |
hlipka | 0:f2727a16072f | 116 | _socket->close(); |
hlipka | 0:f2727a16072f | 117 | delete _socket; |
hlipka | 0:f2727a16072f | 118 | _closed=true; |
hlipka | 0:f2727a16072f | 119 | } |
hlipka | 0:f2727a16072f | 120 | |
hlipka | 0:f2727a16072f | 121 | string TCPLineStream::readLine(int strLen) { |
hlipka | 0:f2727a16072f | 122 | string r; |
hlipka | 0:f2727a16072f | 123 | r.reserve(strLen); |
hlipka | 0:f2727a16072f | 124 | |
hlipka | 0:f2727a16072f | 125 | int emptyCount=0; |
hlipka | 0:f2727a16072f | 126 | int lineendPos=0; |
hlipka | 0:f2727a16072f | 127 | while (true) { |
hlipka | 0:f2727a16072f | 128 | Net::poll(); |
hlipka | 0:f2727a16072f | 129 | if (_readlen>_readpos) { |
hlipka | 0:f2727a16072f | 130 | while (_readbuf[_readpos]!=0 && _readpos<_readlen) { |
hlipka | 0:f2727a16072f | 131 | char c=_readbuf[_readpos++]; |
hlipka | 0:f2727a16072f | 132 | //if the current char is the right one of the line terminator sequence |
hlipka | 0:f2727a16072f | 133 | if (c==_term[lineendPos]) { |
hlipka | 0:f2727a16072f | 134 | lineendPos++; |
hlipka | 0:f2727a16072f | 135 | if (0==_term[lineendPos]) { // last char of term sequence -> finished |
hlipka | 0:f2727a16072f | 136 | return r; |
hlipka | 0:f2727a16072f | 137 | } |
hlipka | 0:f2727a16072f | 138 | } else { // other characters |
hlipka | 0:f2727a16072f | 139 | int i=0; |
hlipka | 0:f2727a16072f | 140 | while (i<lineendPos) // add missed characters from term to string, if there are any |
hlipka | 0:f2727a16072f | 141 | r.push_back(_term[i++]); |
hlipka | 0:f2727a16072f | 142 | lineendPos=0; |
hlipka | 0:f2727a16072f | 143 | r.push_back(c); |
hlipka | 0:f2727a16072f | 144 | } |
hlipka | 0:f2727a16072f | 145 | } |
hlipka | 0:f2727a16072f | 146 | } else { |
hlipka | 0:f2727a16072f | 147 | int err=_socket->recv(_readbuf,BUFSIZE-1); |
hlipka | 0:f2727a16072f | 148 | if (err < 0) { |
hlipka | 0:f2727a16072f | 149 | printf("error while receiving data: %i!\n",err); |
hlipka | 0:f2727a16072f | 150 | break; |
hlipka | 0:f2727a16072f | 151 | } else if (err>0) { |
hlipka | 0:f2727a16072f | 152 | emptyCount=0; |
hlipka | 0:f2727a16072f | 153 | _readbuf[err]=0; |
hlipka | 0:f2727a16072f | 154 | _readlen=err; |
hlipka | 0:f2727a16072f | 155 | _readpos=0; |
hlipka | 0:f2727a16072f | 156 | // printf("r=%s\n",_readbuf); |
hlipka | 0:f2727a16072f | 157 | } else { |
hlipka | 0:f2727a16072f | 158 | // when we don't receive any data, and are not connected |
hlipka | 0:f2727a16072f | 159 | // we stop because there isn't anything left |
hlipka | 0:f2727a16072f | 160 | if (emptyCount++>2) |
hlipka | 0:f2727a16072f | 161 | if (!_connected) |
hlipka | 0:f2727a16072f | 162 | break; |
hlipka | 0:f2727a16072f | 163 | } |
hlipka | 0:f2727a16072f | 164 | } |
hlipka | 0:f2727a16072f | 165 | wait_us(100); |
hlipka | 0:f2727a16072f | 166 | } |
hlipka | 0:f2727a16072f | 167 | return r; |
hlipka | 0:f2727a16072f | 168 | } |
hlipka | 0:f2727a16072f | 169 |