/* * The Unix Channel * * by Michel Beaudouin-Lafon * * Copyright 1990-1993 * Laboratoire de Recherche en Informatique (LRI) * * Sockets * * $Id$ * $CurLog$ */ #include "Socket.h" #include #include #include extern int errno; /*?class UchSocket The class \typ{UchSocket} derives from \typ{UchChannel}. It is a virtual base class: no objects of class \typ{UchSocket} are ever created. It implements a Unix socket, that is a file descriptor and 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. Addresses are always referenced by pointers. Smart pointers to addresses (\typ{^{pUchAddress}}) can be used anywhere a pointer is used. ?*/ /*? Construct a closed socket bound to address \var{bound} and connected to address \var{connected}. Each or both arguments may be 0. ?*/ UchSocket :: UchSocket (UchAddress* bound, UchAddress* connected) : UchChannel (), BAddr (bound), CAddr (connected), AddrFamily (AF_UNSPEC), Ready (false) { } /*?nodoc?*/ UchSocket :: UchSocket (const UchSocket& s) : UchChannel (s), BAddr (s.BAddr), CAddr (s.CAddr), Ready (s.Ready) { } /*?nodoc?*/ UchSocket :: ~UchSocket () { // will unreference addresses and destroy them if necessary BAddr = 0; CAddr = 0; } #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 UchSocket :: SockType () { } #endif /*?nextdoc?*/ void UchSocket :: BindTo (UchAddress* a) { BAddr = a; } /*? Set the address a socket is to be bound to or connected to. ?*/ void UchSocket :: ConnectTo (UchAddress* a) { 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 UchSocket :: 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; UchChannel::Open (fd); return true; } /*?nextdoc?*/ int UchSocket :: Bind (UchAddress* addr) { if (addr) BAddr = addr; if (! BAddr || ! BAddr->IsValid ()) return -1; if (! Open ()) return -1; int ret = bind (Fd, BAddr->GetSockAddr (), BAddr->Length ()); if (ret < 0) return ret; GEN_ADDR naddr; int alen = sizeof (naddr); if (getsockname (Fd, &naddr.sa, &alen) < 0) return -1; BAddr = UchAddress::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 UchSocket :: Connect (UchAddress* addr) { if (addr) CAddr = addr; if (! CAddr || ! CAddr->IsValid ()) return -1; if (! Open ()) return -1; int ret = connect (Fd, CAddr->GetSockAddr (), CAddr->Length ()); if (ret < 0) return ret; GEN_ADDR naddr; int alen = sizeof (naddr); if (getpeername (Fd, &naddr.sa, &alen) < 0) return -1; CAddr = UchAddress::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 UchSocket :: 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 UchSocket :: Accept () { errno = 0; return accept (Fd, 0, 0); } /*?nodoc?*/ char* UchSocket :: StrRepr (char* buf) { UchChannel :: 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 UchSocket :: 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 UchSocket :: SetFamily (int f) { } /*?nextdoc?*/ UchAddress* UchSocket :: BoundTo () { } /*? Return the address currently bound or connected to the socket. ?*/ UchAddress* UchSocket :: ConnectedTo () { } #endif /* DOC */