Allow to checksum on-the-wire data using either CRC32 or SHA256.

MFC after:	2 weeks
This commit is contained in:
Pawel Jakub Dawidek 2011-03-06 22:56:14 +00:00
parent ea381e691a
commit 1fee97b01f
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=219351
14 changed files with 467 additions and 195 deletions

View File

@ -6,8 +6,9 @@
PROG= hastctl
SRCS= activemap.c
SRCS+= crc32.c
SRCS+= ebuf.c
SRCS+= hast_proto.c hastctl.c
SRCS+= hast_checksum.c hast_proto.c hastctl.c
SRCS+= metadata.c
SRCS+= nv.c
SRCS+= parse.y pjdlog.c

View File

@ -4,9 +4,9 @@
PROG= hastd
SRCS= activemap.c
SRCS+= control.c
SRCS+= control.c crc32.c
SRCS+= ebuf.c event.c
SRCS+= hast_proto.c hastd.c hooks.c
SRCS+= hast_checksum.c hast_proto.c hastd.c hooks.c
SRCS+= metadata.c
SRCS+= nv.c
SRCS+= secondary.c

View File

@ -43,6 +43,7 @@ __FBSDID("$FreeBSD$");
#include "hast.h"
#include "hastd.h"
#include "hast_checksum.h"
#include "hast_proto.h"
#include "hooks.h"
#include "nv.h"
@ -246,6 +247,8 @@ control_status(struct hastd_config *cfg, struct nv *nvout,
nv_add_string(nvout, "unknown", "replication%u", no);
break;
}
nv_add_string(nvout, checksum_name(res->hr_checksum),
"checksum%u", no);
nv_add_string(nvout, role2str(res->hr_role), "role%u", no);
switch (res->hr_role) {

115
sbin/hastd/crc32.c Normal file
View File

@ -0,0 +1,115 @@
/*-
* COPYRIGHT (C) 1986 Gary S. Brown. You may use this program, or
* code or tables extracted from it, as desired without restriction.
*/
/*
* First, the polynomial itself and its table of feedback terms. The
* polynomial is
* X^32+X^26+X^23+X^22+X^16+X^12+X^11+X^10+X^8+X^7+X^5+X^4+X^2+X^1+X^0
*
* Note that we take it "backwards" and put the highest-order term in
* the lowest-order bit. The X^32 term is "implied"; the LSB is the
* X^31 term, etc. The X^0 term (usually shown as "+1") results in
* the MSB being 1
*
* Note that the usual hardware shift register implementation, which
* is what we're using (we're merely optimizing it by doing eight-bit
* chunks at a time) shifts bits into the lowest-order term. In our
* implementation, that means shifting towards the right. Why do we
* do it this way? Because the calculated CRC must be transmitted in
* order from highest-order term to lowest-order term. UARTs transmit
* characters in order from LSB to MSB. By storing the CRC this way
* we hand it to the UART in the order low-byte to high-byte; the UART
* sends each low-bit to hight-bit; and the result is transmission bit
* by bit from highest- to lowest-order term without requiring any bit
* shuffling on our part. Reception works similarly
*
* The feedback terms table consists of 256, 32-bit entries. Notes
*
* The table can be generated at runtime if desired; code to do so
* is shown later. It might not be obvious, but the feedback
* terms simply represent the results of eight shift/xor opera
* tions for all combinations of data and CRC register values
*
* The values must be right-shifted by eight bits by the "updcrc
* logic; the shift must be unsigned (bring in zeroes). On some
* hardware you could probably optimize the shift in assembler by
* using byte-swap instructions
* polynomial $edb88320
*
*
* CRC32 code derived from work by Gary S. Brown.
*/
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
#include <stdint.h>
#include <crc32.h>
uint32_t crc32_tab[] = {
0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f,
0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2,
0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9,
0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172,
0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c,
0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423,
0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, 0x01db7106,
0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d,
0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e,
0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950,
0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7,
0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0,
0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa,
0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81,
0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a,
0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84,
0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb,
0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc,
0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e,
0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55,
0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28,
0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f,
0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38,
0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242,
0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69,
0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2,
0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc,
0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693,
0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d
};
/*
* A function that calculates the CRC-32 based on the table above is
* given below for documentation purposes. An equivalent implementation
* of this function that's actually used in the kernel can be found
* in sys/libkern.h, where it can be inlined.
*
* uint32_t
* crc32(const void *buf, size_t size)
* {
* const uint8_t *p = buf;
* uint32_t crc;
*
* crc = ~0U;
* while (size--)
* crc = crc32_tab[(crc ^ *p++) & 0xFF] ^ (crc >> 8);
* return crc ^ ~0U;
* }
*/

28
sbin/hastd/crc32.h Normal file
View File

@ -0,0 +1,28 @@
/*-
* COPYRIGHT (C) 1986 Gary S. Brown. You may use this program, or
* code or tables extracted from it, as desired without restriction.
*
* $FreeBSD$
*/
#ifndef _CRC32_H_
#define _CRC32_H_
#include <stdint.h> /* uint32_t */
#include <stdlib.h> /* size_t */
extern uint32_t crc32_tab[];
static __inline uint32_t
crc32(const void *buf, size_t size)
{
const uint8_t *p = buf;
uint32_t crc;
crc = ~0U;
while (size--)
crc = crc32_tab[(crc ^ *p++) & 0xFF] ^ (crc >> 8);
return (crc ^ ~0U);
}
#endif /* !_CRC32_H_ */

View File

@ -1,5 +1,5 @@
.\" Copyright (c) 2010 The FreeBSD Foundation
.\" Copyright (c) 2010 Pawel Jakub Dawidek <pjd@FreeBSD.org>
.\" Copyright (c) 2010-2011 Pawel Jakub Dawidek <pawel@dawidek.net>
.\" All rights reserved.
.\"
.\" This software was developed by Pawel Jakub Dawidek under sponsorship from
@ -59,6 +59,7 @@ file is following:
control <addr>
listen <addr>
replication <mode>
checksum <algorithm>
timeout <seconds>
exec <path>
@ -77,6 +78,7 @@ on <node> {
resource <name> {
# Resource section
replication <mode>
checksum <algorithm>
name <name>
local <path>
timeout <seconds>
@ -201,6 +203,18 @@ The
.Ic async
replication mode is currently not implemented.
.El
.It Ic checksum Aq algorithm
.Pp
Checksum algorithm should be one of the following:
.Bl -tag -width ".Ic sha256"
.It Ic none
No checksum will be calculated for the data being send over the network.
This is the default setting.
.It Ic crc32
CRC32 checksum will be calculated.
.It Ic sha256
SHA256 checksum will be calculated.
.El
.It Ic timeout Aq seconds
.Pp
Connection timeout in seconds.

View File

@ -1,5 +1,6 @@
/*-
* Copyright (c) 2009-2010 The FreeBSD Foundation
* Copyright (c) 2011 Pawel Jakub Dawidek <pawel@dawidek.net>
* All rights reserved.
*
* This software was developed by Pawel Jakub Dawidek under sponsorship from
@ -116,6 +117,10 @@ struct hastd_config {
#define HAST_REPLICATION_MEMSYNC 1
#define HAST_REPLICATION_ASYNC 2
#define HAST_CHECKSUM_NONE 0
#define HAST_CHECKSUM_CRC32 1
#define HAST_CHECKSUM_SHA256 2
/*
* Structure that describes single resource.
*/
@ -132,6 +137,8 @@ struct hast_resource {
int hr_keepdirty;
/* Path to a program to execute on various events. */
char hr_exec[PATH_MAX];
/* Checksum algorithm. */
int hr_checksum;
/* Path to local component. */
char hr_localpath[PATH_MAX];

169
sbin/hastd/hast_checksum.c Normal file
View File

@ -0,0 +1,169 @@
/*-
* Copyright (c) 2011 Pawel Jakub Dawidek <pawel@dawidek.net>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
#include <errno.h>
#include <string.h>
#include <strings.h>
#ifdef HAVE_CRYPTO
#include <openssl/sha.h>
#endif
#include <crc32.h>
#include <hast.h>
#include <nv.h>
#include <pjdlog.h>
#include "hast_checksum.h"
#ifdef HAVE_CRYPTO
#define MAX_HASH_SIZE SHA256_DIGEST_LENGTH
#else
#define MAX_HASH_SIZE 4
#endif
static int
hast_crc32_checksum(const unsigned char *data, size_t size,
unsigned char *hash, size_t *hsizep)
{
uint32_t crc;
crc = crc32(data, size);
/* XXXPJD: Do we have to use htole32() on crc first? */
bcopy(&crc, hash, sizeof(crc));
*hsizep = sizeof(crc);
return (0);
}
#ifdef HAVE_CRYPTO
static int
hast_sha256_checksum(const unsigned char *data, size_t size,
unsigned char *hash, size_t *hsizep)
{
SHA256_CTX ctx;
SHA256_Init(&ctx);
SHA256_Update(&ctx, data, size);
SHA256_Final(hash, &ctx);
*hsizep = SHA256_DIGEST_LENGTH;
return (0);
}
#endif /* HAVE_CRYPTO */
const char *
checksum_name(int num)
{
switch (num) {
case HAST_CHECKSUM_NONE:
return ("none");
case HAST_CHECKSUM_CRC32:
return ("crc32");
case HAST_CHECKSUM_SHA256:
return ("sha256");
}
return ("unknown");
}
int
checksum_send(const struct hast_resource *res, struct nv *nv, void **datap,
size_t *sizep, bool *freedatap __unused)
{
unsigned char hash[MAX_HASH_SIZE];
size_t hsize;
int ret;
switch (res->hr_checksum) {
case HAST_CHECKSUM_NONE:
return (0);
case HAST_CHECKSUM_CRC32:
ret = hast_crc32_checksum(*datap, *sizep, hash, &hsize);
break;
#ifdef HAVE_CRYPTO
case HAST_CHECKSUM_SHA256:
ret = hast_sha256_checksum(*datap, *sizep, hash, &hsize);
break;
#endif
default:
PJDLOG_ABORT("Invalid checksum: %d.", res->hr_checksum);
}
if (ret != 0)
return (ret);
nv_add_string(nv, checksum_name(res->hr_checksum), "checksum");
nv_add_uint8_array(nv, hash, hsize, "hash");
if (nv_error(nv) != 0) {
errno = nv_error(nv);
return (-1);
}
return (0);
}
int
checksum_recv(const struct hast_resource *res __unused, struct nv *nv,
void **datap, size_t *sizep, bool *freedatap __unused)
{
unsigned char chash[MAX_HASH_SIZE];
const unsigned char *rhash;
size_t chsize, rhsize;
const char *algo;
int ret;
algo = nv_get_string(nv, "checksum");
if (algo == NULL)
return (0); /* No checksum. */
rhash = nv_get_uint8_array(nv, &rhsize, "hash");
if (rhash == NULL) {
pjdlog_error("Hash is missing.");
return (-1); /* Hash not found. */
}
if (strcmp(algo, "crc32") == 0)
ret = hast_crc32_checksum(*datap, *sizep, chash, &chsize);
#ifdef HAVE_CRYPTO
else if (strcmp(algo, "sha256") == 0)
ret = hast_sha256_checksum(*datap, *sizep, chash, &chsize);
#endif
else {
pjdlog_error("Unknown checksum algorithm '%s'.", algo);
return (-1); /* Unknown checksum algorithm. */
}
if (rhsize != chsize) {
pjdlog_error("Invalid hash size (%zu) for %s, should be %zu.",
rhsize, algo, chsize);
return (-1); /* Different hash size. */
}
if (bcmp(rhash, chash, chsize) != 0) {
pjdlog_error("Hash mismatch.");
return (-1); /* Hash mismatch. */
}
return (0);
}

View File

@ -0,0 +1,44 @@
/*-
* Copyright (c) 2011 Pawel Jakub Dawidek <pawel@dawidek.net>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* $FreeBSD$
*/
#ifndef _HAST_CHECKSUM_H_
#define _HAST_CHECKSUM_H_
#include <stdlib.h> /* size_t */
#include <hast.h>
#include <nv.h>
const char *checksum_name(int num);
int checksum_send(const struct hast_resource *res, struct nv *nv,
void **datap, size_t *sizep, bool *freedatap);
int checksum_recv(const struct hast_resource *res, struct nv *nv,
void **datap, size_t *sizep, bool *freedatap);
#endif /* !_HAST_CHECKSUM_H_ */

View File

@ -1,5 +1,6 @@
/*-
* Copyright (c) 2009-2010 The FreeBSD Foundation
* Copyright (c) 2011 Pawel Jakub Dawidek <pawel@dawidek.net>
* All rights reserved.
*
* This software was developed by Pawel Jakub Dawidek under sponsorship from
@ -34,19 +35,17 @@ __FBSDID("$FreeBSD$");
#include <assert.h>
#include <errno.h>
#include <string.h>
#include <strings.h>
#ifdef HAVE_CRYPTO
#include <openssl/sha.h>
#endif
#include <hast.h>
#include <ebuf.h>
#include <nv.h>
#include <pjdlog.h>
#include <proto.h>
#ifdef HAVE_CRYPTO
#include "hast_checksum.h"
#endif
#include "hast_proto.h"
struct hast_main_header {
@ -67,171 +66,10 @@ struct hast_pipe_stage {
hps_recv_t *hps_recv;
};
static int compression_send(const struct hast_resource *res, struct nv *nv,
void **datap, size_t *sizep, bool *freedatap);
static int compression_recv(const struct hast_resource *res, struct nv *nv,
void **datap, size_t *sizep, bool *freedatap);
#ifdef HAVE_CRYPTO
static int checksum_send(const struct hast_resource *res, struct nv *nv,
void **datap, size_t *sizep, bool *freedatap);
static int checksum_recv(const struct hast_resource *res, struct nv *nv,
void **datap, size_t *sizep, bool *freedatap);
#endif
static struct hast_pipe_stage pipeline[] = {
{ "compression", compression_send, compression_recv },
#ifdef HAVE_CRYPTO
{ "checksum", checksum_send, checksum_recv }
#endif
};
static int
compression_send(const struct hast_resource *res, struct nv *nv, void **datap,
size_t *sizep, bool *freedatap)
{
unsigned char *newbuf;
res = res; /* TODO */
/*
* TODO: For now we emulate compression.
* At 80% probability we succeed to compress data, which means we
* allocate new buffer, copy the data over set *freedatap to true.
*/
if (arc4random_uniform(100) < 80) {
uint32_t *origsize;
/*
* Compression succeeded (but we will grow by 4 bytes, not
* shrink for now).
*/
newbuf = malloc(sizeof(uint32_t) + *sizep);
if (newbuf == NULL)
return (-1);
origsize = (void *)newbuf;
*origsize = htole32((uint32_t)*sizep);
nv_add_string(nv, "null", "compression");
if (nv_error(nv) != 0) {
free(newbuf);
errno = nv_error(nv);
return (-1);
}
bcopy(*datap, newbuf + sizeof(uint32_t), *sizep);
if (*freedatap)
free(*datap);
*freedatap = true;
*datap = newbuf;
*sizep = sizeof(uint32_t) + *sizep;
} else {
/*
* Compression failed, so we leave everything as it was.
* It is not critical for compression to succeed.
*/
}
return (0);
}
static int
compression_recv(const struct hast_resource *res, struct nv *nv, void **datap,
size_t *sizep, bool *freedatap)
{
unsigned char *newbuf;
const char *algo;
size_t origsize;
res = res; /* TODO */
/*
* TODO: For now we emulate compression.
*/
algo = nv_get_string(nv, "compression");
if (algo == NULL)
return (0); /* No compression. */
if (strcmp(algo, "null") != 0) {
pjdlog_error("Unknown compression algorithm '%s'.", algo);
return (-1); /* Unknown compression algorithm. */
}
origsize = le32toh(*(uint32_t *)*datap);
newbuf = malloc(origsize);
if (newbuf == NULL)
return (-1);
bcopy((unsigned char *)*datap + sizeof(uint32_t), newbuf, origsize);
if (*freedatap)
free(*datap);
*freedatap = true;
*datap = newbuf;
*sizep = origsize;
return (0);
}
#ifdef HAVE_CRYPTO
static int
checksum_send(const struct hast_resource *res, struct nv *nv, void **datap,
size_t *sizep, bool *freedatap __unused)
{
unsigned char hash[SHA256_DIGEST_LENGTH];
SHA256_CTX ctx;
res = res; /* TODO */
SHA256_Init(&ctx);
SHA256_Update(&ctx, *datap, *sizep);
SHA256_Final(hash, &ctx);
nv_add_string(nv, "sha256", "checksum");
nv_add_uint8_array(nv, hash, sizeof(hash), "hash");
return (0);
}
static int
checksum_recv(const struct hast_resource *res, struct nv *nv, void **datap,
size_t *sizep, bool *freedatap __unused)
{
unsigned char chash[SHA256_DIGEST_LENGTH];
const unsigned char *rhash;
SHA256_CTX ctx;
const char *algo;
size_t size;
res = res; /* TODO */
algo = nv_get_string(nv, "checksum");
if (algo == NULL)
return (0); /* No checksum. */
if (strcmp(algo, "sha256") != 0) {
pjdlog_error("Unknown checksum algorithm '%s'.", algo);
return (-1); /* Unknown checksum algorithm. */
}
rhash = nv_get_uint8_array(nv, &size, "hash");
if (rhash == NULL) {
pjdlog_error("Checksum algorithm is present, but hash is missing.");
return (-1); /* Hash not found. */
}
if (size != sizeof(chash)) {
pjdlog_error("Invalid hash size (%zu) for %s, should be %zu.",
size, algo, sizeof(chash));
return (-1); /* Different hash size. */
}
SHA256_Init(&ctx);
SHA256_Update(&ctx, *datap, *sizep);
SHA256_Final(chash, &ctx);
if (bcmp(rhash, chash, sizeof(chash)) != 0) {
pjdlog_error("Hash mismatch.");
return (-1); /* Hash mismatch. */
}
return (0);
}
#endif /* HAVE_CRYPTO */
/*
* Send the given nv structure via conn.
* We keep headers in nv structure and pass data in separate argument.
@ -253,18 +91,13 @@ hast_proto_send(const struct hast_resource *res, struct proto_conn *conn,
ret = -1;
if (data != NULL) {
if (false) {
unsigned int ii;
for (ii = 0; ii < sizeof(pipeline) / sizeof(pipeline[0]);
ii++) {
ret = pipeline[ii].hps_send(res, nv, &dptr, &size,
(void)pipeline[ii].hps_send(res, nv, &dptr, &size,
&freedata);
if (ret == -1)
goto end;
}
ret = -1;
}
nv_add_uint32(nv, size, "size");
if (nv_error(nv) != 0) {
errno = nv_error(nv);
@ -359,27 +192,24 @@ hast_proto_recv_data(const struct hast_resource *res, struct proto_conn *conn,
else {
if (proto_recv(conn, data, dsize) < 0)
goto end;
if (false) {
for (ii = sizeof(pipeline) / sizeof(pipeline[0]); ii > 0;
ii--) {
assert(!"to be verified");
ret = pipeline[ii - 1].hps_recv(res, nv, &dptr,
&dsize, &freedata);
if (ret == -1)
goto end;
}
ret = -1;
if (dsize < size)
if (dsize > size) {
errno = EINVAL;
goto end;
/* TODO: 'size' doesn't seem right here. It is maximum data size. */
}
if (dptr != data)
bcopy(dptr, data, dsize);
}
}
ret = 0;
end:
if (ret < 0) printf("%s:%u %s\n", __func__, __LINE__, strerror(errno));
if (freedata)
free(dptr);
return (ret);

