1 /***************************************************************************
3 * Project ___| | | | _ \| |
5 * | (__| |_| | _ <| |___
6 * \___|\___/|_| \_\_____|
8 * Copyright (C) 1998 - 2010, Daniel Stenberg, <daniel@haxx.se>, et al.
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.
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.
18 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
19 * KIND, either express or implied.
21 ***************************************************************************/
25 #ifdef HAVE_SYS_TIME_H
28 #ifdef HAVE_SYS_SOCKET_H
29 #include <sys/socket.h>
31 #ifdef HAVE_NETINET_IN_H
32 #include <netinet/in.h> /* <netinet/tcp.h> may need it */
35 #include <sys/un.h> /* for sockaddr_un */
37 #ifdef HAVE_NETINET_TCP_H
38 #include <netinet/tcp.h> /* for TCP_NODELAY */
40 #ifdef HAVE_SYS_IOCTL_H
41 #include <sys/ioctl.h>
52 #ifdef HAVE_ARPA_INET_H
53 #include <arpa/inet.h>
59 #if (defined(HAVE_IOCTL_FIONBIO) && defined(NETWARE))
60 #include <sys/filio.h>
64 #define in_addr_t unsigned long
75 #define _MPRINTF_REPLACE /* use our functions only */
76 #include <curl/mprintf.h>
83 #include "curl_memory.h"
85 #include "url.h" /* for Curl_safefree() */
87 #include "sockaddr.h" /* required for Curl_sockaddr_storage */
88 #include "inet_ntop.h"
89 #include "inet_pton.h"
90 #include "sslgen.h" /* for Curl_ssl_check_cxn() */
93 /* The last #include file should be: */
97 /* This isn't actually supported under Symbian OS */
101 struct Curl_sockaddr_ex {
105 unsigned int addrlen;
107 struct sockaddr addr;
108 struct Curl_sockaddr_storage buff;
111 #define sa_addr _sa_ex_u.addr
113 static bool verifyconnect(curl_socket_t sockfd, int *error);
116 singleipconnect(struct connectdata *conn,
117 const Curl_addrinfo *ai, /* start connecting to this */
122 * Curl_timeleft() returns the amount of milliseconds left allowed for the
123 * transfer/connection. If the value is negative, the timeout time has already
126 * If 'nowp' is non-NULL, it points to the current time.
127 * 'duringconnect' is FALSE if not during a connect, as then of course the
128 * connect timeout is not taken into account!
130 long Curl_timeleft(struct connectdata *conn,
131 struct timeval *nowp,
134 struct SessionHandle *data = conn->data;
136 long timeout_ms = duringconnect?DEFAULT_CONNECT_TIMEOUT:0;
139 /* if a timeout is set, use the most restrictive one */
141 if(data->set.timeout > 0)
143 if(duringconnect && (data->set.connecttimeout > 0))
146 switch (timeout_set) {
148 timeout_ms = data->set.timeout;
151 timeout_ms = data->set.connecttimeout;
154 if(data->set.timeout < data->set.connecttimeout)
155 timeout_ms = data->set.timeout;
157 timeout_ms = data->set.connecttimeout;
160 /* use the default */
162 /* if we're not during connect, there's no default timeout so if we're
163 at zero we better just return zero and not make it a negative number
174 /* substract elapsed time */
175 timeout_ms -= Curl_tvdiff(*nowp, data->progress.t_startsingle);
181 * waitconnect() waits for a TCP connect on the given socket for the specified
182 * number if milliseconds. It returns:
186 * 2 select() returned with an error condition fd_set
189 #define WAITCONN_CONNECTED 0
190 #define WAITCONN_SELECT_ERROR -1
191 #define WAITCONN_TIMEOUT 1
192 #define WAITCONN_FDSET_ERROR 2
195 int waitconnect(struct connectdata *conn,
196 curl_socket_t sockfd, /* socket */
201 /* Call this function once now, and ignore the results. We do this to
202 "clear" the error state on the socket so that we can later read it
203 reliably. This is reported necessary on the MPE/iX operating system. */
204 (void)verifyconnect(sockfd, NULL);
209 /* now select() until we get connect or timeout */
210 rc = Curl_socket_ready(CURL_SOCKET_BAD, sockfd, (int)(timeout_msec>1000?
213 if(Curl_pgrsUpdate(conn))
214 return CURLE_ABORTED_BY_CALLBACK;
217 /* error, no connect here, try next */
218 return WAITCONN_SELECT_ERROR;
222 timeout_msec -= 1000;
223 if(timeout_msec <= 0)
224 return WAITCONN_TIMEOUT;
229 if(rc & CURL_CSELECT_ERR)
230 /* error condition caught */
231 return WAITCONN_FDSET_ERROR;
235 return WAITCONN_CONNECTED;
238 static CURLcode bindlocal(struct connectdata *conn,
239 curl_socket_t sockfd, int af)
241 struct SessionHandle *data = conn->data;
243 struct Curl_sockaddr_storage sa;
244 struct sockaddr *sock = (struct sockaddr *)&sa; /* bind to this address */
245 curl_socklen_t sizeof_sa = 0; /* size of the data sock points to */
246 struct sockaddr_in *si4 = (struct sockaddr_in *)&sa;
248 struct sockaddr_in6 *si6 = (struct sockaddr_in6 *)&sa;
251 struct Curl_dns_entry *h=NULL;
252 unsigned short port = data->set.localport; /* use this port number, 0 for
254 /* how many port numbers to try to bind to, increasing one at a time */
255 int portnum = data->set.localportrange;
256 const char *dev = data->set.str[STRING_DEVICE];
258 char myhost[256] = "";
259 int done = 0; /* -1 for error, 1 for address found */
261 /*************************************************************
262 * Select device to bind socket to
263 *************************************************************/
265 /* no local kind of binding was requested */
268 memset(&sa, 0, sizeof(struct Curl_sockaddr_storage));
270 if(dev && (strlen(dev)<255) ) {
273 if(Curl_if2ip(af, dev, myhost, sizeof(myhost))) {
275 * We now have the numerical IP address in the 'myhost' buffer
277 infof(data, "Local Interface %s is ip %s using address family %i\n",
281 #ifdef SO_BINDTODEVICE
282 /* I am not sure any other OSs than Linux that provide this feature, and
283 * at the least I cannot test. --Ben
285 * This feature allows one to tightly bind the local socket to a
286 * particular interface. This will force even requests to other local
287 * interfaces to go out the external interface.
290 * Only bind to the interface when specified as interface, not just as a
291 * hostname or ip address.
293 if(setsockopt(sockfd, SOL_SOCKET, SO_BINDTODEVICE,
294 dev, (curl_socklen_t)strlen(dev)+1) != 0) {
296 infof(data, "SO_BINDTODEVICE %s failed with errno %d: %s;"
297 " will do regular bind\n",
298 dev, error, Curl_strerror(conn, error));
299 /* This is typically "errno 1, error: Operation not permitted" if
300 you're not running as root or another suitable privileged user */
306 * This was not an interface, resolve the name as a host name
309 * Temporarily force name resolution to use only the address type
310 * of the connection. The resolve functions should really be changed
311 * to take a type parameter instead.
313 long ipver = data->set.ip_version;
317 data->set.ip_version = CURL_IPRESOLVE_V4;
319 else if (af == AF_INET6)
320 data->set.ip_version = CURL_IPRESOLVE_V6;
323 rc = Curl_resolv(conn, dev, 0, &h);
324 if(rc == CURLRESOLV_PENDING)
325 (void)Curl_wait_for_resolv(conn, &h);
326 data->set.ip_version = ipver;
329 /* convert the resolved address, sizeof myhost >= INET_ADDRSTRLEN */
330 Curl_printable_address(h->addr, myhost, sizeof(myhost));
331 infof(data, "Name '%s' family %i resolved to '%s' family %i\n",
332 dev, af, myhost, h->addr->ai_family);
333 Curl_resolv_unlock(data, h);
338 * provided dev was no interface (or interfaces are not supported
339 * e.g. solaris) no ip address and no domain we fail here
348 if((af == AF_INET6) &&
349 (Curl_inet_pton(AF_INET6, myhost, &si6->sin6_addr) > 0)) {
350 si6->sin6_family = AF_INET6;
351 si6->sin6_port = htons(port);
352 sizeof_sa = sizeof(struct sockaddr_in6);
357 if((af == AF_INET) &&
358 (Curl_inet_pton(AF_INET, myhost, &si4->sin_addr) > 0)) {
359 si4->sin_family = AF_INET;
360 si4->sin_port = htons(port);
361 sizeof_sa = sizeof(struct sockaddr_in);
366 failf(data, "Couldn't bind to '%s'", dev);
367 return CURLE_INTERFACE_FAILED;
371 /* no device was given, prepare sa to match af's needs */
373 if ( af == AF_INET6 ) {
374 si6->sin6_family = AF_INET6;
375 si6->sin6_port = htons(port);
376 sizeof_sa = sizeof(struct sockaddr_in6);
380 if ( af == AF_INET ) {
381 si4->sin_family = AF_INET;
382 si4->sin_port = htons(port);
383 sizeof_sa = sizeof(struct sockaddr_in);
388 if( bind(sockfd, sock, sizeof_sa) >= 0) {
389 /* we succeeded to bind */
390 struct Curl_sockaddr_storage add;
391 curl_socklen_t size = sizeof(add);
392 memset(&add, 0, sizeof(struct Curl_sockaddr_storage));
393 if(getsockname(sockfd, (struct sockaddr *) &add, &size) < 0) {
394 data->state.os_errno = error = SOCKERRNO;
395 failf(data, "getsockname() failed with errno %d: %s",
396 error, Curl_strerror(conn, error));
397 return CURLE_INTERFACE_FAILED;
399 infof(data, "Local port: %hu\n", port);
400 conn->bits.bound = TRUE;
405 infof(data, "Bind to local port %hu failed, trying next\n", port);
406 port++; /* try next port */
407 /* We re-use/clobber the port variable here below */
408 if(sock->sa_family == AF_INET)
409 si4->sin_port = ntohs(port);
412 si6->sin6_port = ntohs(port);
419 data->state.os_errno = error = SOCKERRNO;
420 failf(data, "bind failed with errno %d: %s",
421 error, Curl_strerror(conn, error));
423 return CURLE_INTERFACE_FAILED;
427 * verifyconnect() returns TRUE if the connect really has happened.
429 static bool verifyconnect(curl_socket_t sockfd, int *error)
434 curl_socklen_t errSize = sizeof(err);
438 * In October 2003 we effectively nullified this function on Windows due to
439 * problems with it using all CPU in multi-threaded cases.
441 * In May 2004, we bring it back to offer more info back on connect failures.
442 * Gisle Vanem could reproduce the former problems with this function, but
443 * could avoid them by adding this SleepEx() call below:
445 * "I don't have Rational Quantify, but the hint from his post was
446 * ntdll::NtRemoveIoCompletion(). So I'd assume the SleepEx (or maybe
447 * just Sleep(0) would be enough?) would release whatever
448 * mutex/critical-section the ntdll call is waiting on.
450 * Someone got to verify this on Win-NT 4.0, 2000."
461 if(0 != getsockopt(sockfd, SOL_SOCKET, SO_ERROR, (void *)&err, &errSize))
464 /* Old WinCE versions don't support SO_ERROR */
465 if(WSAENOPROTOOPT == err) {
471 /* Minix 3.1.x doesn't support getsockopt on UDP sockets */
472 if(EBADIOCTL == err) {
477 if((0 == err) || (EISCONN == err))
478 /* we are connected, awesome! */
481 /* This wasn't a successful connect */
493 /* Used within the multi interface. Try next IP address, return TRUE if no
494 more address exists or error */
495 static bool trynextip(struct connectdata *conn,
499 curl_socket_t sockfd;
502 /* first close the failed socket */
503 sclose(conn->sock[sockindex]);
504 conn->sock[sockindex] = CURL_SOCKET_BAD;
507 if(sockindex != FIRSTSOCKET)
508 return TRUE; /* no next */
510 /* try the next address */
511 ai = conn->ip_addr->ai_next;
514 sockfd = singleipconnect(conn, ai, 0L, connected);
515 if(sockfd != CURL_SOCKET_BAD) {
516 /* store the new socket descriptor */
517 conn->sock[sockindex] = sockfd;
527 * Curl_is_connected() is used from the multi interface to check if the
528 * firstsocket has connected.
531 CURLcode Curl_is_connected(struct connectdata *conn,
536 struct SessionHandle *data = conn->data;
537 CURLcode code = CURLE_OK;
538 curl_socket_t sockfd = conn->sock[sockindex];
539 long allow = DEFAULT_CONNECT_TIMEOUT;
541 DEBUGASSERT(sockindex >= FIRSTSOCKET && sockindex <= SECONDARYSOCKET);
543 *connected = FALSE; /* a very negative world view is best */
545 if(conn->bits.tcpconnect) {
546 /* we are connected already! */
547 long allow_total = 0;
549 /* subtract the most strict timeout of the ones */
550 if(data->set.timeout)
551 allow_total = data->set.timeout;
553 Curl_expire(data, allow_total);
558 /* figure out how long time we have left to connect */
559 allow = Curl_timeleft(conn, NULL, TRUE);
562 /* time-out, bail out, go home */
563 failf(data, "Connection time-out");
564 return CURLE_OPERATION_TIMEDOUT;
567 Curl_expire(data, allow);
569 /* check for connect without timeout as we want to return immediately */
570 rc = waitconnect(conn, sockfd, 0);
572 if(WAITCONN_CONNECTED == rc) {
574 if(verifyconnect(sockfd, &error)) {
575 /* we are connected, awesome! */
576 conn->bits.tcpconnect = TRUE;
580 /* nope, not connected for real */
581 data->state.os_errno = error;
582 infof(data, "Connection failed\n");
583 if(trynextip(conn, sockindex, connected)) {
584 failf(data, "Failed connect to %s:%ld; %s",
585 conn->host.name, conn->port, Curl_strerror(conn, error));
586 code = CURLE_COULDNT_CONNECT;
589 else if(WAITCONN_TIMEOUT != rc) {
592 /* nope, not connected */
593 if(WAITCONN_FDSET_ERROR == rc) {
594 (void)verifyconnect(sockfd, &error);
595 data->state.os_errno = error;
596 infof(data, "%s\n",Curl_strerror(conn,error));
599 infof(data, "Connection failed\n");
601 if(trynextip(conn, sockindex, connected)) {
603 data->state.os_errno = error;
604 failf(data, "Failed connect to %s:%ld; %s",
605 conn->host.name, conn->port, Curl_strerror(conn, error));
606 code = CURLE_COULDNT_CONNECT;
610 * If the connection failed here, we should attempt to connect to the "next
611 * address" for the given host.
617 static void tcpnodelay(struct connectdata *conn,
618 curl_socket_t sockfd)
621 struct SessionHandle *data= conn->data;
622 curl_socklen_t onoff = (curl_socklen_t) data->set.tcp_nodelay;
623 int proto = IPPROTO_TCP;
626 /* The use of getprotobyname() is disabled since it isn't thread-safe on
627 numerous systems. On these getprotobyname_r() should be used instead, but
628 that exists in at least one 4 arg version and one 5 arg version, and
629 since the proto number rarely changes anyway we now just use the hard
630 coded number. The "proper" fix would need a configure check for the
631 correct function much in the same style the gethostbyname_r versions are
633 struct protoent *pe = getprotobyname("tcp");
638 if(setsockopt(sockfd, proto, TCP_NODELAY, (void *)&onoff,
640 infof(data, "Could not set TCP_NODELAY: %s\n",
641 Curl_strerror(conn, SOCKERRNO));
643 infof(data,"TCP_NODELAY set\n");
651 /* The preferred method on Mac OS X (10.2 and later) to prevent SIGPIPEs when
652 sending data to a dead peer (instead of relying on the 4th argument to send
653 being MSG_NOSIGNAL). Possibly also existing and in use on other BSD
655 static void nosigpipe(struct connectdata *conn,
656 curl_socket_t sockfd)
658 struct SessionHandle *data= conn->data;
660 if(setsockopt(sockfd, SOL_SOCKET, SO_NOSIGPIPE, (void *)&onoff,
662 infof(data, "Could not set SO_NOSIGPIPE: %s\n",
663 Curl_strerror(conn, SOCKERRNO));
666 #define nosigpipe(x,y)
670 /* When you run a program that uses the Windows Sockets API, you may
671 experience slow performance when you copy data to a TCP server.
673 http://support.microsoft.com/kb/823764
675 Work-around: Make the Socket Send Buffer Size Larger Than the Program Send
679 void Curl_sndbufset(curl_socket_t sockfd)
681 int val = CURL_MAX_WRITE_SIZE + 32;
683 int curlen = sizeof(curval);
685 if (getsockopt(sockfd, SOL_SOCKET, SO_SNDBUF, (char *)&curval, &curlen) == 0)
689 setsockopt(sockfd, SOL_SOCKET, SO_SNDBUF, (const char *)&val, sizeof(val));
694 /* singleipconnect() connects to the given IP only, and it may return without
695 having connected if used from the multi interface. */
697 singleipconnect(struct connectdata *conn,
698 const Curl_addrinfo *ai,
702 struct Curl_sockaddr_ex addr;
707 struct SessionHandle *data = conn->data;
708 curl_socket_t sockfd;
710 const void *iptoprint;
711 struct sockaddr_in * const sa4 = (void *)&addr.sa_addr;
713 struct sockaddr_in6 * const sa6 = (void *)&addr.sa_addr;
717 * The Curl_sockaddr_ex structure is basically libcurl's external API
718 * curl_sockaddr structure with enough space available to directly hold
719 * any protocol-specific address structures. The variable declared here
720 * will be used to pass / receive data to/from the fopensocket callback
721 * if this has been set, before that, it is initialized from parameters.
724 addr.family = ai->ai_family;
725 addr.socktype = conn->socktype;
726 addr.protocol = ai->ai_protocol;
727 addr.addrlen = ai->ai_addrlen;
729 if(addr.addrlen > sizeof(struct Curl_sockaddr_storage))
730 addr.addrlen = sizeof(struct Curl_sockaddr_storage);
731 memcpy(&addr.sa_addr, ai->ai_addr, addr.addrlen);
733 *connected = FALSE; /* default is not connected */
735 if(data->set.fopensocket)
737 * If the opensocket callback is set, all the destination address
738 * information is passed to the callback. Depending on this information the
739 * callback may opt to abort the connection, this is indicated returning
740 * CURL_SOCKET_BAD; otherwise it will return a not-connected socket. When
741 * the callback returns a valid socket the destination address information
742 * might have been changed and this 'new' address will actually be used
745 sockfd = data->set.fopensocket(data->set.opensocket_client,
747 (struct curl_sockaddr *)&addr);
749 /* opensocket callback not set, so simply create the socket now */
750 sockfd = socket(addr.family, addr.socktype, addr.protocol);
752 if(sockfd == CURL_SOCKET_BAD)
753 /* no socket, no connection */
754 return CURL_SOCKET_BAD;
756 #if defined(ENABLE_IPV6) && defined(HAVE_SOCKADDR_IN6_SIN6_SCOPE_ID)
757 if (conn->scope && (addr.family == AF_INET6))
758 sa6->sin6_scope_id = conn->scope;
761 /* FIXME: do we have Curl_printable_address-like with struct sockaddr* as
763 #if defined(HAVE_SYS_UN_H) && defined(AF_UNIX)
764 if(addr.family == AF_UNIX) {
765 infof(data, " Trying %s... ",
766 ((const struct sockaddr_un*)(&addr.sa_addr))->sun_path);
767 snprintf(data->info.ip, MAX_IPADR_LEN, "%s",
768 ((const struct sockaddr_un*)(&addr.sa_addr))->sun_path);
769 strcpy(conn->ip_addr_str, data->info.ip);
775 if(addr.family == AF_INET6) {
776 iptoprint = &sa6->sin6_addr;
777 conn->bits.ipv6 = TRUE;
782 iptoprint = &sa4->sin_addr;
785 if(Curl_inet_ntop(addr.family, iptoprint, addr_buf,
786 sizeof(addr_buf)) != NULL) {
787 infof(data, " Trying %s... ", addr_buf);
788 snprintf(data->info.ip, MAX_IPADR_LEN, "%s", addr_buf);
789 strcpy(conn->ip_addr_str, data->info.ip);
793 if(data->set.tcp_nodelay)
794 tcpnodelay(conn, sockfd);
796 nosigpipe(conn, sockfd);
798 Curl_sndbufset(sockfd);
800 if(data->set.fsockopt) {
801 /* activate callback for setting socket options */
802 error = data->set.fsockopt(data->set.sockopt_client,
806 sclose(sockfd); /* close the socket and bail out */
807 return CURL_SOCKET_BAD;
811 /* possibly bind the local end to an IP, interface or port */
812 res = bindlocal(conn, sockfd, addr.family);
814 sclose(sockfd); /* close socket and bail out */
815 return CURL_SOCKET_BAD;
818 /* set socket non-blocking */
819 curlx_nonblock(sockfd, TRUE);
821 /* Connect TCP sockets, bind UDP */
822 if(conn->socktype == SOCK_STREAM)
823 rc = connect(sockfd, &addr.sa_addr, addr.addrlen);
834 #if (EAGAIN) != (EWOULDBLOCK)
835 /* On some platforms EAGAIN and EWOULDBLOCK are the
836 * same value, and on others they are different, hence
842 rc = waitconnect(conn, sockfd, timeout_ms);
845 /* unknown error, fallthrough and try another address! */
846 failf(data, "Failed to connect to %s: %s",
847 addr_buf, Curl_strerror(conn,error));
848 data->state.os_errno = error;
853 /* The 'WAITCONN_TIMEOUT == rc' comes from the waitconnect(), and not from
854 connect(). We can be sure of this since connect() cannot return 1. */
855 if((WAITCONN_TIMEOUT == rc) &&
856 (data->state.used_interface == Curl_if_multi)) {
857 /* Timeout when running the multi interface */
861 isconnected = verifyconnect(sockfd, &error);
863 if(!rc && isconnected) {
864 /* we are connected, awesome! */
865 *connected = TRUE; /* this is a true connect */
866 infof(data, "connected\n");
869 else if(WAITCONN_TIMEOUT == rc)
870 infof(data, "Timeout\n");
872 data->state.os_errno = error;
873 infof(data, "%s\n", Curl_strerror(conn, error));
876 /* connect failed or timed out */
879 return CURL_SOCKET_BAD;
883 * TCP connect to the given host with timeout, proxy or remote doesn't matter.
884 * There might be more than one IP address to try out. Fill in the passed
885 * pointer with the connected socket.
888 CURLcode Curl_connecthost(struct connectdata *conn, /* context */
889 const struct Curl_dns_entry *remotehost,
890 curl_socket_t *sockconn, /* the connected socket */
891 Curl_addrinfo **addr, /* the one we used */
892 bool *connected) /* really connected? */
894 struct SessionHandle *data = conn->data;
895 curl_socket_t sockfd = CURL_SOCKET_BAD;
899 Curl_addrinfo *curr_addr;
901 struct timeval after;
902 struct timeval before = Curl_tvnow();
904 /*************************************************************
905 * Figure out what maximum time we have left
906 *************************************************************/
908 long timeout_per_addr;
910 DEBUGASSERT(sockconn);
911 *connected = FALSE; /* default to not connected */
913 /* get the timeout left */
914 timeout_ms = Curl_timeleft(conn, &before, TRUE);
917 /* a precaution, no need to continue if time already is up */
918 failf(data, "Connection time-out");
919 return CURLE_OPERATION_TIMEDOUT;
921 Curl_expire(data, timeout_ms);
923 /* Max time for each address */
924 num_addr = Curl_num_addresses(remotehost->addr);
925 timeout_per_addr = timeout_ms / num_addr;
927 ai = remotehost->addr;
929 /* Below is the loop that attempts to connect to all IP-addresses we
930 * know for the given host. One by one until one IP succeeds.
933 if(data->state.used_interface == Curl_if_multi)
934 /* don't hang when doing multi */
935 timeout_per_addr = 0;
938 * Connecting with a Curl_addrinfo chain
940 for (curr_addr = ai, aliasindex=0; curr_addr;
941 curr_addr = curr_addr->ai_next, aliasindex++) {
943 /* start connecting to the IP curr_addr points to */
944 sockfd = singleipconnect(conn, curr_addr, timeout_per_addr, connected);
946 if(sockfd != CURL_SOCKET_BAD)
949 /* get a new timeout for next attempt */
950 after = Curl_tvnow();
951 timeout_ms -= Curl_tvdiff(after, before);
953 failf(data, "connect() timed out!");
954 return CURLE_OPERATION_TIMEDOUT;
957 } /* end of connect-to-each-address loop */
959 *sockconn = sockfd; /* the socket descriptor we've connected */
961 if(sockfd == CURL_SOCKET_BAD) {
962 /* no good connect was made */
963 failf(data, "couldn't connect to host");
964 return CURLE_COULDNT_CONNECT;
967 /* leave the socket in non-blocking mode */
969 /* store the address we use */
973 data->info.numconnects++; /* to track the number of connections made */
979 * Used to extract socket and connectdata struct for the most recent
980 * transfer on the given SessionHandle.
982 * The socket 'long' will be -1 in case of failure!
984 CURLcode Curl_getconnectinfo(struct SessionHandle *data,
986 struct connectdata **connp)
988 if((data->state.lastconnect != -1) &&
989 (data->state.connc->connects[data->state.lastconnect] != NULL)) {
990 struct connectdata *c =
991 data->state.connc->connects[data->state.lastconnect];
993 /* only store this if the caller cares for it */
995 *param_longp = c->sock[FIRSTSOCKET];
996 /* we have a socket connected, let's determine if the server shut down */
997 /* determine if ssl */
998 if(c->ssl[FIRSTSOCKET].use) {
999 /* use the SSL context */
1000 if(!Curl_ssl_check_cxn(c))
1001 *param_longp = -1; /* FIN received */
1003 /* Minix 3.1 doesn't support any flags on recv; just assume socket is OK */
1006 /* use the socket */
1008 if(recv((RECV_TYPE_ARG1)c->sock[FIRSTSOCKET], (RECV_TYPE_ARG2)&buf,
1009 (RECV_TYPE_ARG3)1, (RECV_TYPE_ARG4)MSG_PEEK) == 0) {
1010 *param_longp = -1; /* FIN received */