src/connect/ncbi_conn_stream.cpp

Go to the documentation of this file.
00001 /* $Id: ncbi_conn_stream.cpp 168471 2009-08-17 14:28:02Z lavr $
00002  * ===========================================================================
00003  *
00004  *                            PUBLIC DOMAIN NOTICE
00005  *               National Center for Biotechnology Information
00006  *
00007  *  This software/database is a "United States Government Work" under the
00008  *  terms of the United States Copyright Act.  It was written as part of
00009  *  the author's official duties as a United States Government employee and
00010  *  thus cannot be copyrighted.  This software/database is freely available
00011  *  to the public for use. The National Library of Medicine and the U.S.
00012  *  Government have not placed any restriction on its use or reproduction.
00013  *
00014  *  Although all reasonable efforts have been taken to ensure the accuracy
00015  *  and reliability of the software and data, the NLM and the U.S.
00016  *  Government do not and cannot warrant the performance or results that
00017  *  may be obtained by using this software or data. The NLM and the U.S.
00018  *  Government disclaim all warranties, express or implied, including
00019  *  warranties of performance, merchantability or fitness for any particular
00020  *  purpose.
00021  *
00022  *  Please cite the author in any work or product based on this material.
00023  *
00024  * ===========================================================================
00025  *
00026  * Authors:  Anton Lavrentiev,  Denis Vakatov
00027  *
00028  * File Description:
00029  *   CONN-based C++ streams
00030  *
00031  *   See file <connect/ncbi_conn_stream.hpp> for more detailed information.
00032  *
00033  */
00034 
00035 #include <ncbi_pch.hpp>
00036 #include "ncbi_ansi_ext.h"
00037 #include "ncbi_conn_streambuf.hpp"
00038 #include <connect/error_codes.hpp>
00039 #include <connect/ncbi_conn_exception.hpp>
00040 #include <connect/ncbi_conn_stream.hpp>
00041 #include <connect/ncbi_socket.hpp>
00042 #include <corelib/ncbiapp.hpp>
00043 
00044 
00045 #define NCBI_USE_ERRCODE_X   Connect_Stream
00046 
00047 
00048 BEGIN_NCBI_SCOPE
00049 
00050 
00051 CConn_IOStream::CConn_IOStream(CONNECTOR connector, const STimeout* timeout,
00052                                streamsize buf_size, bool do_tie,
00053                                CT_CHAR_TYPE* ptr, size_t size) :
00054     CNcbiIostream(0), m_CSb(0)
00055 {
00056     auto_ptr<CConn_Streambuf>
00057         csb(new CConn_Streambuf(connector, timeout, buf_size, do_tie,
00058                                 ptr, size));
00059     if (csb->GetCONN()) {
00060         init(csb.get());
00061         m_CSb = csb.release();
00062     } else
00063         init(0); // according to the standard (27.4.4.1.3), badbit is set here
00064 }
00065 
00066 
00067 CConn_IOStream::~CConn_IOStream()
00068 {
00069     Cleanup();
00070 }
00071 
00072 
00073 CONN CConn_IOStream::GetCONN(void) const
00074 {
00075     return m_CSb ? m_CSb->GetCONN() : 0;
00076 }
00077 
00078 
00079 void CConn_IOStream::Close(void)
00080 {
00081     if (m_CSb)
00082         m_CSb->Close();
00083 }
00084 
00085 
00086 void CConn_IOStream::Cleanup(void)
00087 {
00088     streambuf* sb = rdbuf();
00089     delete sb;
00090     if (sb != m_CSb)
00091         delete m_CSb;
00092     m_CSb = 0;
00093 #ifdef AUTOMATIC_STREAMBUF_DESTRUCTION
00094     rdbuf(0);
00095 #endif // AUTOMATIC_STREAMBUF_DESTRUCTION
00096 }
00097 
00098 
00099 CConn_SocketStream::CConn_SocketStream(const string&   host,
00100                                        unsigned short  port,
00101                                        unsigned int    max_try,
00102                                        const STimeout* timeout,
00103                                        streamsize      buf_size)
00104     : CConn_IOStream(SOCK_CreateConnector(host.c_str(), port, max_try),
00105                      timeout, buf_size)
00106 {
00107     return;
00108 }
00109 
00110 
00111 CConn_SocketStream::CConn_SocketStream(SOCK            sock,
00112                                        unsigned int    max_try,
00113                                        const STimeout* timeout,
00114                                        streamsize      buf_size)
00115     : CConn_IOStream(SOCK_CreateConnectorOnTop(sock, max_try),
00116                      timeout, buf_size)
00117 {
00118     return;
00119 }
00120 
00121 
00122 
00123 static SOCK s_GrabSOCK(CSocket& socket)
00124 {
00125     SOCK sock = socket.GetSOCK();
00126     if (socket.SetOwnership(eNoOwnership) == eNoOwnership) {
00127         NCBI_THROW(CIO_Exception, eInvalidArg,
00128                    "CConn_SocketStream::CConn_SocketStream(): "
00129                    "Socket must be owned");
00130     }
00131     socket.Reset(0/*empty*/,
00132                  eNoOwnership/*irrelevant*/,
00133                  eCopyTimeoutsFromSOCK/*irrelevant*/);
00134     return sock;
00135 }
00136 
00137 
00138 CConn_SocketStream::CConn_SocketStream(CSocket&        socket,
00139                                        unsigned int    max_try,
00140                                        const STimeout* timeout,
00141                                        streamsize      buf_size)
00142     : CConn_IOStream(SOCK_CreateConnectorOnTop(s_GrabSOCK(socket), max_try),
00143                      timeout, buf_size)
00144 {
00145     return;
00146 }
00147 
00148 
00149 static void x_SetupUserAgent(SConnNetInfo* net_info)
00150 {
00151     CNcbiApplication* theApp = CNcbiApplication::Instance();
00152     if (theApp) {
00153         string user_agent("User-Agent: ");
00154         user_agent += theApp->GetProgramDisplayName() + "\r\n";
00155         ConnNetInfo_ExtendUserHeader(net_info, user_agent.c_str());
00156     }
00157 }
00158 
00159 
00160 static CONNECTOR s_HttpConnectorBuilder(const SConnNetInfo*  a_net_info,
00161                                         const char*          url,
00162                                         const char*          host,
00163                                         unsigned short       port,
00164                                         const char*          path,
00165                                         const char*          args,
00166                                         const char*          user_header,
00167                                         FHttpParseHTTPHeader parse_header,
00168                                         FHttpAdjustNetInfo   adjust_net_info,
00169                                         void*                adjust_data,
00170                                         FHttpAdjustCleanup   adjust_cleanup,
00171                                         THCC_Flags           flags,
00172                                         const STimeout*      timeout)
00173 {
00174     SConnNetInfo* net_info = a_net_info ?
00175         ConnNetInfo_Clone(a_net_info) : ConnNetInfo_Create(0);
00176     if (!net_info)
00177         return 0;
00178     if (url  &&  !ConnNetInfo_ParseURL(net_info, url))
00179         return 0;
00180     if (host) {
00181         strncpy0(net_info->host, host, sizeof(net_info->host) - 1);
00182         net_info->port = port;
00183     }
00184     if (path)
00185         strncpy0(net_info->path, path, sizeof(net_info->path) - 1);
00186     if (args)
00187         strncpy0(net_info->args, args, sizeof(net_info->args) - 1);
00188     if (user_header)
00189         ConnNetInfo_OverrideUserHeader(net_info, user_header);
00190     x_SetupUserAgent(net_info);
00191     if (timeout  &&  timeout != kDefaultTimeout) {
00192         net_info->tmo     = *timeout;
00193         net_info->timeout = &net_info->tmo;
00194     } else if (!timeout)
00195         net_info->timeout = 0;
00196     CONNECTOR c = HTTP_CreateConnectorEx(net_info, flags,
00197         parse_header, adjust_net_info, adjust_data, adjust_cleanup);
00198     ConnNetInfo_Destroy(net_info);
00199     return c;
00200 }
00201 
00202 
00203 CConn_HttpStream::CConn_HttpStream(const string&   host,
00204                                    const string&   path,
00205                                    const string&   args,
00206                                    const string&   user_header,
00207                                    unsigned short  port,
00208                                    THCC_Flags      flags,
00209                                    const STimeout* timeout,
00210                                    streamsize      buf_size)
00211     : CConn_IOStream(s_HttpConnectorBuilder(0,
00212                                             0,
00213                                             host.c_str(),
00214                                             port,
00215                                             path.c_str(),
00216                                             args.c_str(),
00217                                             user_header.c_str(),
00218                                             0,
00219                                             0,
00220                                             0,
00221                                             0,
00222                                             flags,
00223                                             timeout),
00224                      timeout, buf_size)
00225 {
00226     return;
00227 }
00228 
00229 
00230 CConn_HttpStream::CConn_HttpStream(const string&       url,
00231                                    THCC_Flags          flags,
00232                                    const STimeout*     timeout,
00233                                    streamsize          buf_size)
00234     : CConn_IOStream(s_HttpConnectorBuilder(0,
00235                                             url.c_str(),
00236                                             0,
00237                                             0,
00238                                             0,
00239                                             0,
00240                                             0,
00241                                             0,
00242                                             0,
00243                                             0,
00244                                             0,
00245                                             flags,
00246                                             timeout),
00247                      timeout, buf_size)
00248 {
00249     return;
00250 }
00251 
00252 
00253 CConn_HttpStream::CConn_HttpStream(const string&       url,
00254                                    const SConnNetInfo* net_info,
00255                                    const string&       user_header,
00256                                    THCC_Flags          flags,
00257                                    const STimeout*     timeout,
00258                                    streamsize          buf_size)
00259     : CConn_IOStream(s_HttpConnectorBuilder(net_info,
00260                                             url.c_str(),
00261                                             0,
00262                                             0,
00263                                             0,
00264                                             0,
00265                                             user_header.c_str(),
00266                                             0,
00267                                             0,
00268                                             0,
00269                                             0,
00270                                             flags,
00271                                             timeout),
00272                      timeout, buf_size)
00273 {
00274     return;
00275 }
00276 
00277 
00278 CConn_HttpStream::CConn_HttpStream(const SConnNetInfo*  net_info,
00279                                    const string&        user_header,
00280                                    FHttpParseHTTPHeader parse_header,
00281                                    FHttpAdjustNetInfo   adjust_net_info,
00282                                    void*                adjust_data,
00283                                    FHttpAdjustCleanup   adjust_cleanup,
00284                                    THCC_Flags           flags,
00285                                    const STimeout*      timeout,
00286                                    streamsize           buf_size)
00287     : CConn_IOStream(s_HttpConnectorBuilder(net_info,
00288                                             0,
00289                                             0,
00290                                             0,
00291                                             0,
00292                                             0,
00293                                             user_header.c_str(),
00294                                             parse_header,
00295                                             adjust_net_info,
00296                                             adjust_data,
00297                                             adjust_cleanup,
00298                                             flags,
00299                                             timeout),
00300                      timeout, buf_size)
00301 {
00302     return;
00303 }
00304 
00305 
00306 static CONNECTOR s_ServiceConnectorBuilder(const char*           service,
00307                                            TSERV_Type            types,
00308                                            const SConnNetInfo*   a_net_info,
00309                                            const SSERVICE_Extra* params,
00310                                            const STimeout*       timeout)
00311 {
00312     SConnNetInfo* net_info = a_net_info ?
00313         ConnNetInfo_Clone(a_net_info) : ConnNetInfo_Create(service);
00314     if (!net_info)
00315         return 0;
00316     x_SetupUserAgent(net_info);
00317     if (timeout && timeout != kDefaultTimeout) {
00318         net_info->tmo     = *timeout;
00319         net_info->timeout = &net_info->tmo;
00320     } else if (!timeout)
00321         net_info->timeout = 0;
00322     CONNECTOR c = SERVICE_CreateConnectorEx(service, types, net_info, params);
00323     if (!c) {
00324         ERR_POST_X(1,
00325                    Error << "Cannot connect to service \"" << service << '\"');
00326     }
00327     ConnNetInfo_Destroy(net_info);
00328     return c;
00329 }
00330 
00331 
00332 CConn_ServiceStream::CConn_ServiceStream(const string&         service,
00333                                          TSERV_Type            types,
00334                                          const SConnNetInfo*   net_info,
00335                                          const SSERVICE_Extra* params,
00336                                          const STimeout*       timeout,
00337                                          streamsize            buf_size)
00338     : CConn_IOStream(s_ServiceConnectorBuilder(service.c_str(),
00339                                                types,
00340                                                net_info,
00341                                                params,
00342                                                timeout),
00343                      timeout, buf_size)
00344 {
00345     return;
00346 }
00347 
00348 
00349 CConn_MemoryStream::CConn_MemoryStream(streamsize  buf_size)
00350     : CConn_IOStream(MEMORY_CreateConnector(), 0, buf_size, false),
00351       m_Buf(0), m_Ptr(0)
00352 {
00353     return;
00354 }
00355 
00356 
00357 CConn_MemoryStream::CConn_MemoryStream(BUF         buf,
00358                                        EOwnership  owner,
00359                                        streamsize  buf_size)
00360     : CConn_IOStream(MEMORY_CreateConnectorEx(buf), 0, buf_size, false,
00361                      0, BUF_Size(buf)),
00362       m_Buf(owner == eTakeOwnership ? buf : 0), m_Ptr(0)
00363 {
00364     return;
00365 }
00366 
00367 
00368 CConn_MemoryStream::CConn_MemoryStream(const void* ptr,
00369                                        size_t      size,
00370                                        EOwnership  owner,
00371                                        streamsize  buf_size)
00372     : CConn_IOStream(MEMORY_CreateConnector(), 0, buf_size, false,
00373                      (CT_CHAR_TYPE*) ptr, size),
00374       m_Buf(0), m_Ptr(owner == eTakeOwnership ? ptr : 0)
00375 {
00376     return;
00377 }
00378 
00379 
00380 CConn_MemoryStream::~CConn_MemoryStream()
00381 {
00382     Cleanup();
00383 #ifndef AUTOMATIC_STREAMBUF_DESTRUCTION
00384     rdbuf(0);
00385 #endif // AUTOMATIC_STREAMBUF_DESTRUCTION
00386     BUF_Destroy(m_Buf);
00387     delete[] (char*) m_Ptr;
00388 }
00389 
00390 
00391 void CConn_MemoryStream::ToString(string* str)
00392 {
00393     flush();
00394     if (!str) {
00395         NCBI_THROW(CIO_Exception, eInvalidArg,
00396                    "CConn_MemoryStream::ToString(NULL) is not allowed");
00397     }
00398     CConn_Streambuf* sb = dynamic_cast<CConn_Streambuf*>(rdbuf());
00399     streamsize size = sb ? (size_t)(tellp() - tellg()) : 0;
00400     str->resize(size);
00401     if (sb) {
00402         streamsize s = sb->sgetn(&(*str)[0], size);
00403         _ASSERT(size == s);
00404         str->resize(s);  // NB: this is essentially a NOP when size == s
00405     }
00406 }
00407 
00408 
00409 char* CConn_MemoryStream::ToCStr(void)
00410 {
00411     flush();
00412     CConn_Streambuf* sb = dynamic_cast<CConn_Streambuf*>(rdbuf());
00413     streamsize size = sb ? (size_t)(tellp() - tellg()) : 0;
00414     char* str = new char[size + 1];
00415     if (!str) {
00416         NCBI_THROW(CIO_Exception, eUnknown,
00417                    "CConn_MemoryStream::ToCStr() cannot allocate buffer");
00418     }
00419     if (sb) {
00420         streamsize s = sb->sgetn(str, size);
00421         _ASSERT(size == s);
00422         size = s;
00423     }
00424     str[size] = '\0';
00425     return str;
00426 }
00427 
00428 
00429 void CConn_MemoryStream::ToVector(vector<char>* vec)
00430 {
00431     flush();
00432     if (!vec) {
00433         NCBI_THROW(CIO_Exception, eInvalidArg,
00434                    "CConn_MemoryStream::ToVector(NULL) is not allowed");
00435     }
00436     CConn_Streambuf* sb = dynamic_cast<CConn_Streambuf*>(rdbuf());
00437     streamsize size = sb ? (streamsize)(tellp() - tellg()) : 0;
00438     vec->resize(size);
00439     if (sb) {
00440         streamsize s = sb->sgetn(&(*vec)[0], size);
00441         _ASSERT(size == s);
00442         vec->resize(s);  // NB: this is essentially a NOP when size == s
00443     }
00444 }
00445 
00446 
00447 CConn_PipeStream::CConn_PipeStream(const string&         cmd,
00448                                    const vector<string>& args,
00449                                    CPipe::TCreateFlags   create_flags,
00450                                    const STimeout*       timeout,
00451                                    streamsize            buf_size)
00452     : CConn_IOStream(PIPE_CreateConnector(cmd, args, create_flags, &m_Pipe),
00453                      timeout, buf_size), m_Pipe()
00454 {
00455     return;
00456 }
00457 
00458 
00459 CConn_PipeStream::~CConn_PipeStream()
00460 {
00461     // Explicitly call Cleanup() to avoid using dead m_Pipe otherwise.
00462     Cleanup();
00463 #ifndef AUTOMATIC_STREAMBUF_DESTRUCTION
00464     rdbuf(0);
00465 #endif // AUTOMATIC_STREAMBUF_DESTRUCTION
00466 }
00467 
00468 
00469 CConn_NamedPipeStream::CConn_NamedPipeStream(const string&   pipename,
00470                                              size_t          pipebufsize,
00471                                              const STimeout* timeout,
00472                                              streamsize      buf_size)
00473     : CConn_IOStream(NAMEDPIPE_CreateConnector(pipename, pipebufsize),
00474                      timeout, buf_size)
00475 {
00476     return;
00477 }
00478 
00479 
00480 CConn_FTPDownloadStream::CConn_FTPDownloadStream(const string&   host,
00481                                                  const string&   file,
00482                                                  const string&   user,
00483                                                  const string&   pass,
00484                                                  const string&   path,
00485                                                  unsigned short  port,
00486                                                  TFCDC_Flags     flags,
00487                                                  streamsize      offset,
00488                                                  const STimeout* timeout,
00489                                                  streamsize      buf_size)
00490     : CConn_IOStream(FTP_CreateDownloadConnector(host.c_str(), port,
00491                                                  user.c_str(), pass.c_str(),
00492                                                  path.c_str(), flags),
00493                      timeout, buf_size)
00494 {
00495     if (file != kEmptyStr) {
00496         if (offset != 0) {
00497             write("REST ", 5) << offset << endl;
00498         }
00499         if (good()) {
00500             write("RETR ", 5) << file   << endl;
00501         }
00502     }
00503 }
00504 
00505 
00506 const char* CIO_Exception::GetErrCodeString(void) const
00507 {
00508     switch (GetErrCode()) {
00509     case eTimeout:      return "eIO_Timeout";
00510     case eClosed:       return "eIO_Closed";
00511     case eInterrupt:    return "eIO_Interrupt";
00512     case eInvalidArg:   return "eIO_InvalidArg";
00513     case eNotSupported: return "eIO_NotSupported";
00514     case eUnknown:      return "eIO_Unknown";
00515     default:            return  CException::GetErrCodeString();
00516     }
00517 }
00518 
00519 
00520 END_NCBI_SCOPE
00521 
00522 

Generated on Sun Dec 6 22:22:03 2009 for NCBI C++ ToolKit by  doxygen 1.4.6
Modified on Mon Dec 07 16:20:56 2009 by modify_doxy.py rev. 173732