]>
git.saurik.com Git - apt.git/blob - methods/connect.cc
1 // -*- mode: cpp; mode: fold -*-
3 // $Id: connect.cc,v 1.8 2002/02/28 03:51:55 jgg Exp $
4 /* ######################################################################
6 Connect - Replacement connect call
8 ##################################################################### */
10 // Include Files /*{{{*/
12 #include <apt-pkg/error.h>
13 #include <apt-pkg/fileutl.h>
20 #include <netinet/in.h>
21 #include <sys/socket.h>
22 #include <arpa/inet.h>
25 #include "rfc2553emu.h"
28 static string LastHost
;
29 static int LastPort
= 0;
30 static struct addrinfo
*LastHostAddr
= 0;
31 static struct addrinfo
*LastUsed
= 0;
33 // RotateDNS - Select a new server from a DNS rotation /*{{{*/
34 // ---------------------------------------------------------------------
35 /* This is called during certain errors in order to recover by selecting a
39 if (LastUsed
!= 0 && LastUsed
->ai_next
!= 0)
40 LastUsed
= LastUsed
->ai_next
;
42 LastUsed
= LastHostAddr
;
45 // DoConnect - Attempt a connect operation /*{{{*/
46 // ---------------------------------------------------------------------
47 /* This helper function attempts a connection to a single address. */
48 static bool DoConnect(struct addrinfo
*Addr
,string Host
,
49 unsigned long TimeOut
,int &Fd
,pkgAcqMethod
*Owner
)
51 // Show a status indicator
52 char Name
[NI_MAXHOST
];
53 char Service
[NI_MAXSERV
];
57 getnameinfo(Addr
->ai_addr
,Addr
->ai_addrlen
,
58 Name
,sizeof(Name
),Service
,sizeof(Service
),
59 NI_NUMERICHOST
|NI_NUMERICSERV
);
60 Owner
->Status("Connecting to %s (%s)",Host
.c_str(),Name
);
62 /* If this is an IP rotation store the IP we are using.. If something goes
63 wrong this will get tacked onto the end of the error message */
64 if (LastHostAddr
->ai_next
!= 0)
66 char Name2
[NI_MAXHOST
+ NI_MAXSERV
+ 10];
67 snprintf(Name2
,sizeof(Name2
),"[IP: %s %s]",Name
,Service
);
68 Owner
->SetFailExtraMsg(string(Name2
));
71 Owner
->SetFailExtraMsg("");
74 if ((Fd
= socket(Addr
->ai_family
,Addr
->ai_socktype
,
75 Addr
->ai_protocol
)) < 0)
76 return _error
->Errno("socket","Could not create a socket for %s (f=%u t=%u p=%u)",
77 Name
,Addr
->ai_family
,Addr
->ai_socktype
,Addr
->ai_protocol
);
80 if (connect(Fd
,Addr
->ai_addr
,Addr
->ai_addrlen
) < 0 &&
82 return _error
->Errno("connect","Cannot initiate the connection "
83 "to %s:%s (%s).",Host
.c_str(),Service
,Name
);
85 /* This implements a timeout for connect by opening the connection
87 if (WaitFd(Fd
,true,TimeOut
) == false)
88 return _error
->Error("Could not connect to %s:%s (%s), "
89 "connection timed out",Host
.c_str(),Service
,Name
);
91 // Check the socket for an error condition
93 unsigned int Len
= sizeof(Err
);
94 if (getsockopt(Fd
,SOL_SOCKET
,SO_ERROR
,&Err
,&Len
) != 0)
95 return _error
->Errno("getsockopt","Failed");
100 return _error
->Errno("connect","Could not connect to %s:%s (%s).",Host
.c_str(),
107 // Connect - Connect to a server /*{{{*/
108 // ---------------------------------------------------------------------
109 /* Performs a connection to the server */
110 bool Connect(string Host
,int Port
,const char *Service
,int DefPort
,int &Fd
,
111 unsigned long TimeOut
,pkgAcqMethod
*Owner
)
113 if (_error
->PendingError() == true)
116 // Convert the port name/number
119 snprintf(ServStr
,sizeof(ServStr
),"%u",Port
);
121 snprintf(ServStr
,sizeof(ServStr
),"%s",Service
);
123 /* We used a cached address record.. Yes this is against the spec but
124 the way we have setup our rotating dns suggests that this is more
126 if (LastHost
!= Host
|| LastPort
!= Port
)
128 Owner
->Status("Connecting to %s",Host
.c_str());
130 // Free the old address structure
131 if (LastHostAddr
!= 0)
133 freeaddrinfo(LastHostAddr
);
138 // We only understand SOCK_STREAM sockets.
139 struct addrinfo Hints
;
140 memset(&Hints
,0,sizeof(Hints
));
141 Hints
.ai_socktype
= SOCK_STREAM
;
142 Hints
.ai_protocol
= 0;
144 // Resolve both the host and service simultaneously
148 if ((Res
= getaddrinfo(Host
.c_str(),ServStr
,&Hints
,&LastHostAddr
)) != 0 ||
151 if (Res
== EAI_NONAME
|| Res
== EAI_SERVICE
)
155 snprintf(ServStr
,sizeof(ServStr
),"%u",DefPort
);
159 return _error
->Error("Could not resolve '%s'",Host
.c_str());
162 if (Res
== EAI_AGAIN
)
163 return _error
->Error("Temporary failure resolving '%s'",
165 return _error
->Error("Something wicked happened resolving '%s:%s' (%i)",
166 Host
.c_str(),ServStr
,Res
);
175 // When we have an IP rotation stay with the last IP.
176 struct addrinfo
*CurHost
= LastHostAddr
;
182 if (DoConnect(CurHost
,Host
,TimeOut
,Fd
,Owner
) == true)
190 // Ignore UNIX domain sockets
193 CurHost
= CurHost
->ai_next
;
195 while (CurHost
!= 0 && CurHost
->ai_family
== AF_UNIX
);
197 /* If we reached the end of the search list then wrap around to the
199 if (CurHost
== 0 && LastUsed
!= 0)
200 CurHost
= LastHostAddr
;
202 // Reached the end of the search cycle
203 if (CurHost
== LastUsed
)
210 if (_error
->PendingError() == true)
212 return _error
->Error("Unable to connect to %s %s:",Host
.c_str(),ServStr
);