connect.c 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788
  1. /***************************************************************************
  2. * _ _ ____ _
  3. * Project ___| | | | _ \| |
  4. * / __| | | | |_) | |
  5. * | (__| |_| | _ <| |___
  6. * \___|\___/|_| \_\_____|
  7. *
  8. * Copyright (C) 1998 - 2004, Daniel Stenberg, <[email protected]>, et al.
  9. *
  10. * This software is licensed as described in the file COPYING, which
  11. * you should have received as part of this distribution. The terms
  12. * are also available at http://curl.haxx.se/docs/copyright.html.
  13. *
  14. * You may opt to use, copy, modify, merge, publish, distribute and/or sell
  15. * copies of the Software, and permit persons to whom the Software is
  16. * furnished to do so, under the terms of the COPYING file.
  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. #ifdef HAVE_SYS_TYPES_H
  28. #include <sys/types.h>
  29. #endif
  30. #ifdef HAVE_SYS_SOCKET_H
  31. #include <sys/socket.h>
  32. #endif
  33. #ifdef HAVE_NETINET_IN_H
  34. #include <netinet/in.h> /* <netinet/tcp.h> may need it */
  35. #endif
  36. #ifdef HAVE_NETINET_TCP_H
  37. #include <netinet/tcp.h> /* for TCP_NODELAY */
  38. #endif
  39. #ifdef HAVE_SYS_IOCTL_H
  40. #include <sys/ioctl.h>
  41. #endif
  42. #ifdef HAVE_UNISTD_H
  43. #include <unistd.h>
  44. #endif
  45. #ifdef HAVE_NETDB_H
  46. #include <netdb.h>
  47. #endif
  48. #ifdef HAVE_FCNTL_H
  49. #include <fcntl.h>
  50. #endif
  51. #ifdef HAVE_NETINET_IN_H
  52. #include <netinet/in.h>
  53. #endif
  54. #ifdef HAVE_ARPA_INET_H
  55. #include <arpa/inet.h>
  56. #endif
  57. #ifdef HAVE_STDLIB_H
  58. #include <stdlib.h> /* required for free() prototype, without it, this crashes
  59. on macos 68K */
  60. #endif
  61. #if (defined(HAVE_FIONBIO) && defined(__NOVELL_LIBC__))
  62. #include <sys/filio.h>
  63. #endif
  64. #if (defined(NETWARE) && defined(__NOVELL_LIBC__))
  65. #undef in_addr_t
  66. #define in_addr_t unsigned long
  67. #endif
  68. #ifdef VMS
  69. #include <in.h>
  70. #include <inet.h>
  71. #endif
  72. #endif
  73. #include <stdio.h>
  74. #include <errno.h>
  75. #include <string.h>
  76. #ifndef TRUE
  77. #define TRUE 1
  78. #define FALSE 0
  79. #endif
  80. #ifdef WIN32
  81. #include <windows.h>
  82. #define EINPROGRESS WSAEINPROGRESS
  83. #define EWOULDBLOCK WSAEWOULDBLOCK
  84. #define EISCONN WSAEISCONN
  85. #define ENOTSOCK WSAENOTSOCK
  86. #define ECONNREFUSED WSAECONNREFUSED
  87. #endif
  88. #include "urldata.h"
  89. #include "sendf.h"
  90. #include "if2ip.h"
  91. #include "strerror.h"
  92. #include "connect.h"
  93. #include "curl_memory.h"
  94. /* The last #include file should be: */
  95. #include "memdebug.h"
  96. static bool verifyconnect(curl_socket_t sockfd, int *error);
  97. static curl_socket_t
  98. singleipconnect(struct connectdata *conn,
  99. Curl_addrinfo *ai, /* start connecting to this */
  100. long timeout_ms,
  101. bool *connected);
  102. /*
  103. * Curl_ourerrno() returns the errno (or equivalent) on this platform to
  104. * hide platform specific for the function that calls this.
  105. */
  106. int Curl_ourerrno(void)
  107. {
  108. #ifdef WIN32
  109. return (int)GetLastError();
  110. #else
  111. return errno;
  112. #endif
  113. }
  114. /*
  115. * Curl_nonblock() set the given socket to either blocking or non-blocking
  116. * mode based on the 'nonblock' boolean argument. This function is highly
  117. * portable.
  118. */
  119. int Curl_nonblock(curl_socket_t sockfd, /* operate on this */
  120. int nonblock /* TRUE or FALSE */)
  121. {
  122. #undef SETBLOCK
  123. #ifdef HAVE_O_NONBLOCK
  124. {
  125. /* most recent unix versions */
  126. int flags;
  127. flags = fcntl(sockfd, F_GETFL, 0);
  128. if (TRUE == nonblock)
  129. return fcntl(sockfd, F_SETFL, flags | O_NONBLOCK);
  130. else
  131. return fcntl(sockfd, F_SETFL, flags & (~O_NONBLOCK));
  132. }
  133. #define SETBLOCK 1
  134. #endif
  135. #ifdef HAVE_FIONBIO
  136. {
  137. /* older unix versions */
  138. int flags;
  139. flags = nonblock;
  140. return ioctl(sockfd, FIONBIO, &flags);
  141. }
  142. #ifdef SETBLOCK
  143. # undef SETBLOCK
  144. #endif
  145. #define SETBLOCK 2
  146. #endif
  147. #ifdef HAVE_IOCTLSOCKET
  148. /* Windows? */
  149. unsigned long flags;
  150. flags = nonblock;
  151. return ioctlsocket(sockfd, FIONBIO, &flags);
  152. #define SETBLOCK 3
  153. #endif
  154. #ifdef HAVE_IOCTLSOCKET_CASE
  155. /* presumably for Amiga */
  156. return IoctlSocket(sockfd, FIONBIO, (long)nonblock);
  157. #ifdef SETBLOCK
  158. # undef SETBLOCK
  159. #endif
  160. #define SETBLOCK 4
  161. #endif
  162. #ifdef HAVE_SO_NONBLOCK
  163. /* BeOS */
  164. long b = nonblock ? 1 : 0;
  165. return setsockopt(sockfd, SOL_SOCKET, SO_NONBLOCK, &b, sizeof(b));
  166. #ifdef SETBLOCK
  167. # undef SETBLOCK
  168. #endif
  169. #define SETBLOCK 5
  170. #endif
  171. #ifdef HAVE_DISABLED_NONBLOCKING
  172. (void)nonblock;
  173. (void)sockfd;
  174. return 0; /* returns success */
  175. #ifdef SETBLOCK
  176. # undef SETBLOCK
  177. #endif
  178. #define SETBLOCK 6
  179. #endif
  180. #ifndef SETBLOCK
  181. #error "no non-blocking method was found/used/set"
  182. #endif
  183. }
  184. /*
  185. * waitconnect() waits for a TCP connect on the given socket for the specified
  186. * number if milliseconds. It returns:
  187. * 0 fine connect
  188. * -1 select() error
  189. * 1 select() timeout
  190. * 2 select() returned with an error condition fd_set
  191. */
  192. #define WAITCONN_CONNECTED 0
  193. #define WAITCONN_SELECT_ERROR -1
  194. #define WAITCONN_TIMEOUT 1
  195. #define WAITCONN_FDSET_ERROR 2
  196. static
  197. int waitconnect(curl_socket_t sockfd, /* socket */
  198. long timeout_msec)
  199. {
  200. fd_set fd;
  201. fd_set errfd;
  202. struct timeval interval;
  203. int rc;
  204. #ifdef mpeix
  205. /* Call this function once now, and ignore the results. We do this to
  206. "clear" the error state on the socket so that we can later read it
  207. reliably. This is reported necessary on the MPE/iX operating system. */
  208. verifyconnect(sockfd, NULL);
  209. #endif
  210. /* now select() until we get connect or timeout */
  211. FD_ZERO(&fd);
  212. FD_SET(sockfd, &fd);
  213. FD_ZERO(&errfd);
  214. FD_SET(sockfd, &errfd);
  215. interval.tv_sec = (int)(timeout_msec/1000);
  216. timeout_msec -= interval.tv_sec*1000;
  217. interval.tv_usec = timeout_msec*1000;
  218. rc = select(sockfd+1, NULL, &fd, &errfd, &interval);
  219. if(-1 == rc)
  220. /* error, no connect here, try next */
  221. return WAITCONN_SELECT_ERROR;
  222. else if(0 == rc)
  223. /* timeout, no connect today */
  224. return WAITCONN_TIMEOUT;
  225. if(FD_ISSET(sockfd, &errfd))
  226. /* error condition caught */
  227. return WAITCONN_FDSET_ERROR;
  228. /* we have a connect! */
  229. return WAITCONN_CONNECTED;
  230. }
  231. static CURLcode bindlocal(struct connectdata *conn,
  232. curl_socket_t sockfd)
  233. {
  234. #ifdef HAVE_INET_NTOA
  235. bool bindworked = FALSE;
  236. struct SessionHandle *data = conn->data;
  237. /*************************************************************
  238. * Select device to bind socket to
  239. *************************************************************/
  240. if (strlen(data->set.device)<255) {
  241. struct Curl_dns_entry *h=NULL;
  242. char myhost[256] = "";
  243. in_addr_t in;
  244. int rc;
  245. bool was_iface = FALSE;
  246. /* First check if the given name is an IP address */
  247. in=inet_addr(data->set.device);
  248. if((in == CURL_INADDR_NONE) &&
  249. Curl_if2ip(data->set.device, myhost, sizeof(myhost))) {
  250. /*
  251. * We now have the numerical IPv4-style x.y.z.w in the 'myhost' buffer
  252. */
  253. rc = Curl_resolv(conn, myhost, 0, &h);
  254. if(rc == CURLRESOLV_PENDING)
  255. (void)Curl_wait_for_resolv(conn, &h);
  256. if(h)
  257. was_iface = TRUE;
  258. }
  259. if(!was_iface) {
  260. /*
  261. * This was not an interface, resolve the name as a host name
  262. * or IP number
  263. */
  264. rc = Curl_resolv(conn, data->set.device, 0, &h);
  265. if(rc == CURLRESOLV_PENDING)
  266. (void)Curl_wait_for_resolv(conn, &h);
  267. if(h)
  268. /* we know data->set.device is shorter than the myhost array */
  269. strcpy(myhost, data->set.device);
  270. }
  271. if(! *myhost) {
  272. /* need to fix this
  273. h=Curl_gethost(data,
  274. getmyhost(*myhost,sizeof(myhost)),
  275. hostent_buf,
  276. sizeof(hostent_buf));
  277. */
  278. failf(data, "Couldn't bind to '%s'", data->set.device);
  279. return CURLE_HTTP_PORT_FAILED;
  280. }
  281. infof(data, "We bind local end to %s\n", myhost);
  282. #ifdef SO_BINDTODEVICE
  283. /* I am not sure any other OSs than Linux that provide this feature, and
  284. * at the least I cannot test. --Ben
  285. *
  286. * This feature allows one to tightly bind the local socket to a
  287. * particular interface. This will force even requests to other local
  288. * interfaces to go out the external interface.
  289. *
  290. */
  291. if (was_iface) {
  292. /* Only bind to the interface when specified as interface, not just as a
  293. * hostname or ip address.
  294. */
  295. if (setsockopt(sockfd, SOL_SOCKET, SO_BINDTODEVICE,
  296. data->set.device, strlen(data->set.device)+1) != 0) {
  297. /* printf("Failed to BINDTODEVICE, socket: %d device: %s error: %s\n",
  298. sockfd, data->set.device, Curl_strerror(Curl_ourerrno())); */
  299. infof(data, "SO_BINDTODEVICE %s failed\n",
  300. data->set.device);
  301. /* This is typically "errno 1, error: Operation not permitted" if
  302. you're not running as root or another suitable privileged user */
  303. }
  304. }
  305. #endif
  306. in=inet_addr(myhost);
  307. if (CURL_INADDR_NONE != in) {
  308. if ( h ) {
  309. Curl_addrinfo *addr = h->addr;
  310. Curl_resolv_unlock(data, h);
  311. /* we don't need it anymore after this function has returned */
  312. if( bind(sockfd, addr->ai_addr, (socklen_t)addr->ai_addrlen) >= 0) {
  313. /* we succeeded to bind */
  314. #ifdef ENABLE_IPV6
  315. struct sockaddr_in6 add;
  316. #else
  317. struct sockaddr_in add;
  318. #endif
  319. #ifdef __hpux
  320. int gsize = sizeof(add);
  321. #else
  322. socklen_t gsize = sizeof(add);
  323. #endif
  324. bindworked = TRUE;
  325. if(getsockname(sockfd, (struct sockaddr *) &add,
  326. &gsize)<0) {
  327. failf(data, "getsockname() failed");
  328. return CURLE_HTTP_PORT_FAILED;
  329. }
  330. }
  331. if(!bindworked) {
  332. failf(data, "%s", Curl_strerror(conn, Curl_ourerrno()));
  333. return CURLE_HTTP_PORT_FAILED;
  334. }
  335. } /* end of if h */
  336. else {
  337. failf(data,"could't find my own IP address (%s)", myhost);
  338. return CURLE_HTTP_PORT_FAILED;
  339. }
  340. } /* end of inet_addr */
  341. else {
  342. failf(data, "could't find my own IP address (%s)", myhost);
  343. return CURLE_HTTP_PORT_FAILED;
  344. }
  345. return CURLE_OK;
  346. } /* end of device selection support */
  347. #endif /* end of HAVE_INET_NTOA */
  348. return CURLE_HTTP_PORT_FAILED;
  349. }
  350. /*
  351. * verifyconnect() returns TRUE if the connect really has happened.
  352. */
  353. static bool verifyconnect(curl_socket_t sockfd, int *error)
  354. {
  355. bool rc;
  356. #ifdef SO_ERROR
  357. int err = 0;
  358. #ifdef __hpux
  359. int errSize = sizeof(err);
  360. #else
  361. socklen_t errSize = sizeof(err);
  362. #endif
  363. #ifdef WIN32
  364. /*
  365. * In October 2003 we effectively nullified this function on Windows due to
  366. * problems with it using all CPU in multi-threaded cases.
  367. *
  368. * In May 2004, we bring it back to offer more info back on connect failures.
  369. * Gisle Vanem could reproduce the former problems with this function, but
  370. * could avoid them by adding this SleepEx() call below:
  371. *
  372. * "I don't have Rational Quantify, but the hint from his post was
  373. * ntdll::NtRemoveIoCompletion(). So I'd assume the SleepEx (or maybe
  374. * just Sleep(0) would be enough?) would release whatever
  375. * mutex/critical-section the ntdll call is waiting on.
  376. *
  377. * Someone got to verify this on Win-NT 4.0, 2000."
  378. */
  379. SleepEx(0, FALSE);
  380. #endif
  381. if( -1 == getsockopt(sockfd, SOL_SOCKET, SO_ERROR,
  382. (void *)&err, &errSize))
  383. err = Curl_ourerrno();
  384. if ((0 == err) || (EISCONN == err))
  385. /* we are connected, awesome! */
  386. rc = TRUE;
  387. else
  388. /* This wasn't a successful connect */
  389. rc = FALSE;
  390. if (error)
  391. *error = err;
  392. #else
  393. (void)sockfd;
  394. if (error)
  395. *error = Curl_ourerrno();
  396. #endif
  397. return rc;
  398. }
  399. /* Used within the multi interface. Try next IP address, return TRUE if no
  400. more address exists */
  401. static bool trynextip(struct connectdata *conn,
  402. int sockindex,
  403. bool *connected)
  404. {
  405. curl_socket_t sockfd;
  406. Curl_addrinfo *ai;
  407. if(sockindex != FIRSTSOCKET)
  408. return TRUE; /* no next */
  409. /* try the next address */
  410. ai = conn->ip_addr->ai_next;
  411. while (ai) {
  412. sockfd = singleipconnect(conn, ai, 0L, connected);
  413. if(sockfd != CURL_SOCKET_BAD) {
  414. /* store the new socket descriptor */
  415. conn->sock[sockindex] = sockfd;
  416. conn->ip_addr = ai;
  417. return FALSE;
  418. }
  419. ai = ai->ai_next;
  420. }
  421. return TRUE;
  422. }
  423. /*
  424. * Curl_is_connected() is used from the multi interface to check if the
  425. * firstsocket has connected.
  426. */
  427. CURLcode Curl_is_connected(struct connectdata *conn,
  428. int sockindex,
  429. bool *connected)
  430. {
  431. int rc;
  432. struct SessionHandle *data = conn->data;
  433. CURLcode code = CURLE_OK;
  434. curl_socket_t sockfd = conn->sock[sockindex];
  435. long allow = DEFAULT_CONNECT_TIMEOUT;
  436. long has_passed;
  437. curlassert(sockindex >= FIRSTSOCKET && sockindex <= SECONDARYSOCKET);
  438. *connected = FALSE; /* a very negative world view is best */
  439. /* Evaluate in milliseconds how much time that has passed */
  440. has_passed = Curl_tvdiff(Curl_tvnow(), data->progress.start);
  441. /* subtract the most strict timeout of the ones */
  442. if(data->set.timeout && data->set.connecttimeout) {
  443. if (data->set.timeout < data->set.connecttimeout)
  444. allow = data->set.timeout*1000;
  445. else
  446. allow = data->set.connecttimeout*1000;
  447. }
  448. else if(data->set.timeout) {
  449. allow = data->set.timeout*1000;
  450. }
  451. else if(data->set.connecttimeout) {
  452. allow = data->set.connecttimeout*1000;
  453. }
  454. if(has_passed > allow ) {
  455. /* time-out, bail out, go home */
  456. failf(data, "Connection time-out after %ld ms", has_passed);
  457. return CURLE_OPERATION_TIMEOUTED;
  458. }
  459. if(conn->bits.tcpconnect) {
  460. /* we are connected already! */
  461. *connected = TRUE;
  462. return CURLE_OK;
  463. }
  464. /* check for connect without timeout as we want to return immediately */
  465. rc = waitconnect(sockfd, 0);
  466. if(WAITCONN_CONNECTED == rc) {
  467. if (verifyconnect(sockfd, NULL)) {
  468. /* we are connected, awesome! */
  469. *connected = TRUE;
  470. return CURLE_OK;
  471. }
  472. /* nope, not connected for real */
  473. infof(data, "Connection failed\n");
  474. if(trynextip(conn, sockindex, connected)) {
  475. code = CURLE_COULDNT_CONNECT;
  476. }
  477. }
  478. else if(WAITCONN_TIMEOUT != rc) {
  479. /* nope, not connected */
  480. infof(data, "Connection failed\n");
  481. if(trynextip(conn, sockindex, connected)) {
  482. int error = Curl_ourerrno();
  483. failf(data, "Failed connect to %s:%d; %s",
  484. conn->host.name, conn->port, Curl_strerror(conn,error));
  485. code = CURLE_COULDNT_CONNECT;
  486. }
  487. }
  488. /*
  489. * If the connection failed here, we should attempt to connect to the "next
  490. * address" for the given host.
  491. */
  492. return code;
  493. }
  494. static void tcpnodelay(struct connectdata *conn,
  495. curl_socket_t sockfd)
  496. {
  497. #ifdef TCP_NODELAY
  498. struct SessionHandle *data= conn->data;
  499. socklen_t onoff = (socklen_t) data->set.tcp_nodelay;
  500. if(setsockopt(sockfd, IPPROTO_TCP, TCP_NODELAY, (void *)&onoff,
  501. sizeof(onoff)) < 0)
  502. infof(data, "Could not set TCP_NODELAY: %s\n",
  503. Curl_strerror(conn, Curl_ourerrno()));
  504. else
  505. infof(data,"TCP_NODELAY set\n");
  506. #else
  507. (void)conn;
  508. (void)sockfd;
  509. #endif
  510. }
  511. /* singleipconnect() connects to the given IP only, and it may return without
  512. having connected if used from the multi interface. */
  513. static curl_socket_t
  514. singleipconnect(struct connectdata *conn,
  515. Curl_addrinfo *ai,
  516. long timeout_ms,
  517. bool *connected)
  518. {
  519. char addr_buf[128];
  520. int rc;
  521. int error;
  522. bool conected;
  523. struct SessionHandle *data = conn->data;
  524. curl_socket_t sockfd = socket(ai->ai_family, ai->ai_socktype,
  525. ai->ai_protocol);
  526. if (sockfd == CURL_SOCKET_BAD)
  527. return CURL_SOCKET_BAD;
  528. *connected = FALSE; /* default is not connected */
  529. Curl_printable_address(ai, addr_buf, sizeof(addr_buf));
  530. infof(data, " Trying %s... ", addr_buf);
  531. if(data->set.tcp_nodelay)
  532. tcpnodelay(conn, sockfd);
  533. if(conn->data->set.device) {
  534. /* user selected to bind the outgoing socket to a specified "device"
  535. before doing connect */
  536. CURLcode res = bindlocal(conn, sockfd);
  537. if(res)
  538. return res;
  539. }
  540. /* set socket non-blocking */
  541. Curl_nonblock(sockfd, TRUE);
  542. rc = connect(sockfd, ai->ai_addr, ai->ai_addrlen);
  543. if(-1 == rc) {
  544. error = Curl_ourerrno();
  545. switch (error) {
  546. case EINPROGRESS:
  547. case EWOULDBLOCK:
  548. #if defined(EAGAIN) && EAGAIN != EWOULDBLOCK
  549. /* On some platforms EAGAIN and EWOULDBLOCK are the
  550. * same value, and on others they are different, hence
  551. * the odd #if
  552. */
  553. case EAGAIN:
  554. #endif
  555. rc = waitconnect(sockfd, timeout_ms);
  556. break;
  557. default:
  558. /* unknown error, fallthrough and try another address! */
  559. failf(data, "Failed to connect to %s: %s",
  560. addr_buf, Curl_strerror(conn,error));
  561. break;
  562. }
  563. }
  564. /* The 'WAITCONN_TIMEOUT == rc' comes from the waitconnect(), and not from
  565. connect(). We can be sure of this since connect() cannot return 1. */
  566. if((WAITCONN_TIMEOUT == rc) &&
  567. (data->state.used_interface == Curl_if_multi)) {
  568. /* Timeout when running the multi interface */
  569. return sockfd;
  570. }
  571. conected = verifyconnect(sockfd, &error);
  572. if(!rc && conected) {
  573. /* we are connected, awesome! */
  574. *connected = TRUE; /* this is a true connect */
  575. infof(data, "connected\n");
  576. return sockfd;
  577. }
  578. else if(WAITCONN_TIMEOUT == rc)
  579. infof(data, "Timeout\n");
  580. else
  581. infof(data, "%s\n", Curl_strerror(conn, error));
  582. /* connect failed or timed out */
  583. sclose(sockfd);
  584. return CURL_SOCKET_BAD;
  585. }
  586. /*
  587. * TCP connect to the given host with timeout, proxy or remote doesn't matter.
  588. * There might be more than one IP address to try out. Fill in the passed
  589. * pointer with the connected socket.
  590. */
  591. CURLcode Curl_connecthost(struct connectdata *conn, /* context */
  592. struct Curl_dns_entry *remotehost, /* use this one */
  593. curl_socket_t *sockconn, /* the connected socket */
  594. Curl_addrinfo **addr, /* the one we used */
  595. bool *connected) /* really connected? */
  596. {
  597. struct SessionHandle *data = conn->data;
  598. curl_socket_t sockfd = CURL_SOCKET_BAD;
  599. int aliasindex;
  600. int num_addr;
  601. Curl_addrinfo *ai;
  602. Curl_addrinfo *curr_addr;
  603. struct timeval after;
  604. struct timeval before = Curl_tvnow();
  605. /*************************************************************
  606. * Figure out what maximum time we have left
  607. *************************************************************/
  608. long timeout_ms= DEFAULT_CONNECT_TIMEOUT;
  609. long timeout_per_addr;
  610. *connected = FALSE; /* default to not connected */
  611. if(data->set.timeout || data->set.connecttimeout) {
  612. long has_passed;
  613. /* Evaluate in milliseconds how much time that has passed */
  614. has_passed = Curl_tvdiff(Curl_tvnow(), data->progress.start);
  615. #ifndef min
  616. #define min(a, b) ((a) < (b) ? (a) : (b))
  617. #endif
  618. /* get the most strict timeout of the ones converted to milliseconds */
  619. if(data->set.timeout && data->set.connecttimeout) {
  620. if (data->set.timeout < data->set.connecttimeout)
  621. timeout_ms = data->set.timeout*1000;
  622. else
  623. timeout_ms = data->set.connecttimeout*1000;
  624. }
  625. else if(data->set.timeout)
  626. timeout_ms = data->set.timeout*1000;
  627. else
  628. timeout_ms = data->set.connecttimeout*1000;
  629. /* subtract the passed time */
  630. timeout_ms -= has_passed;
  631. if(timeout_ms < 0) {
  632. /* a precaution, no need to continue if time already is up */
  633. failf(data, "Connection time-out");
  634. return CURLE_OPERATION_TIMEOUTED;
  635. }
  636. }
  637. /* Max time for each address */
  638. num_addr = Curl_num_addresses(remotehost->addr);
  639. timeout_per_addr = timeout_ms / num_addr;
  640. ai = remotehost->addr;
  641. /* Below is the loop that attempts to connect to all IP-addresses we
  642. * know for the given host. One by one until one IP succeeds.
  643. */
  644. if(data->state.used_interface == Curl_if_multi)
  645. /* don't hang when doing multi */
  646. timeout_per_addr = timeout_ms = 0;
  647. /*
  648. * Connecting with a Curl_addrinfo chain
  649. */
  650. for (curr_addr = ai, aliasindex=0; curr_addr;
  651. curr_addr = curr_addr->ai_next, aliasindex++) {
  652. /* start connecting to the IP curr_addr points to */
  653. sockfd = singleipconnect(conn, curr_addr, timeout_per_addr, connected);
  654. if(sockfd != CURL_SOCKET_BAD)
  655. break;
  656. /* get a new timeout for next attempt */
  657. after = Curl_tvnow();
  658. timeout_ms -= Curl_tvdiff(after, before);
  659. if(timeout_ms < 0) {
  660. failf(data, "connect() timed out!");
  661. return CURLE_OPERATION_TIMEOUTED;
  662. }
  663. before = after;
  664. } /* end of connect-to-each-address loop */
  665. if (sockfd == CURL_SOCKET_BAD) {
  666. /* no good connect was made */
  667. *sockconn = CURL_SOCKET_BAD;
  668. return CURLE_COULDNT_CONNECT;
  669. }
  670. /* leave the socket in non-blocking mode */
  671. /* store the address we use */
  672. if(addr)
  673. *addr = curr_addr;
  674. /* allow NULL-pointers to get passed in */
  675. if(sockconn)
  676. *sockconn = sockfd; /* the socket descriptor we've connected */
  677. return CURLE_OK;
  678. }