/*
 * Author:
 *         Kendy Kutzner <kutzner@ira.uka.de>
 *         Roman Krenicky
 *         Johannes Franz
 *
 * (c) 2005 Research Group Dr. Fuhrmann, University of Karlsruhe, Germany
 * All rights reserved.
 *
 * $Id: libigor.h,v 1.31 2006/02/02 16:57:45 kutzner Exp $
 *
 */

/**
  libigor.h
  created: 28.11.2004
  $Id: libigor.h,v 1.31 2006/02/02 16:57:45 kutzner Exp $
*/

#ifndef _LIBIGOR_H
#define _LIBIGOR_H

#include <unistd.h>

#ifdef __cplusplus
#define THROW throw()
#else
#define bool int 
#define THROW
#endif

/** Structure contains DHT-addresses. 
 * This can be either a clear-text destination or the hashed form of it.  A
 * clear text form can be converted into the hashed form.  The other way
 * arround is not possible given the properties of the cryptographic hash
 * function.
 */

struct sa_igor {
	/** Address is a pointer the real address.
	 * The memory pointed to is 
	 *   - either a node id / routing key in its binary form (for example 20 octets for a sha1)
 	 *   - or to some binary data that should be processed by a hash function
	 */
	const char * address;
	/** len is the amount of memory allocated at address. */
	int len;
	/** mustbehashed distinguishes the two cases for address. */
	bool mustbehashed;
};

/**
 * igor_apptype is used to transport application types arround.
 * It has a very similar semantic to sa_igor.
 */

struct igor_apptype {
	const char * apptype;
	int len;
	bool mustbehashed;
};

/** Allow applications use their own memory management.
 * When the library needs dynamic memory, it will allocte the memory with
 * igor_malloc().  Applications which implement their own memory management can
 * overwrite this function pointer.  Default is to use malloc() and free() from
 * the C library. These defaults are set during initialization of the library.
 * This means already the memory used by igor_socket() can be allocated with
 * these routines.
 */

extern void * (*igor_malloc)(size_t) THROW ;
/** See igor_malloc() */
extern void (*igor_free)(void *) THROW ;

#define IGOR_ERR_NOERR 0
#define IGOR_ERR_NOTCONNECTED -2
#define IGOR_ERR_OOM -3
#define IGOR_ERR_INVAL -4


void igor_init() __attribute__((constructor));

/** Create one IGOR-socket.
 * Create the internal data structures needed in the library.
 * \return The socket descriptor (sd) or a negative value if an error occurred
 * Possible errors are:
 *  - IGOR_ERR_NOERR everything fine
 *  - IGOR_ERR_NOTCONNECTED connection to igor failed
 *  - IGOR_ERR_OOM out of memory
 */

int igor_socket ();

/** Bind a IGOR-socket.
 * Associate a igor-socket with an application type.  The socket will only
 * receive messages with the proper application type.
 * \param type is the IGOR application type we want to receive and send possible
 * \return possible errors
 *   - IGOR_ERR_NOERR fine
 *   - IGOR_ERR_INVAL one of the parameters is bogus
 *   - IGOR_ERR_OOM out of memory
 */

int igor_bind(int sd, const struct igor_apptype * type);


/** Closes a IGOR socket.
 * Closes the IGOR socket with the socket descriptor 'sd'.  A possible binding
 * is revoked and all memory associated with that socket is free()d.
 * \param sd The socket to be closed.
 * \return IGOR_ERR_NOERR if succeeded or IGOR_ERR_INVAL if sd was bogus.
*/
int igor_close (int sd);


/* - sends a IGOR message
   - 'sd' is the socket descriptor (implicitly determines the message type)
   - 'msg' is the message to send
   - 'len' is the size of 'msg' in bytes
   - 'upcall' is true iff the message is to be sent one hop forward only
   - 'dest' is the destination (IGOR key for 'sd's message type)
   - returns one of the following errors:
     IGOR_ERR_NOTCONNECTED the connection was not established or died
     IGOR_ERR_INVAL input values bogus
     IGOR_ERR_NOERR msg sent
   - this function is a cancellation point
*/
int igor_sendto (int sd, const void *msg, size_t len, bool upcall, const struct sa_igor *);


