MINOR: peers: move error handling to reduce the size of the I/O handler.

Implement new functions to send error and control class stick-table
messages.

May be backported as far as 1.5.
This commit is contained in:
Frdric Lcaille 2019-01-24 14:24:05 +01:00 committed by Willy Tarreau
parent d5fe14bb96
commit 7d0ceeec80

View File

@ -118,6 +118,12 @@ enum {
/*
* Parameters used by functions to build peer protocol messages. */
struct peer_prep_params {
struct {
struct peer *peer;
} hello;
struct {
unsigned int st1;
} error_status;
struct {
struct stksess *stksess;
struct shared_table *shared_table;
@ -131,6 +137,12 @@ struct peer_prep_params {
struct {
struct shared_table *shared_table;
} ack;
struct {
unsigned char head[2];
} control;
struct {
unsigned char head[2];
} error;
};
/*******************************/
@ -258,6 +270,61 @@ uint64_t intdecode(char **str, char *end)
return 0;
}
/*
* Build a "hello" peer protocol message.
* Return the number of written bytes written to build this messages if succeeded,
* 0 if not.
*/
static int peer_prepare_hellomsg(char *msg, size_t size, struct peer_prep_params *p)
{
int min_ver, ret;
struct peer *peer;
peer = p->hello.peer;
min_ver = (peer->flags & PEER_F_DWNGRD) ? PEER_DWNGRD_MINOR_VER : PEER_MINOR_VER;
/* Prepare headers */
ret = snprintf(msg, size, PEER_SESSION_PROTO_NAME " %u.%u\n%s\n%s %d %d\n",
PEER_MAJOR_VER, min_ver, peer->id, localpeer, (int)getpid(), relative_pid);
if (ret >= size)
return 0;
return ret;
}
/*
* Build a "handshake succeeded" status message.
* Return the number of written bytes written to build this messages if succeeded,
* 0 if not.
*/
static int peer_prepare_status_successmsg(char *msg, size_t size, struct peer_prep_params *p)
{
int ret;
ret = snprintf(msg, size, "%d\n", PEER_SESS_SC_SUCCESSCODE);
if (ret >= size)
return 0;
return ret;
}
/*
* Build an error status message.
* Return the number of written bytes written to build this messages if succeeded,
* 0 if not.
*/
static int peer_prepare_status_errormsg(char *msg, size_t size, struct peer_prep_params *p)
{
int ret;
unsigned int st1;
st1 = p->error_status.st1;
ret = snprintf(msg, size, "%d\n", st1);
if (ret >= size)
return 0;
return ret;
}
/* Set the stick-table UPDATE message type byte at <msg_type> address,
* depending on <use_identifier> and <use_timed> boolean parameters.
* Always successful.
@ -657,6 +724,50 @@ static inline int peer_send_msg(struct appctx *appctx,
return ret;
}
/*
* Send a hello message.
* Return 0 if the message could not be built modifying the appcxt st0 to PEER_SESS_ST_END value.
* Returns -1 if there was not enough room left to send the message,
* any other negative returned value must be considered as an error with an appcxt st0
* returned value equal to PEER_SESS_ST_END.
*/
static inline int peer_send_hellomsg(struct appctx *appctx, struct peer *peer)
{
struct peer_prep_params p = {
.hello.peer = peer,
};
return peer_send_msg(appctx, peer_prepare_hellomsg, &p);
}
/*
* Send a success peer handshake status message.
* Return 0 if the message could not be built modifying the appcxt st0 to PEER_SESS_ST_END value.
* Returns -1 if there was not enough room left to send the message,
* any other negative returned value must be considered as an error with an appcxt st0
* returned value equal to PEER_SESS_ST_END.
*/
static inline int peer_send_status_successmsg(struct appctx *appctx)
{
return peer_send_msg(appctx, peer_prepare_status_successmsg, NULL);
}
/*
* Send a peer handshake status error message.
* Return 0 if the message could not be built modifying the appcxt st0 to PEER_SESS_ST_END value.
* Returns -1 if there was not enough room left to send the message,
* any other negative returned value must be considered as an error with an appcxt st0
* returned value equal to PEER_SESS_ST_END.
*/
static inline int peer_send_status_errormsg(struct appctx *appctx)
{
struct peer_prep_params p = {
.error_status.st1 = appctx->st1,
};
return peer_send_msg(appctx, peer_prepare_status_errormsg, &p);
}
/*
* Send a stick-table switch message.
* Return 0 if the message could not be built modifying the appcxt st0 to PEER_SESS_ST_END value.
@ -710,6 +821,120 @@ static inline int peer_send_updatemsg(struct shared_table *st, struct appctx *ap
return peer_send_msg(appctx, peer_prepare_updatemsg, &p);
}
/*
* Build a peer protocol control class message.
* Returns the number of written bytes used to build the message if succeeded,
* 0 if not.
*/
static int peer_prepare_control_msg(char *msg, size_t size, struct peer_prep_params *p)
{
if (size < sizeof p->control.head)
return 0;
msg[0] = p->control.head[0];
msg[1] = p->control.head[1];
return 2;
}
/*
* Send a stick-table synchronization request message.
* Return 0 if the message could not be built modifying the appcxt st0 to PEER_SESS_ST_END value.
* Returns -1 if there was not enough room left to send the message,
* any other negative returned value must be considered as an error with an appctx st0
* returned value equal to PEER_SESS_ST_END.
*/
static inline int peer_send_resync_reqmsg(struct appctx *appctx)
{
struct peer_prep_params p = {
.control.head = { PEER_MSG_CLASS_CONTROL, PEER_MSG_CTRL_RESYNCREQ, },
};
return peer_send_msg(appctx, peer_prepare_control_msg, &p);
}
/*
* Send a stick-table synchronization confirmation message.
* Return 0 if the message could not be built modifying the appcxt st0 to PEER_SESS_ST_END value.
* Returns -1 if there was not enough room left to send the message,
* any other negative returned value must be considered as an error with an appctx st0
* returned value equal to PEER_SESS_ST_END.
*/
static inline int peer_send_resync_confirmsg(struct appctx *appctx)
{
struct peer_prep_params p = {
.control.head = { PEER_MSG_CLASS_CONTROL, PEER_MSG_CTRL_RESYNCCONFIRM, },
};
return peer_send_msg(appctx, peer_prepare_control_msg, &p);
}
/*
* Send a stick-table synchronization finished message.
* Return 0 if the message could not be built modifying the appcxt st0 to PEER_SESS_ST_END value.
* Returns -1 if there was not enough room left to send the message,
* any other negative returned value must be considered as an error with an appctx st0
* returned value equal to PEER_SESS_ST_END.
*/
static inline int peer_send_resync_finishedmsg(struct appctx *appctx, struct peer *peer)
{
struct peer_prep_params p = {
.control.head = { PEER_MSG_CLASS_CONTROL, },
};
p.control.head[1] = (peer->flags & PEERS_RESYNC_STATEMASK) == PEERS_RESYNC_FINISHED ?
PEER_MSG_CTRL_RESYNCFINISHED : PEER_MSG_CTRL_RESYNCPARTIAL;
return peer_send_msg(appctx, peer_prepare_control_msg, &p);
}
/*
* Build a peer protocol error class message.
* Returns the number of written bytes used to build the message if succeeded,
* 0 if not.
*/
static int peer_prepare_error_msg(char *msg, size_t size, struct peer_prep_params *p)
{
if (size < sizeof p->error.head)
return 0;
msg[0] = p->error.head[0];
msg[1] = p->error.head[1];
return 2;
}
/*
* Send a "size limit reached" error message.
* Return 0 if the message could not be built modifying the appcxt st0 to PEER_SESS_ST_END value.
* Returns -1 if there was not enough room left to send the message,
* any other negative returned value must be considered as an error with an appctx st0
* returned value equal to PEER_SESS_ST_END.
*/
static inline int peer_send_error_size_limitmsg(struct appctx *appctx)
{
struct peer_prep_params p = {
.error.head = { PEER_MSG_CLASS_ERROR, PEER_MSG_ERR_SIZELIMIT, },
};
return peer_send_msg(appctx, peer_prepare_error_msg, &p);
}
/*
* Send a "peer protocol" error message.
* Return 0 if the message could not be built modifying the appcxt st0 to PEER_SESS_ST_END value.
* Returns -1 if there was not enough room left to send the message,
* any other negative returned value must be considered as an error with an appctx st0
* returned value equal to PEER_SESS_ST_END.
*/
static inline int peer_send_error_protomsg(struct appctx *appctx)
{
struct peer_prep_params p = {
.error.head = { PEER_MSG_CLASS_ERROR, PEER_MSG_ERR_PROTOCOL, },
};
return peer_send_msg(appctx, peer_prepare_error_msg, &p);
}
/*
* Function used to lookup for recent stick-table updates associated with
@ -1394,8 +1619,10 @@ static void peer_io_handler(struct appctx *appctx)
int prev_state;
/* Check if the input buffer is available. */
if (si_ic(si)->buf.size == 0)
goto full;
if (si_ic(si)->buf.size == 0) {
si_rx_room_blk(si);
goto out;
}
while (1) {
prev_state = appctx->st0;
@ -1527,14 +1754,11 @@ switchstate:
goto switchstate;
}
}
repl = snprintf(trash.area, trash.size,
"%d\n",
PEER_SESS_SC_SUCCESSCODE);
repl = ci_putblk(si_ic(si), trash.area, repl);
repl = peer_send_status_successmsg(appctx);
if (repl <= 0) {
if (repl == -1)
goto full;
appctx->st0 = PEER_SESS_ST_END;
goto out;
goto switchstate;
}
@ -1592,26 +1816,10 @@ switchstate:
}
}
/* Send headers */
repl = snprintf(trash.area, trash.size,
PEER_SESSION_PROTO_NAME " %u.%u\n%s\n%s %d %d\n",
PEER_MAJOR_VER,
(curpeer->flags & PEER_F_DWNGRD) ? PEER_DWNGRD_MINOR_VER : PEER_MINOR_VER,
curpeer->id,
localpeer,
(int)getpid(),
relative_pid);
if (repl >= trash.size) {
appctx->st0 = PEER_SESS_ST_END;
goto switchstate;
}
repl = ci_putblk(si_ic(si), trash.area, repl);
repl = peer_send_hellomsg(appctx, curpeer);
if (repl <= 0) {
if (repl == -1)
goto full;
appctx->st0 = PEER_SESS_ST_END;
goto out;
goto switchstate;
}
@ -1826,21 +2034,14 @@ incomplete:
if ((curpeer->flags & PEER_F_LEARN_ASSIGN) &&
(curpeers->flags & PEERS_F_RESYNC_ASSIGN) &&
!(curpeers->flags & PEERS_F_RESYNC_PROCESS)) {
unsigned char msg[2];
/* Current peer was elected to request a resync */
msg[0] = PEER_MSG_CLASS_CONTROL;
msg[1] = PEER_MSG_CTRL_RESYNCREQ;
/* message to buffer */
repl = ci_putblk(si_ic(si), (char *)msg, sizeof(msg));
repl = peer_send_resync_reqmsg(appctx);
if (repl <= 0) {
/* no more write possible */
if (repl == -1)
goto full;
appctx->st0 = PEER_SESS_ST_END;
goto out;
goto switchstate;
}
curpeers->flags |= PEERS_F_RESYNC_PROCESS;
}
@ -1912,18 +2113,10 @@ incomplete:
if ((curpeer->flags & PEER_F_TEACH_PROCESS) && !(curpeer->flags & PEER_F_TEACH_FINISHED)) {
unsigned char msg[2];
/* Current peer was elected to request a resync */
msg[0] = PEER_MSG_CLASS_CONTROL;
msg[1] = ((curpeers->flags & PEERS_RESYNC_STATEMASK) == PEERS_RESYNC_FINISHED) ? PEER_MSG_CTRL_RESYNCFINISHED : PEER_MSG_CTRL_RESYNCPARTIAL;
/* process final lesson message */
repl = ci_putblk(si_ic(si), (char *)msg, sizeof(msg));
repl = peer_send_resync_finishedmsg(appctx, curpeer);
if (repl <= 0) {
/* no more write possible */
if (repl == -1)
goto full;
appctx->st0 = PEER_SESS_ST_END;
goto out;
goto switchstate;
}
/* flag finished message sent */
@ -1932,19 +2125,10 @@ incomplete:
/* Confirm finished or partial messages */
while (curpeer->confirm) {
unsigned char msg[2];
/* There is a confirm messages to send */
msg[0] = PEER_MSG_CLASS_CONTROL;
msg[1] = PEER_MSG_CTRL_RESYNCCONFIRM;
/* message to buffer */
repl = ci_putblk(si_ic(si), (char *)msg, sizeof(msg));
repl = peer_send_resync_confirmsg(appctx);
if (repl <= 0) {
/* no more write possible */
if (repl == -1)
goto full;
appctx->st0 = PEER_SESS_ST_END;
goto out;
goto switchstate;
}
curpeer->confirm--;
@ -1957,37 +2141,25 @@ incomplete:
if (prev_state == PEER_SESS_ST_WAITMSG)
HA_ATOMIC_SUB(&connected_peers, 1);
prev_state = appctx->st0;
repl = snprintf(trash.area, trash.size,
"%d\n", appctx->st1);
if (ci_putblk(si_ic(si), trash.area, repl) == -1)
goto full;
if (peer_send_status_errormsg(appctx) == -1)
goto out;
appctx->st0 = PEER_SESS_ST_END;
goto switchstate;
case PEER_SESS_ST_ERRSIZE: {
unsigned char msg[2];
if (prev_state == PEER_SESS_ST_WAITMSG)
HA_ATOMIC_SUB(&connected_peers, 1);
prev_state = appctx->st0;
msg[0] = PEER_MSG_CLASS_ERROR;
msg[1] = PEER_MSG_ERR_SIZELIMIT;
if (ci_putblk(si_ic(si), (char *)msg, sizeof(msg)) == -1)
goto full;
if (peer_send_error_size_limitmsg(appctx) == -1)
goto out;
appctx->st0 = PEER_SESS_ST_END;
goto switchstate;
}
case PEER_SESS_ST_ERRPROTO: {
unsigned char msg[2];
if (prev_state == PEER_SESS_ST_WAITMSG)
HA_ATOMIC_SUB(&connected_peers, 1);
prev_state = appctx->st0;
msg[0] = PEER_MSG_CLASS_ERROR;
msg[1] = PEER_MSG_ERR_PROTOCOL;
if (ci_putblk(si_ic(si), (char *)msg, sizeof(msg)) == -1)
goto full;
if (peer_send_error_protomsg(appctx) == -1)
goto out;
appctx->st0 = PEER_SESS_ST_END;
prev_state = appctx->st0;
/* fall through */
@ -2013,9 +2185,6 @@ out:
if (curpeer)
HA_SPIN_UNLOCK(PEER_LOCK, &curpeer->lock);
return;
full:
si_rx_room_blk(si);
goto out;
}
static struct applet peer_applet = {