#define CORE_PRIVATE
#include "httpd.h"
#include "http_config.h"
#include "http_core.h"
#include "http_log.h"
#include "http_main.h"
#include "http_protocol.h"
#include "http_request.h"
#include "util_script.h"
#include "http_connection.h"
#include "ap_config.h"
#include "ap_regex.h"
#include "apr_errno.h"
#include "apr_network_io.h"
#include "apr_strings.h"
#define TRBUFF 255
#define APR_SOCK_SR_TEST(insct) \
if(r == APR_SUCCESS){\
insct\
}else if(APR_STATUS_IS_EAGAIN(r)){\
apr_sleep(1000);\
}else if(!APR_STATUS_IS_TIMEUP(r))\
break
#define APR_SOCKET_SEND(__sock,__n,__size,__start,__buff) \
__n = __size-__start;\
r = apr_socket_send(__sock,__buff+__start,&__n);\
APR_SOCK_SR_TEST(\
__start += __n;\
)
static char buffer_hostname[APRMAXHOSTLEN + 1];
static char *mod_ucfwd_hostname=NULL;
static int mod_ucfwd_port=-1;
module AP_MODULE_DECLARE_DATA ucfwd_module;
static void mod_ucfwd_forward(apr_socket_t *sockcl, apr_socket_t *socksrv){
char buff_c[TRBUFF],buff_s[TRBUFF];
apr_size_t n_c,n_s,start_c = TRBUFF,start_s = TRBUFF,size_c = TRBUFF,size_s = TRBUFF;
apr_status_t r;
// Met en non bloquant
apr_socket_opt_set(sockcl, APR_SO_NONBLOCK, 1);
apr_socket_opt_set(socksrv, APR_SO_NONBLOCK, 1);
apr_socket_timeout_set(sockcl, 1000);
apr_socket_timeout_set(socksrv, 1000);
while(1){
// Client => Serveur
if(start_c == size_c){
size_c = TRBUFF;
start_c = 0;
r = apr_socket_recv(sockcl,buff_c,&size_c);
APR_SOCK_SR_TEST(
APR_SOCKET_SEND(socksrv,n_c,size_c,start_c,buff_c);
);
}else{
APR_SOCKET_SEND(socksrv,n_c,size_c,start_c,buff_c);
}
// Serveur => Client
if(start_s == size_s){
size_s = TRBUFF;
start_s = 0;
r = apr_socket_recv(socksrv,buff_s,&size_s);
APR_SOCK_SR_TEST(
APR_SOCKET_SEND(sockcl,n_s,size_s,start_s,buff_s);
);
}else{
APR_SOCKET_SEND(sockcl,n_s,size_s,start_s,buff_s);
}
}
}
static apr_socket_t *mod_ucfwd_connect(request_rec *r){
apr_socket_t *sock=NULL;
apr_status_t ret;
char buffer[255];
apr_sockaddr_t *addr=NULL;
if(mod_ucfwd_port==-1){
fprintf(stderr,"Module mod_ucfwd : Unix socket is not supported yet.\n");
return NULL;
}
// Nouvelle adresse
ret = apr_sockaddr_info_get(&addr,mod_ucfwd_hostname,APR_INET,mod_ucfwd_port,0,r->pool);
if(ret!=APR_SUCCESS){
fprintf(stderr,"Module mod_ucfwd : Adress creation failed : %s\n",apr_strerror(ret,buffer,255));
return NULL;
}
// Nouvelle socket
ret = apr_socket_create (&sock, APR_INET, SOCK_STREAM, APR_PROTO_TCP, r->pool);
if(ret!=APR_SUCCESS){
fprintf(stderr,"Module mod_ucfwd : Socket creation failed : %s\n",apr_strerror(ret,buffer,255));
return NULL;
}
// Connection
ret = apr_socket_connect(sock, addr);
if(ret!=APR_SUCCESS){
fprintf(stderr,"Module mod_ucfwd : Connection failed : %s\n",apr_strerror(ret,buffer,255));
return NULL;
}
return sock;
}
static int mod_ucfwd_performGetRequest(request_rec *r) {
apr_socket_t *socksrv;
apr_socket_t *sockcl;
ap_set_content_type(r, "text/html;charset=utf-8");
if(r->method_number==M_GET){
ap_rprintf(r, "\n"
"
UniComCtrl Connection Forwarder"
"UniComCtrl Connection Forwarder
");
}
if(mod_ucfwd_hostname!=NULL){
if(r->method_number==M_GET){
if(mod_ucfwd_port==-1){
ap_rprintf(r,"Configuration [OK].
Socket : UNIX
Path : %s",mod_ucfwd_hostname);
}else{
ap_rprintf(r,"Configuration [OK].
Socket : TCP
Hostname : %s
Port : %d",
mod_ucfwd_hostname,mod_ucfwd_port);
}
}
socksrv = mod_ucfwd_connect(r);
if(socksrv != NULL){
if(r->method_number==M_GET){
ap_rprintf(r,"Connection [OK].
");
}else{
sockcl = ap_get_module_config(r->connection->conn_config, &core_module);
mod_ucfwd_forward(sockcl,socksrv);
}
}else{
if(r->method_number==M_GET){
ap_rprintf(r,"Connection [!!] (see apache log for more informations).
");
}
}
}else{
if(r->method_number==M_GET){
ap_rprintf(r, "Configuration [!!] (see apache log for more informations).
");
}
}
if(r->method_number==M_GET){
ap_rprintf(r, "");
}
fflush(stderr);
return 0;
}
static int mod_ucfwd_method_handler (request_rec *r)
{
if (!r->handler || strcmp(r->handler, "ucfwd"))
return DECLINED;
switch(r->method_number){
case M_CONNECT:
case M_GET:
mod_ucfwd_performGetRequest(r);
break;
default:
return HTTP_METHOD_NOT_ALLOWED;
}
return OK;
}
static void mod_ucfwd_register_hooks (apr_pool_t *p)
{
ap_hook_handler(mod_ucfwd_method_handler, NULL, NULL, APR_HOOK_LAST);
}
static const char* mod_ucfwd_set_server(cmd_parms *cmd, void* empty, char* server)
{
char *prefix=NULL;
char *portstr=NULL;
int tmp;
apr_size_t nmatch;
ap_regmatch_t *pmatch;
ap_regex_t *regex;
mod_ucfwd_hostname=NULL;
// Decoupage de l'adresse
regex = ap_pregcomp(cmd->pool,"((unix)://)?([^:]+)(:([0-9]+))?",AP_REG_EXTENDED);
if(regex==NULL){
fprintf(stderr,"Module mod_ucfwd : Regular expression \"((unix)://)?([^:]+)(:([0-9]+))?\" could not be compiled.\n");
return mod_ucfwd_hostname=NULL;
}
nmatch = regex->re_nsub+1;
pmatch = apr_palloc(cmd->pool,sizeof(ap_regmatch_t) * nmatch);
if(ap_regexec(regex,server,nmatch,pmatch,0)==AP_REG_NOMATCH){
fprintf(stderr,"Module mod_ucfwd : ModUCFwdServer must be in this format : [unix://]hostname_or_path[:port_number]\n");
return mod_ucfwd_hostname=NULL;
}
// Extraction des trois parties : prefixe, nom et numero de port
if(pmatch[2].rm_so!=-1)
prefix = apr_pstrndup(cmd->pool, server+pmatch[2].rm_so,pmatch[2].rm_eo - pmatch[2].rm_so);
if(pmatch[3].rm_so!=-1){
tmp = pmatch[3].rm_eo-pmatch[3].rm_so;
mod_ucfwd_hostname = strncpy(buffer_hostname,server+pmatch[3].rm_so,tmp>APRMAXHOSTLEN?APRMAXHOSTLEN:tmp);
}
if(pmatch[5].rm_so!=-1)
portstr = apr_pstrndup(cmd->pool, server+pmatch[5].rm_so,pmatch[5].rm_eo-pmatch[5].rm_so);
// Extraction des information et test de conformite (coherence)
mod_ucfwd_port=-1;
if(portstr != NULL)
mod_ucfwd_port = (int)apr_atoi64(portstr);
if(mod_ucfwd_hostname == NULL){
fprintf(stderr,"Module mod_ucfwd : Invalid hostname\n"
"ModUCFwdServer must be in this format : [unix://]hostname_or_path[:port_number]\n");
return mod_ucfwd_hostname=NULL;
}
if(prefix == NULL){
}else if(strcmp(prefix,"unix")==0){
mod_ucfwd_port=-1;
}else{
fprintf(stderr,"Module mod_ucfwd : Invalid prefix\n"
"ModUCFwdServer must be in this format : [unix://]hostname_or_path[:port_number]\n");
return mod_ucfwd_hostname=NULL;
}
return NULL;
}
static const command_rec mod_ucfwd_cmd_tbl[] = {
{ "ModUCFwdServer",
(const char *(*)()) mod_ucfwd_set_server,
NULL,
RSRC_CONF,
TAKE1,
"Server adress in this format : [unix://]hostname_or_path[:port_number]" },
{ NULL }
};
module ucfwd_module =
{
STANDARD20_MODULE_STUFF,
NULL,
NULL,
NULL,
NULL,
mod_ucfwd_cmd_tbl,
mod_ucfwd_register_hooks,
};