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.
diff --git a/src/peers.c b/src/peers.c
index 2f93197..04cd046 100644
--- a/src/peers.c
+++ b/src/peers.c
@@ -119,6 +119,12 @@
* 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;
unsigned int updateid;
@@ -131,6 +137,12 @@
struct {
struct shared_table *shared_table;
} ack;
+ struct {
+ unsigned char head[2];
+ } control;
+ struct {
+ unsigned char head[2];
+ } error;
};
/*******************************/
@@ -258,6 +270,61 @@
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.
@@ -658,6 +725,50 @@
}
/*
+ * 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.
* Returns -1 if there was not enough room left to send the message,
@@ -710,8 +821,122 @@
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
* <st> shared stick-table when a lesson must be taught a peer (PEER_F_LEARN_ASSIGN flag set).
*/
@@ -1394,8 +1619,10 @@
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 @@
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 @@
}
}
- /* 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 @@
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 @@
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 @@
/* 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 @@
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 @@
if (curpeer)
HA_SPIN_UNLOCK(PEER_LOCK, &curpeer->lock);
return;
-full:
- si_rx_room_blk(si);
- goto out;
}
static struct applet peer_applet = {