📄 rpc.c
字号:
/* -*- c-file-style: "java"; indent-tabs-mode: nil; fill-column: 78 -*- * * distcc -- A simple distributed compiler system * * Copyright (C) 2002, 2003 by Martin Pool <mbp@samba.org> * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 * USA */ /* 15 Every one that is found shall be thrust * through; and every one that is joined unto * them shall fall by the sword. * -- Isaiah 13 */#include "config.h"#include <stdio.h>#include <stdlib.h>#include <unistd.h>#include <string.h>#include <fcntl.h>#include <errno.h>#include <ctype.h>#include <sys/stat.h>#include "distcc.h"#include "trace.h"#include "exitcode.h"#include "rpc.h"#include "snprintf.h"/** * @file * * Very simple RPC-like layer. Requests and responses are build of * little packets each containing a 4-byte ascii token, an 8-byte hex * value or length, and optionally data corresponding to the length. * * 'x' means transmit, and 'r' means receive. * * This builds on top of io.c and is called by the various routines * that handle communication. **//** * Transmit token name (4 characters) and value (32-bit int, as 8 hex * characters). **/int dcc_x_token_int(int ofd, const char *token, unsigned param){ char buf[13]; int shift; char *p; const char *hex = "0123456789abcdef"; if (strlen(token) != 4) { rs_log_crit("token \"%s\" seems wrong", token); return EXIT_PROTOCOL_ERROR; } memcpy(buf, token, 4); /* Quick and dirty int->hex. The only standard way is to call snprintf * (?), which is undesirably slow for such a frequently-called * function. */ for (shift=28, p = &buf[4]; shift >= 0; shift -= 4, p++) { *p = hex[(param >> shift) & 0xf]; } buf[12] = '\0'; rs_trace("send %s", buf); return dcc_writex(ofd, buf, 12);}/** * Send start of a result: DONE <version> **/int dcc_x_result_header(int ofd, enum dcc_protover protover){ return dcc_x_token_int(ofd, "DONE", protover);}int dcc_x_cc_status(int ofd, int status){ return dcc_x_token_int(ofd, "STAT", (unsigned) status);}int dcc_r_token(int ifd, char *buf){ return dcc_readx(ifd, buf, 4);}/** * We got a mismatch on a token, which indicates either a bug in distcc, or * that somebody (inetd?) is interfering with our network stream, or perhaps * some other network problem. Whatever's happened, a bit more debugging * information would be handy. **/static int dcc_explain_mismatch(const char *buf, size_t buflen, int ifd){ ssize_t ret; char extrabuf[200]; char *p; size_t l; memcpy(extrabuf, buf, buflen); /* Read a bit more context, and find the printable prefix. */ ret = read(ifd, extrabuf + buflen, sizeof extrabuf - 1 - buflen); if (ret == -1) { ret = 0; /* pah, use what we've got */ } l = buflen + ret; extrabuf[l] = '\0'; for (p = extrabuf; *p; p++) if (!(isprint(*p) || *p == ' ' || *p == '\t')) { *p = '\0'; break; } rs_log_error("error context: \"%s\"", extrabuf); return 0; /* i just feel really sad... */}/** * Read a token and value. The receiver always knows what token name * is expected next -- indeed the names are really only there as a * sanity check and to aid debugging. * * @param ifd fd to read from * @param expected 4-char token that is expected to come in next * @param val receives the parameter value **/int dcc_r_token_int(int ifd, const char *expected, unsigned *val){ char buf[13], *bum; int ret; if (strlen(expected) != 4) { rs_log_error("expected token \"%s\" seems wrong", expected); return EXIT_PROTOCOL_ERROR; } if ((ret = dcc_readx(ifd, buf, 12))) { rs_log_error("read failed while waiting for token \"%s\"", expected); return ret; } if (memcmp(buf, expected, 4)) { rs_log_error("protocol derailment: expected token \"%s\"", expected); dcc_explain_mismatch(buf, 12, ifd); return EXIT_PROTOCOL_ERROR; } buf[12] = '\0'; /* terminate */ *val = strtoul(&buf[4], &bum, 16); if (bum != &buf[12]) { rs_log_error("failed to parse parameter of token \"%s\"", expected); dcc_explain_mismatch(buf, 12, ifd); return EXIT_PROTOCOL_ERROR; } rs_trace("got %s", buf); return 0;}/** * Read a byte string of length @p l into a newly allocated buffer, returned in @p buf. **/int dcc_r_str_alloc(int fd, unsigned l, char **buf){ char *s;#if 0 /* never true */ if (l < 0) { rs_log_crit("oops, l < 0"); return EXIT_PROTOCOL_ERROR; }#endif/* rs_trace("read %d byte string", l); */ s = *buf = malloc((size_t) l + 1); if (!s) rs_log_error("malloc failed"); if (dcc_readx(fd, s, (size_t) l)) return EXIT_OUT_OF_MEMORY; s[l] = 0; return 0;}/** * Write a token, and then the string @p buf. * * The length of buf is determined by its nul delimiter, but the \0 is not sent. **/int dcc_x_token_string(int fd, const char *token, const char *buf){ int ret; size_t len; len = strlen(buf); if ((ret = dcc_x_token_int(fd, token, (unsigned) len))) return ret; if ((ret = dcc_writex(fd, buf, len))) return ret; return 0;}int dcc_r_token_string(int ifd, const char *expect_token, char **p_str){ unsigned a_len; int ret; if ((ret = dcc_r_token_int(ifd, expect_token, &a_len))) return ret; if ((ret = dcc_r_str_alloc(ifd, a_len, p_str))) return ret; return 0;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -