connect.c 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905
  1. /***************************************************************************
  2. * _ _ ____ _
  3. * Project ___| | | | _ \| |
  4. * / __| | | | |_) | |
  5. * | (__| |_| | _ <| |___
  6. * \___|\___/|_| \_\_____|
  7. *
  8. * Copyright (C) 1998 - 2006, Daniel Stenberg, <daniel@haxx.se>, 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. #ifdef HAVE_SYS_TIME_H
  27. #include <sys/time.h>
  28. #endif
  29. #ifdef HAVE_SYS_TYPES_H
  30. #include <sys/types.h>
  31. #endif
  32. #ifdef HAVE_SYS_SOCKET_H
  33. #include <sys/socket.h>
  34. #endif
  35. #ifdef HAVE_NETINET_IN_H
  36. #include <netinet/in.h> /* <netinet/tcp.h> may need it */
  37. #endif
  38. #ifdef HAVE_NETINET_TCP_H
  39. #include <netinet/tcp.h> /* for TCP_NODELAY */
  40. #endif
  41. #ifdef HAVE_SYS_IOCTL_H
  42. #include <sys/ioctl.h>
  43. #endif
  44. #ifdef HAVE_UNISTD_H
  45. #include <unistd.h>
  46. #endif
  47. #ifdef HAVE_NETDB_H
  48. #include <netdb.h>
  49. #endif
  50. #ifdef HAVE_FCNTL_H
  51. #include <fcntl.h>
  52. #endif
  53. #ifdef HAVE_NETINET_IN_H
  54. #include <netinet/in.h>
  55. #endif
  56. #ifdef HAVE_ARPA_INET_H
  57. #include <arpa/inet.h>
  58. #endif
  59. #ifdef HAVE_STDLIB_H
  60. #include <stdlib.h> /* required for free() prototype, without it, this crashes
  61. on macos 68K */
  62. #endif
  63. #if (defined(HAVE_FIONBIO) && defined(__NOVELL_LIBC__))
  64. #include <sys/filio.h>
  65. #endif
  66. #if (defined(NETWARE) && defined(__NOVELL_LIBC__))
  67. #undef in_addr_t
  68. #define in_addr_t unsigned long
  69. #endif
  70. #ifdef VMS
  71. #include <in.h>
  72. #include <inet.h>
  73. #endif
  74. #endif
  75. #include <stdio.h>
  76. #include <errno.h>
  77. #include <string.h>
  78. #ifndef TRUE
  79. #define TRUE 1
  80. #define FALSE 0
  81. #endif
  82. #ifdef USE_WINSOCK
  83. #define EINPROGRESS WSAEINPROGRESS
  84. #define EWOULDBLOCK WSAEWOULDBLOCK
  85. #define EISCONN WSAEISCONN
  86. #define ENOTSOCK WSAENOTSOCK
  87. #define ECONNREFUSED WSAECONNREFUSED
  88. #endif
  89. #include "urldata.h"
  90. #include "sendf.h"
  91. #include "if2ip.h"
  92. #include "strerror.h"
  93. #include "connect.h"
  94. #include "memory.h"
  95. #include "select.h"
  96. #include "url.h" /* for Curl_safefree() */
  97. #include "multiif.h"
  98. #include "sockaddr.h" /* required for Curl_sockaddr_storage */
  99. #include "inet_ntop.h"
  100. /* The last #include file should be: */
  101. #include "memdebug.h"
  102. static bool verifyconnect(curl_socket_t sockfd, int *error);
  103. static curl_socket_t
  104. singleipconnect(struct connectdata *conn,
  105. const Curl_addrinfo *ai, /* start connecting to this */
  106. long timeout_ms,
  107. bool *connected);
  108. /*
  109. * Curl_sockerrno() returns the *socket-related* errno (or equivalent) on this
  110. * platform to hide platform specific for the function that calls this.
  111. */
  112. int Curl_sockerrno(void)
  113. {
  114. #ifdef USE_WINSOCK
  115. return (int)WSAGetLastError();
  116. #else
  117. return errno;
  118. #endif
  119. }
  120. /*
  121. * Curl_nonblock() set the given socket to either blocking or non-blocking
  122. * mode based on the 'nonblock' boolean argument. This function is highly
  123. * portable.
  124. */
  125. int Curl_nonblock(curl_socket_t sockfd, /* operate on this */
  126. int nonblock /* TRUE or FALSE */)
  127. {
  128. #undef SETBLOCK
  129. #define SETBLOCK 0
  130. #ifdef HAVE_O_NONBLOCK
  131. /* most recent unix versions */
  132. int flags;
  133. flags = fcntl(sockfd, F_GETFL, 0);
  134. if (TRUE == nonblock)
  135. return fcntl(sockfd, F_SETFL, flags | O_NONBLOCK);
  136. else
  137. return fcntl(sockfd, F_SETFL, flags & (~O_NONBLOCK));
  138. #undef SETBLOCK
  139. #define SETBLOCK 1
  140. #endif
  141. #if defined(HAVE_FIONBIO) && (SETBLOCK == 0)
  142. /* older unix versions */
  143. int flags;
  144. flags = nonblock;
  145. return ioctl(sockfd, FIONBIO, &flags);
  146. #undef SETBLOCK
  147. #define SETBLOCK 2
  148. #endif
  149. #if defined(HAVE_IOCTLSOCKET) && (SETBLOCK == 0)
  150. /* Windows? */
  151. unsigned long flags;
  152. flags = nonblock;
  153. return ioctlsocket(sockfd, FIONBIO, &flags);
  154. #undef SETBLOCK
  155. #define SETBLOCK 3
  156. #endif
  157. #if defined(HAVE_IOCTLSOCKET_CASE) && (SETBLOCK == 0)
  158. /* presumably for Amiga */
  159. return IoctlSocket(sockfd, FIONBIO, (long)nonblock);
  160. #undef SETBLOCK
  161. #define SETBLOCK 4
  162. #endif
  163. #if defined(HAVE_SO_NONBLOCK) && (SETBLOCK == 0)
  164. /* BeOS */
  165. long b = nonblock ? 1 : 0;
  166. return setsockopt(sockfd, SOL_SOCKET, SO_NONBLOCK, &b, sizeof(b));
  167. #undef SETBLOCK
  168. #define SETBLOCK 5
  169. #endif
  170. #ifdef HAVE_DISABLED_NONBLOCKING
  171. return 0; /* returns success */
  172. #undef SETBLOCK
  173. #define SETBLOCK 6
  174. #endif
  175. #if (SETBLOCK == 0)
  176. #error "no non-blocking method was found/used/set"
  177. #endif
  178. }
  179. /*
  180. * waitconnect() waits for a TCP connect on the given socket for the specified
  181. * number if milliseconds. It returns:
  182. * 0 fine connect
  183. * -1 select() error
  184. * 1 select() timeout
  185. * 2 select() returned with an error condition fd_set
  186. */
  187. #define WAITCONN_CONNECTED 0
  188. #define WAITCONN_SELECT_ERROR -1
  189. #define WAITCONN_TIMEOUT 1
  190. #define WAITCONN_FDSET_ERROR 2
  191. static
  192. int waitconnect(curl_socket_t sockfd, /* socket */
  193. long timeout_msec)
  194. {
  195. int rc;
  196. #ifdef mpeix
  197. /* Call this function once now, and ignore the results. We do this to
  198. "clear" the error state on the socket so that we can later read it
  199. reliably. This is reported necessary on the MPE/iX operating system. */
  200. (void)verifyconnect(sockfd, NULL);
  201. #endif
  202. /* now select() until we get connect or timeout */
  203. rc = Curl_select(CURL_SOCKET_BAD, sockfd, (int)timeout_msec);
  204. if(-1 == rc)
  205. /* error, no connect here, try next */
  206. return WAITCONN_SELECT_ERROR;
  207. else if(0 == rc)
  208. /* timeout, no connect today */
  209. return WAITCONN_TIMEOUT;
  210. if(rc & CSELECT_ERR)
  211. /* error condition caught */
  212. return WAITCONN_FDSET_ERROR;
  213. /* we have a connect! */
  214. return WAITCONN_CONNECTED;
  215. }
  216. static CURLcode bindlocal(struct connectdata *conn,
  217. curl_socket_t sockfd)
  218. {
  219. struct SessionHandle *data = conn->data;
  220. struct sockaddr_in me;
  221. struct sockaddr *sock = NULL; /* bind to this address */
  222. socklen_t socksize; /* size of the data sock points to */
  223. unsigned short port = data->set.localport; /* use this port number, 0 for
  224. "random" */
  225. /* how many port numbers to try to bind to, increasing one at a time */
  226. int portnum = data->set.localportrange;
  227. /*************************************************************
  228. * Select device to bind socket to
  229. *************************************************************/
  230. if (data->set.device && (strlen(data->set.device)<255) ) {
  231. struct Curl_dns_entry *h=NULL;
  232. char myhost[256] = "";
  233. in_addr_t in;
  234. int rc;
  235. bool was_iface = FALSE;
  236. /* First check if the given name is an IP address */
  237. in=inet_addr(data->set.device);
  238. if((in == CURL_INADDR_NONE) &&
  239. Curl_if2ip(data->set.device, myhost, sizeof(myhost))) {
  240. /*
  241. * We now have the numerical IPv4-style x.y.z.w in the 'myhost' buffer
  242. */
  243. rc = Curl_resolv(conn, myhost, 0, &h);
  244. if(rc == CURLRESOLV_PENDING)
  245. (void)Curl_wait_for_resolv(conn, &h);
  246. if(h) {
  247. was_iface = TRUE;
  248. Curl_resolv_unlock(data, h);
  249. }
  250. }
  251. if(!was_iface) {
  252. /*
  253. * This was not an interface, resolve the name as a host name
  254. * or IP number
  255. */
  256. rc = Curl_resolv(conn, data->set.device, 0, &h);
  257. if(rc == CURLRESOLV_PENDING)
  258. (void)Curl_wait_for_resolv(conn, &h);
  259. if(h) {
  260. if(in == CURL_INADDR_NONE)
  261. /* convert the resolved address, sizeof myhost >= INET_ADDRSTRLEN */
  262. Curl_inet_ntop(h->addr->ai_addr->sa_family,
  263. &((struct sockaddr_in*)h->addr->ai_addr)->sin_addr,
  264. myhost, sizeof myhost);
  265. else
  266. /* we know data->set.device is shorter than the myhost array */
  267. strcpy(myhost, data->set.device);
  268. Curl_resolv_unlock(data, h);
  269. }
  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, "Bind local address 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_sockerrno())); */
  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. failf(data,"couldn't find my own IP address (%s)", myhost);
  309. return CURLE_HTTP_PORT_FAILED;
  310. } /* end of inet_addr */
  311. if ( h ) {
  312. Curl_addrinfo *addr = h->addr;
  313. sock = addr->ai_addr;
  314. socksize = addr->ai_addrlen;
  315. }
  316. else
  317. return CURLE_HTTP_PORT_FAILED;
  318. }
  319. else if(port) {
  320. /* if a local port number is requested but no local IP, extract the
  321. address from the socket */
  322. memset(&me, 0, sizeof(struct sockaddr));
  323. me.sin_family = AF_INET;
  324. me.sin_addr.s_addr = INADDR_ANY;
  325. sock = (struct sockaddr *)&me;
  326. socksize = sizeof(struct sockaddr);
  327. }
  328. else
  329. /* no local kind of binding was requested */
  330. return CURLE_OK;
  331. do {
  332. /* Set port number to bind to, 0 makes the system pick one */
  333. if(sock->sa_family == AF_INET)
  334. ((struct sockaddr_in *)sock)->sin_port = htons(port);
  335. #ifdef ENABLE_IPV6
  336. else
  337. ((struct sockaddr_in6 *)sock)->sin6_port = htons(port);
  338. #endif
  339. if( bind(sockfd, sock, socksize) >= 0) {
  340. /* we succeeded to bind */
  341. struct Curl_sockaddr_storage add;
  342. socklen_t size;
  343. size = sizeof(add);
  344. if(getsockname(sockfd, (struct sockaddr *) &add, &size) < 0) {
  345. failf(data, "getsockname() failed");
  346. return CURLE_HTTP_PORT_FAILED;
  347. }
  348. /* We re-use/clobber the port variable here below */
  349. if(((struct sockaddr *)&add)->sa_family == AF_INET)
  350. port = ntohs(((struct sockaddr_in *)&add)->sin_port);
  351. #ifdef ENABLE_IPV6
  352. else
  353. port = ntohs(((struct sockaddr_in6 *)&add)->sin6_port);
  354. #endif
  355. infof(data, "Local port: %d\n", port);
  356. return CURLE_OK;
  357. }
  358. if(--portnum > 0) {
  359. infof(data, "Bind to local port %d failed, trying next\n", port);
  360. port++; /* try next port */
  361. }
  362. else
  363. break;
  364. } while(1);
  365. data->state.os_errno = Curl_sockerrno();
  366. failf(data, "bind failure: %s",
  367. Curl_strerror(conn, data->state.os_errno));
  368. return CURLE_HTTP_PORT_FAILED;
  369. }
  370. /*
  371. * verifyconnect() returns TRUE if the connect really has happened.
  372. */
  373. static bool verifyconnect(curl_socket_t sockfd, int *error)
  374. {
  375. bool rc = TRUE;
  376. #ifdef SO_ERROR
  377. int err = 0;
  378. socklen_t errSize = sizeof(err);
  379. #ifdef WIN32
  380. /*
  381. * In October 2003 we effectively nullified this function on Windows due to
  382. * problems with it using all CPU in multi-threaded cases.
  383. *
  384. * In May 2004, we bring it back to offer more info back on connect failures.
  385. * Gisle Vanem could reproduce the former problems with this function, but
  386. * could avoid them by adding this SleepEx() call below:
  387. *
  388. * "I don't have Rational Quantify, but the hint from his post was
  389. * ntdll::NtRemoveIoCompletion(). So I'd assume the SleepEx (or maybe
  390. * just Sleep(0) would be enough?) would release whatever
  391. * mutex/critical-section the ntdll call is waiting on.
  392. *
  393. * Someone got to verify this on Win-NT 4.0, 2000."
  394. */
  395. #ifdef _WIN32_WCE
  396. Sleep(0);
  397. #else
  398. SleepEx(0, FALSE);
  399. #endif
  400. #endif
  401. if( -1 == getsockopt(sockfd, SOL_SOCKET, SO_ERROR,
  402. (void *)&err, &errSize))
  403. err = Curl_sockerrno();
  404. #ifdef _WIN32_WCE
  405. /* Always returns this error, bug in CE? */
  406. if(WSAENOPROTOOPT==err)
  407. err=0;
  408. #endif
  409. if ((0 == err) || (EISCONN == err))
  410. /* we are connected, awesome! */
  411. rc = TRUE;
  412. else
  413. /* This wasn't a successful connect */
  414. rc = FALSE;
  415. if (error)
  416. *error = err;
  417. #else
  418. (void)sockfd;
  419. if (error)
  420. *error = Curl_sockerrno();
  421. #endif
  422. return rc;
  423. }
  424. CURLcode Curl_store_ip_addr(struct connectdata *conn)
  425. {
  426. char addrbuf[256];
  427. Curl_printable_address(conn->ip_addr, addrbuf, sizeof(addrbuf));
  428. /* save the string */
  429. Curl_safefree(conn->ip_addr_str);
  430. conn->ip_addr_str = strdup(addrbuf);
  431. if(!conn->ip_addr_str)
  432. return CURLE_OUT_OF_MEMORY; /* FAIL */
  433. #ifdef PF_INET6
  434. if(conn->ip_addr->ai_family == PF_INET6)
  435. conn->bits.ipv6 = TRUE;
  436. #endif
  437. return CURLE_OK;
  438. }
  439. /* Used within the multi interface. Try next IP address, return TRUE if no
  440. more address exists */
  441. static bool trynextip(struct connectdata *conn,
  442. int sockindex,
  443. bool *connected)
  444. {
  445. curl_socket_t sockfd;
  446. Curl_addrinfo *ai;
  447. /* first close the failed socket */
  448. sclose(conn->sock[sockindex]);
  449. conn->sock[sockindex] = CURL_SOCKET_BAD;
  450. *connected = FALSE;
  451. if(sockindex != FIRSTSOCKET)
  452. return TRUE; /* no next */
  453. /* try the next address */
  454. ai = conn->ip_addr->ai_next;
  455. while (ai) {
  456. sockfd = singleipconnect(conn, ai, 0L, connected);
  457. if(sockfd != CURL_SOCKET_BAD) {
  458. /* store the new socket descriptor */
  459. conn->sock[sockindex] = sockfd;
  460. conn->ip_addr = ai;
  461. Curl_store_ip_addr(conn);
  462. return FALSE;
  463. }
  464. ai = ai->ai_next;
  465. }
  466. return TRUE;
  467. }
  468. /*
  469. * Curl_is_connected() is used from the multi interface to check if the
  470. * firstsocket has connected.
  471. */
  472. CURLcode Curl_is_connected(struct connectdata *conn,
  473. int sockindex,
  474. bool *connected)
  475. {
  476. int rc;
  477. struct SessionHandle *data = conn->data;
  478. CURLcode code = CURLE_OK;
  479. curl_socket_t sockfd = conn->sock[sockindex];
  480. long allow = DEFAULT_CONNECT_TIMEOUT;
  481. long allow_total = 0;
  482. long has_passed;
  483. curlassert(sockindex >= FIRSTSOCKET && sockindex <= SECONDARYSOCKET);
  484. *connected = FALSE; /* a very negative world view is best */
  485. /* Evaluate in milliseconds how much time that has passed */
  486. has_passed = Curl_tvdiff(Curl_tvnow(), data->progress.t_startsingle);
  487. /* subtract the most strict timeout of the ones */
  488. if(data->set.timeout && data->set.connecttimeout) {
  489. if (data->set.timeout < data->set.connecttimeout)
  490. allow_total = allow = data->set.timeout*1000;
  491. else
  492. allow = data->set.connecttimeout*1000;
  493. }
  494. else if(data->set.timeout) {
  495. allow_total = allow = data->set.timeout*1000;
  496. }
  497. else if(data->set.connecttimeout) {
  498. allow = data->set.connecttimeout*1000;
  499. }
  500. if(has_passed > allow ) {
  501. /* time-out, bail out, go home */
  502. failf(data, "Connection time-out after %ld ms", has_passed);
  503. return CURLE_OPERATION_TIMEOUTED;
  504. }
  505. if(conn->bits.tcpconnect) {
  506. /* we are connected already! */
  507. Curl_expire(data, allow_total);
  508. *connected = TRUE;
  509. return CURLE_OK;
  510. }
  511. Curl_expire(data, allow);
  512. /* check for connect without timeout as we want to return immediately */
  513. rc = waitconnect(sockfd, 0);
  514. if(WAITCONN_CONNECTED == rc) {
  515. int error;
  516. if (verifyconnect(sockfd, &error)) {
  517. /* we are connected, awesome! */
  518. *connected = TRUE;
  519. return CURLE_OK;
  520. }
  521. /* nope, not connected for real */
  522. data->state.os_errno = error;
  523. infof(data, "Connection failed\n");
  524. if(trynextip(conn, sockindex, connected)) {
  525. code = CURLE_COULDNT_CONNECT;
  526. }
  527. }
  528. else if(WAITCONN_TIMEOUT != rc) {
  529. int error = 0;
  530. /* nope, not connected */
  531. if (WAITCONN_FDSET_ERROR == rc) {
  532. (void)verifyconnect(sockfd, &error);
  533. data->state.os_errno = error;
  534. infof(data, "%s\n",Curl_strerror(conn,error));
  535. }
  536. else
  537. infof(data, "Connection failed\n");
  538. if(trynextip(conn, sockindex, connected)) {
  539. error = Curl_sockerrno();
  540. data->state.os_errno = error;
  541. failf(data, "Failed connect to %s:%d; %s",
  542. conn->host.name, conn->port, Curl_strerror(conn,error));
  543. code = CURLE_COULDNT_CONNECT;
  544. }
  545. }
  546. /*
  547. * If the connection failed here, we should attempt to connect to the "next
  548. * address" for the given host.
  549. */
  550. return code;
  551. }
  552. static void tcpnodelay(struct connectdata *conn,
  553. curl_socket_t sockfd)
  554. {
  555. #ifdef TCP_NODELAY
  556. struct SessionHandle *data= conn->data;
  557. socklen_t onoff = (socklen_t) data->set.tcp_nodelay;
  558. int proto = IPPROTO_TCP;
  559. #ifdef HAVE_GETPROTOBYNAME
  560. struct protoent *pe = getprotobyname("tcp");
  561. if (pe)
  562. proto = pe->p_proto;
  563. #endif
  564. if(setsockopt(sockfd, proto, TCP_NODELAY, (void *)&onoff,
  565. sizeof(onoff)) < 0)
  566. infof(data, "Could not set TCP_NODELAY: %s\n",
  567. Curl_strerror(conn, Curl_sockerrno()));
  568. else
  569. infof(data,"TCP_NODELAY set\n");
  570. #else
  571. (void)conn;
  572. (void)sockfd;
  573. #endif
  574. }
  575. #ifdef SO_NOSIGPIPE
  576. /* The preferred method on Mac OS X (10.2 and later) to prevent SIGPIPEs when
  577. sending data to a dead peer (instead of relying on the 4th argument to send
  578. being MSG_NOSIGNAL). Possibly also existing and in use on other BSD
  579. systems? */
  580. static void nosigpipe(struct connectdata *conn,
  581. curl_socket_t sockfd)
  582. {
  583. struct SessionHandle *data= conn->data;
  584. int onoff = 1;
  585. if(setsockopt(sockfd, SOL_SOCKET, SO_NOSIGPIPE, (void *)&onoff,
  586. sizeof(onoff)) < 0)
  587. infof(data, "Could not set SO_NOSIGPIPE: %s\n",
  588. Curl_strerror(conn, Curl_sockerrno()));
  589. }
  590. #else
  591. #define nosigpipe(x,y)
  592. #endif
  593. /* singleipconnect() connects to the given IP only, and it may return without
  594. having connected if used from the multi interface. */
  595. static curl_socket_t
  596. singleipconnect(struct connectdata *conn,
  597. const Curl_addrinfo *ai,
  598. long timeout_ms,
  599. bool *connected)
  600. {
  601. char addr_buf[128];
  602. int rc;
  603. int error;
  604. bool isconnected;
  605. struct SessionHandle *data = conn->data;
  606. curl_socket_t sockfd;
  607. CURLcode res;
  608. sockfd = socket(ai->ai_family, conn->socktype, ai->ai_protocol);
  609. if (sockfd == CURL_SOCKET_BAD)
  610. return CURL_SOCKET_BAD;
  611. *connected = FALSE; /* default is not connected */
  612. Curl_printable_address(ai, addr_buf, sizeof(addr_buf));
  613. infof(data, " Trying %s... ", addr_buf);
  614. if(data->set.tcp_nodelay)
  615. tcpnodelay(conn, sockfd);
  616. nosigpipe(conn, sockfd);
  617. if(data->set.fsockopt) {
  618. /* activate callback for setting socket options */
  619. error = data->set.fsockopt(data->set.sockopt_client,
  620. sockfd,
  621. CURLSOCKTYPE_IPCXN);
  622. if (error) {
  623. sclose(sockfd); /* close the socket and bail out */
  624. return CURL_SOCKET_BAD;
  625. }
  626. }
  627. /* possibly bind the local end to an IP, interface or port */
  628. res = bindlocal(conn, sockfd);
  629. if(res) {
  630. sclose(sockfd); /* close socket and bail out */
  631. return CURL_SOCKET_BAD;
  632. }
  633. /* set socket non-blocking */
  634. Curl_nonblock(sockfd, TRUE);
  635. /* Connect TCP sockets, bind UDP */
  636. if(conn->socktype == SOCK_STREAM)
  637. rc = connect(sockfd, ai->ai_addr, ai->ai_addrlen);
  638. else
  639. rc = 0;
  640. if(-1 == rc) {
  641. error = Curl_sockerrno();
  642. switch (error) {
  643. case EINPROGRESS:
  644. case EWOULDBLOCK:
  645. #if defined(EAGAIN) && EAGAIN != EWOULDBLOCK
  646. /* On some platforms EAGAIN and EWOULDBLOCK are the
  647. * same value, and on others they are different, hence
  648. * the odd #if
  649. */
  650. case EAGAIN:
  651. #endif
  652. rc = waitconnect(sockfd, timeout_ms);
  653. break;
  654. default:
  655. /* unknown error, fallthrough and try another address! */
  656. failf(data, "Failed to connect to %s: %s",
  657. addr_buf, Curl_strerror(conn,error));
  658. data->state.os_errno = error;
  659. break;
  660. }
  661. }
  662. /* The 'WAITCONN_TIMEOUT == rc' comes from the waitconnect(), and not from
  663. connect(). We can be sure of this since connect() cannot return 1. */
  664. if((WAITCONN_TIMEOUT == rc) &&
  665. (data->state.used_interface == Curl_if_multi)) {
  666. /* Timeout when running the multi interface */
  667. return sockfd;
  668. }
  669. isconnected = verifyconnect(sockfd, &error);
  670. if(!rc && isconnected) {
  671. /* we are connected, awesome! */
  672. *connected = TRUE; /* this is a true connect */
  673. infof(data, "connected\n");
  674. return sockfd;
  675. }
  676. else if(WAITCONN_TIMEOUT == rc)
  677. infof(data, "Timeout\n");
  678. else {
  679. data->state.os_errno = error;
  680. infof(data, "%s\n", Curl_strerror(conn, error));
  681. }
  682. /* connect failed or timed out */
  683. sclose(sockfd);
  684. return CURL_SOCKET_BAD;
  685. }
  686. /*
  687. * TCP connect to the given host with timeout, proxy or remote doesn't matter.
  688. * There might be more than one IP address to try out. Fill in the passed
  689. * pointer with the connected socket.
  690. */
  691. CURLcode Curl_connecthost(struct connectdata *conn, /* context */
  692. const struct Curl_dns_entry *remotehost, /* use this one */
  693. curl_socket_t *sockconn, /* the connected socket */
  694. Curl_addrinfo **addr, /* the one we used */
  695. bool *connected) /* really connected? */
  696. {
  697. struct SessionHandle *data = conn->data;
  698. curl_socket_t sockfd = CURL_SOCKET_BAD;
  699. int aliasindex;
  700. int num_addr;
  701. Curl_addrinfo *ai;
  702. Curl_addrinfo *curr_addr;
  703. struct timeval after;
  704. struct timeval before = Curl_tvnow();
  705. /*************************************************************
  706. * Figure out what maximum time we have left
  707. *************************************************************/
  708. long timeout_ms= DEFAULT_CONNECT_TIMEOUT;
  709. long timeout_per_addr;
  710. *connected = FALSE; /* default to not connected */
  711. if(data->set.timeout || data->set.connecttimeout) {
  712. long has_passed;
  713. /* Evaluate in milliseconds how much time that has passed */
  714. has_passed = Curl_tvdiff(Curl_tvnow(), data->progress.t_startsingle);
  715. #ifndef min
  716. #define min(a, b) ((a) < (b) ? (a) : (b))
  717. #endif
  718. /* get the most strict timeout of the ones converted to milliseconds */
  719. if(data->set.timeout && data->set.connecttimeout) {
  720. if (data->set.timeout < data->set.connecttimeout)
  721. timeout_ms = data->set.timeout*1000;
  722. else
  723. timeout_ms = data->set.connecttimeout*1000;
  724. }
  725. else if(data->set.timeout)
  726. timeout_ms = data->set.timeout*1000;
  727. else
  728. timeout_ms = data->set.connecttimeout*1000;
  729. /* subtract the passed time */
  730. timeout_ms -= has_passed;
  731. if(timeout_ms < 0) {
  732. /* a precaution, no need to continue if time already is up */
  733. failf(data, "Connection time-out");
  734. return CURLE_OPERATION_TIMEOUTED;
  735. }
  736. }
  737. Curl_expire(data, timeout_ms);
  738. /* Max time for each address */
  739. num_addr = Curl_num_addresses(remotehost->addr);
  740. timeout_per_addr = timeout_ms / num_addr;
  741. ai = remotehost->addr;
  742. /* Below is the loop that attempts to connect to all IP-addresses we
  743. * know for the given host. One by one until one IP succeeds.
  744. */
  745. if(data->state.used_interface == Curl_if_multi)
  746. /* don't hang when doing multi */
  747. timeout_per_addr = 0;
  748. /*
  749. * Connecting with a Curl_addrinfo chain
  750. */
  751. for (curr_addr = ai, aliasindex=0; curr_addr;
  752. curr_addr = curr_addr->ai_next, aliasindex++) {
  753. /* start connecting to the IP curr_addr points to */
  754. sockfd = singleipconnect(conn, curr_addr, timeout_per_addr, connected);
  755. if(sockfd != CURL_SOCKET_BAD)
  756. break;
  757. /* get a new timeout for next attempt */
  758. after = Curl_tvnow();
  759. timeout_ms -= Curl_tvdiff(after, before);
  760. if(timeout_ms < 0) {
  761. failf(data, "connect() timed out!");
  762. return CURLE_OPERATION_TIMEOUTED;
  763. }
  764. before = after;
  765. } /* end of connect-to-each-address loop */
  766. if (sockfd == CURL_SOCKET_BAD) {
  767. /* no good connect was made */
  768. *sockconn = CURL_SOCKET_BAD;
  769. failf(data, "couldn't connect to host");
  770. return CURLE_COULDNT_CONNECT;
  771. }
  772. /* leave the socket in non-blocking mode */
  773. /* store the address we use */
  774. if(addr)
  775. *addr = curr_addr;
  776. /* allow NULL-pointers to get passed in */
  777. if(sockconn)
  778. *sockconn = sockfd; /* the socket descriptor we've connected */
  779. data->info.numconnects++; /* to track the number of connections made */
  780. return CURLE_OK;
  781. }