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