/*
This file is part of GNUnet.
(C) 2009 Christian Grothoff (and other contributing authors)
GNUnet is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published
by the Free Software Foundation; either version 3, or (at your
option) any later version.
GNUnet is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with GNUnet; see the file COPYING. If not, write to the
Free Software Foundation, Inc., 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA.
*/
/**
* @file hello/hello.c
* @brief helper library for handling HELLOs
* @author Christian Grothoff
*/
#include "platform.h"
#include "gnunet_hello_lib.h"
#include "gnunet_protocols.h"
#include "gnunet_util_lib.h"
#include "gnunet_transport_plugin.h"
GNUNET_NETWORK_STRUCT_BEGIN
/**
* A HELLO message is used to exchange information about
* transports with other peers. This struct is always
* followed by the actual network addresses which have
* the format:
*
* 1) transport-name (0-terminated)
* 2) address-length (uint16_t, network byte order; possibly
* unaligned!)
* 3) address expiration (GNUNET_TIME_AbsoluteNBO); possibly
* unaligned!)
* 4) address (address-length bytes; possibly unaligned!)
*/
struct GNUNET_HELLO_Message
{
/**
* Type will be GNUNET_MESSAGE_TYPE_HELLO.
*/
struct GNUNET_MessageHeader header;
/**
* Always zero (for alignment).
*/
uint32_t reserved GNUNET_PACKED;
/**
* The public key of the peer.
*/
struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded publicKey;
};
GNUNET_NETWORK_STRUCT_END
/**
* Context used for building our own URI.
*/
struct GNUNET_HELLO_ComposeUriContext
{
/**
* Final URI.
*/
char *uri;
/**
* Function for finding transport plugins by name.
*/
GNUNET_HELLO_TransportPluginsFind plugins_find;
};
/**
* Context for 'add_address_to_hello'.
*/
struct GNUNET_HELLO_ParseUriContext
{
/**
* Position in the URI with the next address to parse.
*/
const char *pos;
/**
* Set to GNUNET_SYSERR to indicate parse errors.
*/
int ret;
/**
* Function for finding transport plugins by name.
*/
GNUNET_HELLO_TransportPluginsFind plugins_find;
};
/**
* Copy the given address information into
* the given buffer using the format of HELLOs.
*
* @param address the address
* @param expiration expiration for the address
* @param target where to copy the address
* @param max maximum number of bytes to copy to target
* @return number of bytes copied, 0 if
* the target buffer was not big enough.
*/
size_t
GNUNET_HELLO_add_address (const struct GNUNET_HELLO_Address *address,
struct GNUNET_TIME_Absolute expiration, char *target,
size_t max)
{
uint16_t alen;
size_t slen;
struct GNUNET_TIME_AbsoluteNBO exp;
slen = strlen (address->transport_name) + 1;
if (slen + sizeof (uint16_t) + sizeof (struct GNUNET_TIME_AbsoluteNBO) +
address->address_length > max)
return 0;
exp = GNUNET_TIME_absolute_hton (expiration);
alen = htons ((uint16_t) address->address_length);
memcpy (target, address->transport_name, slen);
memcpy (&target[slen], &alen, sizeof (uint16_t));
slen += sizeof (uint16_t);
memcpy (&target[slen], &exp, sizeof (struct GNUNET_TIME_AbsoluteNBO));
slen += sizeof (struct GNUNET_TIME_AbsoluteNBO);
memcpy (&target[slen], address->address, address->address_length);
slen += address->address_length;
return slen;
}
/**
* Get the size of an address entry in a HELLO message.
*
* @param buf pointer to the start of the address entry
* @param max maximum size of the entry (end of buf)
* @param ralen set to the address length
* @return size of the entry, or 0 if max is not large enough
*/
static size_t
get_hello_address_size (const char *buf, size_t max, uint16_t * ralen)
{
const char *pos;
uint16_t alen;
size_t left;
size_t slen;
left = max;
pos = buf;
slen = 1;
while ((left > 0) && ('\0' != *pos))
{
left--;
pos++;
slen++;
}
if (left == 0)
{
/* 0-termination not found */
GNUNET_break_op (0);
return 0;
}
pos++;
if (left < sizeof (uint16_t) + sizeof (struct GNUNET_TIME_AbsoluteNBO))
{
/* not enough space for addrlen */
GNUNET_break_op (0);
return 0;
}
memcpy (&alen, pos, sizeof (uint16_t));
alen = ntohs (alen);
*ralen = alen;
slen += alen + sizeof (uint16_t) + sizeof (struct GNUNET_TIME_AbsoluteNBO);
if (max < slen)
{
/* not enough space for addr */
GNUNET_break_op (0);
return 0;
}
return slen;
}
/**
* Construct a HELLO message given the public key,
* expiration time and an iterator that spews the
* transport addresses.
*
* @return the hello message
*/
struct GNUNET_HELLO_Message *
GNUNET_HELLO_create (const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded
*publicKey,
GNUNET_HELLO_GenerateAddressListCallback addrgen,
void *addrgen_cls)
{
char buffer[GNUNET_SERVER_MAX_MESSAGE_SIZE - 1 - 256