GME  13
BinHTTPURLInputStream.cpp
Go to the documentation of this file.
00001 /*
00002  * Licensed to the Apache Software Foundation (ASF) under one or more
00003  * contributor license agreements.  See the NOTICE file distributed with
00004  * this work for additional information regarding copyright ownership.
00005  * The ASF licenses this file to You under the Apache License, Version 2.0
00006  * (the "License"); you may not use this file except in compliance with
00007  * the License.  You may obtain a copy of the License at
00008  *
00009  *      http://www.apache.org/licenses/LICENSE-2.0
00010  *
00011  * Unless required by applicable law or agreed to in writing, software
00012  * distributed under the License is distributed on an "AS IS" BASIS,
00013  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
00014  * See the License for the specific language governing permissions and
00015  * limitations under the License.
00016  */
00017 
00018 /*
00019  * $Id: BinHTTPURLInputStream.cpp 936316 2010-04-21 14:19:58Z borisk $
00020  */
00021 
00022 
00023 #include <xercesc/util/NetAccessors/WinSock/BinHTTPURLInputStream.hpp>
00024 #include <windows.h>
00025 
00026 #ifdef WITH_IPV6
00027 #include <ws2tcpip.h>
00028 #endif
00029 
00030 #include <stdio.h>
00031 #include <string.h>
00032 
00033 #include <xercesc/util/PlatformUtils.hpp>
00034 #include <xercesc/util/XMLNetAccessor.hpp>
00035 #include <xercesc/util/XMLString.hpp>
00036 #include <xercesc/util/XMLExceptMsgs.hpp>
00037 #include <xercesc/util/Janitor.hpp>
00038 #include <xercesc/util/XMLUniDefs.hpp>
00039 #include <xercesc/util/Mutexes.hpp>
00040 
00041 XERCES_CPP_NAMESPACE_BEGIN
00042 
00043 typedef u_short (WSAAPI * LPFN_HTONS)(u_short hostshort);
00044 typedef SOCKET (WSAAPI * LPFN_SOCKET)(int af, int type, int protocol);
00045 typedef int (WSAAPI * LPFN_CONNECT)(SOCKET s, const struct sockaddr* name, int namelen);
00046 typedef int (WSAAPI * LPFN_SEND)(SOCKET s, const char* buf, int len, int flags);
00047 typedef int (WSAAPI * LPFN_RECV)(SOCKET s, char* buf, int len, int flags);
00048 typedef int (WSAAPI * LPFN_SHUTDOWN)(SOCKET s, int how);
00049 typedef int (WSAAPI * LPFN_CLOSESOCKET)(SOCKET s);
00050 typedef int (WSAAPI * LPFN_WSACLEANUP)();
00051 typedef int (WSAAPI * LPFN_WSASTARTUP)(WORD wVersionRequested, LPWSADATA lpWSAData);
00052 #ifdef WITH_IPV6
00053 typedef int (WSAAPI * LPFN_GETADDRINFO)(const char* nodename, const char * servname, const struct addrinfo * hints, struct addrinfo ** res);
00054 typedef void (WSAAPI * LPFN_FREEADDRINFO)(struct addrinfo * ai);
00055 #else
00056 typedef struct hostent *(WSAAPI * LPFN_GETHOSTBYNAME)(const char* name);
00057 typedef struct hostent *(WSAAPI * LPFN_GETHOSTBYADDR)(const char* addr, int len, int type);
00058 typedef unsigned long (WSAAPI * LPFN_INET_ADDR)(const char* cp);
00059 #endif
00060 
00061 static HMODULE gWinsockLib = NULL;
00062 static LPFN_HTONS gWShtons = NULL;
00063 static LPFN_SOCKET gWSsocket = NULL;
00064 static LPFN_CONNECT gWSconnect = NULL;
00065 static LPFN_SEND gWSsend = NULL;
00066 static LPFN_RECV gWSrecv = NULL;
00067 static LPFN_SHUTDOWN gWSshutdown = NULL;
00068 static LPFN_CLOSESOCKET gWSclosesocket = NULL;
00069 static LPFN_WSACLEANUP gWSACleanup = NULL;
00070 #ifdef WITH_IPV6
00071 static LPFN_GETADDRINFO gWSgetaddrinfo = NULL;
00072 static LPFN_FREEADDRINFO gWSfreeaddrinfo = NULL;
00073 #else
00074 static LPFN_GETHOSTBYNAME gWSgethostbyname = NULL;
00075 static LPFN_GETHOSTBYADDR gWSgethostbyaddr = NULL;
00076 static LPFN_INET_ADDR gWSinet_addr = NULL;
00077 #endif
00078 
00079 static u_short wrap_htons(u_short hostshort)
00080 {
00081     return (*gWShtons)(hostshort);
00082 }
00083 
00084 static SOCKET wrap_socket(int af,int type,int protocol)
00085 {
00086     return (*gWSsocket)(af,type,protocol);
00087 }
00088 
00089 static int wrap_connect(SOCKET s,const struct sockaddr* name,int namelen)
00090 {
00091     return (*gWSconnect)(s,name,namelen);
00092 }
00093 
00094 static int wrap_send(SOCKET s,const char* buf,int len,int flags)
00095 {
00096     return (*gWSsend)(s,buf,len,flags);
00097 }
00098 
00099 static int wrap_recv(SOCKET s,char* buf,int len,int flags)
00100 {
00101     return (*gWSrecv)(s,buf,len,flags);
00102 }
00103 
00104 static int wrap_shutdown(SOCKET s,int how)
00105 {
00106     return (*gWSshutdown)(s,how);
00107 }
00108 
00109 static int wrap_closesocket(SOCKET socket)
00110 {
00111     return (*gWSclosesocket)(socket);
00112 }
00113 
00114 #ifdef WITH_IPV6
00115 static int wrap_getaddrinfo(const char* nodename,const char* servname,const struct addrinfo* hints,struct addrinfo** res)
00116 {
00117    return (*gWSgetaddrinfo)(nodename,servname,hints,res);
00118 }
00119 
00120 static void wrap_freeaddrinfo(struct addrinfo* ai)
00121 {
00122     (*gWSfreeaddrinfo)(ai);
00123 }
00124 #else
00125 static struct hostent* wrap_gethostbyname(const char* name)
00126 {
00127     return (*gWSgethostbyname)(name);
00128 }
00129 
00130 static struct hostent* wrap_gethostbyaddr(const char* addr,int len,int type)
00131 {
00132     return (*gWSgethostbyaddr)(addr,len,type);
00133 }
00134 
00135 static unsigned long wrap_inet_addr(const char* cp)
00136 {
00137     return (*gWSinet_addr)(cp);
00138 }
00139 
00140 #endif
00141 
00142 
00143 class SocketJanitor
00144 {
00145 public:
00146     // -----------------------------------------------------------------------
00147     //  Constructors and Destructor
00148     // -----------------------------------------------------------------------
00149     SocketJanitor(SOCKET* toDelete) : fData(toDelete) {}
00150     ~SocketJanitor() { reset(); }
00151 
00152     SOCKET* get() const { return fData; }
00153     SOCKET* release() {    SOCKET* p = fData; fData = 0; return p; }
00154 
00155     void reset(SOCKET* p = 0)
00156     {
00157         if(fData) {
00158             wrap_shutdown(*fData, SD_BOTH);
00159             wrap_closesocket(*fData);
00160         }
00161         fData = p;
00162     }
00163     bool isDataNull() { return (fData == 0); }
00164 
00165 private :
00166     // -----------------------------------------------------------------------
00167     //  Unimplemented constructors and operators
00168     // -----------------------------------------------------------------------
00169     SocketJanitor();
00170     SocketJanitor(const SocketJanitor&);
00171     SocketJanitor& operator=(const SocketJanitor&);
00172 
00173     // -----------------------------------------------------------------------
00174     //  Private data members
00175     //
00176     //  fData
00177     //      This is the pointer to the socket that must be closed when
00178     //      this object is destroyed.
00179     // -----------------------------------------------------------------------
00180     SOCKET*  fData;
00181 };
00182 
00183 bool BinHTTPURLInputStream::fInitialized = false;
00184 
00185 void BinHTTPURLInputStream::Initialize(MemoryManager* const manager)
00186 {
00187     //
00188     // Initialize the WinSock library here.
00189     //
00190     WORD        wVersionRequested;
00191     WSADATA     wsaData;
00192 
00193     LPFN_WSASTARTUP startup = NULL;
00194     if(gWinsockLib == NULL)
00195     {
00196 #ifdef WITH_IPV6
00197       gWinsockLib = LoadLibraryA("WS2_32");
00198 #else
00199       gWinsockLib = LoadLibraryA("WSOCK32");
00200 #endif
00201       if(gWinsockLib == NULL)
00202       {
00203           ThrowXMLwithMemMgr(NetAccessorException, XMLExcepts::NetAcc_InitFailed, manager);
00204       }
00205       else
00206       {
00207           startup = (LPFN_WSASTARTUP) GetProcAddress(gWinsockLib,"WSAStartup");
00208           gWSACleanup = (LPFN_WSACLEANUP) GetProcAddress(gWinsockLib,"WSACleanup");
00209           gWShtons = (LPFN_HTONS) GetProcAddress(gWinsockLib,"htons");
00210           gWSsocket = (LPFN_SOCKET) GetProcAddress(gWinsockLib,"socket");
00211           gWSconnect = (LPFN_CONNECT) GetProcAddress(gWinsockLib,"connect");
00212           gWSsend = (LPFN_SEND) GetProcAddress(gWinsockLib,"send");
00213           gWSrecv = (LPFN_RECV) GetProcAddress(gWinsockLib,"recv");
00214           gWSshutdown = (LPFN_SHUTDOWN) GetProcAddress(gWinsockLib,"shutdown");
00215           gWSclosesocket = (LPFN_CLOSESOCKET) GetProcAddress(gWinsockLib,"closesocket");
00216 #ifdef WITH_IPV6
00217           gWSgetaddrinfo = (LPFN_GETADDRINFO) GetProcAddress(gWinsockLib,"getaddrinfo");
00218           gWSfreeaddrinfo = (LPFN_FREEADDRINFO) GetProcAddress(gWinsockLib,"freeaddrinfo");
00219 #else
00220           gWSgethostbyname = (LPFN_GETHOSTBYNAME) GetProcAddress(gWinsockLib,"gethostbyname");
00221           gWSgethostbyaddr = (LPFN_GETHOSTBYADDR) GetProcAddress(gWinsockLib,"gethostbyaddr");
00222           gWSinet_addr = (LPFN_INET_ADDR) GetProcAddress(gWinsockLib,"inet_addr");
00223 #endif
00224 
00225           if(startup == NULL
00226              || gWSACleanup == NULL
00227              || gWShtons == NULL
00228              || gWSsocket == NULL
00229              || gWSconnect == NULL
00230              || gWSsend == NULL
00231              || gWSrecv == NULL
00232              || gWSshutdown == NULL
00233              || gWSclosesocket == NULL
00234 #ifdef WITH_IPV6
00235              || gWSgetaddrinfo == NULL
00236              || gWSfreeaddrinfo == NULL
00237 #else
00238              || gWSgethostbyname == NULL
00239              || gWSgethostbyaddr == NULL
00240              || gWSinet_addr == NULL
00241 #endif
00242           )
00243           {
00244               gWSACleanup = NULL;
00245               Cleanup();
00246               ThrowXMLwithMemMgr(NetAccessorException, XMLExcepts::NetAcc_InitFailed, manager);
00247           }
00248       }
00249     }
00250 
00251     wVersionRequested = MAKEWORD( 2, 2 );
00252 
00253     int err = (*startup)(wVersionRequested, &wsaData);
00254     if (err != 0)
00255     {
00256         // Call WSAGetLastError() to get the last error.
00257         ThrowXMLwithMemMgr(NetAccessorException, XMLExcepts::NetAcc_InitFailed, manager);
00258     }
00259     fInitialized = true;
00260 }
00261 
00262 void BinHTTPURLInputStream::Cleanup()
00263 {
00264     XMLMutexLock lock(XMLPlatformUtils::fgAtomicMutex);
00265 
00266     if(fInitialized)
00267     {
00268         if(gWSACleanup) (*gWSACleanup)();
00269         gWSACleanup = NULL;
00270         FreeLibrary(gWinsockLib);
00271         gWinsockLib = NULL;
00272         gWShtons = NULL;
00273         gWSsocket = NULL;
00274         gWSconnect = NULL;
00275         gWSsend = NULL;
00276         gWSrecv = NULL;
00277         gWSshutdown = NULL;
00278         gWSclosesocket = NULL;
00279 #ifdef WITH_IPV6
00280         gWSgetaddrinfo = NULL;
00281         gWSfreeaddrinfo = NULL;
00282 #else
00283         gWSgethostbyname = NULL;
00284         gWSgethostbyaddr = NULL;
00285         gWSinet_addr = NULL;
00286 #endif
00287 
00288         fInitialized = false;
00289     }
00290 }
00291 
00292 BinHTTPURLInputStream::BinHTTPURLInputStream(const XMLURL& urlSource, const XMLNetHTTPInfo* httpInfo /*=0*/)
00293       : BinHTTPInputStreamCommon(urlSource.getMemoryManager())
00294       , fSocketHandle(0)
00295 {
00296     MemoryManager *memoryManager = urlSource.getMemoryManager();
00297 
00298     // Check if we need to load the winsock library. While locking the
00299     // mutex every time may be somewhat slow, we don't care in this
00300     // particular case since the next operation will most likely be
00301     // the network access which is a lot slower.
00302     //
00303     {
00304         XMLMutexLock lock(XMLPlatformUtils::fgAtomicMutex);
00305 
00306         if (!fInitialized)
00307           Initialize(memoryManager);
00308     }
00309 
00310     //
00311     // Pull all of the parts of the URL out of th urlSource object, and transcode them
00312     //   and transcode them back to ASCII.
00313     //
00314     const XMLCh*        hostName = urlSource.getHost();
00315 
00316     if (hostName == 0)
00317       ThrowXMLwithMemMgr1(NetAccessorException,
00318                           XMLExcepts::File_CouldNotOpenFile,
00319                           urlSource.getURLText(),
00320                           memoryManager);
00321 
00322     char*               hostNameAsCharStar = XMLString::transcode(hostName, memoryManager);
00323     ArrayJanitor<char>  janHostNameAsCharStar(hostNameAsCharStar, memoryManager);
00324 
00325     XMLURL url(urlSource);
00326     int redirectCount = 0;
00327     SocketJanitor janSock(0);
00328 
00329     do {
00330         //
00331         // Set up a socket.
00332         //
00333 
00334 #ifdef WITH_IPV6
00335         struct addrinfo hints, *res, *ai;
00336 
00337         CharBuffer portBuffer(10, memoryManager);
00338         portBuffer.appendDecimalNumber(url.getPortNum());
00339 
00340         memset(&hints, 0, sizeof(struct addrinfo));
00341         hints.ai_family = PF_UNSPEC;
00342         hints.ai_socktype = SOCK_STREAM;
00343         int n = wrap_getaddrinfo(hostNameAsCharStar,portBuffer.getRawBuffer(),&hints, &res);
00344         if(n != 0)
00345         {
00346             hints.ai_flags = AI_NUMERICHOST;
00347             n = wrap_getaddrinfo(hostNameAsCharStar,(const char*)tempbuf,&hints, &res);
00348             if(n != 0)
00349                 ThrowXMLwithMemMgr1(NetAccessorException, XMLExcepts::NetAcc_TargetResolution, hostName, memoryManager);
00350         }
00351         janSock.reset();
00352         for (ai = res; ai != NULL; ai = ai->ai_next) {
00353             // Open a socket with the correct address family for this address.
00354             fSocketHandle = wrap_socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
00355             if (fSocketHandle == INVALID_SOCKET)
00356                 continue;
00357             janSock.reset(&fSocketHandle);
00358             if (wrap_connect(fSocketHandle, ai->ai_addr, (int)ai->ai_addrlen) == SOCKET_ERROR)
00359             {
00360                 wrap_freeaddrinfo(res);
00361                 // Call WSAGetLastError() to get the error number.
00362                 ThrowXMLwithMemMgr1(NetAccessorException,
00363                          XMLExcepts::NetAcc_ConnSocket, url.getURLText(), memoryManager);
00364             }
00365             break;
00366         }
00367         wrap_freeaddrinfo(res);
00368         if (fSocketHandle == INVALID_SOCKET)
00369         {
00370             // Call WSAGetLastError() to get the error number.
00371             ThrowXMLwithMemMgr1(NetAccessorException,
00372                      XMLExcepts::NetAcc_CreateSocket, url.getURLText(), memoryManager);
00373         }
00374 #else
00375         struct hostent*     hostEntPtr = 0;
00376         struct sockaddr_in  sa;
00377 
00378 
00379         if ((hostEntPtr = wrap_gethostbyname(hostNameAsCharStar)) == NULL)
00380         {
00381             unsigned long  numAddress = wrap_inet_addr(hostNameAsCharStar);
00382             if (numAddress == INADDR_NONE)
00383             {
00384                 // Call WSAGetLastError() to get the error number.
00385                 ThrowXMLwithMemMgr1(NetAccessorException,
00386                     XMLExcepts::NetAcc_TargetResolution, hostName, memoryManager);
00387             }
00388             if ((hostEntPtr =
00389                     wrap_gethostbyaddr((const char *) &numAddress,
00390                         sizeof(unsigned long), AF_INET)) == NULL)
00391             {
00392                 // Call WSAGetLastError() to get the error number.
00393                 ThrowXMLwithMemMgr1(NetAccessorException,
00394                     XMLExcepts::NetAcc_TargetResolution, hostName, memoryManager);
00395             }
00396         }
00397 
00398         memcpy((void *) &sa.sin_addr,
00399             (const void *) hostEntPtr->h_addr, hostEntPtr->h_length);
00400         sa.sin_family = hostEntPtr->h_addrtype;
00401         sa.sin_port = wrap_htons((unsigned short)url.getPortNum());
00402 
00403         janSock.reset();
00404         fSocketHandle = wrap_socket(hostEntPtr->h_addrtype, SOCK_STREAM, 0);
00405         if (fSocketHandle == INVALID_SOCKET)
00406         {
00407             // Call WSAGetLastError() to get the error number.
00408             ThrowXMLwithMemMgr1(NetAccessorException,
00409                 XMLExcepts::NetAcc_CreateSocket, url.getURLText(), memoryManager);
00410         }
00411         janSock.reset(&fSocketHandle);
00412 
00413         if (wrap_connect(fSocketHandle, (struct sockaddr *) &sa, sizeof(sa)) == SOCKET_ERROR)
00414         {
00415             // Call WSAGetLastError() to get the error number.
00416             ThrowXMLwithMemMgr1(NetAccessorException,
00417                 XMLExcepts::NetAcc_ConnSocket, url.getURLText(), memoryManager);
00418         }
00419 
00420 #endif
00421 
00422         int status = sendRequest(url, httpInfo);
00423 
00424         if(status == 200) {
00425             // HTTP 200 OK response means we're done.
00426             // We're done
00427             break;
00428         }
00429         // a 3xx response means there was an HTTP redirect
00430         else if(status >= 300 && status <= 307) {
00431             redirectCount++;
00432 
00433             XMLCh *newURLString = findHeader("Location");
00434             ArrayJanitor<XMLCh> janNewURLString(newURLString, memoryManager);
00435 
00436             if(newURLString == 0 || *newURLString == 0) {
00437                 ThrowXMLwithMemMgr1(NetAccessorException, XMLExcepts::File_CouldNotOpenFile, url.getURLText(), memoryManager);
00438             }
00439 
00440             XMLURL newURL(memoryManager);
00441             newURL.setURL(url, newURLString);
00442             if(newURL.getProtocol() != XMLURL::HTTP) {
00443                 ThrowXMLwithMemMgr1(NetAccessorException, XMLExcepts::File_CouldNotOpenFile, newURL.getURLText(), memoryManager);
00444             }
00445 
00446             url = newURL;
00447             hostName = newURL.getHost();
00448 
00449             if (hostName == 0)
00450               ThrowXMLwithMemMgr1(NetAccessorException,
00451                                   XMLExcepts::File_CouldNotOpenFile,
00452                                   newURL.getURLText(),
00453                                   memoryManager);
00454 
00455             janHostNameAsCharStar.release();
00456             hostNameAsCharStar = XMLString::transcode(hostName, memoryManager);
00457             janHostNameAsCharStar.reset(hostNameAsCharStar, memoryManager);
00458         }
00459         else {
00460             // Most likely a 404 Not Found error.
00461             ThrowXMLwithMemMgr1(NetAccessorException, XMLExcepts::File_CouldNotOpenFile, url.getURLText(), memoryManager);
00462         }
00463     } while(redirectCount < 6);
00464 
00465     janSock.release();
00466 }
00467 
00468 BinHTTPURLInputStream::~BinHTTPURLInputStream()
00469 {
00470     wrap_shutdown(fSocketHandle, SD_BOTH);
00471     wrap_closesocket(fSocketHandle);
00472 }
00473 
00474 bool BinHTTPURLInputStream::send(const char *buf, XMLSize_t len)
00475 {
00476     XMLSize_t done = 0;
00477     int ret;
00478 
00479     while(done < len) {
00480         ret = wrap_send(fSocketHandle, buf + done, (int)(len - done), 0);
00481         if(ret == SOCKET_ERROR) return false;
00482         done += ret;
00483     }
00484 
00485     return true;
00486 }
00487 
00488 int BinHTTPURLInputStream::receive(char *buf, XMLSize_t len)
00489 {
00490     int iLen = wrap_recv(fSocketHandle, buf, (int)len, 0);
00491     if (iLen == SOCKET_ERROR) return -1;
00492     return iLen;
00493 }
00494 
00495 XERCES_CPP_NAMESPACE_END