ns-3-simu_zebra_ipv6-2nd
view src/process-manager/unix-datagram-socket-fd.cc @ 4769:6ac4aa4c80ca
make sure we update the ancillary buffer length, even when no ancillary data is present
| author | Mathieu Lacage <mathieu.lacage@sophia.inria.fr> |
|---|---|
| date | Mon Sep 07 13:50:18 2009 +0200 (2 years ago) |
| parents | 54dd4fd1d4b6 |
| children | fc2c29a13125 |
line source
1 #include "process.h"
2 #include "process-manager.h"
3 #include "utils.h"
4 #include "unix-datagram-socket-fd.h"
5 #include "ns3/log.h"
6 #include "ns3/socket.h"
7 #include "ns3/packet.h"
8 #include "ns3/simulator.h"
9 #include "ns3/inet-socket-address.h"
10 #include "cmsg.h"
11 #include <errno.h>
12 #include <netinet/in.h>
13 #include <linux/types.h>
14 #include <linux/errqueue.h>
15 #include <arpa/inet.h>
17 NS_LOG_COMPONENT_DEFINE ("UnixDatagramSocketFd");
19 namespace ns3 {
21 UnixDatagramSocketFd::UnixDatagramSocketFd (Ptr<Socket> sock)
22 : UnixSocketFd (sock)
23 {
24 // XXX: should I really do this here ?
25 m_socket->SetAttributeFailSafe ("IcmpCallback", CallbackValue (MakeCallback (&UnixDatagramSocketFd::IcmpCallback, this)));
26 }
28 bool
29 UnixDatagramSocketFd::CanRecv (void) const
30 {
31 return m_socket != 0 && m_socket->GetRxAvailable () != 0;
32 }
33 bool
34 UnixDatagramSocketFd::CanSend (void) const
35 {
36 return m_socket != 0 && m_socket->GetTxAvailable () != 0;
37 }
39 void
40 UnixDatagramSocketFd::QueueErr (sock_extended_err ee, struct sockaddr_in offender, uint8_t ttl)
41 {
42 NS_LOG_FUNCTION (this);
43 if (!IsRecvErr ())
44 {
45 return;
46 }
47 struct Error e;
48 e.ee = ee;
49 e.offender = offender;
50 e.ttl = ttl;
51 m_errQueue.push_back (e);
52 }
54 void
55 UnixDatagramSocketFd::IcmpCallback (Ipv4Address icmpSource, uint8_t icmpTtl,
56 uint8_t icmpType, uint8_t icmpCode,
57 uint32_t icmpInfo)
58 {
59 NS_LOG_FUNCTION (this << icmpSource << (uint32_t)icmpTtl << (uint32_t)icmpType <<
60 (uint32_t)icmpCode << icmpInfo);
61 // received icmp errors never interrupt a blocked recv and
62 // never notify a blocked select/poll.
64 sock_extended_err ee;
65 struct sockaddr_in offender;
67 if (icmpType == Icmpv4Header::DEST_UNREACH &&
68 icmpCode == Icmpv4DestinationUnreachable::FRAG_NEEDED)
69 {
71 ee.ee_errno = EMSGSIZE;
72 }
73 else if (icmpType == Icmpv4Header::DEST_UNREACH &&
74 icmpCode == Icmpv4DestinationUnreachable::PORT_UNREACHABLE)
75 {
77 ee.ee_errno = EHOSTUNREACH;
78 }
79 else if (icmpType == Icmpv4Header::TIME_EXCEEDED &&
80 icmpCode == Icmpv4TimeExceeded::TIME_TO_LIVE)
81 {
82 ee.ee_errno = EHOSTUNREACH;
83 }
84 else
85 {
86 NS_ASSERT (false);
87 ee.ee_errno = 0;
88 }
89 ee.ee_origin = SO_EE_ORIGIN_ICMP;
90 ee.ee_type = icmpType;
91 ee.ee_code = icmpCode;
92 ee.ee_pad = 0;
93 ee.ee_info = icmpInfo;
94 ee.ee_data = 0;
95 offender.sin_family = AF_INET;
96 offender.sin_addr.s_addr = htonl (icmpSource.Get ());
97 offender.sin_port = 0;
98 QueueErr (ee, offender, icmpTtl);
99 }
101 ssize_t
102 UnixDatagramSocketFd::Recvmsg (struct msghdr *msg, int flags)
103 {
104 Thread *current = Current ();
105 NS_LOG_FUNCTION (this << current);
106 NS_ASSERT (current != 0);
108 if (flags & MSG_ERRQUEUE)
109 {
110 // MSG_ERRQUEUE is valid only for DGRAM sockets.
111 if (m_errQueue.empty ())
112 {
113 current->err = EAGAIN;
114 return -1;
115 }
117 Cmsg cmsg = Cmsg (msg);
118 if (IsRecvErr ())
119 {
120 cmsg.Add (SOL_IP, IP_RECVERR, sizeof (struct Error), (const uint8_t*)&m_errQueue.front ());
121 }
122 if (IsRecvTtl ())
123 {
124 int tmp = m_errQueue.front ().ttl;
125 cmsg.Add (SOL_IP, IP_TTL, sizeof (int), (const uint8_t*)&tmp);
126 }
127 cmsg.Finish ();
128 m_errQueue.pop_front ();
129 return 0;
130 }
131 else
132 {
133 msg->msg_controllen = 0;
134 }
136 if (!WaitRecvDoSignal (flags & MSG_DONTWAIT))
137 {
138 // current->err set by call above.
139 return -1;
140 }
142 uint32_t count = msg->msg_iov[0].iov_len;
143 uint8_t *buf = (uint8_t *)msg->msg_iov[0].iov_base;
144 // we ignore the secondary items of the iovec buffers.
145 // because we implement a datagram-only socket for now.
146 Address from;
147 Ptr<Packet> packet = m_socket->RecvFrom (count, flags, from);
148 if (packet == 0)
149 {
150 current->err = ErrnoToSimuErrno ();
151 return -1;
152 }
153 Ns3AddressToPosixAddress (from, (struct sockaddr*)msg->msg_name, &msg->msg_namelen);
154 // XXX: we ignore MSG_TRUNC for the return value.
155 NS_ASSERT (packet->GetSize () <= count);
156 memcpy (buf, packet->PeekData (), packet->GetSize ());
157 return packet->GetSize ();
158 }
159 ssize_t
160 UnixDatagramSocketFd::Sendmsg(const struct msghdr *msg, int flags)
161 {
162 Thread *current = Current ();
163 NS_LOG_FUNCTION (this << current);
164 NS_ASSERT (current != 0);
167 ssize_t retval = 0;
168 for (uint32_t i = 0; i < msg->msg_iovlen; ++i)
169 {
170 uint8_t *buf = (uint8_t *)msg->msg_iov[i].iov_base;
171 uint32_t len = msg->msg_iov[i].iov_len;
172 Ptr<Packet> packet = Create<Packet> (buf, len);
173 int result;
174 if (msg->msg_name != 0 && msg->msg_namelen != 0)
175 {
176 Address ad = PosixAddressToNs3Address ((const struct sockaddr *)msg->msg_name,
177 (socklen_t)msg->msg_namelen);
178 result = m_socket->SendTo (packet, flags, ad);
179 }
180 else
181 {
182 result = m_socket->Send (packet);
183 }
184 if (result == -1)
185 {
186 current->err = ErrnoToSimuErrno ();
187 return -1;
188 }
189 retval += result;
190 }
191 return retval;
192 }
193 int
194 UnixDatagramSocketFd::Listen (int backlog)
195 {
196 Thread *current = Current ();
197 NS_LOG_FUNCTION (this << current);
198 NS_ASSERT (current != 0);
199 current->err = EOPNOTSUPP;
200 return -1;
201 }
202 int
203 UnixDatagramSocketFd::Accept (struct sockaddr *my_addr, socklen_t *addrlen)
204 {
205 Thread *current = Current ();
206 NS_LOG_FUNCTION (this << current << my_addr << addrlen);
207 NS_ASSERT (current != 0);
208 current->err = EOPNOTSUPP;
209 return -1;
210 }
211 int
212 UnixDatagramSocketFd::Shutdown (int how)
213 {
214 Thread *current = Current ();
215 NS_LOG_FUNCTION (this << current << how);
216 NS_ASSERT (current != 0);
217 // XXX: linux does not generate EOPNOTSUPP for this. I _think_ it
218 // generates ENOTCONN which, honestly, makes _zero_ sense.
219 current->err = EOPNOTSUPP;
220 return -1;
221 }
224 } // namespace ns3
