connect.c 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581
  1. /*****************************************************************************
  2. * _ _ ____ _
  3. * Project ___| | | | _ \| |
  4. * / __| | | | |_) | |
  5. * | (__| |_| | _ <| |___
  6. * \___|\___/|_| \_\_____|
  7. *
  8. * Copyright (C) 2001, Daniel Stenberg, <[email protected]>, et al.
  9. *
  10. * In order to be useful for every potential user, curl and libcurl are
  11. * dual-licensed under the MPL and the MIT/X-derivate licenses.
  12. *
  13. * You may opt to use, copy, modify, merge, publish, distribute and/or sell
  14. * copies of the Software, and permit persons to whom the Software is
  15. * furnished to do so, under the terms of the MPL or the MIT/X-derivate
  16. * licenses. You may pick one of these licenses.
  17. *
  18. * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
  19. * KIND, either express or implied.
  20. *
  21. * $Id$
  22. *****************************************************************************/
  23. #include "setup.h"
  24. #ifndef WIN32
  25. /* headers for non-win32 */
  26. #include <sys/time.h>
  27. #include <sys/socket.h>
  28. #include <sys/types.h>
  29. #include <sys/ioctl.h>
  30. #ifdef HAVE_UNISTD_H
  31. #include <unistd.h>
  32. #endif
  33. #ifdef HAVE_NETDB_H
  34. #include <netdb.h>
  35. #endif
  36. #ifdef HAVE_FCNTL_H
  37. #include <fcntl.h>
  38. #endif
  39. #ifdef HAVE_NETINET_IN_H
  40. #include <netinet/in.h>
  41. #endif
  42. #ifdef HAVE_ARPA_INET_H
  43. #include <arpa/inet.h>
  44. #endif
  45. #ifdef HAVE_STDLIB_H
  46. #include <stdlib.h> /* required for free() prototype, without it, this crashes
  47. on macos 68K */
  48. #endif
  49. #ifdef VMS
  50. #include <in.h>
  51. #include <inet.h>
  52. #endif
  53. #endif
  54. #include <stdio.h>
  55. #include <errno.h>
  56. #include <string.h>
  57. #ifndef TRUE
  58. #define TRUE 1
  59. #define FALSE 0
  60. #endif
  61. #ifdef WIN32
  62. #define HAVE_IOCTLSOCKET
  63. #include <windows.h>
  64. #include <winsock.h>
  65. #define EINPROGRESS WSAEINPROGRESS
  66. #define EWOULDBLOCK WSAEWOULDBLOCK
  67. #define EISCONN WSAEISCONN
  68. #endif
  69. #include "urldata.h"
  70. #include "sendf.h"
  71. #include "if2ip.h"
  72. /* The last #include file should be: */
  73. #ifdef MALLOCDEBUG
  74. #include "memdebug.h"
  75. #endif
  76. static
  77. int geterrno(void)
  78. {
  79. #ifdef WIN32
  80. return (int)GetLastError();
  81. #else
  82. return errno;
  83. #endif
  84. }
  85. /*************************************************************************
  86. * Curl_nonblock
  87. *
  88. * Description:
  89. * Set the socket to either blocking or non-blocking mode.
  90. */
  91. int Curl_nonblock(int socket, /* operate on this */
  92. int nonblock /* TRUE or FALSE */)
  93. {
  94. #undef SETBLOCK
  95. #ifdef HAVE_O_NONBLOCK
  96. int flags;
  97. flags = fcntl(socket, F_GETFL, 0);
  98. if (TRUE == nonblock)
  99. return fcntl(socket, F_SETFL, flags | O_NONBLOCK);
  100. else
  101. return fcntl(socket, F_SETFL, flags & (~O_NONBLOCK));
  102. #define SETBLOCK 1
  103. #endif
  104. #ifdef HAVE_FIONBIO
  105. int flags;
  106. flags = nonblock;
  107. return ioctl(socket, FIONBIO, &flags);
  108. #define SETBLOCK 2
  109. #endif
  110. #ifdef HAVE_IOCTLSOCKET
  111. int flags;
  112. flags = nonblock;
  113. return ioctlsocket(socket, FIONBIO, &flags);
  114. #define SETBLOCK 3
  115. #endif
  116. #ifdef HAVE_IOCTLSOCKET_CASE
  117. return IoctlSocket(socket, FIONBIO, (long)nonblock);
  118. #define SETBLOCK 4
  119. #endif
  120. #ifdef HAVE_DISABLED_NONBLOCKING
  121. return 0; /* returns success */
  122. #define SETBLOCK 5
  123. #endif
  124. #ifndef SETBLOCK
  125. #error "no non-blocking method was found/used/set"
  126. #endif
  127. }
  128. /*
  129. * Return 0 on fine connect, -1 on error and 1 on timeout.
  130. */
  131. static
  132. int waitconnect(int sockfd, /* socket */
  133. int timeout_msec)
  134. {
  135. fd_set fd;
  136. fd_set errfd;
  137. struct timeval interval;
  138. int rc;
  139. /* now select() until we get connect or timeout */
  140. FD_ZERO(&fd);
  141. FD_SET(sockfd, &fd);
  142. FD_ZERO(&errfd);
  143. FD_SET(sockfd, &errfd);
  144. interval.tv_sec = timeout_msec/1000;
  145. timeout_msec -= interval.tv_sec*1000;
  146. interval.tv_usec = timeout_msec*1000;
  147. rc = select(sockfd+1, NULL, &fd, &errfd, &interval);
  148. if(-1 == rc)
  149. /* error, no connect here, try next */
  150. return -1;
  151. else if(0 == rc)
  152. /* timeout, no connect today */
  153. return 1;
  154. if(FD_ISSET(sockfd, &errfd)) {
  155. /* error condition caught */
  156. return 2;
  157. }
  158. /* we have a connect! */
  159. return 0;
  160. }
  161. #ifndef ENABLE_IPV6
  162. static CURLcode bindlocal(struct connectdata *conn,
  163. int sockfd)
  164. {
  165. #if !defined(WIN32)||defined(__CYGWIN32__)
  166. /* We don't generally like checking for OS-versions, we should make this
  167. HAVE_XXXX based, although at the moment I don't have a decent test for
  168. this! */
  169. #ifdef HAVE_INET_NTOA
  170. #ifndef INADDR_NONE
  171. #define INADDR_NONE (in_addr_t) ~0
  172. #endif
  173. struct SessionHandle *data = conn->data;
  174. /*************************************************************
  175. * Select device to bind socket to
  176. *************************************************************/
  177. if (strlen(data->set.device)<255) {
  178. struct sockaddr_in sa;
  179. struct hostent *h=NULL;
  180. char *hostdataptr=NULL;
  181. size_t size;
  182. char myhost[256] = "";
  183. in_addr_t in;
  184. if(Curl_if2ip(data->set.device, myhost, sizeof(myhost))) {
  185. h = Curl_resolv(data, myhost, 0, &hostdataptr);
  186. }
  187. else {
  188. if(strlen(data->set.device)>1) {
  189. h = Curl_resolv(data, data->set.device, 0, &hostdataptr);
  190. }
  191. if(h) {
  192. /* we know data->set.device is shorter than the myhost array */
  193. strcpy(myhost, data->set.device);
  194. }
  195. }
  196. if(! *myhost) {
  197. /* need to fix this
  198. h=Curl_gethost(data,
  199. getmyhost(*myhost,sizeof(myhost)),
  200. hostent_buf,
  201. sizeof(hostent_buf));
  202. */
  203. return CURLE_HTTP_PORT_FAILED;
  204. }
  205. infof(data, "We bind local end to %s\n", myhost);
  206. in=inet_addr(myhost);
  207. if (INADDR_NONE != in) {
  208. if ( h ) {
  209. memset((char *)&sa, 0, sizeof(sa));
  210. memcpy((char *)&sa.sin_addr,
  211. h->h_addr,
  212. h->h_length);
  213. sa.sin_family = AF_INET;
  214. sa.sin_addr.s_addr = in;
  215. sa.sin_port = 0; /* get any port */
  216. if( bind(sockfd, (struct sockaddr *)&sa, sizeof(sa)) >= 0) {
  217. /* we succeeded to bind */
  218. struct sockaddr_in add;
  219. size = sizeof(add);
  220. if(getsockname(sockfd, (struct sockaddr *) &add,
  221. (socklen_t *)&size)<0) {
  222. failf(data, "getsockname() failed");
  223. return CURLE_HTTP_PORT_FAILED;
  224. }
  225. }
  226. else {
  227. switch(errno) {
  228. case EBADF:
  229. failf(data, "Invalid descriptor: %d", errno);
  230. break;
  231. case EINVAL:
  232. failf(data, "Invalid request: %d", errno);
  233. break;
  234. case EACCES:
  235. failf(data, "Address is protected, user not superuser: %d", errno);
  236. break;
  237. case ENOTSOCK:
  238. failf(data,
  239. "Argument is a descriptor for a file, not a socket: %d",
  240. errno);
  241. break;
  242. case EFAULT:
  243. failf(data, "Inaccessable memory error: %d", errno);
  244. break;
  245. case ENAMETOOLONG:
  246. failf(data, "Address too long: %d", errno);
  247. break;
  248. case ENOMEM:
  249. failf(data, "Insufficient kernel memory was available: %d", errno);
  250. break;
  251. default:
  252. failf(data, "errno %d", errno);
  253. break;
  254. } /* end of switch(errno) */
  255. return CURLE_HTTP_PORT_FAILED;
  256. } /* end of else */
  257. } /* end of if h */
  258. else {
  259. failf(data,"could't find my own IP address (%s)", myhost);
  260. return CURLE_HTTP_PORT_FAILED;
  261. }
  262. } /* end of inet_addr */
  263. else {
  264. failf(data, "could't find my own IP address (%s)", myhost);
  265. return CURLE_HTTP_PORT_FAILED;
  266. }
  267. return CURLE_OK;
  268. } /* end of device selection support */
  269. #endif /* end of HAVE_INET_NTOA */
  270. #endif /* end of not WIN32 */
  271. return CURLE_HTTP_PORT_FAILED;
  272. }
  273. #endif /* end of ipv4-specific section */
  274. static
  275. int socketerror(int sockfd)
  276. {
  277. int err = 0;
  278. socklen_t errSize = sizeof(err);
  279. if( -1 == getsockopt(sockfd, SOL_SOCKET, SO_ERROR,
  280. (void *)&err, &errSize))
  281. err = geterrno();
  282. return err;
  283. }
  284. /*
  285. * TCP connect to the given host with timeout, proxy or remote doesn't matter.
  286. * There might be more than one IP address to try out. Fill in the passed
  287. * pointer with the connected socket.
  288. */
  289. CURLcode Curl_connecthost(struct connectdata *conn, /* context */
  290. Curl_addrinfo *remotehost, /* use one in here */
  291. int port, /* connect to this */
  292. int *sockconn, /* the connected socket */
  293. Curl_ipconnect **addr) /* the one we used */
  294. {
  295. struct SessionHandle *data = conn->data;
  296. int rc;
  297. int sockfd=-1;
  298. int aliasindex=0;
  299. struct timeval after;
  300. struct timeval before = Curl_tvnow();
  301. /*************************************************************
  302. * Figure out what maximum time we have left
  303. *************************************************************/
  304. long timeout_ms=300000; /* milliseconds, default to five minutes */
  305. if(data->set.timeout || data->set.connecttimeout) {
  306. double has_passed;
  307. /* Evaluate in milliseconds how much time that has passed */
  308. has_passed = Curl_tvdiff(Curl_tvnow(), data->progress.start);
  309. #ifndef min
  310. #define min(a, b) ((a) < (b) ? (a) : (b))
  311. #endif
  312. /* get the most strict timeout of the ones converted to milliseconds */
  313. if(data->set.timeout && data->set.connecttimeout) {
  314. if (data->set.timeout < data->set.connecttimeout)
  315. timeout_ms = data->set.timeout*1000;
  316. else
  317. timeout_ms = data->set.connecttimeout*1000;
  318. }
  319. else if(data->set.timeout)
  320. timeout_ms = data->set.timeout*1000;
  321. else
  322. timeout_ms = data->set.connecttimeout*1000;
  323. /* subtract the passed time */
  324. timeout_ms -= (long)has_passed;
  325. if(timeout_ms < 0) {
  326. /* a precaution, no need to continue if time already is up */
  327. failf(data, "Connection time-out");
  328. return CURLE_OPERATION_TIMEOUTED;
  329. }
  330. }
  331. #ifdef ENABLE_IPV6
  332. /*
  333. * Connecting with IPv6 support is so much easier and cleanly done
  334. */
  335. {
  336. struct addrinfo *ai;
  337. port =0; /* prevent compiler warning */
  338. for (ai = remotehost; ai; ai = ai->ai_next, aliasindex++) {
  339. sockfd = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
  340. if (sockfd < 0)
  341. continue;
  342. /* set socket non-blocking */
  343. Curl_nonblock(sockfd, TRUE);
  344. rc = connect(sockfd, ai->ai_addr, ai->ai_addrlen);
  345. if(-1 == rc) {
  346. int error=geterrno();
  347. switch (error) {
  348. case EINPROGRESS:
  349. case EWOULDBLOCK:
  350. #if defined(EAGAIN) && EAGAIN != EWOULDBLOCK
  351. /* On some platforms EAGAIN and EWOULDBLOCK are the
  352. * same value, and on others they are different, hence
  353. * the odd #if
  354. */
  355. case EAGAIN:
  356. #endif
  357. case EINTR:
  358. /* asynchronous connect, wait for connect or timeout */
  359. rc = waitconnect(sockfd, timeout_ms);
  360. break;
  361. case ECONNREFUSED: /* no one listening */
  362. default:
  363. /* unknown error, fallthrough and try another address! */
  364. failf(data, "Failed to connect");
  365. break;
  366. }
  367. }
  368. if(0 == rc) {
  369. /* we might be connected, if the socket says it is OK! Ask it! */
  370. int err;
  371. err = socketerror(sockfd);
  372. if ((0 == err) || (EISCONN == err)) {
  373. /* we are connected, awesome! */
  374. break;
  375. }
  376. /* we are _not_ connected, it was a false alert, continue please */
  377. }
  378. /* connect failed or timed out */
  379. sclose(sockfd);
  380. sockfd = -1;
  381. /* get a new timeout for next attempt */
  382. after = Curl_tvnow();
  383. timeout_ms -= Curl_tvdiff(after, before);
  384. if(timeout_ms < 0) {
  385. failf(data, "connect() timed out!");
  386. return CURLE_OPERATION_TIMEOUTED;
  387. }
  388. before = after;
  389. continue;
  390. }
  391. if (sockfd < 0) {
  392. failf(data, "connect() failed");
  393. return CURLE_COULDNT_CONNECT;
  394. }
  395. /* leave the socket in non-blocking mode */
  396. if(addr)
  397. *addr = ai; /* the address we ended up connected to */
  398. }
  399. #else
  400. /*
  401. * Connecting with IPv4-only support
  402. */
  403. if(!remotehost->h_addr_list[0]) {
  404. /* If there is no addresses in the address list, then we return
  405. error right away */
  406. failf(data, "no address available");
  407. return CURLE_COULDNT_CONNECT;
  408. }
  409. /* create an IPv4 TCP socket */
  410. sockfd = socket(AF_INET, SOCK_STREAM, 0);
  411. if(-1 == sockfd) {
  412. failf(data, "couldn't create socket");
  413. return CURLE_COULDNT_CONNECT; /* big time error */
  414. }
  415. if(conn->data->set.device) {
  416. /* user selected to bind the outgoing socket to a specified "device"
  417. before doing connect */
  418. CURLcode res = bindlocal(conn, sockfd);
  419. if(res)
  420. return res;
  421. }
  422. /* Convert socket to non-blocking type */
  423. Curl_nonblock(sockfd, TRUE);
  424. /* This is the loop that attempts to connect to all IP-addresses we
  425. know for the given host. One by one. */
  426. for(rc=-1, aliasindex=0;
  427. rc && (struct in_addr *)remotehost->h_addr_list[aliasindex];
  428. aliasindex++) {
  429. struct sockaddr_in serv_addr;
  430. /* do this nasty work to do the connect */
  431. memset((char *) &serv_addr, '\0', sizeof(serv_addr));
  432. memcpy((char *)&(serv_addr.sin_addr),
  433. (struct in_addr *)remotehost->h_addr_list[aliasindex],
  434. sizeof(struct in_addr));
  435. serv_addr.sin_family = remotehost->h_addrtype;
  436. serv_addr.sin_port = htons(port);
  437. rc = connect(sockfd, (struct sockaddr *)&serv_addr,
  438. sizeof(serv_addr));
  439. if(-1 == rc) {
  440. int error=geterrno();
  441. switch (error) {
  442. case EINPROGRESS:
  443. case EWOULDBLOCK:
  444. #if defined(EAGAIN) && EAGAIN != EWOULDBLOCK
  445. /* On some platforms EAGAIN and EWOULDBLOCK are the
  446. * same value, and on others they are different, hence
  447. * the odd #if
  448. */
  449. case EAGAIN:
  450. #endif
  451. /* asynchronous connect, wait for connect or timeout */
  452. rc = waitconnect(sockfd, timeout_ms);
  453. break;
  454. default:
  455. /* unknown error, fallthrough and try another address! */
  456. failf(data, "Failed to connect to IP number %d", aliasindex+1);
  457. break;
  458. }
  459. }
  460. if(0 == rc) {
  461. int err = socketerror(sockfd);
  462. if ((0 == err) || (EISCONN == err)) {
  463. /* we are connected, awesome! */
  464. break;
  465. }
  466. /* nope, not connected for real */
  467. rc = -1;
  468. }
  469. if(0 != rc) {
  470. /* get a new timeout for next attempt */
  471. after = Curl_tvnow();
  472. timeout_ms -= Curl_tvdiff(after, before);
  473. if(timeout_ms < 0) {
  474. failf(data, "Connect timeout on IP number %d", aliasindex+1);
  475. break;
  476. }
  477. before = after;
  478. continue; /* try next address */
  479. }
  480. break;
  481. }
  482. if(0 != rc) {
  483. /* no good connect was made */
  484. sclose(sockfd);
  485. *sockconn = -1;
  486. failf(data, "Couldn't connect to host");
  487. return CURLE_COULDNT_CONNECT;
  488. }
  489. /* leave the socket in non-blocking mode */
  490. if(addr)
  491. /* this is the address we've connected to */
  492. *addr = (struct in_addr *)remotehost->h_addr_list[aliasindex];
  493. #endif
  494. /* allow NULL-pointers to get passed in */
  495. if(sockconn)
  496. *sockconn = sockfd; /* the socket descriptor we've connected */
  497. return CURLE_OK;
  498. }