A simple class to do line-based TCP communication. To be used with the NetServicesMin library-.

Dependents:   pop3demo

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?

UserRevisionLine numberNew 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