#include <config.h>
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <syslog.h>
#include <sys/types.h>
#include <fcntl.h>
#include <netinet/in.h>
#include <sys/un.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <ctype.h>
#include <time.h>
#include "assert.h"
#include "acl.h"
#include "map.h"
#include "retry.h"
#include "util.h"
#include "lock.h"
#include "exitcodes.h"
#include "message_uuid.h"
#include "xmalloc.h"
#if 0
#include "acappush.h"
#endif
static int schema = 0;
static struct {
unsigned char prefix[8];
unsigned long count;
} schema_1;
static int
message_uuid_record(struct message_uuid *uuid)
{
unsigned char *s = &uuid->value[0];
int rc = 1;
switch (s[0]) {
case 0:
schema = 0;
break;
case 1:
schema = 1;
memcpy(&schema_1.prefix[0], &s[1], 8);
schema_1.count = 0;
break;
default:
rc = 0;
break;
}
return(rc);
}
static int
message_uuid_extract(struct message_uuid *uuid)
{
unsigned char *s = &uuid->value[0];
int rc = 1;
switch (schema) {
case 0:
message_uuid_set_null(uuid);
break;
case 1:
s[0] = 1;
memcpy(&s[1], &schema_1.prefix[0], 8);
s[9] = ((schema_1.count & 0xff0000) >> 16);
s[10] = ((schema_1.count & 0x00ff00) >> 8);
s[11] = ((schema_1.count & 0x0000ff));
break;
default:
syslog(LOG_ERR, "UUID: Unknown schema");
message_uuid_set_null(uuid);
rc = 0;
break;
}
return(rc);
}
int
message_uuid_client_init(char *uuid_prefix)
{
struct message_uuid tmp;
unsigned char *s = &tmp.value[0];
unsigned long count, checksum;
message_uuid_set_null(&tmp);
message_uuid_record(&tmp);
if (uuid_prefix == NULL)
return(1);
if (!message_uuid_from_text(&tmp, uuid_prefix))
return(0);
switch (s[0]) {
case 0:
break;
case 1:
count = (s[0] << 16) + (s[1] << 8) + s[2];
count += (s[3] << 16) + (s[4] << 8) + s[5];
count += (s[6] << 16) + (s[7] << 8) + s[8];
count &= 0x00ffffff;
checksum = (s[9] << 16) + (s[10] << 8) + s[11];
if (checksum != count) {
syslog(LOG_ERR, "UUID checksum mismatch for %s", uuid_prefix);
return(0);
}
s[9] = 0;
s[10] = 0;
s[11] = 0;
if (!message_uuid_record(&tmp))
return(0);
break;
default:
syslog(LOG_ERR,
"Attempt to initialise invalid UUID prefix: %s", uuid_prefix);
return(0);
break;
}
return(1);
}
int
message_uuid_assign(struct message_uuid *uuid)
{
int rc = 1;
switch (schema) {
case 0:
message_uuid_set_null(uuid);
break;
case 1:
if (schema_1.count >= (256*256*256)) {
message_uuid_set_null(uuid);
break;
}
if (!message_uuid_extract(uuid)) {
message_uuid_set_null(uuid);
rc = 0;
break;
}
schema_1.count++;
break;
default:
message_uuid_set_null(uuid);
rc = 0;
break;
}
return(rc);
}
struct message_uuid *
message_uuid_alloc()
{
struct message_uuid *current = xmalloc(sizeof(struct message_uuid));
if (!message_uuid_assign(current))
return(NULL);
return(current);
}
void
message_uuid_free(struct message_uuid **uuidp)
{
free(*uuidp);
*uuidp = NULL;
}
int
message_uuid_copy(struct message_uuid *dst, struct message_uuid *src)
{
memcpy(dst, src, sizeof(struct message_uuid));
return(1);
}
int
message_uuid_compare(struct message_uuid *uuid1, struct message_uuid *uuid2)
{
unsigned char *s = &uuid1->value[0];
unsigned char *t = &uuid2->value[0];
int i;
for (i = 0; i < MESSAGE_UUID_SIZE; i++) {
if (s[i] != t[i]) return(0);
}
return(1);
}
unsigned long
message_uuid_hash(struct message_uuid *uuid, int hash_size)
{
int i;
unsigned long result = 0;
unsigned char *s = &uuid->value[0];
assert(hash_size > 1);
if (hash_size > 1024) {
for (i = 0; i < MESSAGE_UUID_SIZE; i+=2) {
if ((i+1) < MESSAGE_UUID_SIZE)
result += (s[i] << 8) + s[i+1];
else
result += s[i] << 8;
}
} else for (i = 0; i < MESSAGE_UUID_SIZE; i++)
result += s[i];
return(result % hash_size);
}
int
message_uuid_set_null(struct message_uuid *dst)
{
memset(dst, 0, MESSAGE_UUID_SIZE);
return(1);
}
int
message_uuid_isnull(struct message_uuid *uuid)
{
unsigned char *p = &uuid->value[0];
int i;
if (*p) return(0);
for (i = 0 ; i < MESSAGE_UUID_SIZE ; i++) {
if (*p) {
syslog(LOG_WARNING, "Invalid NULL UUID: not completely zero");
break;
}
p++;
}
return(1);
}
int
message_uuid_pack(struct message_uuid *uuid, char *packed)
{
assert(MESSAGE_UUID_SIZE == MESSAGE_UUID_PACKED_SIZE);
memcpy(packed, &uuid->value[0], MESSAGE_UUID_SIZE);
return(1);
}
int
message_uuid_unpack(struct message_uuid *uuid, const unsigned char *packed)
{
assert(MESSAGE_UUID_SIZE == MESSAGE_UUID_PACKED_SIZE);
memcpy(&uuid->value[0], packed, MESSAGE_UUID_SIZE);
return(1);
}
char *
message_uuid_text(struct message_uuid *uuid)
{
static char buf[MESSAGE_UUID_TEXT_SIZE+1];
static char *hex = "0123456789abcdef";
unsigned char *value = &uuid->value[0];
char *p = buf;
int i;
for (i = 0 ; i < MESSAGE_UUID_SIZE ; i++) {
*p++ = hex[(value[i] & 0xf0) >> 4];
*p++ = hex[value[i] & 0x0f];
}
*p = '\0';
return(buf);
}
int
message_uuid_from_text(struct message_uuid *uuid, const char *text)
{
const char *p = text;
unsigned char *buf = &uuid->value[0];
int i;
for (i = 0 ; i < MESSAGE_UUID_SIZE ; i++) {
if (!isxdigit(*p)) return(0);
if ((*p >= 'a') && (*p <= 'f'))
buf[i] = 16 * (*p - 'a' + 10);
else if ((*p >= 'A') && (*p <= 'F'))
buf[i] = 16 * (*p - 'A' + 10);
else
buf[i] = 16 * (*p - '0');
p++;
if (!isxdigit(*p)) return(0);
if ((*p >= 'a') && (*p <= 'f'))
buf[i] += (*p - 'a' + 10);
else if ((*p >= 'A') && (*p <= 'F'))
buf[i] += (*p - 'A' + 10);
else
buf[i] += (*p - '0');
p++;
}
return((*p == '\0'));
}
int
message_uuid_text_valid(const char *p)
{
int i;
for (i = 0 ; i < MESSAGE_UUID_TEXT_SIZE ; i++) {
if (!isxdigit(*p)) return(0);
p++;
}
return((*p == '\0') ? 1 : 0);
}
int
message_uuid_text_isnull(const char *p)
{
int i;
if ((p[0] != '0') || (p[1] != '0')) return(0);
for (i = 0; i < MESSAGE_UUID_TEXT_SIZE; i++) {
if (p[i] != '0') {
syslog(LOG_WARNING, "Invalid NULL message UUID: %s", p);
return(1);
}
}
if (p[MESSAGE_UUID_TEXT_SIZE] != '\0')
syslog(LOG_WARNING, "Invalid NULL message UUID: incorrect length");
return(1);
}