#include <UDP.h>
Classes | |
| struct | SockDesc |
Public Types | |
| typedef std::list< SockDesc * > | SockDescList |
| typedef std::map< int, SockDesc * > | SocketsByIdMap |
| typedef std::map< int, SockDescList > | SocketsByPortMap |
Public Member Functions | |
| UDP () | |
| virtual | ~UDP () |
Protected Member Functions | |
| virtual void | updateDisplayString () |
| virtual void | bind (int gateIndex, UDPControlInfo *ctrl) |
| virtual void | connect (int sockId, IPvXAddress addr, int port) |
| virtual void | unbind (int sockId) |
| virtual ushort | getEphemeralPort () |
| virtual bool | matchesSocket (SockDesc *sd, UDPPacket *udp, IPControlInfo *ctrl) |
| virtual bool | matchesSocket (SockDesc *sd, UDPPacket *udp, IPv6ControlInfo *ctrl) |
| virtual bool | matchesSocket (SockDesc *sd, const IPvXAddress &localAddr, const IPvXAddress &remoteAddr, ushort remotePort) |
| virtual void | sendUp (cPacket *payload, UDPPacket *udpHeader, IPControlInfo *ctrl, SockDesc *sd) |
| virtual void | sendUp (cPacket *payload, UDPPacket *udpHeader, IPv6ControlInfo *ctrl, SockDesc *sd) |
| virtual void | processUndeliverablePacket (UDPPacket *udpPacket, cPolymorphic *ctrl) |
| virtual void | sendUpErrorNotification (SockDesc *sd, int msgkind, const IPvXAddress &localAddr, const IPvXAddress &remoteAddr, ushort remotePort) |
| virtual void | processICMPError (cPacket *icmpErrorMsg) |
| virtual void | processUDPPacket (UDPPacket *udpPacket) |
| virtual void | processMsgFromApp (cPacket *appData) |
| virtual void | processCommandFromApp (cMessage *msg) |
| virtual UDPPacket * | createUDPPacket (const char *name) |
| virtual void | initialize () |
| virtual void | handleMessage (cMessage *msg) |
Protected Attributes | |
| SocketsByIdMap | socketsByIdMap |
| SocketsByPortMap | socketsByPortMap |
| ushort | lastEphemeralPort |
| ICMP * | icmp |
| ICMPv6 * | icmpv6 |
| int | numSent |
| int | numPassedUp |
| int | numDroppedWrongPort |
| int | numDroppedBadChecksum |
Implements the UDP protocol: encapsulates/decapsulates user data into/from UDP.
More info in the NED file.
Definition at line 46 of file UDP.h.
| typedef std::list<SockDesc *> UDP::SockDescList |
| typedef std::map<int,SockDesc *> UDP::SocketsByIdMap |
| typedef std::map<int,SockDescList> UDP::SocketsByPortMap |
| UDP::~UDP | ( | ) | [virtual] |
Definition at line 75 of file UDP.cc.
{
for (SocketsByIdMap::iterator i=socketsByIdMap.begin(); i!=socketsByIdMap.end(); ++i)
delete i->second;
}
| void UDP::bind | ( | int | gateIndex, | |
| UDPControlInfo * | ctrl | |||
| ) | [protected, virtual] |
Definition at line 100 of file UDP.cc.
Referenced by processCommandFromApp().
{
// XXX checks could be added, of when the bind should be allowed to proceed
// create and fill in SockDesc
SockDesc *sd = new SockDesc();
sd->sockId = ctrl->getSockId();
sd->userId = ctrl->getUserId();
sd->appGateIndex = gateIndex;
sd->localAddr = ctrl->getSrcAddr();
sd->remoteAddr = ctrl->getDestAddr();
sd->localPort = ctrl->getSrcPort();
sd->remotePort = ctrl->getDestPort();
sd->interfaceId = ctrl->getInterfaceId();
if (sd->sockId==-1)
error("sockId in BIND message not filled in");
if (sd->localPort==0)
sd->localPort = getEphemeralPort();
sd->onlyLocalPortIsSet = sd->localAddr.isUnspecified() &&
sd->remoteAddr.isUnspecified() &&
sd->remotePort==0 &&
sd->interfaceId==-1;
EV << "Binding socket: " << *sd << "\n";
// add to socketsByIdMap
ASSERT(socketsByIdMap.find(sd->sockId)==socketsByIdMap.end());
socketsByIdMap[sd->sockId] = sd;
// add to socketsByPortMap
SockDescList& list = socketsByPortMap[sd->localPort]; // create if doesn't exist
list.push_back(sd);
}
| void UDP::connect | ( | int | sockId, | |
| IPvXAddress | addr, | |||
| int | port | |||
| ) | [protected, virtual] |
Definition at line 136 of file UDP.cc.
Referenced by processCommandFromApp().
{
SocketsByIdMap::iterator it = socketsByIdMap.find(sockId);
if (it==socketsByIdMap.end())
error("socket id=%d doesn't exist (already closed?)", sockId);
if (addr.isUnspecified())
opp_error("connect: unspecified remote address");
if (port<=0 || port>65535)
opp_error("connect: invalid remote port number %d", port);
SockDesc *sd = it->second;
sd->remoteAddr = addr;
sd->remotePort = port;
sd->onlyLocalPortIsSet = false;
EV << "Connecting socket: " << *sd << "\n";
}
| UDPPacket * UDP::createUDPPacket | ( | const char * | name | ) | [protected, virtual] |
Definition at line 526 of file UDP.cc.
Referenced by processMsgFromApp().
{
return new UDPPacket(name);
}
| ushort UDP::getEphemeralPort | ( | ) | [protected, virtual] |
Definition at line 176 of file UDP.cc.
Referenced by bind().
{
// start at the last allocated port number + 1, and search for an unused one
ushort searchUntil = lastEphemeralPort++;
if (lastEphemeralPort == EPHEMERAL_PORTRANGE_END) // wrap
lastEphemeralPort = EPHEMERAL_PORTRANGE_START;
while (socketsByPortMap.find(lastEphemeralPort)!=socketsByPortMap.end())
{
if (lastEphemeralPort == searchUntil) // got back to starting point?
error("Ephemeral port range %d..%d exhausted, all ports occupied", EPHEMERAL_PORTRANGE_START, EPHEMERAL_PORTRANGE_END);
lastEphemeralPort++;
if (lastEphemeralPort == EPHEMERAL_PORTRANGE_END) // wrap
lastEphemeralPort = EPHEMERAL_PORTRANGE_START;
}
// found a free one, return it
return lastEphemeralPort;
}
| void UDP::handleMessage | ( | cMessage * | msg | ) | [protected, virtual] |
Definition at line 196 of file UDP.cc.
{
// received from IP layer
if (msg->arrivedOn("ipIn") || msg->arrivedOn("ipv6In"))
{
if (dynamic_cast<ICMPMessage *>(msg) || dynamic_cast<ICMPv6Message *>(msg))
processICMPError(PK(msg));
else
processUDPPacket(check_and_cast<UDPPacket *>(msg));
}
else // received from application layer
{
if (msg->getKind()==UDP_C_DATA)
processMsgFromApp(PK(msg));
else
processCommandFromApp(msg);
}
if (ev.isGUI())
updateDisplayString();
}
| void UDP::initialize | ( | ) | [protected, virtual] |
Definition at line 81 of file UDP.cc.
{
WATCH_PTRMAP(socketsByIdMap);
WATCH_MAP(socketsByPortMap);
lastEphemeralPort = EPHEMERAL_PORTRANGE_START;
icmp = NULL;
icmpv6 = NULL;
numSent = 0;
numPassedUp = 0;
numDroppedWrongPort = 0;
numDroppedBadChecksum = 0;
WATCH(numSent);
WATCH(numPassedUp);
WATCH(numDroppedWrongPort);
WATCH(numDroppedBadChecksum);
}
| bool UDP::matchesSocket | ( | SockDesc * | sd, | |
| const IPvXAddress & | localAddr, | |||
| const IPvXAddress & | remoteAddr, | |||
| ushort | remotePort | |||
| ) | [protected, virtual] |
| bool UDP::matchesSocket | ( | SockDesc * | sd, | |
| UDPPacket * | udp, | |||
| IPControlInfo * | ctrl | |||
| ) | [protected, virtual] |
Definition at line 230 of file UDP.cc.
Referenced by processICMPError(), and processUDPPacket().
{
// IPv4 version
if (sd->remotePort!=0 && sd->remotePort!=udp->getSourcePort())
return false;
if (!sd->localAddr.isUnspecified() && sd->localAddr.get4()!=ipCtrl->getDestAddr())
return false;
if (!sd->remoteAddr.isUnspecified() && sd->remoteAddr.get4()!=ipCtrl->getSrcAddr())
return false;
if (sd->interfaceId!=-1 && sd->interfaceId!=ipCtrl->getInterfaceId())
return false;
return true;
}
| bool UDP::matchesSocket | ( | SockDesc * | sd, | |
| UDPPacket * | udp, | |||
| IPv6ControlInfo * | ctrl | |||
| ) | [protected, virtual] |
Definition at line 244 of file UDP.cc.
{
// IPv6 version
if (sd->remotePort!=0 && sd->remotePort!=udp->getSourcePort())
return false;
if (!sd->localAddr.isUnspecified() && sd->localAddr.get6()!=ipCtrl->getDestAddr())
return false;
if (!sd->remoteAddr.isUnspecified() && sd->remoteAddr.get6()!=ipCtrl->getSrcAddr())
return false;
if (sd->interfaceId!=-1 && sd->interfaceId!=ipCtrl->getInterfaceId())
return false;
return true;
}
| void UDP::processCommandFromApp | ( | cMessage * | msg | ) | [protected, virtual] |
Definition at line 531 of file UDP.cc.
Referenced by handleMessage().
{
UDPControlInfo *udpCtrl = check_and_cast<UDPControlInfo *>(msg->removeControlInfo());
switch (msg->getKind())
{
case UDP_C_BIND:
bind(msg->getArrivalGate()->getIndex(), udpCtrl);
break;
case UDP_C_CONNECT:
connect(udpCtrl->getSockId(), udpCtrl->getDestAddr(), udpCtrl->getDestPort());
break;
case UDP_C_UNBIND:
unbind(udpCtrl->getSockId());
break;
default:
error("unknown command code (message kind) %d received from app", msg->getKind());
}
delete udpCtrl;
delete msg;
}
| void UDP::processICMPError | ( | cPacket * | icmpErrorMsg | ) | [protected, virtual] |
Definition at line 326 of file UDP.cc.
Referenced by handleMessage().
{
// extract details from the error message, then try to notify socket that sent bogus packet
int type, code;
IPvXAddress localAddr, remoteAddr;
ushort localPort, remotePort;
if (dynamic_cast<ICMPMessage *>(msg))
{
ICMPMessage *icmpMsg = (ICMPMessage *)msg;
type = icmpMsg->getType();
code = icmpMsg->getCode();
// Note: we must NOT use decapsulate() because payload in ICMP is conceptually truncated
IPDatagram *datagram = check_and_cast<IPDatagram *>(icmpMsg->getEncapsulatedMsg());
UDPPacket *packet = check_and_cast<UDPPacket *>(datagram->getEncapsulatedMsg());
localAddr = datagram->getSrcAddress();
remoteAddr = datagram->getDestAddress();
localPort = packet->getSourcePort();
remotePort = packet->getDestinationPort();
delete icmpMsg;
}
else if (dynamic_cast<ICMPv6Message *>(msg))
{
ICMPv6Message *icmpMsg = (ICMPv6Message *)msg;
type = icmpMsg->getType();
code = -1; // FIXME this is dependent on getType()...
// Note: we must NOT use decapsulate() because payload in ICMP is conceptually truncated
IPv6Datagram *datagram = check_and_cast<IPv6Datagram *>(icmpMsg->getEncapsulatedMsg());
UDPPacket *packet = check_and_cast<UDPPacket *>(datagram->getEncapsulatedMsg());
localAddr = datagram->getSrcAddress();
remoteAddr = datagram->getDestAddress();
localPort = packet->getSourcePort();
remotePort = packet->getDestinationPort();
delete icmpMsg;
}
EV << "ICMP error received: type=" << type << " code=" << code
<< " about packet " << localAddr << ":" << localPort << " > "
<< remoteAddr << ":" << remotePort << "\n";
// identify socket and report error to it
SocketsByPortMap::iterator it = socketsByPortMap.find(localPort);
if (it==socketsByPortMap.end())
{
EV << "No socket on that local port, ignoring ICMP error\n";
return;
}
SockDescList& list = it->second;
SockDesc *srcSocket = NULL;
for (SockDescList::iterator it=list.begin(); it!=list.end(); ++it)
{
SockDesc *sd = *it;
if (sd->onlyLocalPortIsSet || matchesSocket(sd, localAddr, remoteAddr, remotePort))
{
srcSocket = sd; // FIXME what to do if there's more than one matching socket ???
}
}
if (!srcSocket)
{
EV << "No matching socket, ignoring ICMP error\n";
return;
}
// send UDP_I_ERROR to socket
EV << "Source socket is sockId=" << srcSocket->sockId << ", notifying.\n";
sendUpErrorNotification(srcSocket, UDP_I_ERROR, localAddr, remoteAddr, remotePort);
}
| void UDP::processMsgFromApp | ( | cPacket * | appData | ) | [protected, virtual] |
Definition at line 483 of file UDP.cc.
Referenced by handleMessage().
{
UDPControlInfo *udpCtrl = check_and_cast<UDPControlInfo *>(appData->removeControlInfo());
UDPPacket *udpPacket = createUDPPacket(appData->getName());
udpPacket->setByteLength(UDP_HEADER_BYTES);
udpPacket->encapsulate(appData);
// set source and destination port
udpPacket->setSourcePort(udpCtrl->getSrcPort());
udpPacket->setDestinationPort(udpCtrl->getDestPort());
if (!udpCtrl->getDestAddr().isIPv6())
{
// send to IPv4
EV << "Sending app packet " << appData->getName() << " over IPv4.\n";
IPControlInfo *ipControlInfo = new IPControlInfo();
ipControlInfo->setProtocol(IP_PROT_UDP);
ipControlInfo->setSrcAddr(udpCtrl->getSrcAddr().get4());
ipControlInfo->setDestAddr(udpCtrl->getDestAddr().get4());
ipControlInfo->setInterfaceId(udpCtrl->getInterfaceId());
udpPacket->setControlInfo(ipControlInfo);
delete udpCtrl;
send(udpPacket,"ipOut");
}
else
{
// send to IPv6
EV << "Sending app packet " << appData->getName() << " over IPv6.\n";
IPv6ControlInfo *ipControlInfo = new IPv6ControlInfo();
ipControlInfo->setProtocol(IP_PROT_UDP);
ipControlInfo->setSrcAddr(udpCtrl->getSrcAddr().get6());
ipControlInfo->setDestAddr(udpCtrl->getDestAddr().get6());
// ipControlInfo->setInterfaceId(udpCtrl->InterfaceId()); FIXME extend IPv6 with this!!!
udpPacket->setControlInfo(ipControlInfo);
delete udpCtrl;
send(udpPacket,"ipv6Out");
}
numSent++;
}
| void UDP::processUDPPacket | ( | UDPPacket * | udpPacket | ) | [protected, virtual] |
Definition at line 408 of file UDP.cc.
Referenced by handleMessage().
{
// simulate checksum: discard packet if it has bit error
EV << "Packet " << udpPacket->getName() << " received from network, dest port " << udpPacket->getDestinationPort() << "\n";
if (udpPacket->hasBitError())
{
EV << "Packet has bit error, discarding\n";
delete udpPacket;
numDroppedBadChecksum++;
return;
}
int destPort = udpPacket->getDestinationPort();
cPolymorphic *ctrl = udpPacket->removeControlInfo();
// send back ICMP error if no socket is bound to that port
SocketsByPortMap::iterator it = socketsByPortMap.find(destPort);
if (it==socketsByPortMap.end())
{
EV << "No socket registered on port " << destPort << "\n";
processUndeliverablePacket(udpPacket, ctrl);
return;
}
SockDescList& list = it->second;
int matches = 0;
// deliver a copy of the packet to each matching socket
cPacket *payload = udpPacket->getEncapsulatedMsg();
if (dynamic_cast<IPControlInfo *>(ctrl)!=NULL)
{
IPControlInfo *ctrl4 = (IPControlInfo *)ctrl;
for (SockDescList::iterator it=list.begin(); it!=list.end(); ++it)
{
SockDesc *sd = *it;
if (sd->onlyLocalPortIsSet || matchesSocket(sd, udpPacket, ctrl4))
{
EV << "Socket sockId=" << sd->sockId << " matches, sending up a copy.\n";
sendUp((cPacket*)payload->dup(), udpPacket, ctrl4, sd);
matches++;
}
}
}
else if (dynamic_cast<IPv6ControlInfo *>(ctrl)!=NULL)
{
IPv6ControlInfo *ctrl6 = (IPv6ControlInfo *)ctrl;
for (SockDescList::iterator it=list.begin(); it!=list.end(); ++it)
{
SockDesc *sd = *it;
if (sd->onlyLocalPortIsSet || matchesSocket(sd, udpPacket, ctrl6))
{
EV << "Socket sockId=" << sd->sockId << " matches, sending up a copy.\n";
sendUp((cPacket*)payload->dup(), udpPacket, ctrl6, sd);
matches++;
}
}
}
else
{
error("(%s)%s arrived from lower layer without control info", udpPacket->getClassName(), udpPacket->getName());
}
// send back ICMP error if there is no matching socket
if (matches==0)
{
EV << "None of the sockets on port " << destPort << " matches the packet\n";
processUndeliverablePacket(udpPacket, ctrl);
return;
}
delete udpPacket;
delete ctrl;
}
| void UDP::processUndeliverablePacket | ( | UDPPacket * | udpPacket, | |
| cPolymorphic * | ctrl | |||
| ) | [protected, virtual] |
Definition at line 299 of file UDP.cc.
Referenced by processUDPPacket().
{
numDroppedWrongPort++;
// send back ICMP PORT_UNREACHABLE
if (dynamic_cast<IPControlInfo *>(ctrl)!=NULL)
{
if (!icmp)
icmp = ICMPAccess().get();
IPControlInfo *ctrl4 = (IPControlInfo *)ctrl;
if (!ctrl4->getDestAddr().isMulticast())
icmp->sendErrorMessage(udpPacket, ctrl4, ICMP_DESTINATION_UNREACHABLE, ICMP_DU_PORT_UNREACHABLE);
}
else if (dynamic_cast<IPv6ControlInfo *>(udpPacket->getControlInfo())!=NULL)
{
if (!icmpv6)
icmpv6 = ICMPv6Access().get();
IPv6ControlInfo *ctrl6 = (IPv6ControlInfo *)ctrl;
if (!ctrl6->getDestAddr().isMulticast())
icmpv6->sendErrorMessage(udpPacket, ctrl6, ICMPv6_DESTINATION_UNREACHABLE, PORT_UNREACHABLE);
}
else
{
error("(%s)%s arrived from lower layer without control info", udpPacket->getClassName(), udpPacket->getName());
}
}
| void UDP::sendUp | ( | cPacket * | payload, | |
| UDPPacket * | udpHeader, | |||
| IPv6ControlInfo * | ctrl, | |||
| SockDesc * | sd | |||
| ) | [protected, virtual] |
Definition at line 282 of file UDP.cc.
{
// send payload with UDPControlInfo up to the application -- IPv6 version
UDPControlInfo *udpCtrl = new UDPControlInfo();
udpCtrl->setSockId(sd->sockId);
udpCtrl->setUserId(sd->userId);
udpCtrl->setSrcAddr(ipCtrl->getSrcAddr());
udpCtrl->setDestAddr(ipCtrl->getDestAddr());
udpCtrl->setSrcPort(udpHeader->getSourcePort());
udpCtrl->setDestPort(udpHeader->getDestinationPort());
udpCtrl->setInterfaceId(ipCtrl->getInterfaceId());
payload->setControlInfo(udpCtrl);
send(payload, "appOut", sd->appGateIndex);
numPassedUp++;
}
| void UDP::sendUp | ( | cPacket * | payload, | |
| UDPPacket * | udpHeader, | |||
| IPControlInfo * | ctrl, | |||
| SockDesc * | sd | |||
| ) | [protected, virtual] |
Definition at line 265 of file UDP.cc.
Referenced by processUDPPacket().
{
// send payload with UDPControlInfo up to the application -- IPv4 version
UDPControlInfo *udpCtrl = new UDPControlInfo();
udpCtrl->setSockId(sd->sockId);
udpCtrl->setUserId(sd->userId);
udpCtrl->setSrcAddr(ipCtrl->getSrcAddr());
udpCtrl->setDestAddr(ipCtrl->getDestAddr());
udpCtrl->setSrcPort(udpHeader->getSourcePort());
udpCtrl->setDestPort(udpHeader->getDestinationPort());
udpCtrl->setInterfaceId(ipCtrl->getInterfaceId());
payload->setControlInfo(udpCtrl);
send(payload, "appOut", sd->appGateIndex);
numPassedUp++;
}
| void UDP::sendUpErrorNotification | ( | SockDesc * | sd, | |
| int | msgkind, | |||
| const IPvXAddress & | localAddr, | |||
| const IPvXAddress & | remoteAddr, | |||
| ushort | remotePort | |||
| ) | [protected, virtual] |
Definition at line 393 of file UDP.cc.
Referenced by processICMPError().
{
cPacket *notifyMsg = new cPacket("ERROR", msgkind);
UDPControlInfo *udpCtrl = new UDPControlInfo();
udpCtrl->setSockId(sd->sockId);
udpCtrl->setUserId(sd->userId);
udpCtrl->setSrcAddr(localAddr);
udpCtrl->setDestAddr(remoteAddr);
udpCtrl->setSrcPort(sd->localPort);
udpCtrl->setDestPort(remotePort);
notifyMsg->setControlInfo(udpCtrl);
send(notifyMsg, "appOut", sd->appGateIndex);
}
| void UDP::unbind | ( | int | sockId | ) | [protected, virtual] |
Definition at line 155 of file UDP.cc.
Referenced by processCommandFromApp().
{
// remove from socketsByIdMap
SocketsByIdMap::iterator it = socketsByIdMap.find(sockId);
if (it==socketsByIdMap.end())
error("socket id=%d doesn't exist (already closed?)", sockId);
SockDesc *sd = it->second;
socketsByIdMap.erase(it);
EV << "Unbinding socket: " << *sd << "\n";
// remove from socketsByPortMap
SockDescList& list = socketsByPortMap[sd->localPort];
for (SockDescList::iterator it=list.begin(); it!=list.end(); ++it)
if (*it == sd)
{list.erase(it); break;}
if (list.empty())
socketsByPortMap.erase(sd->localPort);
delete sd;
}
| void UDP::updateDisplayString | ( | ) | [protected, virtual] |
Definition at line 218 of file UDP.cc.
Referenced by handleMessage().
{
char buf[80];
sprintf(buf, "passed up: %d pks\nsent: %d pks", numPassedUp, numSent);
if (numDroppedWrongPort>0)
{
sprintf(buf+strlen(buf), "\ndropped (no app): %d pks", numDroppedWrongPort);
getDisplayString().setTagArg("i",1,"red");
}
getDisplayString().setTagArg("t",0,buf);
}
ICMPv6* UDP::icmpv6 [protected] |
Definition at line 74 of file UDP.h.
Referenced by initialize(), and processUndeliverablePacket().
ushort UDP::lastEphemeralPort [protected] |
Definition at line 72 of file UDP.h.
Referenced by getEphemeralPort(), and initialize().
int UDP::numDroppedBadChecksum [protected] |
Definition at line 80 of file UDP.h.
Referenced by initialize(), and processUDPPacket().
int UDP::numDroppedWrongPort [protected] |
Definition at line 79 of file UDP.h.
Referenced by initialize(), processUndeliverablePacket(), and updateDisplayString().
int UDP::numPassedUp [protected] |
Definition at line 78 of file UDP.h.
Referenced by initialize(), sendUp(), and updateDisplayString().
int UDP::numSent [protected] |
Definition at line 77 of file UDP.h.
Referenced by initialize(), processMsgFromApp(), and updateDisplayString().
SocketsByIdMap UDP::socketsByIdMap [protected] |
SocketsByPortMap UDP::socketsByPortMap [protected] |
Definition at line 69 of file UDP.h.
Referenced by bind(), getEphemeralPort(), initialize(), processICMPError(), processUDPPacket(), and unbind().
1.7.1