[MAJOR] added generic protocol support

A new generic protocol mechanism has been added. It provides
an easy method to implement new protocols with different
listeners (eg: unix sockets).

The listeners are automatically started at the right moment
and enabled after the possible fork().
This commit is contained in:
Willy Tarreau 2007-10-16 12:25:14 +02:00
parent d680371064
commit dd81598553
9 changed files with 271 additions and 16 deletions

View File

@ -226,7 +226,7 @@ LDFLAGS = -g
all: haproxy
OBJS = src/haproxy.o src/sessionhash.o src/base64.o \
OBJS = src/haproxy.o src/sessionhash.o src/base64.o src/protocols.o \
src/uri_auth.o src/standard.o src/buffers.o src/log.o src/task.o \
src/time.o src/fd.o src/regex.o src/cfgparse.o src/server.o \
src/checks.o src/queue.o src/client.o src/proxy.o \

View File

@ -98,7 +98,7 @@ LIBS = $(LIBS.$(TARGET)) $(LIBS.$(REGEX)) $(ADDLIB)
CFLAGS = -Wall $(COPTS) $(DEBUG)
LDFLAGS = -g
OBJS = src/haproxy.o src/sessionhash.o src/base64.o \
OBJS = src/haproxy.o src/sessionhash.o src/base64.o src/protocols.o \
src/uri_auth.o src/standard.o src/buffers.o src/log.o src/task.o \
src/time.o src/fd.o src/regex.o src/cfgparse.o src/server.o \
src/checks.o src/queue.o src/client.o src/proxy.o \

View File

@ -95,7 +95,7 @@ LIBS = $(LIBS.$(TARGET)) $(LIBS.$(REGEX)) $(ADDLIB)
CFLAGS = -Wall $(COPTS) $(DEBUG) -isysroot /Developer/SDKs/MacOSX10.4u.sdk -arch ppc -arch i386
LDFLAGS = -g -isysroot /Developer/SDKs/MacOSX10.4u.sdk -arch ppc -arch i386
OBJS = src/haproxy.o src/sessionhash.o src/base64.o \
OBJS = src/haproxy.o src/sessionhash.o src/base64.o src/protocols.o \
src/uri_auth.o src/standard.o src/buffers.o src/log.o src/task.o \
src/time.o src/fd.o src/regex.o src/cfgparse.o src/server.o \
src/checks.o src/queue.o src/client.o src/proxy.o \

61
include/proto/protocols.h Normal file
View File

@ -0,0 +1,61 @@
/*
include/proto/protocols.h
This file declares generic protocol primitives.
Copyright (C) 2000-2007 Willy Tarreau - w@1wt.eu
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation, version 2.1
exclusively.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef _PROTO_PROTOCOLS_H
#define _PROTO_PROTOCOLS_H
#include <types/protocols.h>
/* Registers the protocol <proto> */
void protocol_register(struct protocol *proto);
/* Unregisters the protocol <proto>. Note that all listeners must have
* previously been unbound.
*/
void protocol_unregister(struct protocol *proto);
/* binds all listeneres of all registered protocols. Returns a composition
* of ERR_NONE, ERR_RETRYABLE, ERR_FATAL.
*/
int protocol_bind_all(void);
/* unbinds all listeners of all registered protocols. They are also closed.
* This must be performed before calling exit() in order to get a chance to
* remove file-system based sockets and pipes.
* Returns a composition of ERR_NONE, ERR_RETRYABLE, ERR_FATAL.
*/
int protocol_unbind_all(void);
/* enables all listeners of all registered protocols. This is intended to be
* used after a fork() to enable reading on all file descriptors. Returns a
* composition of ERR_NONE, ERR_RETRYABLE, ERR_FATAL.
*/
int protocol_enable_all(void);
#endif /* _PROTO_PROTOCOLS_H */
/*
* Local variables:
* c-indent-level: 8
* c-basic-offset: 8
* End:
*/

View File

