Mercurial > notdcc
diff dcclib/aop.c @ 0:c7f6b056b673
First import of vendor version
author | Peter Gervai <grin@grin.hu> |
---|---|
date | Tue, 10 Mar 2009 13:49:58 +0100 |
parents | |
children |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dcclib/aop.c Tue Mar 10 13:49:58 2009 +0100 @@ -0,0 +1,201 @@ +/* Distributed Checksum Clearinghouse + * + * ask for and administrative operation + * + * Copyright (c) 2008 by Rhyolite Software, LLC + * + * This agreement is not applicable to any entity which sells anti-spam + * solutions to others or provides an anti-spam solution as part of a + * security solution sold to other entities, or to a private network + * which employs the DCC or uses data provided by operation of the DCC + * but does not provide corresponding data to other users. + * + * Permission to use, copy, modify, and distribute this software without + * changes for any purpose with or without fee is hereby granted, provided + * that the above copyright notice and this permission notice appear in all + * copies and any distributed versions or copies are either unchanged + * or not called anything similar to "DCC" or "Distributed Checksum + * Clearinghouse". + * + * Parties not eligible to receive a license under this agreement can + * obtain a commercial license to use DCC by contacting Rhyolite Software + * at sales@rhyolite.com. + * + * A commercial license would be for Distributed Checksum and Reputation + * Clearinghouse software. That software includes additional features. This + * free license for Distributed ChecksumClearinghouse Software does not in any + * way grant permision to use Distributed Checksum and Reputation Clearinghouse + * software + * + * THE SOFTWARE IS PROVIDED "AS IS" AND RHYOLITE SOFTWARE, LLC DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL RHYOLITE SOFTWARE, LLC + * BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES + * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, + * WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, + * ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS + * SOFTWARE. + * + * Rhyolite Software DCC 1.3.103-1.39 $Revision$ + */ + +#include "dcc_clnt.h" + + +/* ask for an administrative operation */ +DCC_OPS /* DCC_OP_INVALID=failed, else result */ +dcc_aop(DCC_EMSG emsg, /* result if DCC_OP_ERROR or _INVALID */ + DCC_CLNT_CTXT *ctxt, + DCC_CLNT_FGS clnt_fgs, /* DCC_CLNT_FG_* */ + SRVR_INX anum, /* server index or NO_SRVR */ + time_t dsecs, /* fudge timestamp by this */ + DCC_AOPS aop, + u_int32_t val1, u_char val2, u_char val3, + u_char val4, u_char *val5, u_int val5_len, + DCC_OP_RESP *resp, + DCC_SOCKU *resp_su) /* IP address of server used */ +{ + DCC_ADMN_REQ req; + DCC_EMSG loc_emsg; + DCC_OP_RESP resp0; + char resp_buf[DCC_OPBUF]; + + memset(&req, 0, sizeof(req)); + req.date = htonl(time(0) + dsecs); + req.aop = aop; + req.val1 = ntohl(val1); + req.val2 = val2; + req.val3 = val3; + req.val4 = val4; + if (val5_len != 0) { + if (val5_len > MAX_DCC_ADMN_REQ_VAL5) + dcc_logbad(EX_SOFTWARE, "bogus aop val5 length %d", + val5_len); + memcpy(req.val5, val5, val5_len); + } + if (!resp) { + resp = &resp0; + } else if (clnt_fgs & DCC_CLNT_FG_RETRANS) { + req.hdr.op_nums.r = resp->hdr.op_nums.r; + } + memset(resp, 0, sizeof(*resp)); + if (!dcc_clnt_op(loc_emsg, ctxt, + clnt_fgs | DCC_CLNT_FG_NO_FAIL, &anum, 0, resp_su, + &req.hdr, sizeof(req)-MAX_DCC_ADMN_REQ_VAL5+val5_len, + DCC_OP_ADMN, + resp, sizeof(*resp))) { + dcc_pemsg(dcc_ex_code, emsg, "%s: %s", + dcc_aop2str(resp_buf, sizeof(resp_buf), aop, val1), + loc_emsg); + return DCC_OP_INVALID; + } + + if (resp->hdr.op == DCC_OP_OK) + return DCC_OP_OK; + if (resp->hdr.op == DCC_OP_ADMN) { + /* clear signature after possible string */ + int len = (ntohs(resp->hdr.len) + - (sizeof(resp->resp) + - sizeof(resp->resp.val.string))); + if (len < ISZ(resp->resp.val.string)) + resp->resp.val.string[len] = '\0'; + return DCC_OP_ADMN; + } + if (resp->hdr.op == DCC_OP_ERROR) { + dcc_pemsg(dcc_ex_code, emsg, "%s: %s", + dcc_aop2str(resp_buf, sizeof(resp_buf), aop, val1), + resp->resp.val.string); + return DCC_OP_ERROR; + } + dcc_pemsg(EX_PROTOCOL, emsg, "%s unexpected response: %s", + dcc_aop2str(0, 0, aop, val1), + dcc_hdr_op2str(resp_buf, sizeof(resp_buf), &resp->hdr)); + return DCC_OP_INVALID; +} + + + +/* try for a long time or until the server hears */ +u_char /* 1=ok, 0=failed */ +dcc_aop_persist(DCC_EMSG emsg, + DCC_CLNT_CTXT *ctxt, + DCC_CLNT_FGS clnt_fgs, + u_char debug, + DCC_AOPS aop, u_int32_t val1, + int secs, /* try for this long */ + DCC_OP_RESP *aop_resp) /* results here */ +{ + struct timeval begin, now, op_start; + char buf1[DCC_OPBUF]; + char buf2[DCC_OPBUF]; + u_char complained, fast; + time_t us; + DCC_OPS result; + + gettimeofday(&begin, 0); + complained = 0; + fast = 0; + + for (;;) { + /* This kludge on the transaction ID makes all of our + * requests appear to be retransmissions of a single request. + * This is nice for operations such as DCC_AOP_FLOD_SHUTDOWN + * that are not idempotent when the server has been stalled by + * the operating system. */ + gettimeofday(&op_start, 0); + + result = dcc_aop(emsg, ctxt, clnt_fgs, NO_SRVR, 0, + aop, val1, 0, 0, 0, 0, 0, aop_resp, 0); + /* finished if that worked */ + if (result == DCC_OP_ADMN || result == DCC_OP_OK) + return 1; + + /* use the same transaction ID next time */ + if (aop_resp) + clnt_fgs |= DCC_CLNT_FG_RETRANS; + + if (result != DCC_OP_ERROR && result != DCC_OP_INVALID) + dcc_pemsg(EX_UNAVAILABLE, emsg, "%s: %s", + dcc_aop2str(buf1, sizeof(buf1), aop, val1), + aop_resp + ? dcc_hdr_op2str(buf2, sizeof(buf2), + &aop_resp->hdr) + : ""); + + /* deal with time change */ + gettimeofday(&now, 0); + us = tv_diff2us(&now, &begin); + if (us < 0) + begin = op_start = now; + + /* eventually give up */ + if (us/DCC_US >= secs) + return 0; + + us = tv_diff2us(&now, &op_start); + if (us >= DCC_US) { + fast = 0; + } else { + /* assume the server is dead if it persistently fails + * immediately */ + if (result == DCC_OP_INVALID && ++fast > 4) { + if (debug) + quiet_trace_msg("%s: assume dccd dead", + dcc_aop2str(buf1, + sizeof(buf1), + aop, val1)); + return 0; + } + /* explicit delay since the request didn't delay */ + usleep(1000); + } + + /* sometimes emit a message if we are going to try again */ + if ((result != DCC_OP_ERROR && result != DCC_OP_INVALID) + && (debug || !complained)) { + complained = 1; + dcc_error_msg("%s", emsg); + emsg[0] = '\0'; + } + } +}