connect.c 19 KB

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