blob: c0b287d7ba9dac1f7b0268aa31311e1f786195ba [file] [log] [blame]
// Copyright (C) 1999-2005 Open Source Telecom Corporation.
// Copyright (C) 2006-2010 David Sugar, Tycho Softworks.
//
// This program 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 2 of the License, or
// (at your option) any later version.
//
// This program 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 this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
//
// As a special exception, you may use this file as part of a free software
// library without restriction. Specifically, if other files instantiate
// templates or use macros or inline functions from this file, or you compile
// this file and link it with other files to produce an executable, this
// file does not by itself cause the resulting executable to be covered by
// the GNU General Public License. This exception does not however
// invalidate any other reasons why the executable file might be covered by
// the GNU General Public License.
//
// This exception applies only to the code released under the name GNU
// Common C++. If you copy code from other releases into a copy of GNU
// Common C++, as the General Public License permits, the exception does
// not apply to the code that you add in this way. To avoid misleading
// anyone as to the status of such modified files, you must delete
// this exception notice from them.
//
// If you write modifications of your own for GNU Common C++, it is your choice
// whether to permit this exception to apply to your modifications.
// If you do not wish that, delete this exception notice.
//
/**
* @file commoncpp/udp.h
* @short udp derived socket classes.
**/
#ifndef COMMONCPP_UDP_H_
#define COMMONCPP_UDP_H_
#include <cstdio>
#ifndef COMMONCPP_CONFIG_H_
#include <commoncpp/config.h>
#endif
#ifndef COMMONCPP_STRING_H_
#include <commoncpp/string.h>
#endif
#ifndef COMMONCPP_ADDRESS_H_
#include <commoncpp/address.h>
#endif
#ifndef COMMONCPP_SOCKET_H_
#include <commoncpp/socket.h>
#endif
NAMESPACE_COMMONCPP
/**
* UDP sockets implement the TCP SOCK_DGRAM UDP protocol. They can be
* used to pass unverified messages between hosts, or to broadcast a
* specific message to an entire subnet. Please note that Streaming of
* realtime data commonly use UDPDuplex related classes rather than
* UDPSocket.
*
* In addition to connected TCP sessions, Common C++ supports UDP sockets and
* these also cover a range of functionality. Like a TCPSocket, A UDPSocket
* can be created bound to a specific network interface and/or port address,
* though this is not required. UDP sockets also are usually either
* connected or otherwise "associated" with a specific "peer" UDP socket.
* Since UDP sockets operate through discreet packets, there are no streaming
* operators used with UDP sockets.
*
* In addition to the UDP "socket" class, there is a "UDPBroadcast" class.
* The UDPBroadcast is a socket that is set to send messages to a subnet as a
* whole rather than to an individual peer socket that it may be associated
* with.
*
* UDP sockets are often used for building "realtime" media streaming
* protocols and full duplex messaging services. When used in this manner,
* typically a pair of UDP sockets are used together; one socket is used to
* send and the other to receive data with an associated pair of UDP sockets
* on a "peer" host. This concept is represented through the Common C++
* UDPDuplex object, which is a pair of sockets that communicate with another
* UDPDuplex pair.
*
*
* @author David Sugar <dyfet@ostel.com>
* @short Unreliable Datagram Protocol sockets.
*/
class __EXPORT UDPSocket : public Socket
{
private:
inline Error setKeepAlive(bool enable)
{return Socket::setKeepAlive(enable);};
protected:
#ifdef CCXX_IPV6
union {
struct sockaddr_in6 ipv6;
struct sockaddr_in ipv4;
} peer;
#else
union {
struct sockaddr_in ipv4;
} peer;
#endif
Family family;
public:
/**
* Create an unbound UDP socket, mostly for internal use.
*/
UDPSocket(Family family = IPV4);
/**
* Create a UDP socket bound by a service name.
*/
UDPSocket(const char *name, Family family = IPV4);
/**
* Create a UDP socket and bind it to a specific interface
* and port address so that other UDP sockets on remote
* machines (or the same host) may find and send UDP messages
* to it. On failure to bind, an exception is thrown.
*
* @param bind address to bind this socket to.
* @param port number to bind this socket to.
*/
UDPSocket(const IPV4Address &bind, tpport_t port);
#ifdef CCXX_IPV6
UDPSocket(const IPV6Address &bind, tpport_t port);
#endif
/**
* Destroy a UDP socket as a socket.
*/
virtual ~UDPSocket();
/**
* Set the loopback.
*/
inline Error setLoopback(bool enable)
{return Socket::setLoopbackByFamily(enable, family);}
/**
* Set the multicast.
*/
inline Error setMulticast(bool enable)
{return Socket::setMulticastByFamily(enable, family);}
/**
* Set time to live.
*/
inline Error setTimeToLive(char ttl)
{return Socket::setTimeToLiveByFamily(ttl, family);}
/**
* set the peer address to send message packets to. This can be
* set before every send() call if nessisary.
*
* @param host address to send packets to.
* @param port number to deliver packets to.
*/
void setPeer(const IPV4Host &host, tpport_t port);
void connect(const IPV4Host &host, tpport_t port);
#ifdef CCXX_IPV6
void setPeer(const IPV6Host &host, tpport_t port);
void connect(const IPV6Host &host, tpport_t port);
#endif
/**
* get the interface index for a named network device
*
* @param ethX is device name, like "eth0" or "eth1"
* @param InterfaceIndex is the index value returned by os
* @todo Win32 and ipv6 specific implementation.
*/
Socket::Error getInterfaceIndex(const char *ethX,int& InterfaceIndex);
/**
* join a multicast group on a particular interface
*
* @param ia is the multicast address to use
* @param InterfaceIndex is the index value returned by
* getInterfaceIndex
* @todo Win32 and ipv6 specific implementation.
*/
Socket::Error join(const IPV4Multicast &ia,int InterfaceIndex);
/**
* Send a message packet to a peer host.
*
* @param buf pointer to packet buffer to send.
* @param len of packet buffer to send.
* @return number of bytes sent.
*/
ssize_t send(const void *buf, size_t len);
/**
* Receive a message from any host.
*
* @param buf pointer to packet buffer to receive.
* @param len of packet buffer to receive.
* @param reply save sender address for reply if true.
* @return number of bytes received.
*/
ssize_t receive(void *buf, size_t len, bool reply = false);
/**
* Examine address of sender of next waiting packet. This also
* sets "peer" address to the sender so that the next "send"
* message acts as a "reply". This additional behavior overides
* the standard socket getSender behavior.
*
* @param port pointer to hold port number.
*/
IPV4Host getIPV4Peer(tpport_t *port = NULL) const;
inline IPV4Host getPeer(tpport_t *port = NULL) const
{return getIPV4Peer(port);}
#ifdef CCXX_IPV6
IPV6Host getIPV6Peer(tpport_t *port = NULL) const;
#endif
/**
* Examine contents of next waiting packet.
*
* @param buf pointer to packet buffer for contents.
* @param len of packet buffer.
* @return number of bytes examined.
*/
inline ssize_t peek(void *buf, size_t len)
{return ::recv(so, (char *)buf, len, MSG_PEEK);};
/**
* Associate socket with a named connection
*/
void setPeer(const char *service);
void connect(const char *service);
/**
* Disassociate this socket from any host connection. No data
* should be read or written until a connection is established.
*/
Error disconnect(void);
};
/**
* Representing a UDP socket used for subnet broadcasts, this class
* provides an alternate binding and setPeer() capability for UDP
* sockets.
*
* @author David Sugar <dyfet@ostel.com>
* @short Unreliable Datagram for subnet broadcasts.
*/
class __EXPORT UDPBroadcast : public UDPSocket
{
private:
void setPeer(const IPV4Host &ia, tpport_t port);
Error setBroadcast(bool enable)
{return Socket::setBroadcast(enable);};
public:
/**
* Create and bind a subnet broadcast socket.
*
* @param ia address to bind socket under locally.
* @param port to bind socket under locally.
*/
UDPBroadcast(const IPV4Address &ia, tpport_t port);
/**
* Set peer by subnet rather than specific host.
*
* @param subnet of peer hosts to send to.
* @param port number to use.
*/
void setPeer(const IPV4Broadcast &subnet, tpport_t port);
};
/**
* Representing half of a two-way UDP connection, the UDP transmitter
* can broadcast data to another selected peer host or to an entire
* subnet.
*
* @author David Sugar <dyfet@ostel.com>
* @short Unreliable Datagram Peer Associations.
*/
class __EXPORT UDPTransmit : protected UDPSocket
{
private:
/**
* Common code for diferent flavours of Connect (host, broadcast,
* multicast).
*
* @param ia network address to associate with
* @param port port number to associate with
*/
Error cConnect(const IPV4Address &ia, tpport_t port);
protected:
/**
* Create a UDP transmitter.
*/
UDPTransmit(Family family = IPV4);
/**
* Create a UDP transmitter, bind it to a specific interface
* and port address so that other UDP sockets on remote
* machines (or the same host) may find and send UDP messages
* to it, and associate it with a given port on a peer host.
* On failure to bind, an exception is thrown. This class is
* only used to build the UDP Duplex.
*
* @param bind address to bind this socket to.
* @param port number to bind this socket to.
*/
UDPTransmit(const IPV4Address &bind, tpport_t port = 5005);
#ifdef CCXX_IPV6
UDPTransmit(const IPV6Address &bind, tpport_t port = 5005);
#endif
/**
* Associate this socket with a specified peer host. The port
* number from the constructor will be used. All UDP packets
* will be sent to and received from the specified host.
*
* @return 0 on success, -1 on error.
* @param host address to connect socket to.
* @param port to connect socket to.
*/
Error connect(const IPV4Host &host, tpport_t port);
#ifdef CCXX_IPV6
Error connect(const IPV6Address &host, tpport_t port);
#endif
/**
* Associate this socket with a subnet of peer hosts for
* subnet broadcasting. The server must be able to assert
* broadcast permission for the socket.
*
* @return 0 on success, -1 on error.
* @param subnet subnet address to broadcast into.
* @param port transport port to broadcast into.
*/
Error connect(const IPV4Broadcast &subnet, tpport_t port);
/**
* Associate this socket with a multicast group.
*
* @return 0 on success, -1 on error.
* @param mgroup address of the multicast group to send to.
* @param port port number
*/
Error connect(const IPV4Multicast &mgroup, tpport_t port);
#ifdef CCXX_IPV6
Error connect(const IPV6Multicast &mgroup, tpport_t port);
#endif
/**
* Transmit "send" to use "connected" send rather than sendto.
*
* @return number of bytes sent.
* @param buf address of buffer to send.
* @param len of bytes to send.
*/
inline ssize_t send(const void *buf, size_t len)
{return ::send(so, (const char *)buf, len, MSG_NOSIGNAL);}
/**
* Stop transmitter.
*/
inline void endTransmitter(void)
{Socket::endSocket();}
/*
* Get transmitter socket.
*
* @return transmitter.
*/
inline SOCKET getTransmitter(void)
{return so;};
inline Error setMulticast(bool enable)
{return Socket::setMulticastByFamily(enable, family);}
inline Error setTimeToLive(unsigned char ttl)
{return Socket::setTimeToLiveByFamily(ttl, family);};
public:
/**
* Transmit "send" to use "connected" send rather than sendto.
*
* @note Windows does not support MSG_DONTWAIT, so it is defined
* as 0 on that platform.
* @return number of bytes sent.
* @param buffer address of buffer to send.
* @param len of bytes to send.
*/
inline ssize_t transmit(const char *buffer, size_t len)
{return ::send(so, buffer, len, MSG_DONTWAIT|MSG_NOSIGNAL);}
/**
* See if output queue is empty for sending more packets.
*
* @return true if output available.
* @param timeout in milliseconds to wait.
*/
inline bool isOutputReady(unsigned long timeout = 0l)
{return Socket::isPending(Socket::pendingOutput, timeout);};
inline Error setRouting(bool enable)
{return Socket::setRouting(enable);};
inline Error setTypeOfService(Tos tos)
{return Socket::setTypeOfService(tos);};
inline Error setBroadcast(bool enable)
{return Socket::setBroadcast(enable);};
};
/**
* Representing half of a two-way UDP connection, the UDP receiver
* can receive data from another peer host or subnet. This class is
* used exclusivily to derive the UDPDuplex.
*
* @author David Sugar <dyfet@ostel.com>
* @short Unreliable Datagram Peer Associations.
*/
class __EXPORT UDPReceive : protected UDPSocket
{
protected:
/**
* Create a UDP receiver, bind it to a specific interface
* and port address so that other UDP sockets on remote
* machines (or the same host) may find and send UDP messages
* to it, and associate it with a given port on a peer host.
* On failure to bind, an exception is thrown.
*
* @param bind address to bind this socket to.
* @param port number to bind this socket to.
*/
UDPReceive(const IPV4Address &bind, tpport_t port);
#ifdef CCXX_IPV6
UDPReceive(const IPV6Address &bind, tpport_t port);
#endif
/**
* Associate this socket with a specified peer host. The port
* number from the constructor will be used. All UDP packets
* will be sent received from the specified host.
*
* @return 0 on success, -1 on error.
* @param host host network address to connect socket to.
* @param port host transport port to connect socket to.
*/
Error connect(const IPV4Host &host, tpport_t port);
#ifdef CCXX_IPV6
Error connect(const IPV6Host &host, tpport_t port);
#endif
/**
* Check for pending data.
*
* @return true if data is waiting.
* @param timeout in milliseconds.
*/
bool isPendingReceive(timeout_t timeout)
{return Socket::isPending(Socket::pendingInput, timeout);};
/**
* End receiver.
*/
inline void endReceiver(void)
{Socket::endSocket();}
inline SOCKET getReceiver(void) const
{return so;};
inline Error setRouting(bool enable)
{return Socket::setRouting(enable);}
inline Error setMulticast(bool enable)
{return Socket::setMulticastByFamily(enable, family);}
inline Error join(const IPV4Multicast &ia)
{return Socket::join(ia);}
#ifdef CCXX_IPV6
inline Error join(const IPV6Multicast &ia)
{return Socket::join(ia);}
#endif
inline Error drop(const IPV4Multicast &ia)
{return Socket::drop(ia);}
#ifdef CCXX_IPV6
inline Error drop(const IPV6Multicast &ia)
{return Socket::drop(ia);}
#endif
public:
/**
* Receive a data packet from the connected peer host.
*
* @return num of bytes actually received.
* @param buf address of data receive buffer.
* @param len size of data receive buffer.
*/
inline ssize_t receive(void *buf, size_t len)
{return ::recv(so, (char *)buf, len, 0);};
/**
* See if input queue has data packets available.
*
* @return true if data packets available.
* @param timeout in milliseconds.
*/
inline bool isInputReady(timeout_t timeout = TIMEOUT_INF)
{return Socket::isPending(Socket::pendingInput, timeout);};
};
/**
* UDP duplex connections impliment a bi-directional point-to-point UDP
* session between two peer hosts. Two UDP sockets are typically used
* on alternating port addresses to assure that sender and receiver
* data does not collide or echo back. A UDP Duplex is commonly used
* for full duplex real-time streaming of UDP data between hosts.
*
* @author David Sugar <dyfet@ostel.com>
* @short Unreliable Datagram Peer Associations.
*/
class __EXPORT UDPDuplex : public UDPTransmit, public UDPReceive
{
public:
/**
* Create a UDP duplex as a pair of UDP simplex objects
* bound to alternating and interconnected port addresses.
*
* @param bind address to bind this socket to.
* @param port number to bind sender.
*/
UDPDuplex(const IPV4Address &bind, tpport_t port);
#ifdef CCXX_IPV6
UDPDuplex(const IPV6Address &bind, tpport_t port);
#endif
/**
* Associate the duplex with a specified peer host. Both
* the sender and receiver will be interconnected with
* the remote host.
*
* @return 0 on success, error code on error.
* @param host address to connect socket to.
* @param port number to connect socket to.
*/
Error connect(const IPV4Host &host, tpport_t port);
#ifdef CCXX_IPV6
Error connect(const IPV6Host &host, tpport_t port);
#endif
/**
* Disassociate this duplex from any host connection. No data
* should be read or written until a connection is established.
*
* @return 0 on success, error code on error.
*/
Error disconnect(void);
};
END_NAMESPACE
#endif