#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"
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);
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);
}
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);
}
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);
ret = read(ifd, extrabuf + buflen, sizeof extrabuf - 1 - buflen);
if (ret == -1) {
ret = 0;
}
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;
}
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';
*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;
}
int dcc_r_str_alloc(int fd, unsigned l, char **buf)
{
char *s;
#if 0
if (l < 0) {
rs_log_crit("oops, l < 0");
return EXIT_PROTOCOL_ERROR;
}
#endif
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;
}
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;
}