]>
Commit | Line | Data |
---|---|---|
95d659f0 | 1 | |
983061ed | 2 | /* |
cbdec147 | 3 | * $Id: ssl.cc,v 1.84 1998/07/20 17:20:09 wessels Exp $ |
983061ed | 4 | * |
30a4f2a8 | 5 | * DEBUG: section 26 Secure Sockets Layer Proxy |
6 | * AUTHOR: Duane Wessels | |
7 | * | |
42c04c16 | 8 | * SQUID Internet Object Cache http://squid.nlanr.net/Squid/ |
30a4f2a8 | 9 | * -------------------------------------------------------- |
10 | * | |
11 | * Squid is the result of efforts by numerous individuals from the | |
12 | * Internet community. Development is led by Duane Wessels of the | |
13 | * National Laboratory for Applied Network Research and funded by | |
14 | * the National Science Foundation. | |
15 | * | |
16 | * This program is free software; you can redistribute it and/or modify | |
17 | * it under the terms of the GNU General Public License as published by | |
18 | * the Free Software Foundation; either version 2 of the License, or | |
19 | * (at your option) any later version. | |
20 | * | |
21 | * This program is distributed in the hope that it will be useful, | |
22 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
23 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
24 | * GNU General Public License for more details. | |
25 | * | |
26 | * You should have received a copy of the GNU General Public License | |
27 | * along with this program; if not, write to the Free Software | |
cbdec147 | 28 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA. |
30a4f2a8 | 29 | * |
983061ed | 30 | */ |
983061ed | 31 | |
30a4f2a8 | 32 | #include "squid.h" |
983061ed | 33 | |
34 | typedef struct { | |
35 | char *url; | |
98ffb7e4 | 36 | char *host; /* either request->host or proxy host */ |
37 | u_short port; | |
983061ed | 38 | request_t *request; |
983061ed | 39 | struct { |
40 | int fd; | |
41 | int len; | |
983061ed | 42 | char *buf; |
43 | } client, server; | |
88738790 | 44 | size_t *size_ptr; /* pointer to size in an ConnStateData for logging */ |
93868820 | 45 | int proxying; |
983061ed | 46 | } SslStateData; |
47 | ||
0ee4272b | 48 | static const char *const conn_established = "HTTP/1.0 200 Connection established\r\n\r\n"; |
983061ed | 49 | |
54cff85f | 50 | static CNCB sslConnectDone; |
51 | static ERCB sslErrorComplete; | |
adb78bd4 | 52 | static PF sslServerClosed; |
54cff85f | 53 | static PF sslClientClosed; |
54 | static PF sslReadClient; | |
55 | static PF sslReadServer; | |
5c5783a2 | 56 | static PF sslTimeout; |
54cff85f | 57 | static PF sslWriteClient; |
58 | static PF sslWriteServer; | |
59 | static PSC sslPeerSelectComplete; | |
60 | static PSC sslPeerSelectFail; | |
adb78bd4 | 61 | static void sslStateFree(SslStateData * sslState); |
f5b8bbc4 | 62 | static void sslConnected(int fd, void *); |
63 | static void sslProxyConnected(int fd, void *); | |
adb78bd4 | 64 | static void sslSetSelect(SslStateData * sslState); |
30a4f2a8 | 65 | |
b8d8561b | 66 | static void |
adb78bd4 | 67 | sslServerClosed(int fd, void *data) |
30a4f2a8 | 68 | { |
adb78bd4 | 69 | SslStateData *sslState = data; |
70 | debug(26, 3) ("sslServerClosed: FD %d\n", fd); | |
71 | assert(fd == sslState->server.fd); | |
72 | sslState->server.fd = -1; | |
73 | if (sslState->client.fd == -1) | |
74 | sslStateFree(sslState); | |
30a4f2a8 | 75 | } |
76 | ||
b177367b | 77 | static void |
78 | sslClientClosed(int fd, void *data) | |
30a4f2a8 | 79 | { |
b177367b | 80 | SslStateData *sslState = data; |
a3d5953d | 81 | debug(26, 3) ("sslClientClosed: FD %d\n", fd); |
adb78bd4 | 82 | assert(fd == sslState->client.fd); |
83 | sslState->client.fd = -1; | |
84 | if (sslState->server.fd == -1) | |
85 | sslStateFree(sslState); | |
30a4f2a8 | 86 | } |
983061ed | 87 | |
b177367b | 88 | static void |
adb78bd4 | 89 | sslStateFree(SslStateData * sslState) |
983061ed | 90 | { |
adb78bd4 | 91 | debug(26, 3) ("sslStateFree: sslState=%p\n", sslState); |
92 | assert(sslState != NULL); | |
93 | assert(sslState->client.fd == -1); | |
94 | assert(sslState->server.fd == -1); | |
983061ed | 95 | safe_free(sslState->server.buf); |
96 | safe_free(sslState->client.buf); | |
adb78bd4 | 97 | safe_free(sslState->url); |
98 | sslState->host = NULL; | |
30a4f2a8 | 99 | requestUnlink(sslState->request); |
7dd44885 | 100 | sslState->request = NULL; |
101 | cbdataFree(sslState); | |
983061ed | 102 | } |
103 | ||
adb78bd4 | 104 | static void |
105 | sslSetSelect(SslStateData * sslState) | |
106 | { | |
107 | assert(sslState->server.fd > -1 || sslState->client.fd > -1); | |
108 | if (sslState->client.fd > -1) { | |
109 | if (sslState->server.len > 0) { | |
110 | commSetSelect(sslState->client.fd, | |
111 | COMM_SELECT_WRITE, | |
112 | sslWriteClient, | |
113 | sslState, | |
114 | 0); | |
115 | } | |
116 | if (sslState->client.len < SQUID_TCP_SO_RCVBUF) { | |
117 | commSetSelect(sslState->client.fd, | |
118 | COMM_SELECT_READ, | |
119 | sslReadClient, | |
120 | sslState, | |
121 | Config.Timeout.read); | |
122 | } | |
123 | } else if (sslState->client.len == 0) { | |
124 | comm_close(sslState->server.fd); | |
125 | } | |
126 | if (sslState->server.fd > -1) { | |
127 | if (sslState->client.len > 0) { | |
128 | commSetSelect(sslState->server.fd, | |
129 | COMM_SELECT_WRITE, | |
130 | sslWriteServer, | |
131 | sslState, | |
132 | 0); | |
133 | } | |
134 | if (sslState->server.len < SQUID_TCP_SO_RCVBUF) { | |
135 | /* Have room to read more */ | |
136 | commSetSelect(sslState->server.fd, | |
137 | COMM_SELECT_READ, | |
138 | sslReadServer, | |
139 | sslState, | |
140 | Config.Timeout.read); | |
141 | } | |
142 | } else if (sslState->client.fd == -1) { | |
143 | /* client already closed, nothing more to do */ | |
144 | } else if (sslState->server.len == 0) { | |
145 | comm_close(sslState->client.fd); | |
146 | } | |
147 | } | |
148 | ||
983061ed | 149 | /* Read from server side and queue it for writing to the client */ |
b8d8561b | 150 | static void |
b177367b | 151 | sslReadServer(int fd, void *data) |
983061ed | 152 | { |
b177367b | 153 | SslStateData *sslState = data; |
983061ed | 154 | int len; |
adb78bd4 | 155 | assert(fd == sslState->server.fd); |
156 | debug(26, 3) ("sslReadServer: FD %d, reading %d bytes at offset %d\n", | |
157 | fd, SQUID_TCP_SO_RCVBUF - sslState->server.len, | |
158 | sslState->server.len); | |
159 | len = read(fd, | |
160 | sslState->server.buf + sslState->server.len, | |
161 | SQUID_TCP_SO_RCVBUF - sslState->server.len); | |
162 | debug(26, 3) ("sslReadServer: FD %d, read %d bytes\n", fd, len); | |
ee1679df | 163 | if (len > 0) { |
adb78bd4 | 164 | fd_bytes(fd, len, FD_READ); |
a0f32775 | 165 | kb_incr(&Counter.server.all.kbytes_in, len); |
166 | kb_incr(&Counter.server.other.kbytes_in, len); | |
adb78bd4 | 167 | sslState->server.len += len; |
ee1679df | 168 | } |
adb78bd4 | 169 | cbdataLock(sslState); |
983061ed | 170 | if (len < 0) { |
a3d5953d | 171 | debug(50, 1) ("sslReadServer: FD %d: read failure: %s\n", |
adb78bd4 | 172 | fd, xstrerror()); |
173 | if (!ignoreErrno(errno)) | |
174 | comm_close(fd); | |
983061ed | 175 | } else if (len == 0) { |
adb78bd4 | 176 | comm_close(sslState->server.fd); |
983061ed | 177 | } |
adb78bd4 | 178 | if (cbdataValid(sslState)) |
179 | sslSetSelect(sslState); | |
180 | cbdataUnlock(sslState); | |
983061ed | 181 | } |
182 | ||
183 | /* Read from client side and queue it for writing to the server */ | |
b8d8561b | 184 | static void |
b177367b | 185 | sslReadClient(int fd, void *data) |
983061ed | 186 | { |
b177367b | 187 | SslStateData *sslState = data; |
983061ed | 188 | int len; |
adb78bd4 | 189 | assert(fd == sslState->client.fd); |
190 | debug(26, 3) ("sslReadClient: FD %d, reading %d bytes at offset %d\n", | |
191 | fd, SQUID_TCP_SO_RCVBUF - sslState->client.len, | |
192 | sslState->client.len); | |
193 | len = read(fd, | |
194 | sslState->client.buf + sslState->client.len, | |
195 | SQUID_TCP_SO_RCVBUF - sslState->client.len); | |
196 | debug(26, 3) ("sslReadClient: FD %d, read %d bytes\n", fd, len); | |
ee1679df | 197 | if (len > 0) { |
adb78bd4 | 198 | fd_bytes(fd, len, FD_READ); |
ee1679df | 199 | kb_incr(&Counter.client_http.kbytes_in, len); |
adb78bd4 | 200 | sslState->client.len += len; |
ee1679df | 201 | } |
adb78bd4 | 202 | cbdataLock(sslState); |
983061ed | 203 | if (len < 0) { |
a3d5953d | 204 | debug(50, 1) ("sslReadClient: FD %d: read failure: %s\n", |
983061ed | 205 | fd, xstrerror()); |
adb78bd4 | 206 | if (!ignoreErrno(errno)) |
207 | comm_close(fd); | |
983061ed | 208 | } else if (len == 0) { |
adb78bd4 | 209 | comm_close(fd); |
983061ed | 210 | } |
adb78bd4 | 211 | if (cbdataValid(sslState)) |
212 | sslSetSelect(sslState); | |
213 | cbdataUnlock(sslState); | |
983061ed | 214 | } |
215 | ||
216 | /* Writes data from the client buffer to the server side */ | |
b8d8561b | 217 | static void |
b177367b | 218 | sslWriteServer(int fd, void *data) |
983061ed | 219 | { |
b177367b | 220 | SslStateData *sslState = data; |
983061ed | 221 | int len; |
adb78bd4 | 222 | assert(fd == sslState->server.fd); |
223 | debug(26, 3) ("sslWriteServer: FD %d, %d bytes to write\n", | |
224 | fd, sslState->client.len); | |
225 | len = write(fd, | |
226 | sslState->client.buf, | |
227 | sslState->client.len); | |
228 | debug(26, 3) ("sslWriteServer: FD %d, %d bytes written\n", fd, len); | |
ee1679df | 229 | if (len > 0) { |
adb78bd4 | 230 | fd_bytes(fd, len, FD_WRITE); |
a0f32775 | 231 | kb_incr(&Counter.server.all.kbytes_out, len); |
232 | kb_incr(&Counter.server.other.kbytes_out, len); | |
adb78bd4 | 233 | assert(len <= sslState->client.len); |
234 | sslState->client.len -= len; | |
235 | if (sslState->client.len > 0) { | |
236 | /* we didn't write the whole thing */ | |
237 | xmemmove(sslState->client.buf, | |
238 | sslState->client.buf + len, | |
239 | sslState->client.len); | |
0a0bf5db | 240 | } |
983061ed | 241 | } |
adb78bd4 | 242 | cbdataLock(sslState); |
243 | if (len < 0) { | |
244 | debug(50, 1) ("sslWriteServer: FD %d: write failure: %s.\n", | |
245 | fd, xstrerror()); | |
246 | if (!ignoreErrno(errno)) | |
247 | comm_close(fd); | |
983061ed | 248 | } |
adb78bd4 | 249 | if (cbdataValid(sslState)) |
250 | sslSetSelect(sslState); | |
251 | cbdataUnlock(sslState); | |
983061ed | 252 | } |
253 | ||
254 | /* Writes data from the server buffer to the client side */ | |
b8d8561b | 255 | static void |
b177367b | 256 | sslWriteClient(int fd, void *data) |
983061ed | 257 | { |
b177367b | 258 | SslStateData *sslState = data; |
983061ed | 259 | int len; |
adb78bd4 | 260 | assert(fd == sslState->client.fd); |
261 | debug(26, 3) ("sslWriteClient: FD %d, %d bytes to write\n", | |
262 | fd, sslState->server.len); | |
263 | len = write(fd, | |
264 | sslState->server.buf, | |
265 | sslState->server.len); | |
266 | debug(26, 3) ("sslWriteClient: FD %d, %d bytes written\n", fd, len); | |
ee1679df | 267 | if (len > 0) { |
adb78bd4 | 268 | fd_bytes(fd, len, FD_WRITE); |
ee1679df | 269 | kb_incr(&Counter.client_http.kbytes_out, len); |
adb78bd4 | 270 | assert(len <= sslState->server.len); |
271 | sslState->server.len -= len; | |
272 | /* increment total object size */ | |
273 | if (sslState->size_ptr) | |
274 | *sslState->size_ptr += len; | |
275 | if (sslState->server.len > 0) { | |
276 | /* we didn't write the whole thing */ | |
277 | xmemmove(sslState->server.buf, | |
278 | sslState->server.buf + len, | |
279 | sslState->server.len); | |
0a0bf5db | 280 | } |
983061ed | 281 | } |
adb78bd4 | 282 | cbdataLock(sslState); |
283 | if (len < 0) { | |
284 | debug(50, 1) ("sslWriteClient: FD %d: write failure: %s.\n", | |
285 | fd, xstrerror()); | |
286 | if (!ignoreErrno(errno)) | |
287 | comm_close(fd); | |
983061ed | 288 | } |
adb78bd4 | 289 | if (cbdataValid(sslState)) |
290 | sslSetSelect(sslState); | |
291 | cbdataUnlock(sslState); | |
983061ed | 292 | } |
293 | ||
b8d8561b | 294 | static void |
5c5783a2 | 295 | sslTimeout(int fd, void *data) |
983061ed | 296 | { |
b177367b | 297 | SslStateData *sslState = data; |
a3d5953d | 298 | debug(26, 3) ("sslTimeout: FD %d\n", fd); |
adb78bd4 | 299 | if (sslState->client.fd > -1) |
300 | comm_close(sslState->client.fd); | |
301 | if (sslState->server.fd > -1) | |
302 | comm_close(sslState->server.fd); | |
983061ed | 303 | } |
304 | ||
b8d8561b | 305 | static void |
b177367b | 306 | sslConnected(int fd, void *data) |
983061ed | 307 | { |
b177367b | 308 | SslStateData *sslState = data; |
a3d5953d | 309 | debug(26, 3) ("sslConnected: FD %d sslState=%p\n", fd, sslState); |
54cff85f | 310 | xstrncpy(sslState->server.buf, conn_established, SQUID_TCP_SO_RCVBUF); |
983061ed | 311 | sslState->server.len = strlen(conn_established); |
adb78bd4 | 312 | sslSetSelect(sslState); |
983061ed | 313 | } |
314 | ||
b8d8561b | 315 | static void |
adb78bd4 | 316 | sslErrorComplete(int fdnotused, void *data, size_t sizenotused) |
30a4f2a8 | 317 | { |
adb78bd4 | 318 | SslStateData *sslState = data; |
9b312a19 | 319 | assert(sslState != NULL); |
adb78bd4 | 320 | if (sslState->client.fd > -1) |
321 | comm_close(sslState->client.fd); | |
322 | if (sslState->server.fd > -1) | |
323 | comm_close(sslState->server.fd); | |
30a4f2a8 | 324 | } |
325 | ||
983061ed | 326 | |
b8d8561b | 327 | static void |
79d39a72 | 328 | sslConnectDone(int fdnotused, int status, void *data) |
983061ed | 329 | { |
b15fe823 | 330 | SslStateData *sslState = data; |
30a4f2a8 | 331 | request_t *request = sslState->request; |
9b312a19 | 332 | ErrorState *err = NULL; |
edeb28fd | 333 | if (status == COMM_ERR_DNS) { |
a3d5953d | 334 | debug(26, 4) ("sslConnect: Unknown host: %s\n", sslState->host); |
fe40a877 | 335 | err = errorCon(ERR_DNS_FAIL, HTTP_NOT_FOUND); |
9b312a19 | 336 | err->request = requestLink(request); |
337 | err->dnsserver_msg = xstrdup(dns_error_message); | |
338 | err->callback = sslErrorComplete; | |
339 | err->callback_data = sslState; | |
340 | errorSend(sslState->client.fd, err); | |
edeb28fd | 341 | } else if (status != COMM_OK) { |
fe40a877 | 342 | err = errorCon(ERR_CONNECT_FAIL, HTTP_SERVICE_UNAVAILABLE); |
c45ed9ad | 343 | err->xerrno = errno; |
9b312a19 | 344 | err->host = xstrdup(sslState->host); |
345 | err->port = sslState->port; | |
346 | err->request = requestLink(request); | |
347 | err->callback = sslErrorComplete; | |
348 | err->callback_data = sslState; | |
349 | errorSend(sslState->client.fd, err); | |
fe40a877 | 350 | } else { |
351 | if (sslState->proxying) | |
352 | sslProxyConnected(sslState->server.fd, sslState); | |
4e3f29eb | 353 | else |
fe40a877 | 354 | sslConnected(sslState->server.fd, sslState); |
1afe05c5 | 355 | commSetTimeout(sslState->server.fd, |
356 | Config.Timeout.read, | |
357 | sslTimeout, | |
358 | sslState); | |
983061ed | 359 | } |
983061ed | 360 | } |
30a4f2a8 | 361 | |
770f051d | 362 | void |
9b312a19 | 363 | sslStart(int fd, const char *url, request_t * request, size_t * size_ptr) |
30a4f2a8 | 364 | { |
365 | /* Create state structure. */ | |
366 | SslStateData *sslState = NULL; | |
367 | int sock; | |
9b312a19 | 368 | ErrorState *err = NULL; |
a3d5953d | 369 | debug(26, 3) ("sslStart: '%s %s'\n", |
30a4f2a8 | 370 | RequestMethodStr[request->method], url); |
a0f32775 | 371 | Counter.server.all.requests++; |
372 | Counter.server.other.requests++; | |
30a4f2a8 | 373 | /* Create socket. */ |
16b204c4 | 374 | sock = comm_open(SOCK_STREAM, |
375 | 0, | |
376 | Config.Addrs.tcp_outgoing, | |
377 | 0, | |
378 | COMM_NONBLOCKING, | |
379 | url); | |
30a4f2a8 | 380 | if (sock == COMM_ERROR) { |
a3d5953d | 381 | debug(26, 4) ("sslStart: Failed because we're out of sockets.\n"); |
fe40a877 | 382 | err = errorCon(ERR_SOCKET_FAILURE, HTTP_INTERNAL_SERVER_ERROR); |
c45ed9ad | 383 | err->xerrno = errno; |
9b312a19 | 384 | err->request = requestLink(request); |
385 | errorSend(fd, err); | |
770f051d | 386 | return; |
30a4f2a8 | 387 | } |
388 | sslState = xcalloc(1, sizeof(SslStateData)); | |
3f6c0fb2 | 389 | cbdataAdd(sslState, MEM_NONE); |
30a4f2a8 | 390 | sslState->url = xstrdup(url); |
391 | sslState->request = requestLink(request); | |
30a4f2a8 | 392 | sslState->size_ptr = size_ptr; |
393 | sslState->client.fd = fd; | |
394 | sslState->server.fd = sock; | |
395 | sslState->server.buf = xmalloc(SQUID_TCP_SO_RCVBUF); | |
396 | sslState->client.buf = xmalloc(SQUID_TCP_SO_RCVBUF); | |
397 | comm_add_close_handler(sslState->server.fd, | |
adb78bd4 | 398 | sslServerClosed, |
cd1fb0eb | 399 | sslState); |
30a4f2a8 | 400 | comm_add_close_handler(sslState->client.fd, |
b177367b | 401 | sslClientClosed, |
cd1fb0eb | 402 | sslState); |
5c5783a2 | 403 | commSetTimeout(sslState->client.fd, |
4f92c80c | 404 | Config.Timeout.lifetime, |
405 | sslTimeout, | |
406 | sslState); | |
cf1edeae | 407 | commSetTimeout(sslState->server.fd, |
408 | Config.Timeout.connect, | |
409 | sslTimeout, | |
410 | sslState); | |
b6c0e933 | 411 | peerSelect(request, |
641941c0 | 412 | NULL, |
b6c0e933 | 413 | sslPeerSelectComplete, |
414 | sslPeerSelectFail, | |
415 | sslState); | |
adb78bd4 | 416 | /* |
417 | * Disable the client read handler until peer selection is complete | |
418 | * Take control away from client_side.c. | |
419 | */ | |
420 | commSetSelect(sslState->client.fd, COMM_SELECT_READ, NULL, NULL, 0); | |
30a4f2a8 | 421 | } |
98ffb7e4 | 422 | |
b8d8561b | 423 | static void |
b177367b | 424 | sslProxyConnected(int fd, void *data) |
98ffb7e4 | 425 | { |
b177367b | 426 | SslStateData *sslState = data; |
e1e72f06 | 427 | MemBuf mb; |
428 | HttpHeader hdr_out; | |
429 | Packer p; | |
a3d5953d | 430 | debug(26, 3) ("sslProxyConnected: FD %d sslState=%p\n", fd, sslState); |
e1e72f06 | 431 | memBufDefInit(&mb); |
432 | memBufPrintf(&mb, "CONNECT %s HTTP/1.0\r\n", sslState->url); | |
433 | httpBuildRequestHeader(sslState->request, | |
434 | sslState->request, | |
5999b776 | 435 | NULL, /* StoreEntry */ |
e1e72f06 | 436 | &hdr_out, |
437 | sslState->client.fd, | |
5999b776 | 438 | 0); /* flags */ |
e1e72f06 | 439 | packerToMemInit(&p, &mb); |
440 | httpHeaderPackInto(&hdr_out, &p); | |
441 | httpHeaderClean(&hdr_out); | |
442 | packerClean(&p); | |
443 | memBufAppend(&mb, "\r\n", 2); | |
444 | xstrncpy(sslState->client.buf, mb.buf, SQUID_TCP_SO_RCVBUF); | |
445 | debug(26, 3) ("sslProxyConnected: Sending {%s}\n", sslState->client.buf); | |
446 | sslState->client.len = mb.size; | |
e1e72f06 | 447 | memBufClean(&mb); |
86cf9987 | 448 | commSetTimeout(sslState->server.fd, |
449 | Config.Timeout.read, | |
450 | sslTimeout, | |
451 | sslState); | |
adb78bd4 | 452 | sslSetSelect(sslState); |
98ffb7e4 | 453 | } |
33ea9fff | 454 | |
33ea9fff | 455 | static void |
641941c0 | 456 | sslPeerSelectComplete(peer * p, void *data) |
33ea9fff | 457 | { |
458 | SslStateData *sslState = data; | |
459 | request_t *request = sslState->request; | |
deb79f06 | 460 | peer *g = NULL; |
b6c0e933 | 461 | sslState->proxying = p ? 1 : 0; |
462 | sslState->host = p ? p->host : request->host; | |
463 | if (p == NULL) { | |
b3b64e58 | 464 | sslState->port = request->port; |
b6c0e933 | 465 | } else if (p->http_port != 0) { |
466 | sslState->port = p->http_port; | |
40a1495e | 467 | } else if ((g = peerFindByName(p->host))) { |
b3b64e58 | 468 | sslState->port = g->http_port; |
33ea9fff | 469 | } else { |
b3b64e58 | 470 | sslState->port = CACHE_HTTP_PORT; |
33ea9fff | 471 | } |
edeb28fd | 472 | commConnectStart(sslState->server.fd, |
473 | sslState->host, | |
474 | sslState->port, | |
475 | sslConnectDone, | |
33ea9fff | 476 | sslState); |
477 | } | |
b6c0e933 | 478 | |
479 | static void | |
79d39a72 | 480 | sslPeerSelectFail(peer * peernotused, void *data) |
b6c0e933 | 481 | { |
482 | SslStateData *sslState = data; | |
fe40a877 | 483 | ErrorState *err; |
fe40a877 | 484 | err = errorCon(ERR_CANNOT_FORWARD, HTTP_SERVICE_UNAVAILABLE); |
9b312a19 | 485 | err->request = requestLink(sslState->request); |
486 | err->callback = sslErrorComplete; | |
487 | err->callback_data = sslState; | |
488 | errorSend(sslState->client.fd, err); | |
489 | ||
b6c0e933 | 490 | } |