00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
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);
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,
00132 eNoOwnership,
00133 eCopyTimeoutsFromSOCK);
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);
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);
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
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