X-Git-Url: https://git.gag.com/?a=blobdiff_plain;f=common-src%2Fprotocol.c;h=932cfc3ceb7011cbe18a31c2cc61d894572c4f30;hb=911bfb4415195b5c0a98b8c957caa8968313fd81;hp=4274e70b3a7a50244bbc1be700b4b014417f1cf9;hpb=1194fb66aa28d9929c3f2bef3cc6c1c3f40a60a4;p=debian%2Famanda diff --git a/common-src/protocol.c b/common-src/protocol.c index 4274e70..932cfc3 100644 --- a/common-src/protocol.c +++ b/common-src/protocol.c @@ -24,32 +24,44 @@ * file named AUTHORS, in the root directory of this distribution. */ /* - * $Id: protocol.c,v 1.39 2006/02/28 16:36:13 martinea Exp $ + * $Id: protocol.c,v 1.45 2006/05/25 17:07:31 martinea Exp $ * * implements amanda protocol */ #include "amanda.h" +#include "conffile.h" #include "event.h" #include "packet.h" #include "security.h" #include "protocol.h" -/*#define PROTO_DEBUG*/ +#define proto_debug(i, ...) do { \ + if ((i) <= debug_protocol) { \ + dbprintf(__VA_ARGS__); \ + } \ +} while (0) /* * Valid actions that can be passed to the state machine */ typedef enum { - A_START, A_TIMEOUT, A_ERROR, A_RCVDATA, A_CONTPEND, A_PENDING, - A_CONTINUE, A_FINISH, A_ABORT -} action_t; + PA_START, + PA_TIMEOUT, + PA_ERROR, + PA_RCVDATA, + PA_CONTPEND, + PA_PENDING, + PA_CONTINUE, + PA_FINISH, + PA_ABORT +} p_action_t; /* * The current state type. States are represented as function * vectors. */ struct proto; -typedef action_t (*pstate_t) P((struct proto *, action_t, pkt_t *)); +typedef p_action_t (*pstate_t)(struct proto *, p_action_t, pkt_t *); /* * This is a request structure that is wrapped around a packet while it @@ -66,26 +78,24 @@ typedef struct proto { time_t origtime; /* orig start time of this request */ time_t curtime; /* time when this attempt started */ int connecttries; /* times we'll retry a connect */ - int reqtries; /* times we'll resend a REQ */ - int acktries; /* times we'll wait for an a ACK */ + int resettries; /* times we'll resend a REQ */ + int reqtries; /* times we'll wait for an a ACK */ pkt_t req; /* the actual wire request */ protocol_sendreq_callback continuation; /* call when req dies/finishes */ void *datap; /* opaque cookie passed to above */ - char *(*conf_fn) P((char *, void *));/* configuration function */ + char *(*conf_fn)(char *, void *); /* configuration function */ } proto_t; -#define CONNECT_TRIES 3 /* num retries after connect errors */ #define CONNECT_WAIT 5 /* secs between connect attempts */ #define ACK_WAIT 10 /* time (secs) to wait for ACK - keep short */ -#define ACK_TRIES 3 /* num retries after ACK_WAIT timeout */ -#define REQ_TRIES 2 /* num restarts (reboot/crash) */ +#define RESET_TRIES 2 /* num restarts (reboot/crash) */ #define CURTIME (time(0) - proto_init_time) /* time relative to start */ /* if no reply in an hour, just forget it */ #define DROP_DEAD_TIME(t) (CURTIME - (t) > (60 * 60)) /* get the size of an array */ -#define ASIZE(arr) (sizeof(arr) / sizeof((arr)[0])) +#define ASIZE(arr) (int)(sizeof(arr) / sizeof((arr)[0])) /* * Initialization time @@ -94,20 +104,17 @@ static time_t proto_init_time; /* local functions */ -#ifdef PROTO_DEBUG -static const char *action2str P((action_t)); -static const char *pstate2str P((pstate_t)); -#endif +static const char *action2str(p_action_t); +static const char *pstate2str(pstate_t); -static void connect_callback P((void *, security_handle_t *, - security_status_t)); -static void connect_wait_callback P((void *)); -static void recvpkt_callback P((void *, pkt_t *, security_status_t)); +static void connect_callback(void *, security_handle_t *, security_status_t); +static void connect_wait_callback(void *); +static void recvpkt_callback(void *, pkt_t *, security_status_t); -static action_t s_sendreq P((proto_t *, action_t, pkt_t *)); -static action_t s_ackwait P((proto_t *, action_t, pkt_t *)); -static action_t s_repwait P((proto_t *, action_t, pkt_t *)); -static void state_machine P((proto_t *, action_t, pkt_t *)); +static p_action_t s_sendreq(proto_t *, p_action_t, pkt_t *); +static p_action_t s_ackwait(proto_t *, p_action_t, pkt_t *); +static p_action_t s_repwait(proto_t *, p_action_t, pkt_t *); +static void state_machine(proto_t *, p_action_t, pkt_t *); /* * ------------------- @@ -118,7 +125,7 @@ static void state_machine P((proto_t *, action_t, pkt_t *)); * Initialize globals. */ void -protocol_init() +protocol_init(void) { proto_init_time = time(NULL); @@ -129,18 +136,18 @@ protocol_init() * for transmission. */ void -protocol_sendreq(hostname, security_driver, conf_fn, req, repwait, continuation, datap) - const char *hostname; - const security_driver_t *security_driver; - char *(*conf_fn) P((char *, void *)); - const char *req; - time_t repwait; - protocol_sendreq_callback continuation; - void *datap; +protocol_sendreq( + const char * hostname, + const security_driver_t * security_driver, + char * (*conf_fn)(char *, void *), + const char * req, + time_t repwait, + protocol_sendreq_callback continuation, + void * datap) { proto_t *p; - p = alloc(sizeof(proto_t)); + p = alloc(SIZEOF(proto_t)); p->state = s_sendreq; p->hostname = stralloc(hostname); p->security_driver = security_driver; @@ -148,11 +155,11 @@ protocol_sendreq(hostname, security_driver, conf_fn, req, repwait, continuation, p->repwait = repwait; p->origtime = CURTIME; /* p->curtime set in the sendreq state */ - p->connecttries = CONNECT_TRIES; - p->reqtries = REQ_TRIES; - p->acktries = ACK_TRIES; + p->connecttries = getconf_int(CNF_CONNECT_TRIES); + p->resettries = RESET_TRIES; + p->reqtries = getconf_int(CNF_REQ_TRIES); p->conf_fn = conf_fn; - pkt_init(&p->req, P_REQ, req); + pkt_init(&p->req, P_REQ, "%s", req); /* * These are here for the caller @@ -163,12 +170,11 @@ protocol_sendreq(hostname, security_driver, conf_fn, req, repwait, continuation, p->continuation = continuation; p->datap = datap; -#ifdef PROTO_DEBUG - dbprintf(("%s: security_connect: host %s -> p %X\n", - debug_prefix_time(": protocol"), hostname, (int)p)); -#endif + proto_debug(1, _("protocol: security_connect: host %s -> p %p\n"), + hostname, p); - security_connect(p->security_driver, p->hostname, conf_fn, connect_callback, p); + security_connect(p->security_driver, p->hostname, conf_fn, connect_callback, + p, p->datap); } /* @@ -180,28 +186,25 @@ protocol_sendreq(hostname, security_driver, conf_fn, req, repwait, continuation, * be had via security_geterror on the handle. */ static void -connect_callback(cookie, security_handle, status) - void *cookie; - security_handle_t *security_handle; - security_status_t status; +connect_callback( + void * cookie, + security_handle_t * security_handle, + security_status_t status) { proto_t *p = cookie; assert(p != NULL); p->security_handle = security_handle; -#ifdef PROTO_DEBUG - dbprintf(("%s: connect_callback: p %X\n", - debug_prefix_time(": protocol"), (int)p)); -#endif + proto_debug(1, _("protocol: connect_callback: p %p\n"), p); switch (status) { case S_OK: - state_machine(p, A_START, NULL); + state_machine(p, PA_START, NULL); break; case S_TIMEOUT: - security_seterror(p->security_handle, "timeout during connect"); + security_seterror(p->security_handle, _("timeout during connect")); /* FALLTHROUGH */ case S_ERROR: @@ -211,12 +214,10 @@ connect_callback(cookie, security_handle, status) * an error back to the caller. */ if (--p->connecttries == 0) { - state_machine(p, A_ABORT, NULL); + state_machine(p, PA_ABORT, NULL); } else { -#ifdef PROTO_DEBUG - dbprintf(("%s: connect_callback: p %X: retrying %s\n", - debug_prefix_time(": protocol"), (int)p, p->hostname)); -#endif + proto_debug(1, _("protocol: connect_callback: p %p: retrying %s\n"), + p, p->hostname); security_close(p->security_handle); /* XXX overload p->security handle to hold the event handle */ p->security_handle = @@ -236,14 +237,14 @@ connect_callback(cookie, security_handle, status) * initial connection attempts failed. */ static void -connect_wait_callback(cookie) - void *cookie; +connect_wait_callback( + void * cookie) { proto_t *p = cookie; event_release((event_handle_t *)p->security_handle); security_connect(p->security_driver, p->hostname, p->conf_fn, - connect_callback, p); + connect_callback, p, p->datap); } @@ -256,7 +257,7 @@ connect_wait_callback(cookie) * requests if they plan on doing a lot of work. */ void -protocol_check() +protocol_check(void) { /* arg == 1 means don't block */ @@ -272,7 +273,7 @@ protocol_check() * and are just waiting for all of the answers to come back. */ void -protocol_run() +protocol_run(void) { /* arg == 0 means block forever until no more events are left */ @@ -291,55 +292,48 @@ protocol_run() * with timeouts and successfull replies. */ static void -state_machine(p, action, pkt) - proto_t *p; - action_t action; - pkt_t *pkt; +state_machine( + proto_t * p, + p_action_t action, + pkt_t * pkt) { pstate_t curstate; - action_t retaction; + p_action_t retaction; -#ifdef PROTO_DEBUG - dbprintf(("%s: state_machine: initial: p %X action %s pkt %X\n", - debug_prefix_time(": protocol"), - (int)p, action2str(action), NULL)); -#endif + proto_debug(1, _("protocol: state_machine: initial: p %p action %s pkt %p\n"), + p, action2str(action), (void *)NULL); assert(p != NULL); - assert(action == A_RCVDATA || pkt == NULL); + assert(action == PA_RCVDATA || pkt == NULL); assert(p->state != NULL); for (;;) { -#ifdef PROTO_DEBUG - dbprintf(("%s: state_machine: p %X state %s action %s\n", - debug_prefix_time(": protocol"), - (int)p, pstate2str(p->state), action2str(action))); + proto_debug(1, _("protocol: state_machine: p %p state %s action %s\n"), + p, pstate2str(p->state), action2str(action)); if (pkt != NULL) { - dbprintf(("%s: pkt: %s (t %d) orig REQ (t %d cur %d)\n", - debug_prefix(": protocol"), - pkt_type2str(pkt->type), (int)CURTIME, - (int)p->origtime, (int)p->curtime)); - dbprintf(("%s: pkt contents:\n-----\n%s-----\n", - debug_prefix(": protocol"), pkt->body)); + proto_debug(1, _("protocol: pkt: %s (t %d) orig REQ (t %d cur %d)\n"), + pkt_type2str(pkt->type), (int)CURTIME, + (int)p->origtime, (int)p->curtime); + proto_debug(1, _("protocol: pkt contents:\n-----\n%s-----\n"), + pkt->body); } -#endif /* * p->state is a function pointer to the current state a request * is in. * * We keep track of the last state we were in so we can make - * sure states which return A_CONTINUE really have transitioned + * sure states which return PA_CONTINUE really have transitioned * the request to a new state. */ curstate = p->state; - if (action == A_ABORT) + if (action == PA_ABORT) /* * If the passed action indicates a terminal error, then we * need to move to abort right away. */ - retaction = A_ABORT; + retaction = PA_ABORT; else /* * Else we run the state and perform the action it @@ -347,15 +341,12 @@ state_machine(p, action, pkt) */ retaction = (*curstate)(p, action, pkt); -#ifdef PROTO_DEBUG - dbprintf(("%s: state_machine: p %X state %s returned %s\n", - debug_prefix_time(": protocol"), - (int)p, pstate2str(p->state), action2str(retaction))); -#endif + proto_debug(1, _("protocol: state_machine: p %p state %s returned %s\n"), + p, pstate2str(p->state), action2str(retaction)); /* * The state function is expected to return one of the following - * action_t's. + * p_action_t's. */ switch (retaction) { @@ -364,37 +355,31 @@ state_machine(p, action, pkt) * Setup to receive another pkt, and wait for the recv event * to occur. */ - case A_CONTPEND: + case PA_CONTPEND: (*p->continuation)(p->datap, pkt, p->security_handle); /* FALLTHROUGH */ - case A_PENDING: -#ifdef PROTO_DEBUG - dbprintf(("%s: state_machine: p %X state %s: timeout %d\n", - debug_prefix_time(": protocol"), - (int)p, pstate2str(p->state), (int)p->timeout)); -#endif + case PA_PENDING: + proto_debug(1, _("protocol: state_machine: p %p state %s: timeout %d\n"), + p, pstate2str(p->state), (int)p->timeout); /* * Get the security layer to register a receive event for this * security handle on our behalf. Have it timeout in p->timeout * seconds. */ security_recvpkt(p->security_handle, recvpkt_callback, p, - p->timeout); + (int)p->timeout); return; /* * Request has moved to another state. Loop and run it again. */ - case A_CONTINUE: + case PA_CONTINUE: assert(p->state != curstate); -#ifdef PROTO_DEBUG - dbprintf(("%s: state_machine: p %X: moved from %s to %s\n", - debug_prefix_time(": protocol"), - (unsigned int)p, pstate2str(curstate), - pstate2str(p->state))); -#endif + proto_debug(1, _("protocol: state_machine: p %p: moved from %s to %s\n"), + p, pstate2str(curstate), + pstate2str(p->state)); continue; /* @@ -403,10 +388,10 @@ state_machine(p, action, pkt) * pkt to NULL to indicate failure to the callback, and then * fall through to the common finish code. * - * Note that remote failures finish via A_FINISH, because they did + * Note that remote failures finish via PA_FINISH, because they did * complete successfully locally. */ - case A_ABORT: + case PA_ABORT: pkt = NULL; /* FALLTHROUGH */ @@ -415,10 +400,11 @@ state_machine(p, action, pkt) * Free up resources the request has used, call the continuation * function specified by the caller and quit. */ - case A_FINISH: + case PA_FINISH: (*p->continuation)(p->datap, pkt, p->security_handle); security_close(p->security_handle); amfree(p->hostname); + amfree(p->req.body); amfree(p); return; @@ -426,9 +412,9 @@ state_machine(p, action, pkt) assert(0); break; /* in case asserts are turned off */ } - /* NOTREACHED */ + /*NOTREACHED*/ } - /* NOTREACHED */ + /*NOTREACHED*/ } /* @@ -437,20 +423,22 @@ state_machine(p, action, pkt) * moves to the acknowledgement wait state. We return from the state * machine at this point, and let the request be received from the network. */ -static action_t -s_sendreq(p, action, pkt) - proto_t *p; - action_t action; - pkt_t *pkt; +static p_action_t +s_sendreq( + proto_t * p, + p_action_t action, + pkt_t * pkt) { assert(p != NULL); + (void)action; /* Quiet unused parameter warning */ + (void)pkt; /* Quiet unused parameter warning */ if (security_sendpkt(p->security_handle, &p->req) < 0) { /* XXX should retry */ - security_seterror(p->security_handle, "error sending REQ: %s", + security_seterror(p->security_handle, _("error sending REQ: %s"), security_geterror(p->security_handle)); - return (A_ABORT); + return (PA_ABORT); } /* @@ -463,27 +451,27 @@ s_sendreq(p, action, pkt) */ p->state = s_ackwait; p->timeout = ACK_WAIT; - return (A_PENDING); + return (PA_PENDING); } /* * The acknowledge wait state. We can enter here two ways: * * - the caller has received a packet, located the request for - * that packet, and called us with an action of A_RCVDATA. + * that packet, and called us with an action of PA_RCVDATA. * * - the caller has determined that a request has timed out, - * and has called us with A_TIMEOUT. + * and has called us with PA_TIMEOUT. * * Here we process the acknowledgment, which usually means that * the client has agreed to our request and is working on it. * It will later send a reply when finished. */ -static action_t -s_ackwait(p, action, pkt) - proto_t *p; - action_t action; - pkt_t *pkt; +static p_action_t +s_ackwait( + proto_t * p, + p_action_t action, + pkt_t * pkt) { assert(p != NULL); @@ -493,19 +481,19 @@ s_ackwait(p, action, pkt) * fail this request. Otherwise, move to the send state * to retry the request. */ - if (action == A_TIMEOUT) { + if (action == PA_TIMEOUT) { assert(pkt == NULL); - if (--p->acktries == 0) { - security_seterror(p->security_handle, "timeout waiting for ACK"); - return (A_ABORT); + if (--p->reqtries == 0) { + security_seterror(p->security_handle, _("timeout waiting for ACK")); + return (PA_ABORT); } p->state = s_sendreq; - return (A_CONTINUE); + return (PA_CONTINUE); } - assert(action == A_RCVDATA); + assert(action == PA_RCVDATA); assert(pkt != NULL); /* @@ -522,16 +510,16 @@ s_ackwait(p, action, pkt) case P_ACK: p->state = s_repwait; p->timeout = p->repwait; - return (A_PENDING); + return (PA_PENDING); /* * Received a NAK. The request failed, so free up the * resources associated with it and return. * - * This should NOT return A_ABORT because it is not a local failure. + * This should NOT return PA_ABORT because it is not a local failure. */ case P_NAK: - return (A_FINISH); + return (PA_FINISH); /* * The client skipped the ACK, and replied right away. @@ -540,53 +528,57 @@ s_ackwait(p, action, pkt) case P_REP: case P_PREP: p->state = s_repwait; - return (A_CONTINUE); + return (PA_CONTINUE); /* * Unexpected packet. Requeue this request and hope * we get what we want later. */ default: - return (A_PENDING); + return (PA_PENDING); } } /* * The reply wait state. We enter here much like we do with s_ackwait. */ -static action_t -s_repwait(p, action, pkt) - proto_t *p; - action_t action; - pkt_t *pkt; +static p_action_t +s_repwait( + proto_t * p, + p_action_t action, + pkt_t * pkt) { pkt_t ack; /* * Timeout waiting for a reply. */ - if (action == A_TIMEOUT) { + if (action == PA_TIMEOUT) { assert(pkt == NULL); /* * If we've blown our timeout limit, free up this packet and * return. */ - if (p->reqtries == 0 || DROP_DEAD_TIME(p->origtime)) { - security_seterror(p->security_handle, "timeout waiting for REP"); - return (A_ABORT); + if (p->resettries == 0 || DROP_DEAD_TIME(p->origtime)) { + security_seterror(p->security_handle, _("timeout waiting for REP")); + return (PA_ABORT); } /* * We still have some tries left. Resend the request. */ - p->reqtries--; + p->resettries--; p->state = s_sendreq; - p->acktries = ACK_TRIES; - return (A_CONTINUE); + p->reqtries = getconf_int(CNF_REQ_TRIES); + return (PA_CONTINUE); } - assert(action == A_RCVDATA); + assert(action == PA_RCVDATA); + + /* Finish if we get a NAK */ + if (pkt->type == P_NAK) + return (PA_FINISH); /* * We've received some data. If we didn't get a reply, @@ -594,35 +586,39 @@ s_repwait(p, action, pkt) * the reply, cleanup this packet, and return. */ if (pkt->type != P_REP && pkt->type != P_PREP) - return (A_PENDING); + return (PA_PENDING); if(pkt->type == P_REP) { - pkt_init(&ack, P_ACK, ""); + pkt_init_empty(&ack, P_ACK); if (security_sendpkt(p->security_handle, &ack) < 0) { /* XXX should retry */ - security_seterror(p->security_handle, "error sending ACK: %s", + amfree(ack.body); + security_seterror(p->security_handle, _("error sending ACK: %s"), security_geterror(p->security_handle)); - return (A_ABORT); + return (PA_ABORT); } - return (A_FINISH); + amfree(ack.body); + return (PA_FINISH); } else if(pkt->type == P_PREP) { p->timeout = p->repwait - CURTIME + p->curtime + 1; - return (A_CONTPEND); + if (p->timeout <= 0) + p->timeout = 1; + return (PA_CONTPEND); } /* should never go here, shut up compiler warning */ - return (A_FINISH); + return (PA_FINISH); } /* * event callback that receives a packet */ static void -recvpkt_callback(cookie, pkt, status) - void *cookie; - pkt_t *pkt; - security_status_t status; +recvpkt_callback( + void * cookie, + pkt_t * pkt, + security_status_t status) { proto_t *p = cookie; @@ -630,13 +626,13 @@ recvpkt_callback(cookie, pkt, status) switch (status) { case S_OK: - state_machine(p, A_RCVDATA, pkt); + state_machine(p, PA_RCVDATA, pkt); break; case S_TIMEOUT: - state_machine(p, A_TIMEOUT, NULL); + state_machine(p, PA_TIMEOUT, NULL); break; case S_ERROR: - state_machine(p, A_ABORT, NULL); + state_machine(p, PA_ABORT, NULL); break; default: assert(0); @@ -649,13 +645,12 @@ recvpkt_callback(cookie, pkt, status) * Misc functions */ -#ifdef PROTO_DEBUG /* * Convert a pstate_t into a printable form. */ static const char * -pstate2str(pstate) - pstate_t pstate; +pstate2str( + pstate_t pstate) { static const struct { pstate_t type; @@ -672,30 +667,30 @@ pstate2str(pstate) for (i = 0; i < ASIZE(pstates); i++) if (pstate == pstates[i].type) return (pstates[i].name); - return ("BOGUS PSTATE"); + return (_("BOGUS PSTATE")); } /* - * Convert an action_t into a printable form + * Convert an p_action_t into a printable form */ static const char * -action2str(action) - action_t action; +action2str( + p_action_t action) { static const struct { - action_t type; + p_action_t type; const char name[12]; } actions[] = { #define X(s) { s, stringize(s) } - X(A_START), - X(A_TIMEOUT), - X(A_ERROR), - X(A_RCVDATA), - X(A_CONTPEND), - X(A_PENDING), - X(A_CONTINUE), - X(A_FINISH), - X(A_ABORT), + X(PA_START), + X(PA_TIMEOUT), + X(PA_ERROR), + X(PA_RCVDATA), + X(PA_CONTPEND), + X(PA_PENDING), + X(PA_CONTINUE), + X(PA_FINISH), + X(PA_ABORT), #undef X }; int i; @@ -703,6 +698,5 @@ action2str(action) for (i = 0; i < ASIZE(actions); i++) if (action == actions[i].type) return (actions[i].name); - return ("BOGUS ACTION"); + return (_("BOGUS ACTION")); } -#endif /* PROTO_DEBUG */