| 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
|