source: icXML/icXML-devel/src/xercesc/util/NetAccessors/WinSock/BinHTTPURLInputStream.cpp @ 3565

Last change on this file since 3565 was 3565, checked in by cameron, 6 years ago

Updates to xercesc sources

File size: 16.3 KB
Line 
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 936317 2010-04-21 14:20:51Z 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 <icxercesc/util/PlatformUtils.hpp>
34#include <xercesc/util/XMLNetAccessor.hpp>
35#include <icxercesc/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
41XERCES_CPP_NAMESPACE_BEGIN
42
43typedef u_short (WSAAPI * LPFN_HTONS)(u_short hostshort);
44typedef SOCKET (WSAAPI * LPFN_SOCKET)(int af, int type, int protocol);
45typedef int (WSAAPI * LPFN_CONNECT)(SOCKET s, const struct sockaddr* name, int namelen);
46typedef int (WSAAPI * LPFN_SEND)(SOCKET s, const char* buf, int len, int flags);
47typedef int (WSAAPI * LPFN_RECV)(SOCKET s, char* buf, int len, int flags);
48typedef int (WSAAPI * LPFN_SHUTDOWN)(SOCKET s, int how);
49typedef int (WSAAPI * LPFN_CLOSESOCKET)(SOCKET s);
50typedef int (WSAAPI * LPFN_WSACLEANUP)();
51typedef int (WSAAPI * LPFN_WSASTARTUP)(WORD wVersionRequested, LPWSADATA lpWSAData);
52#ifdef WITH_IPV6
53typedef int (WSAAPI * LPFN_GETADDRINFO)(const char* nodename, const char * servname, const struct addrinfo * hints, struct addrinfo ** res);
54typedef void (WSAAPI * LPFN_FREEADDRINFO)(struct addrinfo * ai);
55#else
56typedef struct hostent *(WSAAPI * LPFN_GETHOSTBYNAME)(const char* name);
57typedef struct hostent *(WSAAPI * LPFN_GETHOSTBYADDR)(const char* addr, int len, int type);
58typedef unsigned long (WSAAPI * LPFN_INET_ADDR)(const char* cp);
59#endif
60
61static HMODULE gWinsockLib = NULL;
62static LPFN_HTONS gWShtons = NULL;
63static LPFN_SOCKET gWSsocket = NULL;
64static LPFN_CONNECT gWSconnect = NULL;
65static LPFN_SEND gWSsend = NULL;
66static LPFN_RECV gWSrecv = NULL;
67static LPFN_SHUTDOWN gWSshutdown = NULL;
68static LPFN_CLOSESOCKET gWSclosesocket = NULL;
69static LPFN_WSACLEANUP gWSACleanup = NULL;
70#ifdef WITH_IPV6
71static LPFN_GETADDRINFO gWSgetaddrinfo = NULL;
72static LPFN_FREEADDRINFO gWSfreeaddrinfo = NULL;
73#else
74static LPFN_GETHOSTBYNAME gWSgethostbyname = NULL;
75static LPFN_GETHOSTBYADDR gWSgethostbyaddr = NULL;
76static LPFN_INET_ADDR gWSinet_addr = NULL;
77#endif
78
79static u_short wrap_htons(u_short hostshort)
80{
81    return (*gWShtons)(hostshort);
82}
83
84static SOCKET wrap_socket(int af,int type,int protocol)
85{
86    return (*gWSsocket)(af,type,protocol);
87}
88
89static int wrap_connect(SOCKET s,const struct sockaddr* name,int namelen)
90{
91    return (*gWSconnect)(s,name,namelen);
92}
93
94static int wrap_send(SOCKET s,const char* buf,int len,int flags)
95{
96    return (*gWSsend)(s,buf,len,flags);
97}
98
99static int wrap_recv(SOCKET s,char* buf,int len,int flags)
100{
101    return (*gWSrecv)(s,buf,len,flags);
102}
103
104static int wrap_shutdown(SOCKET s,int how)
105{
106    return (*gWSshutdown)(s,how);
107}
108
109static int wrap_closesocket(SOCKET socket)
110{
111    return (*gWSclosesocket)(socket);
112}
113
114#ifdef WITH_IPV6
115static 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
120static void wrap_freeaddrinfo(struct addrinfo* ai)
121{
122    (*gWSfreeaddrinfo)(ai);
123}
124#else
125static struct hostent* wrap_gethostbyname(const char* name)
126{
127    return (*gWSgethostbyname)(name);
128}
129
130static struct hostent* wrap_gethostbyaddr(const char* addr,int len,int type)
131{
132    return (*gWSgethostbyaddr)(addr,len,type);
133}
134
135static unsigned long wrap_inet_addr(const char* cp)
136{
137    return (*gWSinet_addr)(cp);
138}
139
140#endif
141
142
143class SocketJanitor
144{
145public:
146    // -----------------------------------------------------------------------
147    //  Constructors and Destructor
148    // -----------------------------------------------------------------------
149    SocketJanitor(SOCKET* toDelete) : fData(toDelete) {}
150    ~SocketJanitor() { reset(); }
151
152    SOCKET* get() const { return fData; }
153    SOCKET* release() {    SOCKET* p = fData; fData = 0; return p; }
154
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    }
163    bool isDataNull() { return (fData == 0); }
164
165private :
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
183bool BinHTTPURLInputStream::fInitialized = false;
184
185void 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
262void 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
292BinHTTPURLInputStream::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
468BinHTTPURLInputStream::~BinHTTPURLInputStream()
469{
470    wrap_shutdown(fSocketHandle, SD_BOTH);
471    wrap_closesocket(fSocketHandle);
472}
473
474bool 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
488int 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
495XERCES_CPP_NAMESPACE_END
Note: See TracBrowser for help on using the repository browser.