/* * The Unix Channel * * by Michel Beaudouin-Lafon * * Copyright 1990-1997 * Laboratoire de Recherche en Informatique (LRI) * * Datagrams * * $Id$ * $CurLog$ */ #include "Datagram.h" #include "MsgBuffer.h" #include #include /*?class IvlDatagram A datagram socket can send to and receive from any other datagram socket, unless it is connected. Thus, establishing a datagram connection is simple. Datagram sockets are not reliable: messages can be lost, duplicated, or be received in a different order. They keep the message boundaries: when \var{n} bytes are written, you will read at most \var{n} bytes; but if you ask to read less than \var{n} bytes, then the end of the message will be lost. When a datagram socket is not connected, you must provide an address when you send a message; when a message is read, the address of the sender can be retrieved (with function \fun{From}). When a datagram socket is connected, messages can only be sent to and read from the connected address. The \fun{Read} and \fun{Write} calls can be used in this case. Before any data can be sent or received, the socket must be set up with \fun{Setup}, or \fun{Open} followed by \fun{Bind} and \fun{Connect} if necessary. ?*/ /*? These constructors are similar to those of the class \typ{IvlSocket}. ?*/ IvlDatagram :: IvlDatagram (IvlAddress* bound, IvlAddress* connected) : IvlSocket (bound, connected), FAddr (0) { } /*?nodoc?*/ IvlDatagram :: IvlDatagram (const IvlDatagram& d) : IvlSocket (d), FAddr (d.FAddr) { } /*?nodoc?*/ IvlDatagram :: ~IvlDatagram () { } #ifdef DOC /*? Return the address of the sender of the last received message. ?*/ IvlAddress* IvlDatagram :: From () { } #endif /* DOC */ /*?nodoc?*/ IvlChannel* IvlDatagram :: Copy () const { return new IvlDatagram (*this); } /*?nodoc?*/ int IvlDatagram :: SockType () { return SOCK_DGRAM; } /*? Send \var{len} bytes of \var{buf} on the datagram, to a destination address \var{to}. Return the number of bytes actually transferred, or -1 if a system error occurred. If the datagram is connected, you must use \fun{Write} instead. ?*/ int IvlDatagram :: Send (byte* buf, int len, IvlAddress& to) { return sendto (FilDes (), (char*) buf, len, 0, to.GetSockAddr (), to.Length ()); } /*? Receive at most \var{len} bytes into \var{buf}. Return the number of bytes actually transferred, or -1 if a system error occurred. The address of the sender can be retrieved with \fun{From}. If the socket is connected, you must use \fun{Read} instead. ?*/ int IvlDatagram :: Receive (byte* buf, int len) { GEN_ADDR addr; socklen_t alen = sizeof (addr); int ret; ret = recvfrom (Fd, (char*) buf, len, 0, &addr.sa, &alen); if (ret < 0) return ret; FAddr = IvlAddress::Decode (&addr, alen); return ret; } /*? This is equivalent to \fun{Send(buf, len, From ())}: it sends \fun{len} bytes to the sender of the last received message. If there is no such sender, it returns -1. ?*/ int IvlDatagram :: Reply (byte* buf, int len) { if (! FAddr) return -1; return sendto (FilDes (), (char*) buf, len, 0, FAddr->GetSockAddr (), FAddr->Length ()); } /*?nextdoc?*/ int IvlDatagram :: Send (IvlMsgBuffer& buf, IvlAddress& to, bool peek) { int n = Send (buf.Buffer (), buf.BufLength (), to); if (! peek) buf.Flush (n); return n; } /*?nextdoc?*/ int IvlDatagram :: Receive (IvlMsgBuffer& buf) { int n = Receive (buf.Free (), buf.FreeLength ()); if (n > 0) buf.More (n); return n; } /*? The same functions but with a \typ{IvlMsgBuffer} argument instead of a byte pointer and size. As usual, if \var{peek} is true the buffer is not flushed. ?*/ int IvlDatagram :: Reply (IvlMsgBuffer& buf, bool peek) { int n = Reply (buf.Buffer (), buf.BufLength ()); if (! peek) buf.Flush (n); return n; }