@ -30,6 +30,7 @@
#include <common/config.h>
#include <types/task.h>
#include <types/buffers.h>
#include <types/protocols.h>
/* different possible states for the fd */
#define FD_STCLOSE 0
@ -66,6 +67,7 @@ struct fdtab {
unsigned char ev; /* event seen in return of poll() : FD_POLL_* */
struct sockaddr *peeraddr; /* pointer to peer's network address, or NULL if unset */
socklen_t peerlen; /* peer's address length, or 0 if unset */
struct listener *listener; /* the listener which created this fd, or NULL if unset */
};
/*

93
include/types/protocols.h Normal file
View File

@ -0,0 +1,93 @@
/*
include/types/protocols.h
This file defines the structures used by generic network protocols.
Copyright (C) 2000-2007 Willy Tarreau - w@1wt.eu
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation, version 2.1
exclusively.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef _TYPES_PROTOCOLS_H
#define _TYPES_PROTOCOLS_H
#include <sys/types.h>
#include <sys/socket.h>
#include <common/config.h>
#include <common/mini-clist.h>
/* max length of a protcol name, including trailing zero */
#define PROTO_NAME_LEN 16
/* return codes for bind_all() */
#define ERR_NONE 0 /* no error */
#define ERR_RETRYABLE 1 /* retryable error, may be cumulated */
#define ERR_FATAL 2 /* fatal error, may be cumulated */
/* listener state */
#define LI_NEW 0 /* not initialized yet */
#define LI_LISTEN 1 /* started, listening but not enabled */
#define LI_READY 2 /* started, listening and enabled */
#define LI_FULL 3 /* reached its connection limit */
/* The listener will be directly referenced by the fdtab[] which holds its
* socket. The listener provides the protocol-specific accept() function to
* the fdtab.
*/
struct listener {
int fd; /* the listen socket */
int state; /* state: NEW, READY, FULL */
struct sockaddr_storage addr; /* the address we listen to */
struct protocol *proto; /* protocol this listener belongs to */
int nbconn; /* current number of connections on this listener */
int maxconn; /* maximum connections allowed on this listener */
struct listener *next; /* next address for the same proxy, or NULL */
struct list proto_list; /* list in the protocol header */
int (*accept)(int fd); /* accept() function passed to fdtab[] */
void (*handler)(struct task *t, struct timeval *next); /* protocol handler */
struct timeval *timeout; /* pointer to client-side timeout */
void *private; /* any private data which may be used by accept() */
};
/* This structure contains all information needed to easily handle a protocol.
* Its primary goal is to ease listeners maintenance. Specifically, the
* bind_all() primitive must be used before any fork(), and the enable_all()
* primitive must be called after the fork() to enable all fds. Last, the
* unbind_all() primitive closes all listeners.
*/
struct protocol {
char name[PROTO_NAME_LEN]; /* protocol name, zero-terminated */
int sock_domain; /* socket domain, as passed to socket() */
int sock_type; /* socket type, as passed to socket() */
int sock_prot; /* socket protocol, as passed to socket() */
sa_family_t sock_family; /* socket family, for sockaddr */
int (*read)(int fd); /* generic read function */
int (*write)(int fd); /* generic write function */
int (*bind_all)(struct protocol *proto); /* bind all unbound listeners */
int (*unbind_all)(struct protocol *proto); /* unbind all bound listeners */
int (*enable_all)(struct protocol *proto); /* enable all bound listeners */
struct list listeners; /* list of listeners using this protocol */
int nb_listeners; /* number of listeners */
struct list list; /* list of registered protocols */
};
#endif /* _TYPES_PROTOCOLS_H */
/*
* Local variables:
* c-indent-level: 8
* c-basic-offset: 8
* End:
*/

View File

