00001 // PPTConnection.cc 00002 00003 // This file is part of bes, A C++ back-end server implementation framework 00004 // for the OPeNDAP Data Access Protocol. 00005 00006 // Copyright (c) 2004,2005 University Corporation for Atmospheric Research 00007 // Author: Patrick West <pwest@ucar.edu> and Jose Garcia <jgarcia@ucar.edu> 00008 // 00009 // This library is free software; you can redistribute it and/or 00010 // modify it under the terms of the GNU Lesser General Public 00011 // License as published by the Free Software Foundation; either 00012 // version 2.1 of the License, or (at your option) any later version. 00013 // 00014 // This library is distributed in the hope that it will be useful, 00015 // but WITHOUT ANY WARRANTY; without even the implied warranty of 00016 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00017 // Lesser General Public License for more details. 00018 // 00019 // You should have received a copy of the GNU Lesser General Public 00020 // License along with this library; if not, write to the Free Software 00021 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 00022 // 00023 // You can contact University Corporation for Atmospheric Research at 00024 // 3080 Center Green Drive, Boulder, CO 80301 00025 00026 // (c) COPYRIGHT University Corporation for Atmospheric Research 2004-2005 00027 // Please read the full copyright statement in the file COPYRIGHT_UCAR. 00028 // 00029 // Authors: 00030 // pwest Patrick West <pwest@ucar.edu> 00031 // jgarcia Jose Garcia <jgarcia@ucar.edu> 00032 00033 #include <poll.h> 00034 #include <errno.h> 00035 #include <iostream> 00036 00037 using std::cout ; 00038 using std::flush ; 00039 00040 #include "PPTConnection.h" 00041 #include "PPTProtocol.h" 00042 #include "Socket.h" 00043 #include "PPTException.h" 00044 #include "PPTMarkFinder.h" 00045 00046 void 00047 PPTConnection::send( const string &buffer ) 00048 { 00049 if( buffer != "" ) 00050 { 00051 writeBuffer( buffer ) ; 00052 } 00053 writeBuffer( PPTProtocol::PPT_COMPLETE_DATA_TRANSMITION ) ; 00054 } 00055 00056 void 00057 PPTConnection::sendExit() 00058 { 00059 writeBuffer( PPTProtocol::PPT_EXIT_NOW ) ; 00060 } 00061 00062 void 00063 PPTConnection::writeBuffer( const string &buffer ) 00064 { 00065 _mySock->send( buffer, 0, buffer.length() ) ; 00066 } 00067 00068 /* OLD RECEIVE 00069 bool 00070 PPTConnection::receive( ostream *strm ) 00071 { 00072 bool isDone = false ; 00073 ostream *use_strm = _out ; 00074 if( strm ) 00075 use_strm = strm ; 00076 00077 int termlen = PPTProtocol::PPT_COMPLETE_DATA_TRANSMITION.length() ; 00078 int exitlen = PPTProtocol::PPT_EXIT_NOW.length() ; 00079 int start = termlen ; 00080 bool done = false ; 00081 char *inBuff = new char[PPT_PROTOCOL_BUFFER_SIZE+termlen+1] ; 00082 while( done == false ) 00083 { 00084 int bytesRead = readBuffer( inBuff+termlen ) ; 00085 if( bytesRead != 0 ) 00086 { 00087 if( !strncmp( inBuff+start, PPTProtocol::PPT_EXIT_NOW.c_str(), exitlen ) ) 00088 { 00089 done = true ; 00090 isDone = true ; 00091 } 00092 else 00093 { 00094 int charsInBuff = bytesRead + ( termlen - start ) ; 00095 int writeBytes = charsInBuff - termlen ; 00096 if( charsInBuff >= termlen ) 00097 { 00098 if( !strncmp( inBuff+bytesRead, PPTProtocol::PPT_COMPLETE_DATA_TRANSMITION.c_str(), termlen ) ) 00099 { 00100 done = true ; 00101 } 00102 00103 for( int j = 0; j < writeBytes; j++ ) 00104 { 00105 if( use_strm ) 00106 { 00107 (*use_strm) << inBuff[start+j] ; 00108 } 00109 } 00110 00111 if( !done ) 00112 { 00113 memcpy( inBuff, inBuff + bytesRead, termlen ) ; 00114 start = 0 ; 00115 } 00116 } 00117 else 00118 { 00119 int newstart = termlen - charsInBuff ; 00120 memcpy( inBuff + newstart, inBuff + start, charsInBuff ) ; 00121 start = newstart ; 00122 } 00123 } 00124 } 00125 else 00126 { 00127 done = true ; 00128 } 00129 } 00130 delete [] inBuff ; 00131 return isDone ; 00132 } 00133 */ 00134 00135 bool 00136 PPTConnection::receive( ostream *strm ) 00137 { 00138 bool isDone = false ; 00139 ostream *use_strm = _out ; 00140 if( strm ) 00141 use_strm = strm ; 00142 00143 int bytesRead, markBufBytes, i ; 00144 00145 int termlen = PPTProtocol::PPT_COMPLETE_DATA_TRANSMITION.length() ; 00146 int exitlen = PPTProtocol::PPT_EXIT_NOW.length() ; 00147 00148 PPTMarkFinder mf( (unsigned char *)PPTProtocol::PPT_COMPLETE_DATA_TRANSMITION.c_str(), 00149 termlen ) ; 00150 unsigned char markBuffer[termlen] ; 00151 markBufBytes = 0 ; // zero byte count in the mark buffer 00152 00153 char *inBuff = new char[PPT_PROTOCOL_BUFFER_SIZE+1] ; 00154 bool done = false; 00155 while( !done ) 00156 { 00157 bytesRead = readBuffer( inBuff ) ; 00158 if( bytesRead != 0 ) 00159 { 00160 // did we find an exit string? 00161 if( !strncmp( inBuff, PPTProtocol::PPT_EXIT_NOW.c_str(), exitlen ) ) 00162 { 00163 done = true ; 00164 isDone = true ; 00165 } 00166 else 00167 { 00168 // look at what we got to find the exit or the term string 00169 for( i = 0; i < bytesRead && !done; i++ ) 00170 { 00171 // check for the mark. If we've found the entire marker 00172 // then markCheck returns true. If we haven't yet found 00173 // the entire mark but have found part of it then 00174 // markCheck will return false and the markIndex will be 00175 // greater than 0. If the check failed because the 00176 // character checked is not part of the marker then the 00177 // markIndex is set to 0 and false is returned. 00178 done = mf.markCheck( inBuff[i] ) ; 00179 if( !done ) 00180 { 00181 // didn't find the mark yet, check if we've found 00182 // part of it 00183 if( mf.getMarkIndex() > 0 ) 00184 { 00185 // we found part of it, so cache what we found 00186 // in markBuffer 00187 markBuffer[markBufBytes++] = inBuff[i] ; 00188 } 00189 else 00190 { 00191 // we are here because inBuff[i] does not match 00192 // the current position in the marker. 00193 00194 // if we found part of the mark (there's some 00195 // characters in markBuffer meaning markBufBytes 00196 // is greater than 0) then we need to send the 00197 // first character in the markBuffer and begiin 00198 // checking the rest of the characters in the 00199 // markBuffer against the markFinder. inBuff[i] 00200 // could still be part of the marker, so don't 00201 // send it to the stream just yet. The case here 00202 // is that the inBuff contains PPPT instead of 00203 // PPT as the beginning of the marker. PP is in 00204 // the markBuffer and we've just checked the 00205 // third 'P', which returns false and markIndex 00206 // is set to 0. So, send the first 'P' in 00207 // markBuffer, shift the remaining characters 00208 // and check them against the markFinder. 00209 if( markBufBytes > 0 ) 00210 { 00211 // let's put inBuf[i] in the markBuffer so 00212 // that we don't have to worry about it 00213 // anymore 00214 markBuffer[markBufBytes++] = inBuff[i] ; 00215 00216 bool isdone = false ; 00217 while( !isdone ) 00218 { 00219 // always throw the first character iin 00220 // markBuffer to the stream 00221 (*use_strm) << markBuffer[0] ; 00222 00223 // shift the rest of the characters in 00224 // markBuffer to the left one 00225 for( int j = 1; j < markBufBytes; j++ ) 00226 { 00227 markBuffer[j-1] = markBuffer[j] ; 00228 } 00229 00230 // we've sent the first character to the 00231 // stream, so reduce the number in 00232 // markBuffer 00233 markBufBytes-- ; 00234 00235 // start checking the rest of the 00236 // characters in markBuffer 00237 bool partof = true ; 00238 for( int j = 0; j < markBufBytes && partof; j++ ) 00239 { 00240 // don't need to look at the result 00241 // of markCheck because we already 00242 // know that we have not 00243 // found the complete marker, we're 00244 // just dealing with potentially 00245 // part of the marker 00246 mf.markCheck( markBuffer[j] ) ; 00247 if( mf.getMarkIndex() == 0 ) 00248 { 00249 // if the markIndex is 0 then 00250 // the character we just checked 00251 // is not part of the marker, so 00252 // repeat this process starting 00253 // at for( !isdone ) 00254 partof = false ; 00255 } 00256 } 00257 00258 if( partof == true ) 00259 { 00260 // if we've made it this far then 00261 // what's in the markBuffer is part 00262 // of the marker, so move on to the 00263 // next character in inBuff 00264 isdone = true ; 00265 } 00266 } 00267 } 00268 else 00269 { 00270 // There's nothing in the markBuffer so just 00271 // send inBuff on to the stream 00272 (*use_strm) << inBuff[i] ; 00273 } 00274 } 00275 } 00276 } 00277 } 00278 } 00279 else 00280 { 00281 done = true; 00282 } 00283 } 00284 delete [] inBuff ; 00285 return isDone ; 00286 } 00287 00288 int 00289 PPTConnection::readBuffer( char *inBuff ) 00290 { 00291 return _mySock->receive( inBuff, PPT_PROTOCOL_BUFFER_SIZE ) ; 00292 } 00293 00294 int 00295 PPTConnection::readBufferNonBlocking( char *inBuff ) 00296 { 00297 struct pollfd p ; 00298 p.fd = getSocket()->getSocketDescriptor(); 00299 p.events = POLLIN ; 00300 struct pollfd arr[1] ; 00301 arr[0] = p ; 00302 00303 // Lets loop _timeout times with a delay block on poll of 1000 milliseconds 00304 // and see if there is any data. 00305 for( int j = 0; j < _timeout; j++ ) 00306 { 00307 if( poll( arr, 1, 1000 ) < 0 ) 00308 { 00309 string error( "poll error" ) ; 00310 const char* error_info = strerror( errno ) ; 00311 if( error_info ) 00312 error += " " + (string)error_info ; 00313 throw PPTException( error ) ; 00314 } 00315 else 00316 { 00317 if (arr[0].revents==POLLIN) 00318 { 00319 return readBuffer( inBuff ) ; 00320 } 00321 else 00322 { 00323 cout << " " << j << flush ; 00324 } 00325 } 00326 } 00327 cout << endl ; 00328 return -1 ; 00329 } 00330 00337 void 00338 PPTConnection::dump( ostream &strm ) const 00339 { 00340 strm << BESIndent::LMarg << "PPTConnection::dump - (" 00341 << (void *)this << ")" << endl ; 00342 BESIndent::Indent() ; 00343 Connection::dump( strm ) ; 00344 BESIndent::UnIndent() ; 00345 } 00346