/** * 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); }
static int dcc_write_state(int fd) { int ret; /* Write out as one big blob. fd is positioned at the start of * the file. */ if ((ret = dcc_writex(fd, my_state, sizeof *my_state))) return ret; return 0; }
/* Write host data to host file */ static int write_hosts(struct daemon_data *d) { struct host *h; int r = 0; assert(d); rs_log_info("writing zeroconf data.\n"); if (generic_lock(d->fd, 1, 1, 1) < 0) { rs_log_crit("lock failed: %s\n", strerror(errno)); return -1; } if (lseek(d->fd, 0, SEEK_SET) < 0) { rs_log_crit("lseek() failed: %s\n", strerror(errno)); return -1; } if (ftruncate(d->fd, 0) < 0) { rs_log_crit("ftruncate() failed: %s\n", strerror(errno)); return -1; } remove_duplicate_services(d); for (h = d->hosts; h; h = h->next) { char t[256], a[AVAHI_ADDRESS_STR_MAX]; if (h->resolver) /* Not yet fully resolved */ continue; if (h->address.proto == AVAHI_PROTO_INET6) snprintf(t, sizeof(t), "[%s]:%u/%i\n", avahi_address_snprint(a, sizeof(a), &h->address), h->port, d->n_slots * h->n_cpus); else snprintf(t, sizeof(t), "%s:%u/%i\n", avahi_address_snprint(a, sizeof(a), &h->address), h->port, d->n_slots * h->n_cpus); if (dcc_writex(d->fd, t, strlen(t)) != 0) { rs_log_crit("write() failed: %s\n", strerror(errno)); goto finish; } } r = 0; finish: generic_lock(d->fd, 1, 0, 1); return r; };
/** * 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; }
/* * Attempt handshake exchange with the server to indicate client's * desire to authentciate. * * @param to_net_sd. Socket to write to. * * @param from_net_sd. Socket to read from. * * Returns 0 on success, otherwise error. */ static int dcc_gssapi_send_handshake(int to_net_sd, int from_net_sd) { char auth = HANDSHAKE; fd_set sockets; int ret; struct timeval timeout; rs_log_info("Sending handshake."); if ((ret = dcc_writex(to_net_sd, &auth, sizeof(auth))) != 0) { return ret; } rs_log_info("Sent %c.", auth); FD_ZERO(&sockets); FD_SET(from_net_sd, &sockets); timeout.tv_sec = 1; timeout.tv_usec = 0; ret = select(from_net_sd + 1, &sockets, NULL, NULL, &timeout); if (ret < 0) { rs_log_error("select failed: %s.", strerror(errno)); return EXIT_IO_ERROR; } if (ret == 0) { rs_log_error("Timeout - does this server require authentication?"); return EXIT_TIMEOUT; } rs_log_info("Receiving handshake."); if ((ret = dcc_readx(from_net_sd, &auth, sizeof(auth))) != 0) { return ret; } rs_log_info("Received %c.", auth); if (auth != HANDSHAKE) { rs_log_crit("No server handshake."); return EXIT_GSSAPI_FAILED; } return 0; }
/** * Receive @p in_len compressed bytes from @p in_fd, and write the * decompressed form to @p out_fd. * * There's no way for us to know how big the uncompressed form will be, and * there is also no way to grow the decompression buffer if it turns out to * initially be too small. So we assume a ratio of 10x. If it turns out to * be too small, we increase the buffer and try again. Typical compression of * source or object is about 2x to 4x. On modern Unix we should be able to * allocate (and not touch) many megabytes at little cost, since it will just * turn into an anonymous map. * * LZO doesn't have any way to decompress part of the input and then break to * get more output space, so our buffer needs to be big enough in the first * place or we would waste time repeatedly decompressing it. **/ int dcc_r_bulk_lzo1x(int out_fd, int in_fd, unsigned in_len) { int ret, lzo_ret; char *in_buf = NULL, *out_buf = NULL; size_t out_size = 0; lzo_uint out_len; /* NOTE: out_size is the buffer size, out_len is the amount of actual * data. */ if (in_len == 0) return 0; /* just check */ if ((in_buf = malloc(in_len)) == NULL) { rs_log_error("failed to allocate decompression input"); ret = EXIT_OUT_OF_MEMORY; goto out; } if ((ret = dcc_readx(in_fd, in_buf, in_len)) != 0) goto out; #if 0 /* Initial estimate for output buffer. This is intentionally quite low to * exercise the resizing code -- if it works OK then we can scale this * up. */ out_size = 2 * in_len; #else out_size = 8 * in_len; #endif try_again_with_a_bigger_buffer: if ((out_buf = malloc(out_size)) == NULL) { rs_log_error("failed to allocate decompression buffer"); ret = EXIT_OUT_OF_MEMORY; goto out; } out_len = out_size; lzo_ret = lzo1x_decompress_safe((lzo_byte*)in_buf, in_len, (lzo_byte*)out_buf, &out_len, work_mem); if (lzo_ret == LZO_E_OK) { rs_trace("decompressed %ld bytes to %ld bytes: %d%%", (long) in_len, (long) out_len, (int) (out_len ? 100*in_len / out_len : 0)); ret = dcc_writex(out_fd, out_buf, out_len); goto out; } else if (lzo_ret == LZO_E_OUTPUT_OVERRUN) { free(out_buf); out_buf = 0; out_size *= 2; /* FIXME: Make sure this doesn't overflow memory size? */ rs_trace("LZO_E_OUTPUT_OVERRUN, trying again with %lu byte buffer", (unsigned long) out_size); goto try_again_with_a_bigger_buffer; } else { rs_log_error("LZO1X1 decompression failed: %d", lzo_ret); ret = EXIT_IO_ERROR; goto out; } out: free(in_buf); free(out_buf); return ret; }