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

Dependents:   pop3demo

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers tcplinestream.cpp Source File

tcplinestream.cpp

00001 /*
00002 * TcpLineStream library
00003 * Copyright (c) 2010 Hendrik Lipka
00004 * 
00005 * Permission is hereby granted, free of charge, to any person obtaining a copy
00006 * of this software and associated documentation files (the "Software"), to deal
00007 * in the Software without restriction, including without limitation the rights
00008 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
00009 * copies of the Software, and to permit persons to whom the Software is
00010 * furnished to do so, subject to the following conditions:
00011 * 
00012 * The above copyright notice and this permission notice shall be included in
00013 * all copies or substantial portions of the Software.
00014 * 
00015 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
00016 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
00017 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
00018 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
00019 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
00020 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
00021 * THE SOFTWARE.
00022 */
00023 
00024 #include "Timer.h"
00025 
00026 #include "tcplinestream.h"
00027 
00028 #include "dnsresolve.h"
00029 
00030 void TCPLineStream::onTCPSocketEvent(TCPSocketEvent e) {
00031 //    printf("New TCPSocketEvent: %d\n",e);
00032     switch (e) {
00033         case TCPSOCKET_CONNECTED:
00034             _connected = true;
00035             _connecting=false;
00036             break;
00037 
00038         case TCPSOCKET_READABLE:
00039             break;
00040         case TCPSOCKET_WRITEABLE:
00041             break;
00042 
00043         case TCPSOCKET_CONTIMEOUT:
00044         case TCPSOCKET_CONRST:
00045         case TCPSOCKET_CONABRT:
00046         case TCPSOCKET_ERROR:
00047         case TCPSOCKET_DISCONNECTED: {
00048             // don't close the real socket here, as this may skip the already received data
00049             _connected = false;
00050             _connecting=false;
00051         }
00052         break;
00053     }
00054 }
00055 
00056 TCPLineStream::TCPLineStream(const char *server, int port, const char* term) {
00057     _server=server;
00058     _port=port;
00059     _term=term;
00060 }
00061 
00062 bool TCPLineStream::open() {
00063     _closed=false;
00064     _readpos=0;
00065     _readlen=0;
00066 
00067     _socket=new TCPSocket();
00068     _socket->setOnEvent(this,&TCPLineStream::onTCPSocketEvent);
00069 
00070     IpAddr addr;
00071     // ignore IP adress - is !null even if it is 0.0.0.0
00072     // so do DNS if a name is given
00073     if (NULL!=_server) {
00074 //    printf("do DNS request for %s\n",_server);
00075         DNSResolver dr;
00076         addr=dr.resolveName(_server);
00077     }
00078 //    printf("server=%i.%i.%i.%i/%i\n",addr[0],addr[1],addr[2],addr[3],_port);
00079 
00080     Host host(addr, _port);
00081 
00082 //    printf("connect\n");
00083     TCPSocketErr bindErr = _socket->connect(host);
00084 
00085     if (bindErr != 0) {
00086         printf("connection bind error %i\n", bindErr);
00087         return false;
00088     }
00089 //    printf("connecting\n");
00090     // wait for connection established
00091     _connecting=true;
00092     mbed::Timer tmr;
00093     tmr.start();
00094     tmr.reset();
00095 
00096     while (_connecting) {
00097         Net::poll();
00098         wait_us(100);
00099         if (tmr.read()>20) {
00100             printf("error: reached timeout\n");
00101             break;
00102         }
00103     }
00104     if (!_connected) {
00105         printf("error - could not connect (timeout)\n");
00106         return false;
00107     }
00108 //    printf("connected\n");
00109     return true;
00110 }
00111 
00112 void TCPLineStream::sendLine(string line) {
00113 //    printf("send request[%s]\n",line.c_str());
00114     _socket->send(line.append(_term).c_str(),line.length()+strlen(_term));
00115     Net::poll();
00116 }
00117 
00118 void TCPLineStream::close() {
00119     if (_closed)
00120         return;
00121 
00122     while (_connected) {
00123         Net::poll();
00124         // read remaining data
00125         int err=_socket->recv(_readbuf,BUFSIZE-1);
00126         if (err<=0)
00127             break;
00128     }
00129 
00130     while (true) {
00131         Net::poll();
00132         // read remaining data
00133         int err=_socket->recv(_readbuf,BUFSIZE-1);
00134         if (err<=0)
00135             break;
00136     }
00137 
00138     _socket->resetOnEvent();
00139     _socket->close();
00140     delete _socket;
00141     _closed=true;
00142 }
00143 
00144 string TCPLineStream::readLine(int strLen) {
00145     string r;
00146     r.reserve(strLen);
00147 
00148     int emptyCount=0;
00149     int lineendPos=0;
00150     while (true) {
00151         Net::poll();
00152         if (_readlen>_readpos) {
00153             while (_readbuf[_readpos]!=0 && _readpos<_readlen) {
00154                 char c=_readbuf[_readpos++];
00155                 //if the current char is the right one of the line terminator sequence
00156                 if (c==_term[lineendPos]) {
00157                     lineendPos++;
00158                     if (0==_term[lineendPos]) { // last char of term sequence -> finished
00159                         return r;
00160                     }
00161                 } else { // other characters
00162                     int i=0;
00163                     while (i<lineendPos) // add missed characters from term to string, if there are any
00164                         r.push_back(_term[i++]);
00165                     lineendPos=0;
00166                     r.push_back(c);
00167                 }
00168             }
00169         } else {
00170             int err=_socket->recv(_readbuf,BUFSIZE-1);
00171             if (err < 0) {
00172                 printf("error while receiving data: %i!\n",err);
00173                 break;
00174             } else if (err>0) {
00175                 emptyCount=0;
00176                 _readbuf[err]=0;
00177                 _readlen=err;
00178                 _readpos=0;
00179 //                printf("r=%s\n",_readbuf);
00180             } else {
00181                 // when we don't receive any data, and are not connected
00182                 // we stop because there isn't anything left
00183                 if (emptyCount++>2)
00184                     if (!_connected)
00185                         break;
00186             }
00187         }
00188         wait_us(100);
00189     }
00190     return r;
00191 }
00192