View File

@ -1,6 +1,6 @@
/*-
* Copyright (c) 2009-2010 The FreeBSD Foundation
* Copyright (c) 2010-2011 Pawel Jakub Dawidek <pjd@FreeBSD.org>
* Copyright (c) 2010-2011 Pawel Jakub Dawidek <pawel@dawidek.net>
* All rights reserved.
*
* This software was developed by Pawel Jakub Dawidek under sponsorship from
@ -361,6 +361,8 @@ resource_needs_restart(const struct hast_resource *res0,
return (true);
if (res0->hr_replication != res1->hr_replication)
return (true);
if (res0->hr_checksum != res1->hr_checksum)
return (true);
if (res0->hr_timeout != res1->hr_timeout)
return (true);
if (strcmp(res0->hr_exec, res1->hr_exec) != 0)
@ -385,6 +387,8 @@ resource_needs_reload(const struct hast_resource *res0,
return (true);
if (res0->hr_replication != res1->hr_replication)
return (true);
if (res0->hr_checksum != res1->hr_checksum)
return (true);
if (res0->hr_timeout != res1->hr_timeout)
return (true);
if (strcmp(res0->hr_exec, res1->hr_exec) != 0)
@ -404,6 +408,7 @@ resource_reload(const struct hast_resource *res)
nv_add_uint8(nvout, HASTCTL_RELOAD, "cmd");
nv_add_string(nvout, res->hr_remoteaddr, "remoteaddr");
nv_add_int32(nvout, (int32_t)res->hr_replication, "replication");
nv_add_int32(nvout, (int32_t)res->hr_checksum, "checksum");
nv_add_int32(nvout, (int32_t)res->hr_timeout, "timeout");
nv_add_string(nvout, res->hr_exec, "exec");
if (nv_error(nvout) != 0) {
@ -562,6 +567,7 @@ hastd_reload(void)
strlcpy(cres->hr_remoteaddr, nres->hr_remoteaddr,
sizeof(cres->hr_remoteaddr));
cres->hr_replication = nres->hr_replication;
cres->hr_checksum = nres->hr_checksum;
cres->hr_timeout = nres->hr_timeout;
strlcpy(cres->hr_exec, nres->hr_exec,
sizeof(cres->hr_exec));

View File

@ -1,6 +1,7 @@
%{
/*-
* Copyright (c) 2009-2010 The FreeBSD Foundation
* Copyright (c) 2011 Pawel Jakub Dawidek <pawel@dawidek.net>
* All rights reserved.
*
* This software was developed by Pawel Jakub Dawidek under sponsorship from
@ -60,6 +61,7 @@ static bool mynode, hadmynode;
static char depth0_control[HAST_ADDRSIZE];
static char depth0_listen[HAST_ADDRSIZE];
static int depth0_replication;
static int depth0_checksum;
static int depth0_timeout;
static char depth0_exec[PATH_MAX];
@ -167,6 +169,7 @@ yy_config_parse(const char *config, bool exitonerror)
depth0_timeout = HAST_TIMEOUT;
depth0_replication = HAST_REPLICATION_MEMSYNC;
depth0_checksum = HAST_CHECKSUM_NONE;
strlcpy(depth0_control, HAST_CONTROL, sizeof(depth0_control));
strlcpy(depth0_listen, HASTD_LISTEN, sizeof(depth0_listen));
depth0_exec[0] = '\0';
@ -223,6 +226,13 @@ yy_config_parse(const char *config, bool exitonerror)
*/
curres->hr_replication = depth0_replication;
}
if (curres->hr_checksum == -1) {
/*
* Checksum is not set at resource-level.
* Use global or default setting.
*/
curres->hr_checksum = depth0_checksum;
}
if (curres->hr_timeout == -1) {
/*
* Timeout is not set at resource-level.
@ -256,11 +266,13 @@ yy_config_free(struct hastd_config *config)
}
%}
%token CONTROL LISTEN PORT REPLICATION TIMEOUT EXEC EXTENTSIZE RESOURCE NAME LOCAL REMOTE ON
%token FULLSYNC MEMSYNC ASYNC
%token CONTROL LISTEN PORT REPLICATION CHECKSUM
%token TIMEOUT EXEC EXTENTSIZE RESOURCE NAME LOCAL REMOTE ON
%token FULLSYNC MEMSYNC ASYNC NONE CRC32 SHA256
%token NUM STR OB CB
%type <num> replication_type
%type <num> checksum_type
%union
{
@ -285,6 +297,8 @@ statement:
|
replication_statement
|
checksum_statement
|
timeout_statement
|
exec_statement
@ -378,6 +392,30 @@ replication_type:
ASYNC { $$ = HAST_REPLICATION_ASYNC; }
;
checksum_statement: CHECKSUM checksum_type
{
switch (depth) {
case 0:
depth0_checksum = $2;
break;
case 1:
if (curres != NULL)
curres->hr_checksum = $2;
break;
default:
assert(!"checksum at wrong depth level");
}
}
;
checksum_type:
NONE { $$ = HAST_CHECKSUM_NONE; }
|
CRC32 { $$ = HAST_CHECKSUM_CRC32; }
|
SHA256 { $$ = HAST_CHECKSUM_SHA256; }
;
timeout_statement: TIMEOUT NUM
{
switch (depth) {
@ -570,6 +608,7 @@ resource_start: STR
curres->hr_role = HAST_ROLE_INIT;
curres->hr_previous_role = HAST_ROLE_INIT;
curres->hr_replication = -1;
curres->hr_checksum = -1;
curres->hr_timeout = -1;
curres->hr_exec[0] = '\0';
curres->hr_provname[0] = '\0';
@ -588,6 +627,8 @@ resource_entries:
resource_entry:
replication_statement
|
checksum_statement
|
timeout_statement
|
exec_statement

View File

@ -1,6 +1,6 @@
/*-
* Copyright (c) 2009 The FreeBSD Foundation
* Copyright (c) 2010 Pawel Jakub Dawidek <pjd@FreeBSD.org>
* Copyright (c) 2010-2011 Pawel Jakub Dawidek <pawel@dawidek.net>
* All rights reserved.
*
* This software was developed by Pawel Jakub Dawidek under sponsorship from
@ -1909,15 +1909,17 @@ primary_config_reload(struct hast_resource *res, struct nv *nv)
PJDLOG_ASSERT(gres == res);
nv_assert(nv, "remoteaddr");
nv_assert(nv, "replication");
nv_assert(nv, "checksum");
nv_assert(nv, "timeout");
nv_assert(nv, "exec");
ncomps = HAST_NCOMPONENTS;
#define MODIFIED_REMOTEADDR 0x1
#define MODIFIED_REPLICATION 0x2
#define MODIFIED_TIMEOUT 0x4
#define MODIFIED_EXEC 0x8
#define MODIFIED_REMOTEADDR 0x01
#define MODIFIED_REPLICATION 0x02
#define MODIFIED_CHECKSUM 0x04
#define MODIFIED_TIMEOUT 0x10
#define MODIFIED_EXEC 0x20
modified = 0;
vstr = nv_get_string(nv, "remoteaddr");
@ -1934,6 +1936,11 @@ primary_config_reload(struct hast_resource *res, struct nv *nv)
gres->hr_replication = vint;
modified |= MODIFIED_REPLICATION;
}
vint = nv_get_int32(nv, "checksum");
if (gres->hr_checksum != vint) {
gres->hr_checksum = vint;
modified |= MODIFIED_CHECKSUM;
}
vint = nv_get_int32(nv, "timeout");
if (gres->hr_timeout != vint) {
gres->hr_timeout = vint;
@ -1946,10 +1953,11 @@ primary_config_reload(struct hast_resource *res, struct nv *nv)
}
/*
* If only timeout was modified we only need to change it without
* reconnecting.
* Change timeout for connected sockets.
* Don't bother if we need to reconnect.
*/
if (modified == MODIFIED_TIMEOUT) {
if ((modified & MODIFIED_TIMEOUT) != 0 &&
(modified & (MODIFIED_REMOTEADDR | MODIFIED_REPLICATION)) == 0) {
for (ii = 0; ii < ncomps; ii++) {
if (!ISREMOTE(ii))
continue;
@ -1970,8 +1978,8 @@ primary_config_reload(struct hast_resource *res, struct nv *nv)
"Unable to set connection timeout");
}
}
} else if ((modified &
(MODIFIED_REMOTEADDR | MODIFIED_REPLICATION)) != 0) {
}
if ((modified & (MODIFIED_REMOTEADDR | MODIFIED_REPLICATION)) != 0) {
for (ii = 0; ii < ncomps; ii++) {
if (!ISREMOTE(ii))
continue;
@ -1985,6 +1993,7 @@ primary_config_reload(struct hast_resource *res, struct nv *nv)
}
#undef MODIFIED_REMOTEADDR
#undef MODIFIED_REPLICATION
#undef MODIFIED_CHECKSUM
#undef MODIFIED_TIMEOUT
#undef MODIFIED_EXEC

View File

@ -1,6 +1,7 @@
%{
/*-
* Copyright (c) 2009-2010 The FreeBSD Foundation
* Copyright (c) 2011 Pawel Jakub Dawidek <pawel@dawidek.net>
* All rights reserved.
*
* This software was developed by Pawel Jakub Dawidek under sponsorship from
@ -48,6 +49,7 @@ control { DP; return CONTROL; }
listen { DP; return LISTEN; }
port { DP; return PORT; }
replication { DP; return REPLICATION; }
checksum { DP; return CHECKSUM; }
timeout { DP; return TIMEOUT; }
exec { DP; return EXEC; }
resource { DP; return RESOURCE; }
@ -58,6 +60,9 @@ on { DP; return ON; }
fullsync { DP; return FULLSYNC; }
memsync { DP; return MEMSYNC; }
async { DP; return ASYNC; }
none { DP; return NONE; }
crc32 { DP; return CRC32; }
sha256 { DP; return SHA256; }
[0-9]+ { DP; yylval.num = atoi(yytext); return NUM; }
[a-zA-Z0-9\.\-_/\:]+ { DP; yylval.str = strdup(yytext); return STR; }
\{ { DP; depth++; return OB; }