]> git.ipfire.org Git - thirdparty/squid.git/blame - src/comm/ConnOpener.cc
Fix build errors where we meet new SMP code
[thirdparty/squid.git] / src / comm / ConnOpener.cc
CommitLineData
aed188fd
AJ
1#include "config.h"
2#include "comm/ConnOpener.h"
3#include "comm/Connection.h"
4#include "comm.h"
5#include "CommCalls.h"
6#include "fde.h"
7#include "icmp/net_db.h"
8#include "SquidTime.h"
9
10CBDATA_CLASS_INIT(ConnOpener);
11
12ConnOpener::ConnOpener(Comm::ConnectionPointer &c, AsyncCall::Pointer handler) :
13 AsyncJob("ConnOpener"),
14 connect_timeout(Config.Timeout.connect),
15 host(NULL),
16 solo(c),
17 callback(handler),
18 total_tries(0),
19 fail_retries(0),
20 connstart(0)
21{}
22
23ConnOpener::~ConnOpener()
24{
25 safe_free(host);
26 solo = NULL;
27}
28
29void
30ConnOpener::setHost(const char * new_host)
31{
85d2870d
AJ
32 // unset and erase if already set.
33 if (host != NULL)
34 safe_free(host);
35
36 // set the new one if given.
37 if (new_host != NULL)
aed188fd 38 host = xstrdup(new_host);
aed188fd
AJ
39}
40
41const char *
42ConnOpener::getHost() const
43{
44 return host;
45}
46
47void
48ConnOpener::callCallback(comm_err_t status, int xerrno)
49{
50 /* remove handlers we don't want to happen now */
51 comm_remove_close_handler(solo->fd, ConnOpener::EarlyAbort, this);
52 commSetTimeout(solo->fd, -1, NULL, NULL);
53
54 typedef CommConnectCbParams Params;
55 Params &params = GetCommParams<Params>(callback);
56 params.conn = solo;
57 params.flag = status;
58 params.xerrno = xerrno;
59 ScheduleCallHere(callback);
60
61 callback = NULL;
62 delete this;
63}
64
65void
66ConnOpener::start()
67{
68 /* handle connecting to one single path */
69 if (solo->fd < 0) {
70#if USE_IPV6
71 /* outbound sockets have no need to be protocol agnostic. */
72 if (solo->local.IsIPv6() && solo->local.IsIPv4()) {
73 solo->local.SetIPv4();
74 }
75#endif
76 solo->fd = comm_openex(SOCK_STREAM, IPPROTO_TCP, solo->local, solo->flags, solo->tos, host);
77 if (solo->fd <= 0) {
78 callCallback(COMM_ERR_CONNECT, 0);
79 return;
80 }
81
82 AsyncCall::Pointer ea_call = commCbCall(5,4, "ConnOpener::EarlyAbort",
83 CommCloseCbPtrFun(ConnOpener::EarlyAbort, this));
84 comm_add_close_handler(solo->fd, ea_call);
85
86 AsyncCall::Pointer timeout_call = commCbCall(5,4, "ConnOpener::ConnectTimeout",
87 CommTimeoutCbPtrFun(ConnOpener::ConnectTimeout, this));
88 debugs(5, 3, HERE << "FD " << solo->fd << " timeout " << connect_timeout);
89 commSetTimeout(solo->fd, connect_timeout, timeout_call);
90
91 if (connstart == 0) {
92 connstart = squid_curtime;
93 }
94 }
95
96 total_tries++;
97
98 switch (comm_connect_addr(solo->fd, solo->remote) ) {
99
100 case COMM_INPROGRESS:
101 debugs(5, 5, HERE << "FD " << solo->fd << ": COMM_INPROGRESS");
102 commSetSelect(solo->fd, COMM_SELECT_WRITE, ConnOpener::ConnectRetry, this, 0);
103 break;
104
105 case COMM_OK:
106 debugs(5, 5, HERE << "FD " << solo->fd << ": COMM_OK - connected");
107
108 /*
109 * stats.conn_open is used to account for the number of
110 * connections that we have open to the peer, so we can limit
111 * based on the max-conn option. We need to increment here,
112 * even if the connection may fail.
113 */
114 if (solo->getPeer())
115 solo->getPeer()->stats.conn_open++;
116
117 /* TODO: remove these fd_table accesses. But old code still depends on fd_table flags to
118 * indicate the state of a raw fd object being passed around.
119 */
120 fd_table[solo->fd].flags.open = 1;
121 solo->local.SetPort(comm_local_port(solo->fd));
122
85d2870d
AJ
123 if (host != NULL)
124 ipcacheMarkGoodAddr(host, solo->remote);
aed188fd
AJ
125 callCallback(COMM_OK, 0);
126 break;
127
128 default:
129 debugs(5, 5, HERE "FD " << solo->fd << ": * - try again");
130 fail_retries++;
85d2870d
AJ
131 if (host != NULL)
132 ipcacheMarkBadAddr(host, solo->remote);
aed188fd
AJ
133#if USE_ICMP
134 if (Config.onoff.test_reachability)
135 netdbDeleteAddrNetwork(solo->remote);
136#endif
137
138 // check for timeout FIRST.
139 if(squid_curtime - connstart > connect_timeout) {
140 debugs(5, 5, HERE << "FD " << solo->fd << ": * - ERR took too long already.");
141 callCallback(COMM_TIMEOUT, errno);
142 } else if (fail_retries < Config.connect_retries) {
143 start();
144 } else {
145 // send ERROR back to the upper layer.
146 debugs(5, 5, HERE << "FD " << solo->fd << ": * - ERR tried too many times already.");
147 callCallback(COMM_ERR_CONNECT, errno);
148 }
149 }
150}
151
152void
153ConnOpener::EarlyAbort(int fd, void *data)
154{
155 ConnOpener *cs = static_cast<ConnOpener *>(data);
156 debugs(5, 3, HERE << "FD " << fd);
157 cs->callCallback(COMM_ERR_CLOSING, errno); // NP: is closing or shutdown better?
158
159 /* TODO split cases:
160 * remote end rejecting the connection is normal and one of the other paths may be taken.
161 * squid shutting down or forcing abort on the connection attempt(s) are the only real fatal cases.
162 * we may need separate error codes to send back for these two.
163 */
164}
165
166void
167ConnOpener::Connect(void *data)
168{
169 ConnOpener *cs = static_cast<ConnOpener *>(data);
170 cs->start();
171}
172
173void
174ConnOpener::ConnectRetry(int fd, void *data)
175{
176 ConnOpener *cs = static_cast<ConnOpener *>(data);
177 cs->start();
178}
179
180void
181ConnOpener::ConnectTimeout(int fd, void *data)
182{
183 ConnOpener *cs = static_cast<ConnOpener *>(data);
184 cs->start();
185}
186