acl/lib_acl/samples/master/multi_proxy/multi_proxy.c

276 lines
7.9 KiB
C

#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include "lib_acl.h"
#include "multi_proxy.h"
#define VSTREAM_PROXY_BACKEND_FLAG 1
#define VSTREAM_PROXY_FRONT_FLAG 2
typedef struct VSTREAM_PROXY_OBJ {
ACL_VSTREAM *stream;
struct VSTREAM_PROXY_OBJ *peer;
int flag;
} VSTREAM_PROXY_OBJ;
/* int values */
int var_proxy_log_level;
int var_proxy_tmout;
int var_proxy_connect_tmout;
int var_proxy_rw_tmout;
int var_proxy_bufsize;
/* bool values */
int var_proxy_debug_request;
int var_proxy_debug_respond;
/* char values */
char *var_proxy_banner;
char *var_proxy_backend_addr;
char *var_proxy_request_file;
char *var_proxy_respond_file;
static ACL_CONFIG_INT_TABLE __conf_int_tab[] = {
{ VAR_PROXY_LOG_LEVEL, DEF_PROXY_LOG_LEVEL, &var_proxy_log_level, 0, 0 },
{ VAR_PROXY_TMOUT, DEF_PROXY_TMOUT, &var_proxy_tmout, 0, 0 },
{ VAR_PROXY_CONNECT_TMOUT, DEF_PROXY_CONNECT_TMOUT, &var_proxy_connect_tmout, 0, 0 },
{ VAR_PROXY_RW_TMOUT, DEF_PROXY_RW_TMOUT, &var_proxy_rw_tmout, 0, 0 },
{ VAR_PROXY_BUFSIZE, DEF_PROXY_BUFSIZE, &var_proxy_bufsize, 0, 0 },
{ 0, 0, 0, 0, 0 },
};
static ACL_CONFIG_BOOL_TABLE __conf_bool_tab[] = {
{ VAR_PROXY_DEBUG_REQUEST, DEF_PROXY_DEBUG_REQUEST, &var_proxy_debug_request },
{ VAR_PROXY_DEBUG_RESPOND, DEF_PROXY_DEBUG_RESPOND, &var_proxy_debug_respond },
{ 0, 0, 0 },
};
static ACL_CONFIG_STR_TABLE __conf_str_tab[] = {
{ VAR_PROXY_BANNER, DEF_PROXY_BANNER, &var_proxy_banner },
{ VAR_PROXY_BACKEND_ADDR, DEF_PROXY_BACKEND_ADDR, &var_proxy_backend_addr },
{ VAR_PROXY_REQUEST_FILE, DEF_PROXY_REQUEST_FILE, &var_proxy_request_file },
{ VAR_PROXY_RESPOND_FILE, DEF_PROXY_RESPOND_FILE, &var_proxy_respond_file },
{ 0, 0, 0 },
};
static char *__data_buf;
static ACL_VSTREAM *__request_stream;
static ACL_VSTREAM *__respond_stream;
static void __pre_disconnect_fn(ACL_VSTREAM *stream,
char *name acl_unused, char **argv acl_unused)
{
char myname[] = "__pre_disconnect_fn";
VSTREAM_PROXY_OBJ *vpobj, *peer;
if (stream == NULL) {
acl_msg_error("%s(%d)->%s: stream null",
__FILE__, __LINE__, myname);
return;
}
vpobj = (VSTREAM_PROXY_OBJ *) stream->context;
if (vpobj == NULL) {
acl_msg_error("%s(%d)->%s: stream's context null",
__FILE__, __LINE__, myname);
return;
}
peer = vpobj->peer;
if (peer == NULL) {
; /* do nothing */
} else if (peer->stream == NULL) {
acl_msg_error("%s(%d)->%s: peer's stream null",
__FILE__, __LINE__, myname);
} else {
peer->peer = NULL;
acl_multi_server_disconnect(peer->stream);
}
acl_myfree(vpobj);
stream->context = NULL;
}
static void __service(ACL_VSTREAM *stream, char *service, char **argv)
{
char myname[] = "__service";
int n, ret;
VSTREAM_PROXY_OBJ *vpobj, *peer;
/*
* Sanity check. This service takes no command-line arguments.
*/
if (argv[0])
acl_msg_fatal("%s(%d)->%s: unexpected command-line argument: %s",
__FILE__, __LINE__, myname, argv[0]);
if (stream == NULL)
acl_msg_fatal("%s(%d)->%s: stream null",
__FILE__, __LINE__, myname);
vpobj = (VSTREAM_PROXY_OBJ *) stream->context;
if (vpobj == NULL)
acl_msg_fatal("%s(%d)->%s: stream's context null",
__FILE__, __LINE__, myname);
if (acl_msg_verbose > 3)
acl_msg_info("%s(%d)->%s: service name = %s, rw_timeout = %d",
__FILE__, __LINE__, myname, service, stream->rw_timeout);
acl_watchdog_pat();
peer = vpobj->peer;
if (peer == NULL || peer->stream == NULL || peer->peer != vpobj) {
acl_multi_server_disconnect(stream);
return;
}
n = acl_vstream_read(stream, __data_buf, var_proxy_bufsize);
if (n == ACL_VSTREAM_EOF) {
acl_multi_server_disconnect(stream);
if (acl_msg_verbose > 3)
acl_msg_info("%s(%d)->%s: read over",
__FILE__, __LINE__, myname);
return;
}
if (vpobj->flag == VSTREAM_PROXY_FRONT_FLAG && __request_stream) {
ret = acl_vstream_writen(__request_stream, __data_buf, n);
if (ret != n) {
acl_msg_error("%s(%d)->%s: writen to %s, serr = %s",
__FILE__, __LINE__, myname,
var_proxy_request_file, strerror(errno));
acl_vstream_close(__request_stream);
__request_stream = NULL;
}
} else if (vpobj->flag == VSTREAM_PROXY_BACKEND_FLAG && __respond_stream) {
ret = acl_vstream_writen(__respond_stream, __data_buf, n);
if (ret != n) {
acl_msg_error("%s(%d)->%s: writen to %s, serr = %s",
__FILE__, __LINE__, myname,
var_proxy_request_file, strerror(errno));
acl_vstream_close(__respond_stream);
__respond_stream = NULL;
}
}
ret = acl_vstream_writen(peer->stream, __data_buf, n);
if (ret != n) {
acl_multi_server_disconnect(peer->stream);
if (acl_msg_verbose > 3)
acl_msg_info("%s(%d)->%s: write error = %s",
__FILE__, __LINE__, myname,
strerror(errno));
return;
}
}
static int __on_accept_fn(ACL_VSTREAM *front_stream)
{
char myname[] = "__on_accept_fn";
ACL_VSTREAM *backend_stream;
VSTREAM_PROXY_OBJ *backend_obj;
VSTREAM_PROXY_OBJ *front_obj;
backend_stream = acl_vstream_connect(var_proxy_backend_addr,
ACL_BLOCKING,
var_proxy_connect_tmout,
var_proxy_rw_tmout,
var_proxy_bufsize);
if (backend_stream == NULL) {
acl_msg_error("%s(%d)->%s: connect backend_addr = %s, serr = %s",
__FILE__, __LINE__, myname,
var_proxy_backend_addr, strerror(errno));
return (-1);
}
backend_obj = acl_mymalloc(sizeof(VSTREAM_PROXY_OBJ));
front_obj = acl_mymalloc(sizeof(VSTREAM_PROXY_OBJ));
backend_obj->stream = backend_stream;
backend_obj->flag = VSTREAM_PROXY_BACKEND_FLAG;
backend_obj->peer = front_obj;
backend_stream->context = (void *) backend_obj;
front_obj->stream = front_stream;
front_obj->flag = VSTREAM_PROXY_FRONT_FLAG;
front_obj->peer = backend_obj;
front_stream->context = (void *) front_obj;
acl_multi_server_enable_read(backend_stream);
return (0);
}
static void __pre_jail_init_fn(char *name acl_unused, char **argv acl_unused)
{
char myname[] = "__pre_jail_init_fn";
if (acl_msg_verbose)
acl_msg_info("%s(%d)->%s: test only",
__FILE__, __LINE__, myname);
}
static void __post_jail_init_fn(char *name acl_unused, char **argv acl_unused)
{
char myname[] = "__post_jail_init_fn";
ACL_VSTRING *why = acl_vstring_alloc(100);
if (acl_msg_verbose)
acl_msg_info("%s(%d)->%s: test only",
__FILE__, __LINE__, myname);
__data_buf = acl_mymalloc(var_proxy_bufsize);
if (__data_buf == NULL)
acl_msg_fatal("%s(%d)->%s: malloc data_buf, serr = %s",
__FILE__, __LINE__, myname,
strerror(errno));
if (var_proxy_debug_request) {
__request_stream = acl_safe_open(var_proxy_request_file,
O_CREAT | O_RDWR | O_APPEND, 0600,
(struct stat *) 0, (uid_t)-1,
(uid_t )-1, why);
if (__request_stream == NULL)
acl_msg_fatal("%s(%d)->%s: can't open %s, err = %s",
__FILE__, __LINE__, myname,
var_proxy_request_file, acl_vstring_str(why));
}
if (var_proxy_debug_respond) {
__respond_stream = acl_safe_open(var_proxy_respond_file,
O_CREAT | O_RDWR | O_APPEND, 0600,
(struct stat *) 0, (uid_t)-1,
(uid_t )-1, why);
if (__respond_stream == NULL)
acl_msg_fatal("%s(%d)->%s: can't open %s, err = %s",
__FILE__, __LINE__, myname,
var_proxy_respond_file, acl_vstring_str(why));
}
acl_vstring_free(why);
}
int main(int argc, char *argv[])
{
acl_msg_verbose = 0;
acl_msg_info("%s: start...", __FILE__);
printf("%s: starting...", __FILE__);
acl_multi_server_main(argc, argv, __service,
ACL_MASTER_SERVER_INT_TABLE, __conf_int_tab,
ACL_MASTER_SERVER_BOOL_TABLE, __conf_bool_tab,
ACL_MASTER_SERVER_STR_TABLE, __conf_str_tab,
ACL_MASTER_SERVER_PRE_INIT, __pre_jail_init_fn,
ACL_MASTER_SERVER_POST_INIT, __post_jail_init_fn,
ACL_MASTER_SERVER_ON_ACCEPT, __on_accept_fn,
ACL_MASTER_SERVER_ON_CLOSE, __pre_disconnect_fn,
0);
exit (0);
}