A simple class to do line-based TCP communication. To be used with the NetServicesMin library-.
tcplinestream.cpp@1:28416a5a4ec5, 2011-02-18 (annotated)
- Committer:
- hlipka
- Date:
- Fri Feb 18 13:15:43 2011 +0000
- Revision:
- 1:28416a5a4ec5
- Parent:
- 0:f2727a16072f
added license
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
hlipka | 1:28416a5a4ec5 | 1 | /* |
hlipka | 1:28416a5a4ec5 | 2 | * TcpLineStream library |
hlipka | 1:28416a5a4ec5 | 3 | * Copyright (c) 2010 Hendrik Lipka |
hlipka | 1:28416a5a4ec5 | 4 | * |
hlipka | 1:28416a5a4ec5 | 5 | * Permission is hereby granted, free of charge, to any person obtaining a copy |
hlipka | 1:28416a5a4ec5 | 6 | * of this software and associated documentation files (the "Software"), to deal |
hlipka | 1:28416a5a4ec5 | 7 | * in the Software without restriction, including without limitation the rights |
hlipka | 1:28416a5a4ec5 | 8 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
hlipka | 1:28416a5a4ec5 | 9 | * copies of the Software, and to permit persons to whom the Software is |
hlipka | 1:28416a5a4ec5 | 10 | * furnished to do so, subject to the following conditions: |
hlipka | 1:28416a5a4ec5 | 11 | * |
hlipka | 1:28416a5a4ec5 | 12 | * The above copyright notice and this permission notice shall be included in |
hlipka | 1:28416a5a4ec5 | 13 | * all copies or substantial portions of the Software. |
hlipka | 1:28416a5a4ec5 | 14 | * |
hlipka | 1:28416a5a4ec5 | 15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
hlipka | 1:28416a5a4ec5 | 16 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
hlipka | 1:28416a5a4ec5 | 17 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
hlipka | 1:28416a5a4ec5 | 18 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
hlipka | 1:28416a5a4ec5 | 19 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
hlipka | 1:28416a5a4ec5 | 20 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN |
hlipka | 1:28416a5a4ec5 | 21 | * THE SOFTWARE. |
hlipka | 1:28416a5a4ec5 | 22 | */ |
hlipka | 1:28416a5a4ec5 | 23 | |
hlipka | 0:f2727a16072f | 24 | #include "Timer.h" |
hlipka | 0:f2727a16072f | 25 | |
hlipka | 0:f2727a16072f | 26 | #include "tcplinestream.h" |
hlipka | 0:f2727a16072f | 27 | |
hlipka | 0:f2727a16072f | 28 | #include "dnsresolve.h" |
hlipka | 0:f2727a16072f | 29 | |
hlipka | 0:f2727a16072f | 30 | void TCPLineStream::onTCPSocketEvent(TCPSocketEvent e) { |
hlipka | 0:f2727a16072f | 31 | // printf("New TCPSocketEvent: %d\n",e); |
hlipka | 0:f2727a16072f | 32 | switch (e) { |
hlipka | 0:f2727a16072f | 33 | case TCPSOCKET_CONNECTED: |
hlipka | 0:f2727a16072f | 34 | _connected = true; |
hlipka | 0:f2727a16072f | 35 | _connecting=false; |
hlipka | 0:f2727a16072f | 36 | break; |
hlipka | 0:f2727a16072f | 37 | |
hlipka | 0:f2727a16072f | 38 | case TCPSOCKET_READABLE: |
hlipka | 0:f2727a16072f | 39 | break; |
hlipka | 0:f2727a16072f | 40 | case TCPSOCKET_WRITEABLE: |
hlipka | 0:f2727a16072f | 41 | break; |
hlipka | 0:f2727a16072f | 42 | |
hlipka | 0:f2727a16072f | 43 | case TCPSOCKET_CONTIMEOUT: |
hlipka | 0:f2727a16072f | 44 | case TCPSOCKET_CONRST: |
hlipka | 0:f2727a16072f | 45 | case TCPSOCKET_CONABRT: |
hlipka | 0:f2727a16072f | 46 | case TCPSOCKET_ERROR: |
hlipka | 0:f2727a16072f | 47 | case TCPSOCKET_DISCONNECTED: { |
hlipka | 0:f2727a16072f | 48 | // don't close the real socket here, as this may skip the already received data |
hlipka | 0:f2727a16072f | 49 | _connected = false; |
hlipka | 0:f2727a16072f | 50 | _connecting=false; |
hlipka | 0:f2727a16072f | 51 | } |
hlipka | 0:f2727a16072f | 52 | break; |
hlipka | 0:f2727a16072f | 53 | } |
hlipka | 0:f2727a16072f | 54 | } |
hlipka | 0:f2727a16072f | 55 | |
hlipka | 0:f2727a16072f | 56 | TCPLineStream::TCPLineStream(const char *server, int port, const char* term) { |
hlipka | 0:f2727a16072f | 57 | _server=server; |
hlipka | 0:f2727a16072f | 58 | _port=port; |
hlipka | 0:f2727a16072f | 59 | _term=term; |
hlipka | 0:f2727a16072f | 60 | } |
hlipka | 0:f2727a16072f | 61 | |
hlipka | 0:f2727a16072f | 62 | bool TCPLineStream::open() { |
hlipka | 0:f2727a16072f | 63 | _closed=false; |
hlipka | 0:f2727a16072f | 64 | _readpos=0; |
hlipka | 0:f2727a16072f | 65 | _readlen=0; |
hlipka | 0:f2727a16072f | 66 | |
hlipka | 0:f2727a16072f | 67 | _socket=new TCPSocket(); |
hlipka | 0:f2727a16072f | 68 | _socket->setOnEvent(this,&TCPLineStream::onTCPSocketEvent); |
hlipka | 0:f2727a16072f | 69 | |
hlipka | 0:f2727a16072f | 70 | IpAddr addr; |
hlipka | 0:f2727a16072f | 71 | // ignore IP adress - is !null even if it is 0.0.0.0 |
hlipka | 0:f2727a16072f | 72 | // so do DNS if a name is given |
hlipka | 0:f2727a16072f | 73 | if (NULL!=_server) { |
hlipka | 0:f2727a16072f | 74 | // printf("do DNS request for %s\n",_server); |
hlipka | 0:f2727a16072f | 75 | DNSResolver dr; |
hlipka | 0:f2727a16072f | 76 | addr=dr.resolveName(_server); |
hlipka | 0:f2727a16072f | 77 | } |
hlipka | 0:f2727a16072f | 78 | // printf("server=%i.%i.%i.%i/%i\n",addr[0],addr[1],addr[2],addr[3],_port); |
hlipka | 0:f2727a16072f | 79 | |
hlipka | 0:f2727a16072f | 80 | Host host(addr, _port); |
hlipka | 0:f2727a16072f | 81 | |
hlipka | 0:f2727a16072f | 82 | // printf("connect\n"); |
hlipka | 0:f2727a16072f | 83 | TCPSocketErr bindErr = _socket->connect(host); |
hlipka | 0:f2727a16072f | 84 | |
hlipka | 0:f2727a16072f | 85 | if (bindErr != 0) { |
hlipka | 0:f2727a16072f | 86 | printf("connection bind error %i\n", bindErr); |
hlipka | 0:f2727a16072f | 87 | return false; |
hlipka | 0:f2727a16072f | 88 | } |
hlipka | 0:f2727a16072f | 89 | // printf("connecting\n"); |
hlipka | 0:f2727a16072f | 90 | // wait for connection established |
hlipka | 0:f2727a16072f | 91 | _connecting=true; |
hlipka | 0:f2727a16072f | 92 | mbed::Timer tmr; |
hlipka | 0:f2727a16072f | 93 | tmr.start(); |
hlipka | 0:f2727a16072f | 94 | tmr.reset(); |
hlipka | 0:f2727a16072f | 95 | |
hlipka | 0:f2727a16072f | 96 | while (_connecting) { |
hlipka | 0:f2727a16072f | 97 | Net::poll(); |
hlipka | 0:f2727a16072f | 98 | wait_us(100); |
hlipka | 0:f2727a16072f | 99 | if (tmr.read()>20) { |
hlipka | 0:f2727a16072f | 100 | printf("error: reached timeout\n"); |
hlipka | 0:f2727a16072f | 101 | break; |
hlipka | 0:f2727a16072f | 102 | } |
hlipka | 0:f2727a16072f | 103 | } |
hlipka | 0:f2727a16072f | 104 | if (!_connected) { |
hlipka | 0:f2727a16072f | 105 | printf("error - could not connect (timeout)\n"); |
hlipka | 0:f2727a16072f | 106 | return false; |
hlipka | 0:f2727a16072f | 107 | } |
hlipka | 0:f2727a16072f | 108 | // printf("connected\n"); |
hlipka | 0:f2727a16072f | 109 | return true; |
hlipka | 0:f2727a16072f | 110 | } |
hlipka | 0:f2727a16072f | 111 | |
hlipka | 0:f2727a16072f | 112 | void TCPLineStream::sendLine(string line) { |
hlipka | 0:f2727a16072f | 113 | // printf("send request[%s]\n",line.c_str()); |
hlipka | 0:f2727a16072f | 114 | _socket->send(line.append(_term).c_str(),line.length()+strlen(_term)); |
hlipka | 0:f2727a16072f | 115 | Net::poll(); |
hlipka | 0:f2727a16072f | 116 | } |
hlipka | 0:f2727a16072f | 117 | |
hlipka | 0:f2727a16072f | 118 | void TCPLineStream::close() { |
hlipka | 0:f2727a16072f | 119 | if (_closed) |
hlipka | 0:f2727a16072f | 120 | return; |
hlipka | 0:f2727a16072f | 121 | |
hlipka | 0:f2727a16072f | 122 | while (_connected) { |
hlipka | 0:f2727a16072f | 123 | Net::poll(); |
hlipka | 0:f2727a16072f | 124 | // read remaining data |
hlipka | 0:f2727a16072f | 125 | int err=_socket->recv(_readbuf,BUFSIZE-1); |
hlipka | 0:f2727a16072f | 126 | if (err<=0) |
hlipka | 0:f2727a16072f | 127 | break; |
hlipka | 0:f2727a16072f | 128 | } |
hlipka | 0:f2727a16072f | 129 | |
hlipka | 0:f2727a16072f | 130 | while (true) { |
hlipka | 0:f2727a16072f | 131 | Net::poll(); |
hlipka | 0:f2727a16072f | 132 | // read remaining data |
hlipka | 0:f2727a16072f | 133 | int err=_socket->recv(_readbuf,BUFSIZE-1); |
hlipka | 0:f2727a16072f | 134 | if (err<=0) |
hlipka | 0:f2727a16072f | 135 | break; |
hlipka | 0:f2727a16072f | 136 | } |
hlipka | 0:f2727a16072f | 137 | |
hlipka | 0:f2727a16072f | 138 | _socket->resetOnEvent(); |
hlipka | 0:f2727a16072f | 139 | _socket->close(); |
hlipka | 0:f2727a16072f | 140 | delete _socket; |
hlipka | 0:f2727a16072f | 141 | _closed=true; |
hlipka | 0:f2727a16072f | 142 | } |
hlipka | 0:f2727a16072f | 143 | |
hlipka | 0:f2727a16072f | 144 | string TCPLineStream::readLine(int strLen) { |
hlipka | 0:f2727a16072f | 145 | string r; |
hlipka | 0:f2727a16072f | 146 | r.reserve(strLen); |
hlipka | 0:f2727a16072f | 147 | |
hlipka | 0:f2727a16072f | 148 | int emptyCount=0; |
hlipka | 0:f2727a16072f | 149 | int lineendPos=0; |
hlipka | 0:f2727a16072f | 150 | while (true) { |
hlipka | 0:f2727a16072f | 151 | Net::poll(); |
hlipka | 0:f2727a16072f | 152 | if (_readlen>_readpos) { |
hlipka | 0:f2727a16072f | 153 | while (_readbuf[_readpos]!=0 && _readpos<_readlen) { |
hlipka | 0:f2727a16072f | 154 | char c=_readbuf[_readpos++]; |
hlipka | 0:f2727a16072f | 155 | //if the current char is the right one of the line terminator sequence |
hlipka | 0:f2727a16072f | 156 | if (c==_term[lineendPos]) { |
hlipka | 0:f2727a16072f | 157 | lineendPos++; |
hlipka | 0:f2727a16072f | 158 | if (0==_term[lineendPos]) { // last char of term sequence -> finished |
hlipka | 0:f2727a16072f | 159 | return r; |
hlipka | 0:f2727a16072f | 160 | } |
hlipka | 0:f2727a16072f | 161 | } else { // other characters |
hlipka | 0:f2727a16072f | 162 | int i=0; |
hlipka | 0:f2727a16072f | 163 | while (i<lineendPos) // add missed characters from term to string, if there are any |
hlipka | 0:f2727a16072f | 164 | r.push_back(_term[i++]); |
hlipka | 0:f2727a16072f | 165 | lineendPos=0; |
hlipka | 0:f2727a16072f | 166 | r.push_back(c); |
hlipka | 0:f2727a16072f | 167 | } |
hlipka | 0:f2727a16072f | 168 | } |
hlipka | 0:f2727a16072f | 169 | } else { |
hlipka | 0:f2727a16072f | 170 | int err=_socket->recv(_readbuf,BUFSIZE-1); |
hlipka | 0:f2727a16072f | 171 | if (err < 0) { |
hlipka | 0:f2727a16072f | 172 | printf("error while receiving data: %i!\n",err); |
hlipka | 0:f2727a16072f | 173 | break; |
hlipka | 0:f2727a16072f | 174 | } else if (err>0) { |
hlipka | 0:f2727a16072f | 175 | emptyCount=0; |
hlipka | 0:f2727a16072f | 176 | _readbuf[err]=0; |
hlipka | 0:f2727a16072f | 177 | _readlen=err; |
hlipka | 0:f2727a16072f | 178 | _readpos=0; |
hlipka | 0:f2727a16072f | 179 | // printf("r=%s\n",_readbuf); |
hlipka | 0:f2727a16072f | 180 | } else { |
hlipka | 0:f2727a16072f | 181 | // when we don't receive any data, and are not connected |
hlipka | 0:f2727a16072f | 182 | // we stop because there isn't anything left |
hlipka | 0:f2727a16072f | 183 | if (emptyCount++>2) |
hlipka | 0:f2727a16072f | 184 | if (!_connected) |
hlipka | 0:f2727a16072f | 185 | break; |
hlipka | 0:f2727a16072f | 186 | } |
hlipka | 0:f2727a16072f | 187 | } |
hlipka | 0:f2727a16072f | 188 | wait_us(100); |
hlipka | 0:f2727a16072f | 189 | } |
hlipka | 0:f2727a16072f | 190 | return r; |
hlipka | 0:f2727a16072f | 191 | } |
hlipka | 0:f2727a16072f | 192 |