summaryrefslogtreecommitdiff
path: root/comm/Datagram.cc
blob: bd1c4babda6fda3b74ffe0a6e10f215af7550085 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
/*
 *	The Unix Channel
 *
 *	by Michel Beaudouin-Lafon
 *
 *	Copyright 1990-1993
 *	Laboratoire de Recherche en Informatique (LRI)
 *
 *	Datagrams
 *
 *	$Id$
 *	$CurLog$
 */

#include "Datagram.h"
#include "MsgBuffer.h"
#include <stdlib.h>
#include <sys/socket.h>

/*?class UchDatagram
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}.
?*/

/*?
These constructors are similar to those of the class \typ{UchSocket}.
?*/
UchDatagram :: UchDatagram (UchAddress* bound, UchAddress* connected)
: UchSocket (bound, connected),
  FAddr (0)
{
}

/*?nodoc?*/
UchDatagram :: UchDatagram (const UchDatagram& d)
: UchSocket (d),
  FAddr (d.FAddr)
{
}

/*?nodoc?*/
UchDatagram :: ~UchDatagram ()
{
}

#ifdef DOC
/*?
Return the address of the sender of the last received message.
?*/
UchAddress*
UchDatagram :: From ()
{ }

#endif /* DOC */

/*?nodoc?*/
UchChannel*
UchDatagram :: Copy () const
{
	return new UchDatagram (*this);
}

/*?nodoc?*/
int
UchDatagram :: 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
UchDatagram :: Send (byte* buf, int len, UchAddress& 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
UchDatagram :: Receive (byte* buf, int len)
{
	GEN_ADDR addr;
	int alen = sizeof (addr);
	int ret;
	
	ret = recvfrom (Fd, (char*) buf, len, 0, &addr.sa, &alen);
	if (ret < 0)
		return ret;
	
	FAddr = UchAddress::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
UchDatagram :: Reply (byte* buf, int len)
{
	if (! FAddr)
		return -1;
	return sendto (FilDes (), (char*) buf, len, 0, FAddr->GetSockAddr (), FAddr->Length ());
}

/*?nextdoc?*/
int
UchDatagram :: Send (UchMsgBuffer& buf, UchAddress& to, bool peek)
{
	int n = Send (buf.Buffer (), buf.BufLength (), to);
	if (! peek)
		buf.Flush (n);
	return n;
}

/*?nextdoc?*/
int
UchDatagram :: Receive (UchMsgBuffer& buf)
{
	int n = Receive (buf.Free (), buf.FreeLength ());
	if (n > 0)
		buf.More (n);
	return n;
}

/*?
The same functions but with a \typ{UchMsgBuffer} argument instead of a byte pointer and size.
As usual, if \var{peek} is true the buffer is not flushed.
?*/
int
UchDatagram :: Reply (UchMsgBuffer& buf, bool peek)
{
	int n = Reply (buf.Buffer (), buf.BufLength ());
	if (! peek)
		buf.Flush (n);
	return n;
}