connect.c 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707
  1. /***************************************************************************
  2. * _ _ ____ _
  3. * Project ___| | | | _ \| |
  4. * / __| | | | |_) | |
  5. * | (__| |_| | _ <| |___
  6. * \___|\___/|_| \_\_____|
  7. *
  8. * Copyright (C) 1998 - 2002, 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. #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. /* we have a connect! */
  158. return 0;
  159. }
  160. static CURLcode bindlocal(struct connectdata *conn,
  161. int sockfd)
  162. {
  163. #if !defined(WIN32)||defined(__CYGWIN32__)
  164. /* We don't generally like checking for OS-versions, we should make this
  165. HAVE_XXXX based, although at the moment I don't have a decent test for
  166. this! */
  167. #ifdef HAVE_INET_NTOA
  168. #ifndef INADDR_NONE
  169. #define INADDR_NONE (in_addr_t) ~0
  170. #endif
  171. struct SessionHandle *data = conn->data;
  172. /*************************************************************
  173. * Select device to bind socket to
  174. *************************************************************/
  175. if (strlen(data->set.device)<255) {
  176. struct sockaddr_in sa;
  177. struct Curl_dns_entry *h=NULL;
  178. size_t size;
  179. char myhost[256] = "";
  180. in_addr_t in;
  181. if(Curl_if2ip(data->set.device, myhost, sizeof(myhost))) {
  182. /*
  183. * We now have the numerical IPv4-style x.y.z.w in the 'myhost' buffer
  184. */
  185. h = Curl_resolv(data, myhost, 0);
  186. }
  187. else {
  188. if(strlen(data->set.device)>1) {
  189. /*
  190. * This was not an interface, resolve the name as a host name
  191. * or IP number
  192. */
  193. h = Curl_resolv(data, data->set.device, 0);
  194. if(h) {
  195. /* we know data->set.device is shorter than the myhost array */
  196. strcpy(myhost, data->set.device);
  197. }
  198. }
  199. }
  200. if(! *myhost) {
  201. /* need to fix this
  202. h=Curl_gethost(data,
  203. getmyhost(*myhost,sizeof(myhost)),
  204. hostent_buf,
  205. sizeof(hostent_buf));
  206. */
  207. return CURLE_HTTP_PORT_FAILED;
  208. }
  209. infof(data, "We bind local end to %s\n", myhost);
  210. in=inet_addr(myhost);
  211. if (INADDR_NONE != in) {
  212. if ( h ) {
  213. Curl_addrinfo *addr = h->addr;
  214. Curl_resolv_unlock(h);
  215. /* we don't need it anymore after this function has returned */
  216. memset((char *)&sa, 0, sizeof(sa));
  217. #ifdef ENABLE_IPV6
  218. memcpy((char *)&sa.sin_addr, addr->ai_addr, addr->ai_addrlen);
  219. sa.sin_family = addr->ai_family;
  220. #else
  221. memcpy((char *)&sa.sin_addr, addr->h_addr, addr->h_length);
  222. sa.sin_family = AF_INET;
  223. #endif
  224. sa.sin_addr.s_addr = in;
  225. sa.sin_port = 0; /* get any port */
  226. if( bind(sockfd, (struct sockaddr *)&sa, sizeof(sa)) >= 0) {
  227. /* we succeeded to bind */
  228. struct sockaddr_in add;
  229. size = sizeof(add);
  230. if(getsockname(sockfd, (struct sockaddr *) &add,
  231. (socklen_t *)&size)<0) {
  232. failf(data, "getsockname() failed");
  233. return CURLE_HTTP_PORT_FAILED;
  234. }
  235. }
  236. else {
  237. switch(errno) {
  238. case EBADF:
  239. failf(data, "Invalid descriptor: %d", errno);
  240. break;
  241. case EINVAL:
  242. failf(data, "Invalid request: %d", errno);
  243. break;
  244. case EACCES:
  245. failf(data, "Address is protected, user not superuser: %d", errno);
  246. break;
  247. case ENOTSOCK:
  248. failf(data,
  249. "Argument is a descriptor for a file, not a socket: %d",
  250. errno);
  251. break;
  252. case EFAULT:
  253. failf(data, "Inaccessable memory error: %d", errno);
  254. break;
  255. case ENAMETOOLONG:
  256. failf(data, "Address too long: %d", errno);
  257. break;
  258. case ENOMEM:
  259. failf(data, "Insufficient kernel memory was available: %d", errno);
  260. break;
  261. default:
  262. failf(data, "errno %d", errno);
  263. break;
  264. } /* end of switch(errno) */
  265. return CURLE_HTTP_PORT_FAILED;
  266. } /* end of else */
  267. } /* end of if h */
  268. else {
  269. failf(data,"could't find my own IP address (%s)", myhost);
  270. return CURLE_HTTP_PORT_FAILED;
  271. }
  272. } /* end of inet_addr */
  273. else {
  274. failf(data, "could't find my own IP address (%s)", myhost);
  275. return CURLE_HTTP_PORT_FAILED;
  276. }
  277. return CURLE_OK;
  278. } /* end of device selection support */
  279. #endif /* end of HAVE_INET_NTOA */
  280. #endif /* end of not WIN32 */
  281. return CURLE_HTTP_PORT_FAILED;
  282. }
  283. static
  284. int socketerror(int sockfd)
  285. {
  286. int err = 0;
  287. socklen_t errSize = sizeof(err);
  288. if( -1 == getsockopt(sockfd, SOL_SOCKET, SO_ERROR,
  289. (void *)&err, &errSize))
  290. err = geterrno();
  291. return err;
  292. }
  293. /*
  294. * Curl_is_connected() is used from the multi interface to check if the
  295. * firstsocket has connected.
  296. */
  297. CURLcode Curl_is_connected(struct connectdata *conn,
  298. int sockfd,
  299. bool *connected)
  300. {
  301. int rc;
  302. struct SessionHandle *data = conn->data;
  303. *connected = FALSE; /* a very negative world view is best */
  304. if(data->set.timeout || data->set.connecttimeout) {
  305. /* there is a timeout set */
  306. /* Evaluate in milliseconds how much time that has passed */
  307. long has_passed = Curl_tvdiff(Curl_tvnow(), data->progress.start);
  308. /* subtract the most strict timeout of the ones */
  309. if(data->set.timeout && data->set.connecttimeout) {
  310. if (data->set.timeout < data->set.connecttimeout)
  311. has_passed -= data->set.timeout*1000;
  312. else
  313. has_passed -= data->set.connecttimeout*1000;
  314. }
  315. else if(data->set.timeout)
  316. has_passed -= data->set.timeout*1000;
  317. else
  318. has_passed -= data->set.connecttimeout*1000;
  319. if(has_passed > 0 ) {
  320. /* time-out, bail out, go home */
  321. failf(data, "Connection time-out");
  322. return CURLE_OPERATION_TIMEOUTED;
  323. }
  324. }
  325. if(conn->bits.tcpconnect) {
  326. /* we are connected already! */
  327. *connected = TRUE;
  328. return CURLE_OK;
  329. }
  330. /* check for connect without timeout as we want to return immediately */
  331. rc = waitconnect(sockfd, 0);
  332. if(0 == rc) {
  333. int err = socketerror(sockfd);
  334. if ((0 == err) || (EISCONN == err)) {
  335. /* we are connected, awesome! */
  336. *connected = TRUE;
  337. return CURLE_OK;
  338. }
  339. /* nope, not connected for real */
  340. if(err)
  341. return CURLE_COULDNT_CONNECT;
  342. }
  343. /*
  344. * If the connection phase is "done" here, we should attempt to connect
  345. * to the "next address" in the Curl_hostaddr structure that we resolved
  346. * before. But we don't have that struct around anymore and we can't just
  347. * keep a pointer since the cache might in fact have gotten pruned by the
  348. * time we want to read this... Alas, we don't do this yet.
  349. */
  350. return CURLE_OK;
  351. }
  352. /*
  353. * TCP connect to the given host with timeout, proxy or remote doesn't matter.
  354. * There might be more than one IP address to try out. Fill in the passed
  355. * pointer with the connected socket.
  356. */
  357. CURLcode Curl_connecthost(struct connectdata *conn, /* context */
  358. struct Curl_dns_entry *remotehost, /* use this one */
  359. int port, /* connect to this */
  360. int *sockconn, /* the connected socket */
  361. Curl_ipconnect **addr, /* the one we used */
  362. bool *connected) /* really connected? */
  363. {
  364. struct SessionHandle *data = conn->data;
  365. int rc;
  366. int sockfd=-1;
  367. int aliasindex=0;
  368. char *hostname;
  369. struct timeval after;
  370. struct timeval before = Curl_tvnow();
  371. /*************************************************************
  372. * Figure out what maximum time we have left
  373. *************************************************************/
  374. long timeout_ms=300000; /* milliseconds, default to five minutes */
  375. *connected = FALSE; /* default to not connected */
  376. if(data->set.timeout || data->set.connecttimeout) {
  377. double has_passed;
  378. /* Evaluate in milliseconds how much time that has passed */
  379. has_passed = Curl_tvdiff(Curl_tvnow(), data->progress.start);
  380. #ifndef min
  381. #define min(a, b) ((a) < (b) ? (a) : (b))
  382. #endif
  383. /* get the most strict timeout of the ones converted to milliseconds */
  384. if(data->set.timeout && data->set.connecttimeout) {
  385. if (data->set.timeout < data->set.connecttimeout)
  386. timeout_ms = data->set.timeout*1000;
  387. else
  388. timeout_ms = data->set.connecttimeout*1000;
  389. }
  390. else if(data->set.timeout)
  391. timeout_ms = data->set.timeout*1000;
  392. else
  393. timeout_ms = data->set.connecttimeout*1000;
  394. /* subtract the passed time */
  395. timeout_ms -= (long)has_passed;
  396. if(timeout_ms < 0) {
  397. /* a precaution, no need to continue if time already is up */
  398. failf(data, "Connection time-out");
  399. return CURLE_OPERATION_TIMEOUTED;
  400. }
  401. }
  402. hostname = data->change.proxy?conn->proxyhost:conn->hostname;
  403. infof(data, "About to connect() to %s%s%s:%d\n",
  404. conn->bits.ipv6_ip?"[":"",
  405. hostname,
  406. conn->bits.ipv6_ip?"]":"",
  407. port);
  408. #ifdef ENABLE_IPV6
  409. /*
  410. * Connecting with IPv6 support is so much easier and cleanly done
  411. */
  412. {
  413. struct addrinfo *ai;
  414. port =0; /* prevent compiler warning */
  415. for (ai = remotehost->addr; ai; ai = ai->ai_next, aliasindex++) {
  416. sockfd = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
  417. if (sockfd < 0)
  418. continue;
  419. if(conn->data->set.device) {
  420. /* user selected to bind the outgoing socket to a specified "device"
  421. before doing connect */
  422. CURLcode res = bindlocal(conn, sockfd);
  423. if(res)
  424. return res;
  425. }
  426. /* set socket non-blocking */
  427. Curl_nonblock(sockfd, TRUE);
  428. rc = connect(sockfd, ai->ai_addr, ai->ai_addrlen);
  429. if(-1 == rc) {
  430. int error=geterrno();
  431. switch (error) {
  432. case EINPROGRESS:
  433. case EWOULDBLOCK:
  434. #if defined(EAGAIN) && EAGAIN != EWOULDBLOCK
  435. /* On some platforms EAGAIN and EWOULDBLOCK are the
  436. * same value, and on others they are different, hence
  437. * the odd #if
  438. */
  439. case EAGAIN:
  440. #endif
  441. case EINTR:
  442. /* asynchronous connect, wait for connect or timeout */
  443. if(data->state.used_interface == Curl_if_multi)
  444. /* don't hang when doing multi */
  445. timeout_ms = 0;
  446. rc = waitconnect(sockfd, timeout_ms);
  447. break;
  448. case ECONNREFUSED: /* no one listening */
  449. default:
  450. /* unknown error, fallthrough and try another address! */
  451. failf(data, "Failed connect to %s: %d", hostname, error);
  452. break;
  453. }
  454. }
  455. if(0 == rc) {
  456. /* we might be connected, if the socket says it is OK! Ask it! */
  457. int err;
  458. err = socketerror(sockfd);
  459. if ((0 == err) || (EISCONN == err)) {
  460. /* we are connected, awesome! */
  461. *connected = TRUE; /* this is truly a connect */
  462. break;
  463. }
  464. failf(data, "socket error: %d", err);
  465. /* we are _not_ connected, it was a false alert, continue please */
  466. }
  467. else if(data->state.used_interface == Curl_if_multi) {
  468. /* When running the multi interface, we bail out here */
  469. rc = 0;
  470. break;
  471. }
  472. /* connect failed or timed out */
  473. sclose(sockfd);
  474. sockfd = -1;
  475. /* get a new timeout for next attempt */
  476. after = Curl_tvnow();
  477. timeout_ms -= Curl_tvdiff(after, before);
  478. if(timeout_ms < 0) {
  479. failf(data, "connect() timed out!");
  480. return CURLE_OPERATION_TIMEOUTED;
  481. }
  482. before = after;
  483. continue;
  484. }
  485. if (sockfd < 0)
  486. return CURLE_COULDNT_CONNECT;
  487. /* leave the socket in non-blocking mode */
  488. if(addr)
  489. *addr = ai; /* the address we ended up connected to */
  490. }
  491. #else
  492. /*
  493. * Connecting with IPv4-only support
  494. */
  495. if(!remotehost->addr->h_addr_list[0]) {
  496. /* If there is no addresses in the address list, then we return
  497. error right away */
  498. failf(data, "no address available");
  499. return CURLE_COULDNT_CONNECT;
  500. }
  501. /* create an IPv4 TCP socket */
  502. sockfd = socket(AF_INET, SOCK_STREAM, 0);
  503. if(-1 == sockfd) {
  504. failf(data, "couldn't create socket");
  505. return CURLE_COULDNT_CONNECT; /* big time error */
  506. }
  507. if(conn->data->set.device) {
  508. /* user selected to bind the outgoing socket to a specified "device"
  509. before doing connect */
  510. CURLcode res = bindlocal(conn, sockfd);
  511. if(res)
  512. return res;
  513. }
  514. /* Convert socket to non-blocking type */
  515. Curl_nonblock(sockfd, TRUE);
  516. /* This is the loop that attempts to connect to all IP-addresses we
  517. know for the given host. One by one. */
  518. for(rc=-1, aliasindex=0;
  519. rc && (struct in_addr *)remotehost->addr->h_addr_list[aliasindex];
  520. aliasindex++) {
  521. struct sockaddr_in serv_addr;
  522. /* do this nasty work to do the connect */
  523. memset((char *) &serv_addr, '\0', sizeof(serv_addr));
  524. memcpy((char *)&(serv_addr.sin_addr),
  525. (struct in_addr *)remotehost->addr->h_addr_list[aliasindex],
  526. sizeof(struct in_addr));
  527. serv_addr.sin_family = remotehost->addr->h_addrtype;
  528. serv_addr.sin_port = htons((unsigned short)port);
  529. rc = connect(sockfd, (struct sockaddr *)&serv_addr,
  530. sizeof(serv_addr));
  531. if(-1 == rc) {
  532. int error=geterrno();
  533. switch (error) {
  534. case EINPROGRESS:
  535. case EWOULDBLOCK:
  536. #if defined(EAGAIN) && EAGAIN != EWOULDBLOCK
  537. /* On some platforms EAGAIN and EWOULDBLOCK are the
  538. * same value, and on others they are different, hence
  539. * the odd #if
  540. */
  541. case EAGAIN:
  542. #endif
  543. /* asynchronous connect, wait for connect or timeout */
  544. if(data->state.used_interface == Curl_if_multi)
  545. /* don't hang when doing multi */
  546. timeout_ms = 0;
  547. rc = waitconnect(sockfd, timeout_ms);
  548. break;
  549. default:
  550. /* unknown error, fallthrough and try another address! */
  551. failf(data, "Failed to connect to %s IP number %d: %d",
  552. hostname, aliasindex+1, error);
  553. break;
  554. }
  555. }
  556. /* The '1 == rc' comes from the waitconnect(), and not from connect().
  557. We can be sure of this since connect() cannot return 1. */
  558. if((1 == rc) && (data->state.used_interface == Curl_if_multi)) {
  559. /* Timeout when running the multi interface, we return here with a
  560. CURLE_OK return code. */
  561. rc = 0;
  562. break;
  563. }
  564. if(0 == rc) {
  565. int err = socketerror(sockfd);
  566. if ((0 == err) || (EISCONN == err)) {
  567. /* we are connected, awesome! */
  568. *connected = TRUE; /* this is a true connect */
  569. break;
  570. }
  571. /* nope, not connected for real */
  572. rc = -1;
  573. }
  574. if(0 != rc) {
  575. /* get a new timeout for next attempt */
  576. after = Curl_tvnow();
  577. timeout_ms -= Curl_tvdiff(after, before);
  578. if(timeout_ms < 0) {
  579. failf(data, "Connect timeout on IP number %d", aliasindex+1);
  580. break;
  581. }
  582. before = after;
  583. continue; /* try next address */
  584. }
  585. break;
  586. }
  587. if(0 != rc) {
  588. /* no good connect was made */
  589. sclose(sockfd);
  590. *sockconn = -1;
  591. failf(data, "Connect failed");
  592. return CURLE_COULDNT_CONNECT;
  593. }
  594. /* leave the socket in non-blocking mode */
  595. if(addr)
  596. /* this is the address we've connected to */
  597. *addr = (struct in_addr *)remotehost->addr->h_addr_list[aliasindex];
  598. #endif
  599. /* allow NULL-pointers to get passed in */
  600. if(sockconn)
  601. *sockconn = sockfd; /* the socket descriptor we've connected */
  602. return CURLE_OK;
  603. }