ns-3-simu_zebra_ipv6-2nd

annotate src/process-manager/unix-datagram-socket-fd.cc @ 4775:fc2c29a13125

After support for TD/NINA on zebra-0.95
author tazaki@vmlinux-zak
date Thu Oct 01 23:37:18 2009 +0900 (2 years ago)
parents 6ac4aa4c80ca
children fd1d8c5657a7

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