1 /*
2  * Licensed to the Apache Software Foundation (ASF) under one or more
3  * contributor license agreements.  See the NOTICE file distributed with
4  * this work for additional information regarding copyright ownership.
5  * The ASF licenses this file to You under the Apache License, Version 2.0
6  * (the "License"); you may not use this file except in compliance with
7  * the License.  You may obtain a copy of the License at
8  *
9  *      http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  */
17 
18 /*
19  * $Id: BinHTTPURLInputStream.cpp 936316 2010-04-21 14:19:58Z borisk $
20  */
21 
22 
23 #include <xercesc/util/NetAccessors/WinSock/BinHTTPURLInputStream.hpp>
24 #include <windows.h>
25 
26 #ifdef WITH_IPV6
27 #include <ws2tcpip.h>
28 #endif
29 
30 #include <stdio.h>
31 #include <string.h>
32 
33 #include <xercesc/util/PlatformUtils.hpp>
34 #include <xercesc/util/XMLNetAccessor.hpp>
35 #include <xercesc/util/XMLString.hpp>
36 #include <xercesc/util/XMLExceptMsgs.hpp>
37 #include <xercesc/util/Janitor.hpp>
38 #include <xercesc/util/XMLUniDefs.hpp>
39 #include <xercesc/util/Mutexes.hpp>
40 
41 XERCES_CPP_NAMESPACE_BEGIN
42 
43 typedef u_short (WSAAPI * LPFN_HTONS)(u_short hostshort);
44 typedef SOCKET (WSAAPI * LPFN_SOCKET)(int af, int type, int protocol);
45 typedef int (WSAAPI * LPFN_CONNECT)(SOCKET s, const struct sockaddr* name, int namelen);
46 typedef int (WSAAPI * LPFN_SEND)(SOCKET s, const char* buf, int len, int flags);
47 typedef int (WSAAPI * LPFN_RECV)(SOCKET s, char* buf, int len, int flags);
48 typedef int (WSAAPI * LPFN_SHUTDOWN)(SOCKET s, int how);
49 typedef int (WSAAPI * LPFN_CLOSESOCKET)(SOCKET s);
50 typedef int (WSAAPI * LPFN_WSACLEANUP)();
51 typedef int (WSAAPI * LPFN_WSASTARTUP)(WORD wVersionRequested, LPWSADATA lpWSAData);
52 #ifdef WITH_IPV6
53 typedef int (WSAAPI * LPFN_GETADDRINFO)(const char* nodename, const char * servname, const struct addrinfo * hints, struct addrinfo ** res);
54 typedef void (WSAAPI * LPFN_FREEADDRINFO)(struct addrinfo * ai);
55 #else
56 typedef struct hostent *(WSAAPI * LPFN_GETHOSTBYNAME)(const char* name);
57 typedef struct hostent *(WSAAPI * LPFN_GETHOSTBYADDR)(const char* addr, int len, int type);
58 typedef unsigned long (WSAAPI * LPFN_INET_ADDR)(const char* cp);
59 #endif
60 
61 static HMODULE gWinsockLib = NULL;
62 static LPFN_HTONS gWShtons = NULL;
63 static LPFN_SOCKET gWSsocket = NULL;
64 static LPFN_CONNECT gWSconnect = NULL;
65 static LPFN_SEND gWSsend = NULL;
66 static LPFN_RECV gWSrecv = NULL;
67 static LPFN_SHUTDOWN gWSshutdown = NULL;
68 static LPFN_CLOSESOCKET gWSclosesocket = NULL;
69 static LPFN_WSACLEANUP gWSACleanup = NULL;
70 #ifdef WITH_IPV6
71 static LPFN_GETADDRINFO gWSgetaddrinfo = NULL;
72 static LPFN_FREEADDRINFO gWSfreeaddrinfo = NULL;
73 #else
74 static LPFN_GETHOSTBYNAME gWSgethostbyname = NULL;
75 static LPFN_GETHOSTBYADDR gWSgethostbyaddr = NULL;
76 static LPFN_INET_ADDR gWSinet_addr = NULL;
77 #endif
78 
wrap_htons(u_short hostshort)79 static u_short wrap_htons(u_short hostshort)
80 {
81     return (*gWShtons)(hostshort);
82 }
83 
wrap_socket(int af,int type,int protocol)84 static SOCKET wrap_socket(int af,int type,int protocol)
85 {
86     return (*gWSsocket)(af,type,protocol);
87 }
88 
wrap_connect(SOCKET s,const struct sockaddr * name,int namelen)89 static int wrap_connect(SOCKET s,const struct sockaddr* name,int namelen)
90 {
91     return (*gWSconnect)(s,name,namelen);
92 }
93 
wrap_send(SOCKET s,const char * buf,int len,int flags)94 static int wrap_send(SOCKET s,const char* buf,int len,int flags)
95 {
96     return (*gWSsend)(s,buf,len,flags);
97 }
98 
wrap_recv(SOCKET s,char * buf,int len,int flags)99 static int wrap_recv(SOCKET s,char* buf,int len,int flags)
100 {
101     return (*gWSrecv)(s,buf,len,flags);
102 }
103 
wrap_shutdown(SOCKET s,int how)104 static int wrap_shutdown(SOCKET s,int how)
105 {
106     return (*gWSshutdown)(s,how);
107 }
108 
wrap_closesocket(SOCKET socket)109 static int wrap_closesocket(SOCKET socket)
110 {
111     return (*gWSclosesocket)(socket);
112 }
113 
114 #ifdef WITH_IPV6
wrap_getaddrinfo(const char * nodename,const char * servname,const struct addrinfo * hints,struct addrinfo ** res)115 static int wrap_getaddrinfo(const char* nodename,const char* servname,const struct addrinfo* hints,struct addrinfo** res)
116 {
117    return (*gWSgetaddrinfo)(nodename,servname,hints,res);
118 }
119 
wrap_freeaddrinfo(struct addrinfo * ai)120 static void wrap_freeaddrinfo(struct addrinfo* ai)
121 {
122     (*gWSfreeaddrinfo)(ai);
123 }
124 #else
wrap_gethostbyname(const char * name)125 static struct hostent* wrap_gethostbyname(const char* name)
126 {
127     return (*gWSgethostbyname)(name);
128 }
129 
wrap_gethostbyaddr(const char * addr,int len,int type)130 static struct hostent* wrap_gethostbyaddr(const char* addr,int len,int type)
131 {
132     return (*gWSgethostbyaddr)(addr,len,type);
133 }
134 
wrap_inet_addr(const char * cp)135 static unsigned long wrap_inet_addr(const char* cp)
136 {
137     return (*gWSinet_addr)(cp);
138 }
139 
140 #endif
141 
142 
143 class SocketJanitor
144 {
145 public:
146     // -----------------------------------------------------------------------
147     //  Constructors and Destructor
148     // -----------------------------------------------------------------------
SocketJanitor(SOCKET * toDelete)149     SocketJanitor(SOCKET* toDelete) : fData(toDelete) {}
~SocketJanitor()150     ~SocketJanitor() { reset(); }
151 
get() const152     SOCKET* get() const { return fData; }
release()153     SOCKET* release() {    SOCKET* p = fData; fData = 0; return p; }
154 
reset(SOCKET * p=0)155     void reset(SOCKET* p = 0)
156     {
157         if(fData) {
158             wrap_shutdown(*fData, SD_BOTH);
159             wrap_closesocket(*fData);
160         }
161         fData = p;
162     }
isDataNull()163     bool isDataNull() { return (fData == 0); }
164 
165 private :
166     // -----------------------------------------------------------------------
167     //  Unimplemented constructors and operators
168     // -----------------------------------------------------------------------
169     SocketJanitor();
170     SocketJanitor(const SocketJanitor&);
171     SocketJanitor& operator=(const SocketJanitor&);
172 
173     // -----------------------------------------------------------------------
174     //  Private data members
175     //
176     //  fData
177     //      This is the pointer to the socket that must be closed when
178     //      this object is destroyed.
179     // -----------------------------------------------------------------------
180     SOCKET*  fData;
181 };
182 
183 bool BinHTTPURLInputStream::fInitialized = false;
184 
Initialize(MemoryManager * const manager)185 void BinHTTPURLInputStream::Initialize(MemoryManager* const manager)
186 {
187     //
188     // Initialize the WinSock library here.
189     //
190     WORD        wVersionRequested;
191     WSADATA     wsaData;
192 
193     LPFN_WSASTARTUP startup = NULL;
194     if(gWinsockLib == NULL)
195     {
196 #ifdef WITH_IPV6
197       gWinsockLib = LoadLibraryA("WS2_32");
198 #else
199       gWinsockLib = LoadLibraryA("WSOCK32");
200 #endif
201       if(gWinsockLib == NULL)
202       {
203           ThrowXMLwithMemMgr(NetAccessorException, XMLExcepts::NetAcc_InitFailed, manager);
204       }
205       else
206       {
207           startup = (LPFN_WSASTARTUP) GetProcAddress(gWinsockLib,"WSAStartup");
208           gWSACleanup = (LPFN_WSACLEANUP) GetProcAddress(gWinsockLib,"WSACleanup");
209           gWShtons = (LPFN_HTONS) GetProcAddress(gWinsockLib,"htons");
210           gWSsocket = (LPFN_SOCKET) GetProcAddress(gWinsockLib,"socket");
211           gWSconnect = (LPFN_CONNECT) GetProcAddress(gWinsockLib,"connect");
212           gWSsend = (LPFN_SEND) GetProcAddress(gWinsockLib,"send");
213           gWSrecv = (LPFN_RECV) GetProcAddress(gWinsockLib,"recv");
214           gWSshutdown = (LPFN_SHUTDOWN) GetProcAddress(gWinsockLib,"shutdown");
215           gWSclosesocket = (LPFN_CLOSESOCKET) GetProcAddress(gWinsockLib,"closesocket");
216 #ifdef WITH_IPV6
217           gWSgetaddrinfo = (LPFN_GETADDRINFO) GetProcAddress(gWinsockLib,"getaddrinfo");
218           gWSfreeaddrinfo = (LPFN_FREEADDRINFO) GetProcAddress(gWinsockLib,"freeaddrinfo");
219 #else
220           gWSgethostbyname = (LPFN_GETHOSTBYNAME) GetProcAddress(gWinsockLib,"gethostbyname");
221           gWSgethostbyaddr = (LPFN_GETHOSTBYADDR) GetProcAddress(gWinsockLib,"gethostbyaddr");
222           gWSinet_addr = (LPFN_INET_ADDR) GetProcAddress(gWinsockLib,"inet_addr");
223 #endif
224 
225           if(startup == NULL
226              || gWSACleanup == NULL
227              || gWShtons == NULL
228              || gWSsocket == NULL
229              || gWSconnect == NULL
230              || gWSsend == NULL
231              || gWSrecv == NULL
232              || gWSshutdown == NULL
233              || gWSclosesocket == NULL
234 #ifdef WITH_IPV6
235              || gWSgetaddrinfo == NULL
236              || gWSfreeaddrinfo == NULL
237 #else
238              || gWSgethostbyname == NULL
239              || gWSgethostbyaddr == NULL
240              || gWSinet_addr == NULL
241 #endif
242           )
243           {
244               gWSACleanup = NULL;
245               Cleanup();
246               ThrowXMLwithMemMgr(NetAccessorException, XMLExcepts::NetAcc_InitFailed, manager);
247           }
248       }
249     }
250 
251     wVersionRequested = MAKEWORD( 2, 2 );
252 
253     int err = (*startup)(wVersionRequested, &wsaData);
254     if (err != 0)
255     {
256         // Call WSAGetLastError() to get the last error.
257         ThrowXMLwithMemMgr(NetAccessorException, XMLExcepts::NetAcc_InitFailed, manager);
258     }
259     fInitialized = true;
260 }
261 
Cleanup()262 void BinHTTPURLInputStream::Cleanup()
263 {
264     XMLMutexLock lock(XMLPlatformUtils::fgAtomicMutex);
265 
266     if(fInitialized)
267     {
268         if(gWSACleanup) (*gWSACleanup)();
269         gWSACleanup = NULL;
270         FreeLibrary(gWinsockLib);
271         gWinsockLib = NULL;
272         gWShtons = NULL;
273         gWSsocket = NULL;
274         gWSconnect = NULL;
275         gWSsend = NULL;
276         gWSrecv = NULL;
277         gWSshutdown = NULL;
278         gWSclosesocket = NULL;
279 #ifdef WITH_IPV6
280         gWSgetaddrinfo = NULL;
281         gWSfreeaddrinfo = NULL;
282 #else
283         gWSgethostbyname = NULL;
284         gWSgethostbyaddr = NULL;
285         gWSinet_addr = NULL;
286 #endif
287 
288         fInitialized = false;
289     }
290 }
291 
BinHTTPURLInputStream(const XMLURL & urlSource,const XMLNetHTTPInfo * httpInfo)292 BinHTTPURLInputStream::BinHTTPURLInputStream(const XMLURL& urlSource, const XMLNetHTTPInfo* httpInfo /*=0*/)
293       : BinHTTPInputStreamCommon(urlSource.getMemoryManager())
294       , fSocketHandle(0)
295 {
296     MemoryManager *memoryManager = urlSource.getMemoryManager();
297 
298     // Check if we need to load the winsock library. While locking the
299     // mutex every time may be somewhat slow, we don't care in this
300     // particular case since the next operation will most likely be
301     // the network access which is a lot slower.
302     //
303     {
304         XMLMutexLock lock(XMLPlatformUtils::fgAtomicMutex);
305 
306         if (!fInitialized)
307           Initialize(memoryManager);
308     }
309 
310     //
311     // Pull all of the parts of the URL out of th urlSource object, and transcode them
312     //   and transcode them back to ASCII.
313     //
314     const XMLCh*        hostName = urlSource.getHost();
315 
316     if (hostName == 0)
317       ThrowXMLwithMemMgr1(NetAccessorException,
318                           XMLExcepts::File_CouldNotOpenFile,
319                           urlSource.getURLText(),
320                           memoryManager);
321 
322     char*               hostNameAsCharStar = XMLString::transcode(hostName, memoryManager);
323     ArrayJanitor<char>  janHostNameAsCharStar(hostNameAsCharStar, memoryManager);
324 
325     XMLURL url(urlSource);
326     int redirectCount = 0;
327     SocketJanitor janSock(0);
328 
329     do {
330         //
331         // Set up a socket.
332         //
333 
334 #ifdef WITH_IPV6
335         struct addrinfo hints, *res, *ai;
336 
337         CharBuffer portBuffer(10, memoryManager);
338         portBuffer.appendDecimalNumber(url.getPortNum());
339 
340         memset(&hints, 0, sizeof(struct addrinfo));
341         hints.ai_family = PF_UNSPEC;
342         hints.ai_socktype = SOCK_STREAM;
343         int n = wrap_getaddrinfo(hostNameAsCharStar,portBuffer.getRawBuffer(),&hints, &res);
344         if(n != 0)
345         {
346             hints.ai_flags = AI_NUMERICHOST;
347             n = wrap_getaddrinfo(hostNameAsCharStar,(const char*)tempbuf,&hints, &res);
348             if(n != 0)
349                 ThrowXMLwithMemMgr1(NetAccessorException, XMLExcepts::NetAcc_TargetResolution, hostName, memoryManager);
350         }
351         janSock.reset();
352         for (ai = res; ai != NULL; ai = ai->ai_next) {
353             // Open a socket with the correct address family for this address.
354             fSocketHandle = wrap_socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
355             if (fSocketHandle == INVALID_SOCKET)
356                 continue;
357             janSock.reset(&fSocketHandle);
358             if (wrap_connect(fSocketHandle, ai->ai_addr, (int)ai->ai_addrlen) == SOCKET_ERROR)
359             {
360                 wrap_freeaddrinfo(res);
361                 // Call WSAGetLastError() to get the error number.
362                 ThrowXMLwithMemMgr1(NetAccessorException,
363                          XMLExcepts::NetAcc_ConnSocket, url.getURLText(), memoryManager);
364             }
365             break;
366         }
367         wrap_freeaddrinfo(res);
368         if (fSocketHandle == INVALID_SOCKET)
369         {
370             // Call WSAGetLastError() to get the error number.
371             ThrowXMLwithMemMgr1(NetAccessorException,
372                      XMLExcepts::NetAcc_CreateSocket, url.getURLText(), memoryManager);
373         }
374 #else
375         struct hostent*     hostEntPtr = 0;
376         struct sockaddr_in  sa;
377 
378 
379         if ((hostEntPtr = wrap_gethostbyname(hostNameAsCharStar)) == NULL)
380         {
381             unsigned long  numAddress = wrap_inet_addr(hostNameAsCharStar);
382             if (numAddress == INADDR_NONE)
383             {
384                 // Call WSAGetLastError() to get the error number.
385                 ThrowXMLwithMemMgr1(NetAccessorException,
386                     XMLExcepts::NetAcc_TargetResolution, hostName, memoryManager);
387             }
388             if ((hostEntPtr =
389                     wrap_gethostbyaddr((const char *) &numAddress,
390                         sizeof(unsigned long), AF_INET)) == NULL)
391             {
392                 // Call WSAGetLastError() to get the error number.
393                 ThrowXMLwithMemMgr1(NetAccessorException,
394                     XMLExcepts::NetAcc_TargetResolution, hostName, memoryManager);
395             }
396         }
397 
398         memcpy((void *) &sa.sin_addr,
399             (const void *) hostEntPtr->h_addr, hostEntPtr->h_length);
400         sa.sin_family = hostEntPtr->h_addrtype;
401         sa.sin_port = wrap_htons((unsigned short)url.getPortNum());
402 
403         janSock.reset();
404         fSocketHandle = wrap_socket(hostEntPtr->h_addrtype, SOCK_STREAM, 0);
405         if (fSocketHandle == INVALID_SOCKET)
406         {
407             // Call WSAGetLastError() to get the error number.
408             ThrowXMLwithMemMgr1(NetAccessorException,
409                 XMLExcepts::NetAcc_CreateSocket, url.getURLText(), memoryManager);
410         }
411         janSock.reset(&fSocketHandle);
412 
413         if (wrap_connect(fSocketHandle, (struct sockaddr *) &sa, sizeof(sa)) == SOCKET_ERROR)
414         {
415             // Call WSAGetLastError() to get the error number.
416             ThrowXMLwithMemMgr1(NetAccessorException,
417                 XMLExcepts::NetAcc_ConnSocket, url.getURLText(), memoryManager);
418         }
419 
420 #endif
421 
422         int status = sendRequest(url, httpInfo);
423 
424         if(status == 200) {
425             // HTTP 200 OK response means we're done.
426             // We're done
427             break;
428         }
429         // a 3xx response means there was an HTTP redirect
430         else if(status >= 300 && status <= 307) {
431             redirectCount++;
432 
433             XMLCh *newURLString = findHeader("Location");
434             ArrayJanitor<XMLCh> janNewURLString(newURLString, memoryManager);
435 
436             if(newURLString == 0 || *newURLString == 0) {
437                 ThrowXMLwithMemMgr1(NetAccessorException, XMLExcepts::File_CouldNotOpenFile, url.getURLText(), memoryManager);
438             }
439 
440             XMLURL newURL(memoryManager);
441             newURL.setURL(url, newURLString);
442             if(newURL.getProtocol() != XMLURL::HTTP) {
443                 ThrowXMLwithMemMgr1(NetAccessorException, XMLExcepts::File_CouldNotOpenFile, newURL.getURLText(), memoryManager);
444             }
445 
446             url = newURL;
447             hostName = newURL.getHost();
448 
449             if (hostName == 0)
450               ThrowXMLwithMemMgr1(NetAccessorException,
451                                   XMLExcepts::File_CouldNotOpenFile,
452                                   newURL.getURLText(),
453                                   memoryManager);
454 
455             janHostNameAsCharStar.release();
456             hostNameAsCharStar = XMLString::transcode(hostName, memoryManager);
457             janHostNameAsCharStar.reset(hostNameAsCharStar, memoryManager);
458         }
459         else {
460             // Most likely a 404 Not Found error.
461             ThrowXMLwithMemMgr1(NetAccessorException, XMLExcepts::File_CouldNotOpenFile, url.getURLText(), memoryManager);
462         }
463     } while(redirectCount < 6);
464 
465     janSock.release();
466 }
467 
~BinHTTPURLInputStream()468 BinHTTPURLInputStream::~BinHTTPURLInputStream()
469 {
470     wrap_shutdown(fSocketHandle, SD_BOTH);
471     wrap_closesocket(fSocketHandle);
472 }
473 
send(const char * buf,XMLSize_t len)474 bool BinHTTPURLInputStream::send(const char *buf, XMLSize_t len)
475 {
476     XMLSize_t done = 0;
477     int ret;
478 
479     while(done < len) {
480         ret = wrap_send(fSocketHandle, buf + done, (int)(len - done), 0);
481         if(ret == SOCKET_ERROR) return false;
482         done += ret;
483     }
484 
485     return true;
486 }
487 
receive(char * buf,XMLSize_t len)488 int BinHTTPURLInputStream::receive(char *buf, XMLSize_t len)
489 {
490     int iLen = wrap_recv(fSocketHandle, buf, (int)len, 0);
491     if (iLen == SOCKET_ERROR) return -1;
492     return iLen;
493 }
494 
495 XERCES_CPP_NAMESPACE_END
496