@ -37,6 +37,7 @@
#include <types/acl.h>
#include <types/buffers.h>
#include <types/httperr.h>
#include <types/protocols.h>
#include <types/session.h>
#include <types/server.h>
@ -63,18 +64,6 @@
#define PR_CAP_RS 0x0004
#define PR_CAP_LISTEN (PR_CAP_FE|PR_CAP_BE|PR_CAP_RS)
/* return codes for start_proxies */
#define ERR_NONE 0 /* no error */
#define ERR_RETRYABLE 1 /* retryable error, may be cumulated */
#define ERR_FATAL 2 /* fatal error, may be cumulated */
struct listener {
int fd; /* the listen socket */
struct sockaddr_storage addr; /* the address we listen to */
struct listener *next; /* next address or NULL */
};
struct proxy {
struct listener *listen; /* the listen addresses and sockets */
struct in_addr mon_net, mon_mask; /* don't forward connections from this net (network order) FIXME: should support IPv6 */

View File

@ -85,6 +85,7 @@
#include <proto/client.h>
#include <proto/fd.h>
#include <proto/log.h>
#include <proto/protocols.h>
#include <proto/proto_http.h>
#include <proto/proxy.h>
#include <proto/queue.h>
@ -720,7 +721,9 @@ void deinit(void)
p = p->next;
free(p0);
}/* end while(p) */
protocol_unbind_all();
if (global.chroot) free(global.chroot);
global.chroot = NULL;
@ -838,6 +841,14 @@ int main(int argc, char **argv)
exit(1);
}
if (protocol_bind_all() != ERR_NONE) {
Alert("[%s.main()] Some protocols failed to start their listeners! Exiting.\n", argv[0]);
protocol_unbind_all(); /* cleanup everything we can */
if (nb_oldpids)
tell_old_pids(SIGTTIN);
exit(1);
}
/* prepare pause/play signals */
signal(SIGTTOU, sig_pause);
signal(SIGTTIN, sig_listen);
@ -865,6 +876,7 @@ int main(int argc, char **argv)
Alert("[%s.main()] Cannot create pidfile %s\n", argv[0], global.pidfile);
if (nb_oldpids)
tell_old_pids(SIGTTIN);
protocol_unbind_all();
exit(1);
}
pidfile = fdopen(pidfd, "w");
@ -904,6 +916,7 @@ int main(int argc, char **argv)
" Make sure you have enough permissions and that the module is loadable.\n"
" Alternatively, you may disable the 'tcpsplice' options in the configuration.\n"
"", argv[0], global.gid);
protocol_unbind_all();
exit(1);
}
}
@ -919,6 +932,7 @@ int main(int argc, char **argv)
argv[0],
(ret == -1) ? " Incorrect module version.\n"
: " Make sure you have enough permissions and that the module is loaded.\n");
protocol_unbind_all();
exit(1);
}
}
@ -927,6 +941,7 @@ int main(int argc, char **argv)
if ((global.last_checks & LSTCHK_NETADM) && global.uid) {
Alert("[%s.main()] Some configuration options require full privileges, so global.uid cannot be changed.\n"
"", argv[0], global.gid);
protocol_unbind_all();
exit(1);
}
@ -936,6 +951,7 @@ int main(int argc, char **argv)
Alert("[%s.main()] Cannot chroot(%s).\n", argv[0], global.chroot);
if (nb_oldpids)
tell_old_pids(SIGTTIN);
protocol_unbind_all();
exit(1);
}
chdir("/");
@ -951,11 +967,13 @@ int main(int argc, char **argv)
/* setgid / setuid */
if (global.gid && setgid(global.gid) == -1) {
Alert("[%s.main()] Cannot set gid %d.\n", argv[0], global.gid);
protocol_unbind_all();
exit(1);
}
if (global.uid && setuid(global.uid) == -1) {
Alert("[%s.main()] Cannot set uid %d.\n", argv[0], global.uid);
protocol_unbind_all();
exit(1);
}
@ -976,6 +994,7 @@ int main(int argc, char **argv)
ret = fork();
if (ret < 0) {
Alert("[%s.main()] Cannot fork.\n", argv[0]);
protocol_unbind_all();
exit(1); /* there has been an error */
}
else if (ret == 0) /* child breaks here */
@ -1010,6 +1029,7 @@ int main(int argc, char **argv)
fork_poller();
}
protocol_enable_all();
/*
* That's it : the central polling loop. Run until we stop.
*/

90
src/protocols.c Normal file
View File

@ -0,0 +1,90 @@
/*
* Protocol registration functions.
*
* Copyright 2000-2007 Willy Tarreau <w@1wt.eu>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
*
*/
#include <stdio.h>
#include <string.h>
#include <common/config.h>
#include <common/mini-clist.h>
#include <common/standard.h>
#include <types/protocols.h>
/* List head of all registered protocols */
static struct list protocols = LIST_HEAD_INIT(protocols);
/* Registers the protocol <proto> */
void protocol_register(struct protocol *proto)
{
LIST_ADDQ(&protocols, &proto->list);
}
/* Unregisters the protocol <proto>. Note that all listeners must have
* previously been unbound.
*/
void protocol_unregister(struct protocol *proto)
{
LIST_DEL(&proto->list);
LIST_INIT(&proto->list);
}
/* binds all listeneres of all registered protocols. Returns a composition
* of ERR_NONE, ERR_RETRYABLE, ERR_FATAL.
*/
int protocol_bind_all(void)
{
struct protocol *proto;
int err;
err = 0;
list_for_each_entry(proto, &protocols, list) {
if (proto->bind_all)
err |= proto->bind_all(proto);
}
return err;
}
/* unbinds all listeners of all registered protocols. They are also closed.
* This must be performed before calling exit() in order to get a chance to
* remove file-system based sockets and pipes.
* Returns a composition of ERR_NONE, ERR_RETRYABLE, ERR_FATAL.
*/
int protocol_unbind_all(void)
{
struct protocol *proto;
int err;
err = 0;
list_for_each_entry(proto, &protocols, list) {
if (proto->unbind_all)
err |= proto->unbind_all(proto);
}
return err;
}
/* enables all listeners of all registered protocols. This is intended to be
* used after a fork() to enable reading on all file descriptors. Returns a
* composition of ERR_NONE, ERR_RETRYABLE, ERR_FATAL.
*/
int protocol_enable_all(void)
{
struct protocol *proto;
int err;
err = 0;
list_for_each_entry(proto, &protocols, list) {
if (proto->enable_all)
err |= proto->enable_all(proto);
}
return err;
}