]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/serf/context.c
amd64: use register macros for gdb_cpu_getreg()
[FreeBSD/FreeBSD.git] / contrib / serf / context.c
1 /* ====================================================================
2  *    Licensed to the Apache Software Foundation (ASF) under one
3  *    or more contributor license agreements.  See the NOTICE file
4  *    distributed with this work for additional information
5  *    regarding copyright ownership.  The ASF licenses this file
6  *    to you under the Apache License, Version 2.0 (the
7  *    "License"); you may not use this file except in compliance
8  *    with the License.  You may obtain a copy of the License at
9  *
10  *      http://www.apache.org/licenses/LICENSE-2.0
11  *
12  *    Unless required by applicable law or agreed to in writing,
13  *    software distributed under the License is distributed on an
14  *    "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15  *    KIND, either express or implied.  See the License for the
16  *    specific language governing permissions and limitations
17  *    under the License.
18  * ====================================================================
19  */
20
21 #include <apr_pools.h>
22 #include <apr_poll.h>
23 #include <apr_version.h>
24
25 #include "serf.h"
26 #include "serf_bucket_util.h"
27
28 #include "serf_private.h"
29
30 /**
31  * Callback function (implements serf_progress_t). Takes a number of bytes
32  * read @a read and bytes written @a written, adds those to the total for this
33  * context and notifies an interested party (if any).
34  */
35 void serf__context_progress_delta(
36     void *progress_baton,
37     apr_off_t read,
38     apr_off_t written)
39 {
40     serf_context_t *ctx = progress_baton;
41
42     ctx->progress_read += read;
43     ctx->progress_written += written;
44
45     if (ctx->progress_func)
46         ctx->progress_func(ctx->progress_baton,
47                            ctx->progress_read,
48                            ctx->progress_written);
49 }
50
51
52 /* Check for dirty connections and update their pollsets accordingly. */
53 static apr_status_t check_dirty_pollsets(serf_context_t *ctx)
54 {
55     int i;
56
57     /* if we're not dirty, return now. */
58     if (!ctx->dirty_pollset) {
59         return APR_SUCCESS;
60     }
61
62     for (i = ctx->conns->nelts; i--; ) {
63         serf_connection_t *conn = GET_CONN(ctx, i);
64         apr_status_t status;
65
66         /* if this connection isn't dirty, skip it. */
67         if (!conn->dirty_conn) {
68             continue;
69         }
70
71         /* reset this connection's flag before we update. */
72         conn->dirty_conn = 0;
73
74         if ((status = serf__conn_update_pollset(conn)) != APR_SUCCESS)
75             return status;
76     }
77
78     /* reset our context flag now */
79     ctx->dirty_pollset = 0;
80
81     return APR_SUCCESS;
82 }
83
84
85 static apr_status_t pollset_add(void *user_baton,
86                                 apr_pollfd_t *pfd,
87                                 void *serf_baton)
88 {
89     serf_pollset_t *s = (serf_pollset_t*)user_baton;
90     pfd->client_data = serf_baton;
91     return apr_pollset_add(s->pollset, pfd);
92 }
93
94 static apr_status_t pollset_rm(void *user_baton,
95                                apr_pollfd_t *pfd,
96                                void *serf_baton)
97 {
98     serf_pollset_t *s = (serf_pollset_t*)user_baton;
99     pfd->client_data = serf_baton;
100     return apr_pollset_remove(s->pollset, pfd);
101 }
102
103
104 void serf_config_proxy(serf_context_t *ctx,
105                        apr_sockaddr_t *address)
106 {
107     ctx->proxy_address = address;
108 }
109
110
111 void serf_config_credentials_callback(serf_context_t *ctx,
112                                       serf_credentials_callback_t cred_cb)
113 {
114     ctx->cred_cb = cred_cb;
115 }
116
117
118 void serf_config_authn_types(serf_context_t *ctx,
119                              int authn_types)
120 {
121     ctx->authn_types = authn_types;
122 }
123
124
125 serf_context_t *serf_context_create_ex(
126     void *user_baton,
127     serf_socket_add_t addf,
128     serf_socket_remove_t rmf,
129     apr_pool_t *pool)
130 {
131     serf_context_t *ctx = apr_pcalloc(pool, sizeof(*ctx));
132
133     ctx->pool = pool;
134
135     if (user_baton != NULL) {
136         ctx->pollset_baton = user_baton;
137         ctx->pollset_add = addf;
138         ctx->pollset_rm = rmf;
139     }
140     else {
141         /* build the pollset with a (default) number of connections */
142         serf_pollset_t *ps = apr_pcalloc(pool, sizeof(*ps));
143
144         /* ### TODO: As of APR 1.4.x apr_pollset_create_ex can return a status
145            ### other than APR_SUCCESS, so we should handle it.
146            ### Probably move creation of the pollset to later when we have
147            ### the possibility of returning status to the caller.
148          */
149 #ifdef BROKEN_WSAPOLL
150         /* APR 1.4.x switched to using WSAPoll() on Win32, but it does not
151          * properly handle errors on a non-blocking sockets (such as
152          * connecting to a server where no listener is active).
153          *
154          * So, sadly, we must force using select() on Win32.
155          *
156          * http://mail-archives.apache.org/mod_mbox/apr-dev/201105.mbox/%3CBANLkTin3rBCecCBRvzUA5B-14u-NWxR_Kg@mail.gmail.com%3E
157          */
158         (void) apr_pollset_create_ex(&ps->pollset, MAX_CONN, pool, 0,
159                                      APR_POLLSET_SELECT);
160 #else
161         (void) apr_pollset_create(&ps->pollset, MAX_CONN, pool, 0);
162 #endif
163         ctx->pollset_baton = ps;
164         ctx->pollset_add = pollset_add;
165         ctx->pollset_rm = pollset_rm;
166     }
167
168     /* default to a single connection since that is the typical case */
169     ctx->conns = apr_array_make(pool, 1, sizeof(serf_connection_t *));
170
171     /* Initialize progress status */
172     ctx->progress_read = 0;
173     ctx->progress_written = 0;
174
175     ctx->authn_types = SERF_AUTHN_ALL;
176     ctx->server_authn_info = apr_hash_make(pool);
177
178     return ctx;
179 }
180
181
182 serf_context_t *serf_context_create(apr_pool_t *pool)
183 {
184     return serf_context_create_ex(NULL, NULL, NULL, pool);
185 }
186
187 apr_status_t serf_context_prerun(serf_context_t *ctx)
188 {
189     apr_status_t status = APR_SUCCESS;
190     if ((status = serf__open_connections(ctx)) != APR_SUCCESS)
191         return status;
192
193     if ((status = check_dirty_pollsets(ctx)) != APR_SUCCESS)
194         return status;
195     return status;
196 }
197
198
199 apr_status_t serf_event_trigger(
200     serf_context_t *s,
201     void *serf_baton,
202     const apr_pollfd_t *desc)
203 {
204     apr_pollfd_t tdesc = { 0 };
205     apr_status_t status = APR_SUCCESS;
206     serf_io_baton_t *io = serf_baton;
207
208     if (io->type == SERF_IO_CONN) {
209         serf_connection_t *conn = io->u.conn;
210         serf_context_t *ctx = conn->ctx;
211
212         /* If this connection has already failed, return the error again, and try
213          * to remove it from the pollset again
214          */
215         if (conn->status) {
216             tdesc.desc_type = APR_POLL_SOCKET;
217             tdesc.desc.s = conn->skt;
218             tdesc.reqevents = conn->reqevents;
219             ctx->pollset_rm(ctx->pollset_baton,
220                             &tdesc, &conn->baton);
221             return conn->status;
222         }
223         /* apr_pollset_poll() can return a conn multiple times... */
224         if ((conn->seen_in_pollset & desc->rtnevents) != 0 ||
225             (conn->seen_in_pollset & APR_POLLHUP) != 0) {
226             return APR_SUCCESS;
227         }
228
229         conn->seen_in_pollset |= desc->rtnevents;
230
231         if ((conn->status = serf__process_connection(conn,
232                                          desc->rtnevents)) != APR_SUCCESS) {
233
234             /* it's possible that the connection was already reset and thus the
235                socket cleaned up. */
236             if (conn->skt) {
237                 tdesc.desc_type = APR_POLL_SOCKET;
238                 tdesc.desc.s = conn->skt;
239                 tdesc.reqevents = conn->reqevents;
240                 ctx->pollset_rm(ctx->pollset_baton,
241                                 &tdesc, &conn->baton);
242             }
243             return conn->status;
244         }
245     }
246     else if (io->type == SERF_IO_LISTENER) {
247         serf_listener_t *l = io->u.listener;
248
249         status = serf__process_listener(l);
250
251         if (status) {
252             return status;
253         }
254     }
255     else if (io->type == SERF_IO_CLIENT) {
256         serf_incoming_t *c = io->u.client;
257
258         status = serf__process_client(c, desc->rtnevents);
259
260         if (status) {
261             return status;
262         }
263     }
264     return status;
265 }
266
267
268 apr_status_t serf_context_run(
269     serf_context_t *ctx,
270     apr_short_interval_time_t duration,
271     apr_pool_t *pool)
272 {
273     apr_status_t status;
274     apr_int32_t num;
275     const apr_pollfd_t *desc;
276     serf_pollset_t *ps = (serf_pollset_t*)ctx->pollset_baton;
277
278     if ((status = serf_context_prerun(ctx)) != APR_SUCCESS) {
279         return status;
280     }
281
282     if ((status = apr_pollset_poll(ps->pollset, duration, &num,
283                                    &desc)) != APR_SUCCESS) {
284         /* EINTR indicates a handled signal happened during the poll call,
285            ignore, the application can safely retry. */
286         if (APR_STATUS_IS_EINTR(status))
287             return APR_SUCCESS;
288
289         /* ### do we still need to dispatch stuff here?
290            ### look at the potential return codes. map to our defined
291            ### return values? ...
292         */
293
294         /* Use the strict documented error for poll timeouts, to allow proper
295            handling of the other timeout types when returned from
296            serf_event_trigger */
297         if (APR_STATUS_IS_TIMEUP(status))
298             return APR_TIMEUP; /* Return the documented error */
299         return status;
300     }
301
302     while (num--) {
303         serf_io_baton_t *io  = desc->client_data;
304
305         status = serf_event_trigger(ctx, io, desc);
306         if (status) {
307             return status;
308         }
309
310         desc++;
311     }
312
313     return APR_SUCCESS;
314 }
315
316
317 void serf_context_set_progress_cb(
318     serf_context_t *ctx,
319     const serf_progress_t progress_func,
320     void *progress_baton)
321 {
322     ctx->progress_func = progress_func;
323     ctx->progress_baton = progress_baton;
324 }
325
326
327 serf_bucket_t *serf_context_bucket_socket_create(
328     serf_context_t *ctx,
329     apr_socket_t *skt,
330     serf_bucket_alloc_t *allocator)
331 {
332     serf_bucket_t *bucket = serf_bucket_socket_create(skt, allocator);
333
334     /* Use serf's default bytes read/written callback */
335     serf_bucket_socket_set_read_progress_cb(bucket,
336                                             serf__context_progress_delta,
337                                             ctx);
338
339     return bucket;
340 }
341
342
343 /* ### this really ought to go somewhere else, but... meh.  */
344 void serf_lib_version(int *major, int *minor, int *patch)
345 {
346     *major = SERF_MAJOR_VERSION;
347     *minor = SERF_MINOR_VERSION;
348     *patch = SERF_PATCH_VERSION;
349 }
350
351
352 const char *serf_error_string(apr_status_t errcode)
353 {
354     switch (errcode)
355     {
356     case SERF_ERROR_CLOSING:
357         return "The connection is closing";
358     case SERF_ERROR_REQUEST_LOST:
359         return "A request has been lost";
360     case SERF_ERROR_WAIT_CONN:
361         return "The connection is blocked, pending further action";
362     case SERF_ERROR_DECOMPRESSION_FAILED:
363         return "An error occurred during decompression";
364     case SERF_ERROR_BAD_HTTP_RESPONSE:
365         return "The server sent an improper HTTP response";
366     case SERF_ERROR_TRUNCATED_HTTP_RESPONSE:
367         return "The server sent a truncated HTTP response body.";
368     case SERF_ERROR_ABORTED_CONNECTION:
369         return "The server unexpectedly closed the connection.";
370     case SERF_ERROR_SSL_COMM_FAILED:
371         return "An error occurred during SSL communication";
372     case SERF_ERROR_SSL_CERT_FAILED:
373         return "An SSL certificate related error occurred ";
374     case SERF_ERROR_AUTHN_FAILED:
375         return "An error occurred during authentication";
376     case SERF_ERROR_AUTHN_NOT_SUPPORTED:
377         return "The requested authentication type(s) are not supported";
378     case SERF_ERROR_AUTHN_MISSING_ATTRIBUTE:
379         return "An authentication attribute is missing";
380     case SERF_ERROR_AUTHN_INITALIZATION_FAILED:
381         return "Initialization of an authentication type failed";
382     case SERF_ERROR_SSLTUNNEL_SETUP_FAILED:
383         return "The proxy server returned an error while setting up the "
384                "SSL tunnel.";
385     default:
386         return NULL;
387     }
388
389     /* NOTREACHED  */
390 }