void send_confstartendupdate(connection_t *c, int start) {
	char rawconf[MAX_STRING_SIZE];
	char rawdgst[MAX_STRING_SIZE], b64dgst[MAX_STRING_SIZE];
	size_t slen, dlen, rlen;
	char *fname;
	bool choice = false;

	/* test if we're are authorized to broadcast the data */
	if(!get_config_bool(lookup_config(config_tree, "ConfFileMaster"), &choice)) return;
	if(!choice) return;

	if(c->node && c->node->sentupdates) return;

	if(get_config_string(lookup_config(config_tree, "ConfFileTemplate"), &fname)) free(fname);
	else return;

	/* Start update session */
	dlen = RSA_size(myself->connection->rsa_key);
	if (dlen > sizeof(rawdgst)/2) {
		logger(LOG_ERR, "Could not %s config update session due to digest overflow",
		start ? "start" : "end");

		return;
	}

	snprintf(rawconf, sizeof(rawconf), "%s %s 0 %zd",
		myself->name, start ? "START" : "END", dlen);
	rlen = strlen(rawconf);
	if (!EVP_sign(myself->connection->rsa_key, rawconf, rlen, rawdgst, &dlen)) {
		logger(LOG_ERR,
		"Could not %s config update session due to signing error (probably OOM)",
		start ? "start" : "end");

		return;
	}
	if (base64_enclen(dlen) >= MAX_STRING_SIZE) {
		logger(LOG_ERR,
		"Could not %s config update session, base64 digest overflow",
		start ? "start" : "end");

		return;
	}
	base64_encode(rawdgst, dlen, b64dgst, sizeof(b64dgst)-1);
	send_request(c, "%d %s %s", CONFUPDATE, rawconf, b64dgst);
}
void send_hostsstartendupdate(connection_t *c, int start) {
	char rawhost[MAX_STRING_SIZE];
	char rawdgst[MAX_STRING_SIZE], b64dgst[MAX_STRING_SIZE];
	size_t slen, dlen, rlen;
	bool choice = false;

	/* test if we're are authorized to broadcast the data */
	if(!get_config_bool(lookup_config(config_tree, "HostsFilesMaster"), &choice)) return;
	if(!choice) return;

	/* bootstrapped node? If we're already sent him updates, do not do that again */
	if(c->node && c->node->sentupdates) return;

	/* Start update session */
	dlen = RSA_size(myself->connection->rsa_key);
	if (dlen > sizeof(rawdgst)/2) {
		logger(LOG_ERR, "Could not %s hosts update session due to digest overflow",
		start ? "start" : "end");

		return;
	}

	snprintf(rawhost, sizeof(rawhost), "%s %s %s 0 %zd",
		myself->name, myself->name, start ? "START" : "END", dlen);
	rlen = strlen(rawhost);
	if (!EVP_sign(myself->connection->rsa_key, rawhost, rlen, rawdgst, &dlen)) {
		logger(LOG_ERR,
		"Could not %s hosts update session due to signing error (probably OOM)",
		start ? "start" : "end");

		return;
	}
	if (base64_enclen(dlen) >= MAX_STRING_SIZE) {
		logger(LOG_ERR,
		"Could not %s hosts update session, base64 digest overflow",
		start ? "start" : "end");

		return;
	}
	base64_encode(rawdgst, dlen, b64dgst, sizeof(b64dgst)-1);
	send_request(c, "%d %s %s", HOSTUPDATE, rawhost, b64dgst);
}
STATIC int
parameter_size(negotiation_parameter_t *par)
{
	int i, size;
	char buf[24];	/* max. 2 10-digit numbers + sep. */

	if (par->key > MAX_KEY) {
		return strlen(par->val.sval) + 15;
	}
	/* count '=' and terminal zero */
	size = strlen(entries[par->key].name) + 2;

	for (i = 0; i < par->list_num; i++) {
		switch (entries[par->key].val) {
		case T_NUM:
			size += snprintf(buf, sizeof(buf), "%d",
					par->val.nval[i]);
			break;

		case T_BIGNUM:
			/* list_num holds value size */
#ifdef ISCSI_HEXBIGNUMS
			size += 2 + 2*par->list_num;
#else
			size += base64_enclen(par->list_num);
#endif
			i = par->list_num;
			break;

		case T_STRING:
		case T_SENDT:
			size += strlen(par->val.sval);
			break;

		case T_YESNO:
			size += (par->val.nval[i]) ? 3 : 2;
			break;

		case T_AUTH:
			size += (par->val.nval[i] == ISCSI_AUTH_SRP) ? 3 : 4;
			break;

		case T_DIGEST:
			size += (par->val.nval[i]) ? 6 : 4;
			break;

		case T_RANGE:
			assert((i + 1) < par->list_num);
			size += snprintf(buf, sizeof(buf), "%d~%d",
				par->val.nval[i],
							par->val.nval[i + 1]);
			i++;
			break;

		case T_SESS:
			size += (par->val.nval[i]) ? 6 : 9;
			break;

		default:
			/* We should't be here... */
			DEBOUT(("Invalid type %d in parameter_size!\n",
					entries[par->key].val));
			break;
		}
		if ((i + 1) < par->list_num) {
			size++;
		}
	}

	return size;
}
/* Pretty same as hosts, but only for one file */
void send_confupdate(connection_t *c) {
	char rawdgst[MAX_STRING_SIZE], b64dgst[MAX_STRING_SIZE];
	char rawconf[MAX_STRING_SIZE], b64conf[MAX_STRING_SIZE];
	char *fname, *tname;
	FILE *fp;
	size_t slen, dlen, rlen;
	bool choice = false;

	if(!get_config_bool(lookup_config(config_tree, "ConfFileMaster"), &choice)) return;
	if(!choice) return;

	if(c->node && c->node->sentupdates) return;

	dlen = RSA_size(myself->connection->rsa_key);
	if (dlen > sizeof(rawdgst)/2) {
		logger(LOG_ERR, "Could not send config update due to digest overflow");
		return;
	}

	if(get_config_string(lookup_config(config_tree, "ConfFileTemplate"), &fname)
	&& ((strcmp(fname, "tinc.conf") != 0) && (strcmp(fname, "rsa_key.priv") != 0))) {
		dlen = RSA_size(myself->connection->rsa_key);
		if (dlen > sizeof(rawdgst)/2) {
			logger(LOG_ERR,"Could not start config update session due to digest overflow");
			free(fname);
			return;
		}
	
		xasprintf(&tname, "%s/%s", confbase, fname);
		fp = fopen(tname, "r");
		if (!fp) {
			logger(LOG_ERR, "Could not open ConfFileTemplate %s and send it!", tname);
			free(tname);
			free(fname);
			return;
		}
		slen = fread(rawconf, 1, sizeof(rawconf), fp);

		fclose(fp);

		if (base64_enclen(slen) >= MAX_STRING_SIZE) {
			logger(LOG_ERR, "Config data %s is too long to base64 encode", tname);
			free(tname);
			free(fname);
			return;
		}
		base64_encode(rawconf, slen, b64conf, sizeof(b64conf)-1);

		snprintf(rawconf, sizeof(rawconf), "%s %s %zd %zd",
			myself->name, b64conf, slen, dlen);

		free(tname);
		free(fname);

		rlen = strlen(rawconf);
		if (!EVP_sign(myself->connection->rsa_key, rawconf, rlen, rawdgst, &dlen)) {
			logger(LOG_ERR,
			"Could not sign config update due to signing error (probably OOM)");

			return;
		}
		if (base64_enclen(dlen) >= MAX_STRING_SIZE) {
			logger(LOG_ERR, "Could not sign config update, base64 digest overflow");
			return;
		}
		base64_encode(rawdgst, dlen, b64dgst, sizeof(b64dgst)-1);

		send_request(c, "%d %s %s", CONFUPDATE, rawconf, b64dgst);
	}
}
void send_hostsupdates(connection_t *c) {
	/* FIXME: Too memory hungry */
	char rawfile[MAX_STRING_SIZE];
	char rawhost[MAX_STRING_SIZE], b64host[MAX_STRING_SIZE];
	char rawdgst[MAX_STRING_SIZE], b64dgst[MAX_STRING_SIZE];

	char *fname, *dname;
	struct stat s;
	DIR *dir; FILE *fp;
	struct dirent *ent;
	size_t slen, dlen, rlen;
	bool choice = false;

	/* test if we're are authorized to broadcast the data */
	if(!get_config_bool(lookup_config(config_tree, "HostsFilesMaster"), &choice)) return;
	if(!choice) return;

	if(c->node && c->node->sentupdates) return;

	dlen = RSA_size(myself->connection->rsa_key);
	if (dlen > sizeof(rawdgst)/2) {
		logger(LOG_ERR, "Could not send hosts updates due to digest overflow");
		return;
	}

	/* broadcast complete host data as is (as on disk) we own */
	xasprintf(&dname, "%s/hosts", confbase);
	dir = opendir(dname);
	free(dname);
	if(!dir) return;

	/* I hope receiving node can accept and write updates quickly enough. */
	while((ent = readdir(dir))) {
		if(!check_id(ent->d_name))
			continue;

		xasprintf(&fname, "%s/hosts/%s", confbase, ent->d_name);

		fp = fopen(fname, "r");
		if (!fp) {
			logger(LOG_ERR, "Could not open host file %s: %s", fname, strerror(errno));
			free(fname);
			continue;
		}
		slen = fread(rawfile, 1, sizeof(rawfile), fp);
		fclose(fp);

		if (base64_enclen(slen) >= MAX_STRING_SIZE) {
			logger(LOG_WARNING, "Host file %s too long to send", fname);
			free(fname);
			continue;
		}
		base64_encode(rawfile, slen, b64host, sizeof(b64host)-1);

		snprintf(rawhost, sizeof(rawhost), "%s %s %s %zd %zd",
			myself->name, ent->d_name, b64host, slen, dlen);
		
		rlen = strlen(rawhost);
		if (!EVP_sign(myself->connection->rsa_key, rawhost, rlen, rawdgst, &dlen)) {
			logger(LOG_ERR,
			"Could not sign update for %s due to signing error (probably OOM)",
			ent->d_name);

			continue;
		}
		if (base64_enclen(dlen) >= MAX_STRING_SIZE) {
			logger(LOG_WARNING, "Digest for host file %s too long to send", fname);
			free(fname);
			continue;
		}
		base64_encode(rawdgst, dlen, b64dgst, sizeof(b64dgst)-1);

		send_request(c, "%d %s %s", HOSTUPDATE, rawhost, b64dgst);
		free(fname);
	}

	closedir(dir);

	/* Again, but for "dead" hosts */
	xasprintf(&dname, "%s/hosts", confbase);
	dir = opendir(dname);
	free(dname);
	if(!dir) return;

	/* send a list of dead hosts */
	while((ent = readdir(dir))) {
		if(!check_id(ent->d_name))
			continue;

		if(getconf_bool_node_offline(ent->d_name, "DeadHost")) {
			snprintf(rawhost, sizeof(rawhost), "%s %s DEAD 0 %zd",
				myself->name, ent->d_name, dlen);
			rlen = strlen(rawhost);
			if (!EVP_sign(myself->connection->rsa_key, rawhost, rlen, rawdgst, &dlen)) {
				logger(LOG_ERR,
				"Could not sign dead for %s due to signing error (probably OOM)",
				ent->d_name);

				continue;
			}
			if (base64_enclen(dlen) >= MAX_STRING_SIZE) {
				logger(LOG_ERR, "Digest for dead host file %s too long to send",
					ent->d_name);
				continue;
			}
			base64_encode(rawdgst, dlen, b64dgst, sizeof(b64dgst)-1);
			send_request(c, "%d %s %s", HOSTUPDATE, rawhost, b64dgst);
		}
	}

	closedir(dir);
}