/*
Copyright (C) 2003-2004 Douglas Thain and the University of Wisconsin
Copyright (C) 2022 The University of Notre Dame
This software is distributed under the GNU General Public License.
See the file COPYING for details.
*/

#ifndef DATAGRAM_H
#define DATAGRAM_H

/** @file datagram.h UDP datagram communications.
This module implements datagram communications using UDP.
A datagram is a small, fixed size message send to a given
host and port, which is not guaranteed to arrive.
<p>
This module is arguably misnamed: A <tt>struct datagram</tt>
does not represent a datagram, but rather an open port that
can be used to send datagrams with @ref datagram_send.
<p>
Example sender:
<pre>
include "datagram.h"
include "debug.h"

const char *message = "hello world!";
const char *address = "192.168.2.1";
int port = 40000;

d = datagram_create(DATAGRAM_PORT_ANY);
if(!d) fatal("couldn't create datagram port");

datagram_send(d,message,strlen(message),address,port);
</pre>

And an example receiver:

<pre>
include "datagram.h"
include "debug.h"

char message[DATAGRAM_PAYLOAD_MAX];
char address[DATAGRAM_ADDRESS_MAX];
int  port = 40000;

d = datagram_create(port);
if(!d) fatal("couldn't create datagram port");

length = datagram_recv(d,message,sizeof(message),&address,&port,10000000);
if(length>0) {
	message[length] = 0;
	printf("got message: %s\n",message);
} else {
	printf("no message received.\n");
}
</pre>


*/

/** Maximum number of characters in a text formatted datagram address. */
#define DATAGRAM_ADDRESS_MAX 48

/** Maximum number of bytes in a datagram payload */
#define DATAGRAM_PAYLOAD_MAX 65536

/** Used to indicate any available port. */
#define DATAGRAM_PORT_ANY 0

/** The address to send to for broadcasting. */
#define DATAGRAM_ADDRESS_BROADCAST "255.255.255.255"

/** Create a new port for sending or receiving datagrams.
@param port The UDP port number to bind to.  On most versions of Unix, an ordinary user can only bind to ports greater than 1024.
@return A new object for sending or receiving datagrams.  On failure, returns null and sets errno appropriately.  A very common error is EADDRINUSE, which indicates another process is already bound to that port.
*/
struct datagram *datagram_create(int port);

/** Create a new address/port for sending or receiving datagrams.
@param address The IP address to listen on.
@param port The UDP port number to bind to.  On most versions of Unix, an ordinary user can only bind to ports greater than 1024.
@return A new object for sending or receiving datagrams.  On failure, returns null and sets errno appropriately.  A very common error is EADDRINUSE, which indicates another process is already bound to that port.
*/
struct datagram *datagram_create_address(const char *address, int port);

/** Destroy a datagram port.
@param d The datagram object to destroy.
*/
void datagram_delete(struct datagram *d);

/** Receive a datagram.
@param d The datagram object.
@param data Where to store the received message.
@param length The length of the buffer, typically DATAGRAM_PAYLOAD_MAX.
@param addr Pointer to a string of at least DATAGRAM_ADDRESS_MAX characters, which will be filled in with the IP address of the sender.
@param port Pointer to an integer which will be filled in with the port number of the sender.
@param timeout Maximum time to wait, in microseconds.
@return On success, returns the number of bytes received.  On failure, returns less than zero and sets errno appropriately.
*/
int datagram_recv(struct datagram *d, char *data, int length, char *addr, int *port, int timeout);

/** Send a datagram.
@param d The datagram object.
@param data The data to send.
@param length The length of the datagram.
@param addr The address of the recipient.
@param port The port of the recipient.
@return On success, returns the number of bytes sent.  On failure, returns less than zero and sets errno appropriately.
*/
int datagram_send(struct datagram *d, const char *data, int length, const char *addr, int port);

/** Obtain the file descriptor of a datagram object.
@param d The datagram object.
@return The file descriptor associated with the underlying socket.
*/
int datagram_fd(struct datagram *d);

#endif
