/* * Ivy League * * Sockets * * Copyright 1990-2000 * Laboratoire de Recherche en Informatique (LRI) * Centre d'Etudes de la Navigation Aerienne (CENA) * * original code by Michel Beaudouin-Lafon, * modified by Stephane Chatty and Stephane Sire * * $Id$ * */ #include "Socket.h" #include #include #include extern int errno; /*?class IvlSocket The class \typ{IvlSocket} derives from \typ{IvlChannel}. It is a virtual base class: no objects of class \typ{IvlSocket} are ever created. It implements Unix sockets, that is file descriptors with two addresses: the address the socket is bound to, and the address it is connected to. An address needs to be bound to a socket only if another process wants to connect to this socket; a socket needs to be connected to an address only for streams or connected datagrams. Thus, none of the addresses is mandatory. A socket can have potentially two addresses (the one it is BoundTo and the one it is ConnectedTo. Once given to a socket, an \typ{IvlAddress} instance pointer is no more usable because it can be deleted and reallocated by the Socket when it is bound/connected. These address pointers are also deleted by the socket destructor. Thus, to know the address of a socket always use \fun{BoundTo} and \fun{ConnectedTo}. ?*/ /*? Construct a closed socket bound to address \var{bound} and connected to address \var{connected}. Each or both arguments may be 0. These addresses have to be freshly allocated objects and will be deleted by the socket's destructor so it's not necessary (and dangerous) to delete them. always allocated by new. Theses addresses are deleted and reinstanciated after a \fun{Bind}. To obtain the addresses of a socket, use \fun{BoundTo} and \fun{ConnectedTo}. ?*/ IvlSocket :: IvlSocket (IvlAddress* bound, IvlAddress* connected) : IvlChannel (), BAddr (bound), CAddr (connected), AddrFamily (AF_UNSPEC), Ready (false) { } /*?nodoc?*/ IvlSocket :: IvlSocket (const IvlSocket& s) : IvlChannel (s), BAddr (s.BAddr), CAddr (s.CAddr), Ready (s.Ready) { } /*?nodoc?*/ IvlSocket :: ~IvlSocket () { if (BAddr) delete BAddr; if (CAddr) delete CAddr; } #ifdef DOC /*? This virtual function returns the type of the socket: one of \var{SOCK\_UNSPEC}, \var{SOCK\_STREAM}, \var{SOCK\_DGRAM}, depending on the class. ?*/ int IvlSocket :: SockType () { } #endif /*?nextdoc?*/ void IvlSocket :: BindTo (IvlAddress* a) { if (BAddr) delete BAddr; BAddr = a; } /*? Set the address a socket is to be bound to or connected to. ?*/ void IvlSocket :: ConnectTo (IvlAddress* a) { if (CAddr) delete CAddr; CAddr = a; } /*? Open the socket (with the \fun{socket} system call) if it is not already open. The socket must have an address bound or connected to get the protocol family, or its family must have been defined with \fun{SetFamily}. Return false if the family is undefined or if a system error occurred. ?*/ bool IvlSocket :: Open () { errno = 0; if (Fd >= 0) return true; if (AddrFamily == AF_UNSPEC) { if (BAddr) AddrFamily = BAddr->Family (); else if (CAddr) AddrFamily = CAddr->Family (); else return false; } int fd = socket (AddrFamily, SockType (), 0); if (fd < 0) return false; IvlChannel::Open (fd); return true; } /*?nextdoc?*/ int IvlSocket :: Bind (IvlAddress* addr) { if (addr) BindTo (addr); if (! BAddr || ! BAddr->IsValid ()) return -1; if (! Open ()) return -1; int ret = bind (Fd, BAddr->GetSockAddr (), BAddr->Length ()); if (ret < 0) return ret; /* retrieve actual address that was allocated. This is useful if ANYADDR was passed and we need to know the port number */ GEN_ADDR naddr; socklen_t alen = sizeof (naddr); if (getsockname (Fd, &naddr.sa, &alen) < 0) return -1; BindTo (IvlAddress::Decode (&naddr, alen)); return ret; } /*? These two functions implement the Unix system calls \fun{bind} and \fun{connect}. If \var{addr} is given, it is first associated to the socket. Then the socket is opened, and finally the system call is performed. The returned value is that of the system call, unless opening failed in which case -1 is returned. ?*/ int IvlSocket :: Connect (IvlAddress* addr) { if (addr) ConnectTo (addr); if (! CAddr || ! CAddr->IsValid ()) return -1; if (! Open ()) return -1; int ret = connect (Fd, CAddr->GetSockAddr (), CAddr->Length ()); if (ret < 0) return ret; /* retrieve actual address that was allocated. This is useful if ANYADDR was passed and we need to know the port number */ GEN_ADDR naddr; socklen_t alen = sizeof (naddr); if (getpeername (Fd, &naddr.sa, &alen) < 0) return -1; ConnectTo (IvlAddress::Decode (&naddr, alen)); return ret; } /*? Open the socket if it is not already open. Bind and connect it depending on the addresses that are defined. You should use this function instead of calling \fun{Open}, \fun{Bind} and \fun{Connect}, for it is simpler. This function returns false if a system error occurred. In this case, the caller can call \fun{SysError} to report the error. ?*/ bool IvlSocket :: Setup () { if (! Open ()) return Ready = false; if (BAddr && BAddr->IsValid ()) if (Bind () < 0) return Ready = false; if (CAddr && CAddr->IsValid ()) if (Connect () < 0) return Ready = false; return Ready = true; } /*? This function is intended for sockets that accept connections. It returns the file descriptor of the new connection, or -1 in case of failure. ?*/ int IvlSocket :: Accept () { errno = 0; return accept (Fd, 0, 0); } bool IvlSocket :: ReuseAddress (bool on) { int parm = on; int res = setsockopt (Fd, SOL_SOCKET, SO_REUSEADDR, (char *)&parm, sizeof (parm)); return res < 0 ? false : true; } bool IvlSocket :: AllowBroadcast (bool on) { int parm = on; int res = setsockopt (Fd, SOL_SOCKET, SO_BROADCAST, (char *)&parm, sizeof (parm)); return res < 0 ? false : true; } /*?nodoc?*/ char* IvlSocket :: StrRepr (char* buf) { IvlChannel :: StrRepr (buf); strcat (buf, " / "); if (BAddr) BAddr->StrRepr (buf + strlen (buf)); else strcat (buf, "null"); strcat (buf, " / "); if (CAddr) CAddr->StrRepr (buf + strlen (buf)); else strcat (buf, "null"); return buf; } #ifdef DOC /*?nextdoc?*/ int IvlSocket :: Family () { } /*? These function get and set the family. The possible values currently are \var{AF\_UNSPEC}, \var{AF\_UNIX} and \var{AF\_INET}. Other values may be defined if supported by the system. The family must be defined for \fun{Open} (and thus \fun{Setup}) to succeed. If an address is bound or connected to the socket, its family is used. Thus, an application seldom needs to call \fun{SetFamily}. ?*/ void IvlSocket :: SetFamily (int f) { } /*?nextdoc?*/ IvlAddress* IvlSocket :: BoundTo () { } /*? Return the address currently bound or connected to the socket. ?*/ IvlAddress* IvlSocket :: ConnectedTo () { } #endif /* DOC */