main(int unused_argc, char **unused_argv) { VSTRING *raw = vstring_alloc(BUFLEN); VSTRING *hex = vstring_alloc(100); int len; while ((len = read_buf(VSTREAM_IN, raw)) > 0) { hex_quote(hex, STR(raw)); if (hex_unquote(raw, STR(hex)) == 0) msg_fatal("bad input: %.100s", STR(hex)); if (LEN(raw) != len) msg_fatal("len %d != raw len %d", len, LEN(raw)); if (vstream_fwrite(VSTREAM_OUT, STR(raw), LEN(raw)) != LEN(raw)) msg_fatal("write error: %m"); } vstream_fflush(VSTREAM_OUT); vstring_free(raw); vstring_free(hex); return (0); }
static const char *dict_tcp_lookup(DICT *dict, const char *key) { DICT_TCP *dict_tcp = (DICT_TCP *) dict; const char *myname = "dict_tcp_lookup"; int tries; char *start; int last_ch; #define RETURN(errval, result) { dict_errno = errval; return (result); } if (msg_verbose) msg_info("%s: key %s", myname, key); /* * Optionally fold the key. */ if (dict->flags & DICT_FLAG_FOLD_MUL) { if (dict->fold_buf == 0) dict->fold_buf = vstring_alloc(10); vstring_strcpy(dict->fold_buf, key); key = lowercase(vstring_str(dict->fold_buf)); } for (tries = 0; /* see below */ ; /* see below */ ) { /* * Connect to the server, or use an existing connection. */ if (dict_tcp->fp != 0 || dict_tcp_connect(dict_tcp) == 0) { /* * Send request and receive response. Both are %XX quoted and * both are terminated by newline. This encoding is convenient * for data that is mostly text. */ hex_quote(dict_tcp->hex_buf, key); vstream_fprintf(dict_tcp->fp, "get %s\n", STR(dict_tcp->hex_buf)); if (msg_verbose) msg_info("%s: send: get %s", myname, STR(dict_tcp->hex_buf)); last_ch = vstring_get_nonl_bound(dict_tcp->hex_buf, dict_tcp->fp, DICT_TCP_MAXLEN); if (last_ch == '\n') break; /* * Disconnect from the server if it can't talk to us. */ if (last_ch < 0) msg_warn("read TCP map reply from %s: unexpected EOF (%m)", dict_tcp->dict.name); else msg_warn("read TCP map reply from %s: text longer than %d", dict_tcp->dict.name, DICT_TCP_MAXLEN); dict_tcp_disconnect(dict_tcp); } /* * Try to connect a limited number of times before giving up. */ if (++tries >= DICT_TCP_MAXTRY) RETURN(DICT_ERR_RETRY, 0); /* * Sleep between attempts, instead of hammering the server. */ sleep(1); } if (msg_verbose) msg_info("%s: recv: %s", myname, STR(dict_tcp->hex_buf)); /* * Check the general reply syntax. If the reply is malformed, disconnect * and try again later. */ if (start = STR(dict_tcp->hex_buf), !ISDIGIT(start[0]) || !ISDIGIT(start[1]) || !ISDIGIT(start[2]) || !ISSPACE(start[3]) || !hex_unquote(dict_tcp->raw_buf, start + 4)) { msg_warn("read TCP map reply from %s: malformed reply: %.100s", dict_tcp->dict.name, printable(STR(dict_tcp->hex_buf), '_')); dict_tcp_disconnect(dict_tcp); RETURN(DICT_ERR_RETRY, 0); } /* * Examine the reply status code. If the reply is malformed, disconnect * and try again later. */ switch (start[0]) { default: msg_warn("read TCP map reply from %s: bad status code: %.100s", dict_tcp->dict.name, printable(STR(dict_tcp->hex_buf), '_')); dict_tcp_disconnect(dict_tcp); RETURN(DICT_ERR_RETRY, 0); case '4': if (msg_verbose) msg_info("%s: soft error: %s", myname, printable(STR(dict_tcp->hex_buf), '_')); dict_tcp_disconnect(dict_tcp); RETURN(DICT_ERR_RETRY, 0); case '5': if (msg_verbose) msg_info("%s: not found: %s", myname, printable(STR(dict_tcp->hex_buf), '_')); RETURN(DICT_ERR_NONE, 0); case '2': if (msg_verbose) msg_info("%s: found: %s", myname, printable(STR(dict_tcp->raw_buf), '_')); RETURN(DICT_ERR_NONE, STR(dict_tcp->raw_buf)); } }