ns-3-simu_zebra_ipv6-2nd
view src/process-manager/unix-datagram-socket-fd.cc @ 4777:fd1d8c5657a7
during UDP6 support in new ns-3-simu
| author | tazaki@vmlinux-zak |
|---|---|
| date | Fri Oct 16 01:04:42 2009 +0900 (2 years ago) |
| parents | fc2c29a13125 |
| children | 4896a606945d |
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/node.h"
10 #include "ns3/inet-socket-address.h"
11 #include "ns3/ipv6-raw-socket-impl.h"
12 #include "ns3/ipv6.h"
13 #include "ns3/udp6-socket-impl.h"
14 #include "cmsg.h"
15 #include <errno.h>
16 #include <netinet/in.h>
17 #include <linux/types.h>
18 #include <linux/errqueue.h>
19 #include <arpa/inet.h>
21 NS_LOG_COMPONENT_DEFINE ("UnixDatagramSocketFd");
23 namespace ns3 {
25 UnixDatagramSocketFd::UnixDatagramSocketFd (Ptr<Socket> sock)
26 : UnixSocketFd (sock)
27 {
28 // XXX: should I really do this here ?
29 m_socket->SetAttributeFailSafe ("IcmpCallback", CallbackValue (MakeCallback (&UnixDatagramSocketFd::IcmpCallback, this)));
30 }
32 bool
33 UnixDatagramSocketFd::CanRecv (void) const
34 {
35 return m_socket != 0 && m_socket->GetRxAvailable () != 0;
36 }
37 bool
38 UnixDatagramSocketFd::CanSend (void) const
39 {
40 return m_socket != 0 && m_socket->GetTxAvailable () != 0;
41 }
43 void
44 UnixDatagramSocketFd::QueueErr (sock_extended_err ee, struct sockaddr_in offender, uint8_t ttl)
45 {
46 NS_LOG_FUNCTION (this);
47 if (!IsRecvErr ())
48 {
49 return;
50 }
51 struct Error e;
52 e.ee = ee;
53 e.offender = offender;
54 e.ttl = ttl;
55 m_errQueue.push_back (e);
56 }
58 void
59 UnixDatagramSocketFd::IcmpCallback (Ipv4Address icmpSource, uint8_t icmpTtl,
60 uint8_t icmpType, uint8_t icmpCode,
61 uint32_t icmpInfo)
62 {
63 NS_LOG_FUNCTION (this << icmpSource << (uint32_t)icmpTtl << (uint32_t)icmpType <<
64 (uint32_t)icmpCode << icmpInfo);
65 // received icmp errors never interrupt a blocked recv and
66 // never notify a blocked select/poll.
68 sock_extended_err ee;
69 struct sockaddr_in offender;
71 if (icmpType == Icmpv4Header::DEST_UNREACH &&
72 icmpCode == Icmpv4DestinationUnreachable::FRAG_NEEDED)
73 {
75 ee.ee_errno = EMSGSIZE;
76 }
77 else if (icmpType == Icmpv4Header::DEST_UNREACH &&
78 icmpCode == Icmpv4DestinationUnreachable::PORT_UNREACHABLE)
79 {
81 ee.ee_errno = EHOSTUNREACH;
82 }
83 else if (icmpType == Icmpv4Header::TIME_EXCEEDED &&
84 icmpCode == Icmpv4TimeExceeded::TIME_TO_LIVE)
85 {
86 ee.ee_errno = EHOSTUNREACH;
87 }
88 else
89 {
90 NS_ASSERT (false);
91 ee.ee_errno = 0;
92 }
93 ee.ee_origin = SO_EE_ORIGIN_ICMP;
94 ee.ee_type = icmpType;
95 ee.ee_code = icmpCode;
96 ee.ee_pad = 0;
97 ee.ee_info = icmpInfo;
98 ee.ee_data = 0;
99 offender.sin_family = AF_INET;
100 offender.sin_addr.s_addr = htonl (icmpSource.Get ());
101 offender.sin_port = 0;
102 QueueErr (ee, offender, icmpTtl);
103 }
105 ssize_t
106 UnixDatagramSocketFd::Recvmsg (struct msghdr *msg, int flags)
107 {
108 Thread *current = Current ();
109 NS_LOG_FUNCTION (this << current);
110 NS_ASSERT (current != 0);
112 if (flags & MSG_ERRQUEUE)
113 {
114 // MSG_ERRQUEUE is valid only for DGRAM sockets.
115 if (m_errQueue.empty ())
116 {
117 current->err = EAGAIN;
118 return -1;
119 }
121 Cmsg cmsg = Cmsg (msg);
122 if (IsRecvErr ())
123 {
124 cmsg.Add (SOL_IP, IP_RECVERR, sizeof (struct Error), (const uint8_t*)&m_errQueue.front ());
125 }
126 if (IsRecvTtl ())
127 {
128 int tmp = m_errQueue.front ().ttl;
129 cmsg.Add (SOL_IP, IP_TTL, sizeof (int), (const uint8_t*)&tmp);
130 }
131 cmsg.Finish ();
132 m_errQueue.pop_front ();
133 return 0;
134 }
135 else
136 {
137 // msg->msg_controllen = 0;
138 }
140 if (!WaitRecvDoSignal (flags & MSG_DONTWAIT))
141 {
142 // current->err set by call above.
143 return -1;
144 }
146 uint32_t count = msg->msg_iov[0].iov_len;
147 uint8_t *buf = (uint8_t *)msg->msg_iov[0].iov_base;
148 // we ignore the secondary items of the iovec buffers.
149 // because we implement a datagram-only socket for now.
150 Address from;
151 Ptr<Packet> packet = m_socket->RecvFrom (count, flags, from);
152 if (packet == 0)
153 {
154 current->err = ErrnoToSimuErrno ();
155 return -1;
156 }
157 Ns3AddressToPosixAddress (from, (struct sockaddr*)msg->msg_name, &msg->msg_namelen);
159 if(msg->msg_controllen > 0){
160 Cmsg cmsg = Cmsg (msg);
161 if (IsRecvPktInfo ())
162 {
163 struct in6_pktinfo pkt;
165 SocketRecvIfTag tag;
166 bool found;
167 found = packet->FindFirstMatchingByteTag (tag);
168 NS_ASSERT (found);
170 Ptr<Node> node = current->process->manager->GetObject<Node> ();
171 Ptr<Ipv6> ipv6 = node->GetObject<Ipv6> ();
172 pkt.ipi6_ifindex = ipv6->GetInterfaceForDevice (node->GetDevice(tag.GetRecvIf ()));
173 memcpy(&pkt.ipi6_addr, msg->msg_name, sizeof(pkt.ipi6_addr));
174 cmsg.Add (SOL_IPV6, IPV6_PKTINFO, sizeof (struct in6_pktinfo), (const uint8_t*)&pkt);
176 Ipv6Header hdr = Ipv6Header();
177 packet->RemoveHeader (hdr);
178 }
179 cmsg.Finish ();
180 }
183 // XXX: we ignore MSG_TRUNC for the return value.
184 NS_ASSERT (packet->GetSize () <= count);
185 memcpy (buf, packet->PeekData (), packet->GetSize ());
186 return packet->GetSize ();
187 }
188 ssize_t
189 UnixDatagramSocketFd::Sendmsg(const struct msghdr *msg, int flags)
190 {
191 Thread *current = Current ();
192 NS_LOG_FUNCTION (this << current);
193 NS_ASSERT (current != 0);
194 uint32_t old_ifindex = 0;
196 // parse cmsg
197 Cmsg cmsg = Cmsg ((struct msghdr *)msg);
198 int level, type, len;
199 uint8_t *data = NULL;
200 if (cmsg.GetNext (&level, &type, &len, &data) == 0)
201 {
202 switch (type){
203 case IPV6_PKTINFO:{
204 struct in6_pktinfo *pktinfo = (struct in6_pktinfo *)data;
205 if (len != sizeof(struct in6_pktinfo))
206 break;
208 // if(m_socket.GetTypeId().IsChildOf (Ipv6RawSocketImpl::GetTypeId ()))
209 if(typeid(* PeekPointer(m_socket)) == typeid(Ipv6RawSocketImpl))
210 {
211 NS_LOG_INFO("sendmsg: set ifindex to " << pktinfo->ipi6_ifindex);
212 old_ifindex = (dynamic_cast<Ipv6RawSocketImpl *>(PeekPointer(m_socket)))->GetIfIndex();
213 (dynamic_cast<Ipv6RawSocketImpl *>(PeekPointer(m_socket)))->SetIfIndex(pktinfo->ipi6_ifindex);
214 }
215 else if(typeid(* PeekPointer(m_socket)) == typeid(Udp6SocketImpl))
216 {
217 NS_LOG_INFO("sendmsg: set ifindex to " << pktinfo->ipi6_ifindex);
218 old_ifindex = (dynamic_cast<Udp6SocketImpl *>(PeekPointer(m_socket)))->GetIfIndex();
219 (dynamic_cast<Udp6SocketImpl *>(PeekPointer(m_socket)))->SetIfIndex(pktinfo->ipi6_ifindex);
220 }
221 }break;
222 default: {
223 NS_LOG_INFO ("cmsg: Currently not supported");
224 }break;
225 }
226 }
227 cmsg.Finish ();
229 ssize_t retval = 0;
230 for (uint32_t i = 0; i < msg->msg_iovlen; ++i)
231 {
232 uint8_t *buf = (uint8_t *)msg->msg_iov[i].iov_base;
233 uint32_t len = msg->msg_iov[i].iov_len;
234 Ptr<Packet> packet = Create<Packet> (buf, len);
235 int result;
236 if (msg->msg_name != 0 && msg->msg_namelen != 0)
237 {
238 Address ad = PosixAddressToNs3Address ((const struct sockaddr *)msg->msg_name,
239 (socklen_t)msg->msg_namelen);
240 result = m_socket->SendTo (packet, flags, ad);
241 }
242 else
243 {
244 result = m_socket->Send (packet);
245 }
247 if(typeid(* PeekPointer(m_socket)) == typeid(Ipv6RawSocketImpl))
248 {
249 (dynamic_cast<Ipv6RawSocketImpl *>(PeekPointer(m_socket)))->SetIfIndex(old_ifindex);
250 }
251 else if(typeid(* PeekPointer(m_socket)) == typeid(Udp6SocketImpl))
252 {
253 (dynamic_cast<Udp6SocketImpl *>(PeekPointer(m_socket)))->SetIfIndex(old_ifindex);
254 }
256 if (result == -1)
257 {
258 current->err = ErrnoToSimuErrno ();
259 return -1;
260 }
261 retval += result;
262 }
263 return retval;
264 }
265 int
266 UnixDatagramSocketFd::Listen (int backlog)
267 {
268 Thread *current = Current ();
269 NS_LOG_FUNCTION (this << current);
270 NS_ASSERT (current != 0);
271 current->err = EOPNOTSUPP;
272 return -1;
273 }
274 int
275 UnixDatagramSocketFd::Accept (struct sockaddr *my_addr, socklen_t *addrlen)
276 {
277 Thread *current = Current ();
278 NS_LOG_FUNCTION (this << current << my_addr << addrlen);
279 NS_ASSERT (current != 0);
280 current->err = EOPNOTSUPP;
281 return -1;
282 }
283 int
284 UnixDatagramSocketFd::Shutdown (int how)
285 {
286 Thread *current = Current ();
287 NS_LOG_FUNCTION (this << current << how);
288 NS_ASSERT (current != 0);
289 // XXX: linux does not generate EOPNOTSUPP for this. I _think_ it
290 // generates ENOTCONN which, honestly, makes _zero_ sense.
291 current->err = EOPNOTSUPP;
292 return -1;
293 }
296 } // namespace ns3
