|
Packit |
90a5c9 |
/* Licensed to the Apache Software Foundation (ASF) under one or more
|
|
Packit |
90a5c9 |
* contributor license agreements. See the NOTICE file distributed with
|
|
Packit |
90a5c9 |
* this work for additional information regarding copyright ownership.
|
|
Packit |
90a5c9 |
* The ASF licenses this file to You under the Apache License, Version 2.0
|
|
Packit |
90a5c9 |
* (the "License"); you may not use this file except in compliance with
|
|
Packit |
90a5c9 |
* the License. You may obtain a copy of the License at
|
|
Packit |
90a5c9 |
*
|
|
Packit |
90a5c9 |
* http://www.apache.org/licenses/LICENSE-2.0
|
|
Packit |
90a5c9 |
*
|
|
Packit |
90a5c9 |
* Unless required by applicable law or agreed to in writing, software
|
|
Packit |
90a5c9 |
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
Packit |
90a5c9 |
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
Packit |
90a5c9 |
* See the License for the specific language governing permissions and
|
|
Packit |
90a5c9 |
* limitations under the License.
|
|
Packit |
90a5c9 |
*/
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
#include "httpd.h"
|
|
Packit |
90a5c9 |
#include "http_core.h"
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
#include "util_filter.h"
|
|
Packit |
90a5c9 |
#include "http_log.h"
|
|
Packit |
90a5c9 |
#include "http_config.h"
|
|
Packit |
90a5c9 |
#include "http_request.h"
|
|
Packit |
90a5c9 |
#include "http_protocol.h"
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
#include "ap_mpm.h"
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
module AP_MODULE_DECLARE_DATA dialup_module;
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
typedef struct dialup_dcfg_t {
|
|
Packit |
90a5c9 |
apr_size_t bytes_per_second;
|
|
Packit |
90a5c9 |
} dialup_dcfg_t;
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
typedef struct dialup_baton_t {
|
|
Packit |
90a5c9 |
apr_size_t bytes_per_second;
|
|
Packit |
90a5c9 |
request_rec *r;
|
|
Packit |
90a5c9 |
apr_file_t *fd;
|
|
Packit |
90a5c9 |
apr_bucket_brigade *bb;
|
|
Packit |
90a5c9 |
apr_bucket_brigade *tmpbb;
|
|
Packit |
90a5c9 |
} dialup_baton_t;
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
static int
|
|
Packit |
90a5c9 |
dialup_send_pulse(dialup_baton_t *db)
|
|
Packit |
90a5c9 |
{
|
|
Packit |
90a5c9 |
int status;
|
|
Packit |
90a5c9 |
apr_off_t len = 0;
|
|
Packit |
90a5c9 |
apr_size_t bytes_sent = 0;
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
while (!APR_BRIGADE_EMPTY(db->bb) && bytes_sent < db->bytes_per_second) {
|
|
Packit |
90a5c9 |
apr_bucket *e;
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
if (db->r->connection->aborted) {
|
|
Packit |
90a5c9 |
return HTTP_INTERNAL_SERVER_ERROR;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
status = apr_brigade_partition(db->bb, db->bytes_per_second, &e);
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
if (status != APR_SUCCESS && status != APR_INCOMPLETE) {
|
|
Packit |
90a5c9 |
/* XXXXXX: Log me. */
|
|
Packit |
90a5c9 |
return HTTP_INTERNAL_SERVER_ERROR;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
if (e != APR_BRIGADE_SENTINEL(db->bb)) {
|
|
Packit |
90a5c9 |
apr_bucket *f;
|
|
Packit |
90a5c9 |
apr_bucket *b = APR_BUCKET_PREV(e);
|
|
Packit |
90a5c9 |
f = APR_RING_FIRST(&db->bb->list);
|
|
Packit |
90a5c9 |
APR_RING_UNSPLICE(f, b, link);
|
|
Packit |
90a5c9 |
APR_RING_SPLICE_HEAD(&db->tmpbb->list, f, b, apr_bucket, link);
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
else {
|
|
Packit |
90a5c9 |
APR_BRIGADE_CONCAT(db->tmpbb, db->bb);
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
e = apr_bucket_flush_create(db->r->connection->bucket_alloc);
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
APR_BRIGADE_INSERT_TAIL(db->tmpbb, e);
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
apr_brigade_length(db->tmpbb, 1, &len;;
|
|
Packit |
90a5c9 |
bytes_sent += len;
|
|
Packit |
90a5c9 |
status = ap_pass_brigade(db->r->output_filters, db->tmpbb);
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
apr_brigade_cleanup(db->tmpbb);
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
if (status != APR_SUCCESS) {
|
|
Packit |
90a5c9 |
ap_log_rerror(APLOG_MARK, APLOG_ERR, status, db->r, APLOGNO(01867)
|
|
Packit |
90a5c9 |
"dialup: pulse: ap_pass_brigade failed:");
|
|
Packit |
90a5c9 |
return AP_FILTER_ERROR;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
if (APR_BRIGADE_EMPTY(db->bb)) {
|
|
Packit |
90a5c9 |
return DONE;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
else {
|
|
Packit |
90a5c9 |
return SUSPENDED;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
static void
|
|
Packit |
90a5c9 |
dialup_callback(void *baton)
|
|
Packit |
90a5c9 |
{
|
|
Packit |
90a5c9 |
int status;
|
|
Packit |
90a5c9 |
dialup_baton_t *db = (dialup_baton_t *)baton;
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
apr_thread_mutex_lock(db->r->invoke_mtx);
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
status = dialup_send_pulse(db);
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
if (status == SUSPENDED) {
|
|
Packit |
90a5c9 |
ap_mpm_register_timed_callback(apr_time_from_sec(1), dialup_callback, baton);
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
else if (status == DONE) {
|
|
Packit |
90a5c9 |
apr_thread_mutex_unlock(db->r->invoke_mtx);
|
|
Packit |
90a5c9 |
ap_finalize_request_protocol(db->r);
|
|
Packit |
90a5c9 |
ap_process_request_after_handler(db->r);
|
|
Packit |
90a5c9 |
return;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
else {
|
|
Packit |
90a5c9 |
ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, db->r, APLOGNO(01868)
|
|
Packit |
90a5c9 |
"dialup: pulse returned: %d", status);
|
|
Packit |
90a5c9 |
db->r->status = HTTP_OK;
|
|
Packit |
90a5c9 |
ap_die(status, db->r);
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
apr_thread_mutex_unlock(db->r->invoke_mtx);
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
static int
|
|
Packit |
90a5c9 |
dialup_handler(request_rec *r)
|
|
Packit |
90a5c9 |
{
|
|
Packit |
90a5c9 |
int status;
|
|
Packit |
90a5c9 |
apr_status_t rv;
|
|
Packit |
90a5c9 |
dialup_dcfg_t *dcfg;
|
|
Packit |
90a5c9 |
core_dir_config *ccfg;
|
|
Packit |
90a5c9 |
apr_file_t *fd;
|
|
Packit |
90a5c9 |
dialup_baton_t *db;
|
|
Packit |
90a5c9 |
apr_bucket *e;
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
/* See core.c, default handler for all of the cases we just decline. */
|
|
Packit |
90a5c9 |
if (r->method_number != M_GET ||
|
|
Packit |
90a5c9 |
r->finfo.filetype == APR_NOFILE ||
|
|
Packit |
90a5c9 |
r->finfo.filetype == APR_DIR) {
|
|
Packit |
90a5c9 |
return DECLINED;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
dcfg = ap_get_module_config(r->per_dir_config,
|
|
Packit |
90a5c9 |
&dialup_module);
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
if (dcfg->bytes_per_second == 0) {
|
|
Packit |
90a5c9 |
return DECLINED;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
ccfg = ap_get_core_module_config(r->per_dir_config);
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
rv = apr_file_open(&fd, r->filename, APR_READ | APR_BINARY
|
|
Packit |
90a5c9 |
#if APR_HAS_SENDFILE
|
|
Packit |
90a5c9 |
| AP_SENDFILE_ENABLED(ccfg->enable_sendfile)
|
|
Packit |
90a5c9 |
#endif
|
|
Packit |
90a5c9 |
, 0, r->pool);
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
if (rv) {
|
|
Packit |
90a5c9 |
return DECLINED;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
/* copied from default handler: */
|
|
Packit |
90a5c9 |
ap_update_mtime(r, r->finfo.mtime);
|
|
Packit |
90a5c9 |
ap_set_last_modified(r);
|
|
Packit |
90a5c9 |
ap_set_etag(r);
|
|
Packit |
90a5c9 |
ap_set_accept_ranges(r);
|
|
Packit |
90a5c9 |
ap_set_content_length(r, r->finfo.size);
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
status = ap_meets_conditions(r);
|
|
Packit |
90a5c9 |
if (status != OK) {
|
|
Packit |
90a5c9 |
ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(01869)
|
|
Packit |
90a5c9 |
"dialup: declined, meets conditions, good luck core handler");
|
|
Packit |
90a5c9 |
return DECLINED;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
db = apr_palloc(r->pool, sizeof(dialup_baton_t));
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
db->bb = apr_brigade_create(r->pool, r->connection->bucket_alloc);
|
|
Packit |
90a5c9 |
db->tmpbb = apr_brigade_create(r->pool, r->connection->bucket_alloc);
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
e = apr_brigade_insert_file(db->bb, fd, 0, r->finfo.size, r->pool);
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
#if APR_HAS_MMAP
|
|
Packit |
90a5c9 |
if (ccfg->enable_mmap == ENABLE_MMAP_OFF) {
|
|
Packit |
90a5c9 |
apr_bucket_file_enable_mmap(e, 0);
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
#endif
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
db->bytes_per_second = dcfg->bytes_per_second;
|
|
Packit |
90a5c9 |
db->r = r;
|
|
Packit |
90a5c9 |
db->fd = fd;
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
e = apr_bucket_eos_create(r->connection->bucket_alloc);
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
APR_BRIGADE_INSERT_TAIL(db->bb, e);
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
status = dialup_send_pulse(db);
|
|
Packit |
90a5c9 |
if (status != SUSPENDED && status != DONE) {
|
|
Packit |
90a5c9 |
ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(01870)
|
|
Packit |
90a5c9 |
"dialup: failed, send pulse");
|
|
Packit |
90a5c9 |
return status;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
ap_mpm_register_timed_callback(apr_time_from_sec(1), dialup_callback, db);
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
return SUSPENDED;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
#ifndef APR_HOOK_ALMOST_LAST
|
|
Packit |
90a5c9 |
#define APR_HOOK_ALMOST_LAST (APR_HOOK_REALLY_LAST - 1)
|
|
Packit |
90a5c9 |
#endif
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
static void
|
|
Packit |
90a5c9 |
dialup_register_hooks(apr_pool_t *p)
|
|
Packit |
90a5c9 |
{
|
|
Packit |
90a5c9 |
ap_hook_handler(dialup_handler, NULL, NULL, APR_HOOK_ALMOST_LAST);
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
typedef struct modem_speed_t {
|
|
Packit |
90a5c9 |
const char *name;
|
|
Packit |
90a5c9 |
apr_size_t bytes_per_second;
|
|
Packit |
90a5c9 |
} modem_speed_t;
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
#ifndef BITRATE_TO_BYTES
|
|
Packit |
90a5c9 |
#define BITRATE_TO_BYTES(x) ((1000 * x)/8)
|
|
Packit |
90a5c9 |
#endif
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
static const modem_speed_t modem_bitrates[] =
|
|
Packit |
90a5c9 |
{
|
|
Packit |
90a5c9 |
{"V.21", BITRATE_TO_BYTES(0.1)},
|
|
Packit |
90a5c9 |
{"V.26bis", BITRATE_TO_BYTES(2.4)},
|
|
Packit |
90a5c9 |
{"V.32", BITRATE_TO_BYTES(9.6)},
|
|
Packit |
90a5c9 |
{"V.34", BITRATE_TO_BYTES(28.8)},
|
|
Packit |
90a5c9 |
{"V.92", BITRATE_TO_BYTES(56.0)},
|
|
Packit |
90a5c9 |
{"i-was-rich-and-got-a-leased-line", BITRATE_TO_BYTES(1500)},
|
|
Packit |
90a5c9 |
{NULL, 0}
|
|
Packit |
90a5c9 |
};
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
static const char *
|
|
Packit |
90a5c9 |
cmd_modem_standard(cmd_parms *cmd,
|
|
Packit |
90a5c9 |
void *dconf,
|
|
Packit |
90a5c9 |
const char *input)
|
|
Packit |
90a5c9 |
{
|
|
Packit |
90a5c9 |
const modem_speed_t *standard;
|
|
Packit |
90a5c9 |
int i = 0;
|
|
Packit |
90a5c9 |
dialup_dcfg_t *dcfg = (dialup_dcfg_t*)dconf;
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
dcfg->bytes_per_second = 0;
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
while (modem_bitrates[i].name != NULL) {
|
|
Packit |
90a5c9 |
standard = &modem_bitrates[i];
|
|
Packit |
90a5c9 |
if (strcasecmp(standard->name, input) == 0) {
|
|
Packit |
90a5c9 |
dcfg->bytes_per_second = standard->bytes_per_second;
|
|
Packit |
90a5c9 |
break;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
i++;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
if (dcfg->bytes_per_second == 0) {
|
|
Packit |
90a5c9 |
return "mod_diaulup: Unkonwn Modem Standard specified.";
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
return NULL;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
static void *
|
|
Packit |
90a5c9 |
dialup_dcfg_create(apr_pool_t *p, char *dummy)
|
|
Packit |
90a5c9 |
{
|
|
Packit |
90a5c9 |
dialup_dcfg_t *cfg = apr_palloc(p, sizeof(dialup_dcfg_t));
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
cfg->bytes_per_second = 0;
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
return cfg;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
static const command_rec dialup_cmds[] =
|
|
Packit |
90a5c9 |
{
|
|
Packit |
90a5c9 |
AP_INIT_TAKE1("ModemStandard", cmd_modem_standard, NULL, ACCESS_CONF,
|
|
Packit |
90a5c9 |
"Modem Standard to.. simulate. "
|
|
Packit |
90a5c9 |
"Must be one of: 'V.21', 'V.26bis', 'V.32', 'V.34', or 'V.92'"),
|
|
Packit |
90a5c9 |
{NULL}
|
|
Packit |
90a5c9 |
};
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
AP_DECLARE_MODULE(dialup) =
|
|
Packit |
90a5c9 |
{
|
|
Packit |
90a5c9 |
STANDARD20_MODULE_STUFF,
|
|
Packit |
90a5c9 |
dialup_dcfg_create,
|
|
Packit |
90a5c9 |
NULL,
|
|
Packit |
90a5c9 |
NULL,
|
|
Packit |
90a5c9 |
NULL,
|
|
Packit |
90a5c9 |
dialup_cmds,
|
|
Packit |
90a5c9 |
dialup_register_hooks
|
|
Packit |
90a5c9 |
};
|