connect.c 19 KB

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