/* - receives a IGOR messages (blocking)
   - 'sd' is the socket descriptor (implicitly determines the message type)
   - 'msg' will point to the message on successful return 
          should point to NULL when called
	  the memory will be allocated with the function igor_malloc()
   - 'len' will point to the message's size in bytes on successful return
   - '*final' will be true iff this message is for us (on successful return), 
	this is the counterpart to 'upcall'
   - '*src' will be to the message's sender (IGOR key for 'sd's message type). (1)
   - '*dest' will be to the message's destination (IGOR key for 'sd's message. (1)
      type)
   - returns one of the following errors:
     IGOR_ERR_NOERR return pointers are valid
     IGOR_ERR_OOM out of memory, returned values are not valid
     IGOR_ERR_NOTCONNECTED connection doesn't exists (any more)
     IGOR_ERR_INVALID one of the parameters is bogus
   (1) both *src and *dest should be either empty (ie. len=0) or contain dynamic allocated pointers which will be free()ed by this function
*/
int igor_recvfromto (int sd, void **msg, size_t *len, bool *final, struct sa_igor *src, struct sa_igor *dest);

/**
 * continue sending the last message
 *  - the last message where final=false is sent on
 *  - message is unchanged
 * parameters
 *  - 'sd' socket descriptor where the message were received
 * return values same as igor_sendto()
 */

int igor_sendon(int sd);

/**
 * Explain the last occured error in a human readable format.
 * The returned buffer may be overwritten at the next call to this function (per socket descriptor).
 * If multiple thread are transmitting in parallel, the result may be wrong.
 * You can use locking in this case, you can use igor_strerror_r() instead.
 */

const char * igor_strerror(int sd);

/**
 * Explain the last occured error in a human readable format.
 * The explanation is a lot simpler than the one returned by igor_strerror, but it is guaranteed to point to a constant string.
 * This function is thread safe.
 * Note that the parameter is NOT a socket descriptor but an error code.
 */

const char * igor_strerror_r(int errorcode);

/**
 * converts an unhashed sa_igor into a hashed one
 * warning:
 *  sa_igor->address will be passed to igor_free() and reallocated using igor_malloc()
 * parameters:
 *  in/out:
 *   s
 *  return value
 *   IGOR_ERR_NOERR everything is ok
 *   IGOR_ERR_OOM reallocation failed
 */

int igor_hash_sa(sa_igor * s);

/**
 * Same for igor_apptype.
 * See documentation for igor_hashit_sa().
 * Same warning applies here.
 */

int igor_hash_apptype(igor_apptype * t);

/**
 * Compare two sa_igor structures.
 * The hashed and unhashed form of two structs compare equal.
 * parameters: The two structs to compare.
 * return:
 * 	- 0 / false: not equal
 * 	- 1 / true: eqal (maybe after hashing)
 */
bool igor_sa_cmp(const sa_igor* sa1, const sa_igor* sa2);


#ifdef __cplusplus

/**
 * The C++ equivalent of struct sa_igor.
 * Beware: the memory management is still not settled.
 */
class csa_igor {
	public:
	/** Address is a pointer the real address.
	 * The memory pointed to is 
	 *   - either a node id / routing key in its binary form (for example 20 octets for a sha1)
 	 *   - or to some binary data that should be processed by a hash function
	 */
	const char * address;
	/** len is the amount of memory allocated at address. */
	int len;
	/** mustbehashed distinguishes the two cases for address. */
	bool mustbehashed;
	bool operator==(const csa_igor & other) const;
	csa_igor& operator=(const csa_igor & other);
	csa_igor();
	csa_igor(const csa_igor& sa); 
	~csa_igor();
	sa_igor * rawpointer() const;
};
#endif // __cplusplus

#endif // _LIBIGOR_H
