INET Framework for OMNeT++/OMNEST
AnsaUDP.cc
Go to the documentation of this file.
00001 //
00002 // Copyright (C) 2000 Institut fuer Telematik, Universitaet Karlsruhe
00003 // Copyright (C) 2004,2005 Andras Varga
00004 //
00005 // This program is free software; you can redistribute it and/or
00006 // modify it under the terms of the GNU General Public License
00007 // as published by the Free Software Foundation; either version 2
00008 // of the License, or (at your option) any later version.
00009 //
00010 // This program is distributed in the hope that it will be useful,
00011 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00012 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00013 // GNU General Public License for more details.
00014 //
00015 // You should have received a copy of the GNU General Public License
00016 // along with this program; if not, write to the Free Software
00017 // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
00018 //
00019 
00020 
00021 //
00022 // Author: Jochen Reber
00023 // Rewrite: Andras Varga 2004,2005
00024 //
00025 
00026 #include <omnetpp.h>
00027 #include <string.h>
00028 #include "UDPPacket.h"
00029 #include "AnsaUDP.h"
00030 #include "IPControlInfo.h"
00031 #include "IPv6ControlInfo.h"
00032 #include "ICMPAccess.h"
00033 #include "ICMPv6Access.h"
00034 
00035 // the following is only for ICMP error processing
00036 #include "ICMPMessage_m.h"
00037 #include "ICMPv6Message_m.h"
00038 #include "IPDatagram_m.h"
00039 #include "IPv6Datagram_m.h"
00040 
00041 
00042 #define EPHEMERAL_PORTRANGE_START 1024
00043 #define EPHEMERAL_PORTRANGE_END   5000
00044 
00045 
00046 Define_Module( AnsaUDP );
00047 
00048 
00049 static std::ostream & operator << (std::ostream & os, const AnsaUDP::SockDesc& sd)
00050 {
00051     os << "sockId=" << sd.sockId;
00052     os << " appGateIndex=" << sd.appGateIndex;
00053     os << " userId=" << sd.userId;
00054     os << " localPort=" << sd.localPort;
00055     if (sd.remotePort!=0)
00056         os << " remotePort=" << sd.remotePort;
00057     if (!sd.localAddr.isUnspecified())
00058         os << " localAddr=" << sd.localAddr;
00059     if (!sd.remoteAddr.isUnspecified())
00060         os << " remoteAddr=" << sd.remoteAddr;
00061     if (sd.interfaceId!=-1)
00062         os << " interfaceId=" << sd.interfaceId;
00063 
00064     return os;
00065 }
00066 
00067 static std::ostream & operator<<(std::ostream & os, const AnsaUDP::SockDescList& list)
00068 {
00069     for (AnsaUDP::SockDescList::const_iterator i=list.begin(); i!=list.end(); ++i)
00070         os << "sockId=" << (*i)->sockId << " ";
00071     return os;
00072 }
00073  
00074 //--------
00075 
00076 AnsaUDP::~AnsaUDP()
00077 {
00078     for (SocketsByIdMap::iterator i=socketsByIdMap.begin(); i!=socketsByIdMap.end(); ++i)
00079         delete i->second;
00080 }
00081 
00082 void AnsaUDP::initialize()
00083 {
00084     WATCH_PTRMAP(socketsByIdMap);
00085     WATCH_MAP(socketsByPortMap);
00086 
00087     lastEphemeralPort = EPHEMERAL_PORTRANGE_START;
00088     icmp = NULL;
00089     icmpv6 = NULL;
00090 
00091     numSent = 0;
00092     numPassedUp = 0;
00093     numDroppedWrongPort = 0;
00094     numDroppedBadChecksum = 0;
00095     WATCH(numSent);
00096     WATCH(numPassedUp);
00097     WATCH(numDroppedWrongPort);
00098     WATCH(numDroppedBadChecksum);
00099 }
00100 
00101 void AnsaUDP::bind(int gateIndex, AnsaUDPControlInfo *ctrl)
00102 {
00103     // XXX checks could be added, of when the bind should be allowed to proceed
00104 
00105     // create and fill in SockDesc
00106     SockDesc *sd = new SockDesc();
00107     sd->sockId = ctrl->getSockId();
00108     sd->userId = ctrl->getUserId();
00109     sd->appGateIndex = gateIndex;
00110     sd->localAddr = ctrl->getSrcAddr();
00111     sd->remoteAddr = ctrl->getDestAddr();
00112     sd->localPort = ctrl->getSrcPort();
00113     sd->remotePort = ctrl->getDestPort();
00114     sd->interfaceId = ctrl->getInterfaceId();
00115 
00116     if (sd->sockId==-1)
00117         error("sockId in BIND message not filled in");
00118     if (sd->localPort==0)
00119         sd->localPort = getEphemeralPort();
00120 
00121     sd->onlyLocalPortIsSet = sd->localAddr.isUnspecified() &&
00122                              sd->remoteAddr.isUnspecified() &&
00123                              sd->remotePort==0 &&
00124                              sd->interfaceId==-1;
00125 
00126     EV << "Binding socket: " << *sd << "\n";
00127 
00128     // add to socketsByIdMap
00129     ASSERT(socketsByIdMap.find(sd->sockId)==socketsByIdMap.end());
00130     socketsByIdMap[sd->sockId] = sd;
00131 
00132     // add to socketsByPortMap
00133     SockDescList& list = socketsByPortMap[sd->localPort]; // create if doesn't exist
00134     list.push_back(sd);
00135 }
00136 
00137 void AnsaUDP::connect(int sockId, IPvXAddress addr, int port)
00138 {
00139     SocketsByIdMap::iterator it = socketsByIdMap.find(sockId);
00140     if (it==socketsByIdMap.end())
00141         error("socket id=%d doesn't exist (already closed?)", sockId);
00142     if (addr.isUnspecified())
00143         opp_error("connect: unspecified remote address");
00144     if (port<=0 || port>65535)
00145         opp_error("connect: invalid remote port number %d", port);
00146 
00147     SockDesc *sd = it->second;
00148     sd->remoteAddr = addr;
00149     sd->remotePort = port;
00150 
00151     sd->onlyLocalPortIsSet = false;
00152 
00153     EV << "Connecting socket: " << *sd << "\n";
00154 }
00155 
00156 void AnsaUDP::unbind(int sockId)
00157 {
00158     // remove from socketsByIdMap
00159     SocketsByIdMap::iterator it = socketsByIdMap.find(sockId);
00160     if (it==socketsByIdMap.end())
00161         error("socket id=%d doesn't exist (already closed?)", sockId);
00162     SockDesc *sd = it->second;
00163     socketsByIdMap.erase(it);
00164 
00165     EV << "Unbinding socket: " << *sd << "\n";
00166 
00167     // remove from socketsByPortMap
00168     SockDescList& list = socketsByPortMap[sd->localPort];
00169     for (SockDescList::iterator it=list.begin(); it!=list.end(); ++it)
00170         if (*it == sd)
00171             {list.erase(it); break;}
00172     if (list.empty())
00173         socketsByPortMap.erase(sd->localPort);
00174     delete sd;
00175 }
00176 
00177 short AnsaUDP::getEphemeralPort()
00178 {
00179     // start at the last allocated port number + 1, and search for an unused one
00180     short searchUntil = lastEphemeralPort++;
00181     if (lastEphemeralPort == EPHEMERAL_PORTRANGE_END) // wrap
00182         lastEphemeralPort = EPHEMERAL_PORTRANGE_START;
00183 
00184     while (socketsByPortMap.find(lastEphemeralPort)!=socketsByPortMap.end())
00185     {
00186         if (lastEphemeralPort == searchUntil) // got back to starting point?
00187             error("Ephemeral port range %d..%d exhausted, all ports occupied", EPHEMERAL_PORTRANGE_START, EPHEMERAL_PORTRANGE_END);
00188         lastEphemeralPort++;
00189         if (lastEphemeralPort == EPHEMERAL_PORTRANGE_END) // wrap
00190             lastEphemeralPort = EPHEMERAL_PORTRANGE_START;
00191     }
00192 
00193     // found a free one, return it
00194     return lastEphemeralPort;
00195 }
00196 
00197 void AnsaUDP::handleMessage(cMessage *msg)
00198 {
00199     // received from IP layer
00200     if (msg->arrivedOn("ipIn") || msg->arrivedOn("ipv6In"))
00201     {
00202         if (dynamic_cast<ICMPMessage *>(msg) || dynamic_cast<ICMPv6Message *>(msg))
00203             processICMPError(PK(msg));
00204         else
00205             processUDPPacket(check_and_cast<UDPPacket *>(msg));
00206     }
00207     else // received from application layer
00208     {
00209         if (msg->getKind()==UDP_C_DATA)
00210             processMsgFromApp(PK(msg));
00211         else
00212             processCommandFromApp(msg);
00213     }
00214 
00215     if (ev.isGUI())
00216         updateDisplayString();
00217 }
00218 
00219 void AnsaUDP::updateDisplayString()
00220 {
00221     char buf[80];
00222     sprintf(buf, "passed up: %d pks\nsent: %d pks", numPassedUp, numSent);
00223     if (numDroppedWrongPort>0)
00224     {
00225         sprintf(buf+strlen(buf), "\ndropped (no app): %d pks", numDroppedWrongPort);
00226         getDisplayString().setTagArg("i",1,"red");
00227     }
00228     getDisplayString().setTagArg("t",0,buf);
00229 }
00230 
00231 bool AnsaUDP::matchesSocket(SockDesc *sd, UDPPacket *udp, IPControlInfo *ipCtrl)
00232 {
00233     // IPv4 version
00234     if (sd->remotePort!=0 && sd->remotePort!=udp->getSourcePort())
00235         return false;
00236     if (!sd->localAddr.isUnspecified() && sd->localAddr.get4()!=ipCtrl->getDestAddr())
00237         return false;
00238     if (!sd->remoteAddr.isUnspecified() && sd->remoteAddr.get4()!=ipCtrl->getSrcAddr())
00239         return false;
00240     if (sd->interfaceId!=-1 && sd->interfaceId!=ipCtrl->getInterfaceId())
00241         return false;
00242     return true;
00243 }
00244 
00245 bool AnsaUDP::matchesSocket(SockDesc *sd, UDPPacket *udp, IPv6ControlInfo *ipCtrl)
00246 {
00247     // IPv6 version
00248     if (sd->remotePort!=0 && sd->remotePort!=udp->getSourcePort())
00249         return false;
00250     if (!sd->localAddr.isUnspecified() && sd->localAddr.get6()!=ipCtrl->getDestAddr())
00251         return false;
00252     if (!sd->remoteAddr.isUnspecified() && sd->remoteAddr.get6()!=ipCtrl->getSrcAddr())
00253         return false;
00254     if (sd->interfaceId!=-1 && sd->interfaceId!=ipCtrl->getInterfaceId())
00255         return false;
00256     return true;
00257 }
00258 
00259 bool AnsaUDP::matchesSocket(SockDesc *sd, const IPvXAddress& localAddr, const IPvXAddress& remoteAddr, short remotePort)
00260 {
00261     return (sd->remotePort==0 || sd->remotePort!=remotePort) &&
00262            (sd->localAddr.isUnspecified() || sd->localAddr==localAddr) &&
00263            (sd->remoteAddr.isUnspecified() || sd->remoteAddr==remoteAddr);
00264 }
00265 
00266 void AnsaUDP::sendUp(cPacket *payload, UDPPacket *udpHeader, IPControlInfo *ipCtrl, SockDesc *sd)
00267 {
00268     // send payload with AnsaUDPControlInfo up to the application -- IPv4 version
00269     AnsaUDPControlInfo *udpCtrl = new AnsaUDPControlInfo();
00270     udpCtrl->setSockId(sd->sockId);
00271     udpCtrl->setUserId(sd->userId);
00272     udpCtrl->setSrcAddr(ipCtrl->getSrcAddr());
00273     udpCtrl->setDestAddr(ipCtrl->getDestAddr());
00274     udpCtrl->setSrcPort(udpHeader->getSourcePort());
00275     udpCtrl->setDestPort(udpHeader->getDestinationPort());
00276     udpCtrl->setInterfaceId(ipCtrl->getInterfaceId());
00277     payload->setControlInfo(udpCtrl);
00278 
00279     send(payload, "appOut", sd->appGateIndex);
00280     numPassedUp++;
00281 }
00282 
00283 void AnsaUDP::sendUp(cPacket *payload, UDPPacket *udpHeader, IPv6ControlInfo *ipCtrl, SockDesc *sd)
00284 {
00285     // send payload with AnsaUDPControlInfo up to the application -- IPv6 version
00286     AnsaUDPControlInfo *udpCtrl = new AnsaUDPControlInfo();
00287     udpCtrl->setSockId(sd->sockId);
00288     udpCtrl->setUserId(sd->userId);
00289     udpCtrl->setSrcAddr(ipCtrl->getSrcAddr());
00290     udpCtrl->setDestAddr(ipCtrl->getDestAddr());
00291     udpCtrl->setSrcPort(udpHeader->getSourcePort());
00292     udpCtrl->setDestPort(udpHeader->getDestinationPort());
00293     udpCtrl->setInterfaceId(ipCtrl->getInterfaceId());
00294     payload->setControlInfo(udpCtrl);
00295 
00296     send(payload, "appOut", sd->appGateIndex);
00297     numPassedUp++;
00298 }
00299 
00300 void AnsaUDP::processUndeliverablePacket(UDPPacket *udpPacket, cPolymorphic *ctrl)
00301 {
00302     numDroppedWrongPort++;
00303 
00304     // send back ICMP PORT_UNREACHABLE
00305     if (dynamic_cast<IPControlInfo *>(ctrl)!=NULL)
00306     {
00307         if (!icmp)
00308             icmp = ICMPAccess().get();
00309         IPControlInfo *ctrl4 = (IPControlInfo *)ctrl;
00310         if (!ctrl4->getDestAddr().isMulticast())
00311             icmp->sendErrorMessage(udpPacket, ctrl4, ICMP_DESTINATION_UNREACHABLE, ICMP_DU_PORT_UNREACHABLE);
00312     }
00313     else if (dynamic_cast<IPv6ControlInfo *>(udpPacket->getControlInfo())!=NULL)
00314     {
00315         if (!icmpv6)
00316             icmpv6 = ICMPv6Access().get();
00317         IPv6ControlInfo *ctrl6 = (IPv6ControlInfo *)ctrl;
00318         if (!ctrl6->getDestAddr().isMulticast())
00319             icmpv6->sendErrorMessage(udpPacket, ctrl6, ICMPv6_DESTINATION_UNREACHABLE, PORT_UNREACHABLE);
00320     }
00321     else
00322     {
00323         error("(%s)%s arrived from lower layer without control info", udpPacket->getClassName(), udpPacket->getName());
00324     }
00325 }
00326 
00327 void AnsaUDP::processICMPError(cPacket *msg)
00328 {
00329     // extract details from the error message, then try to notify socket that sent bogus packet
00330     int type, code;
00331     IPvXAddress localAddr, remoteAddr;
00332     int localPort, remotePort;
00333 
00334     if (dynamic_cast<ICMPMessage *>(msg))
00335     {
00336         ICMPMessage *icmpMsg = (ICMPMessage *)msg;
00337         type = icmpMsg->getType();
00338         code = icmpMsg->getCode();
00339         icmpMsg->setBitLength(icmpMsg->getEncapsulatedMsg()->getBitLength()); // trick because payload in ICMP is conceptually truncated
00340         IPDatagram *datagram = check_and_cast<IPDatagram *>(icmpMsg->decapsulate());
00341         localAddr = datagram->getSrcAddress();
00342         remoteAddr = datagram->getDestAddress();
00343         UDPPacket *packet = check_and_cast<UDPPacket *>(datagram->decapsulate());
00344         localPort = packet->getSourcePort();
00345         remotePort = packet->getDestinationPort();
00346         delete icmpMsg;
00347         delete datagram;
00348         delete packet;
00349     }
00350     else if (dynamic_cast<ICMPv6Message *>(msg))
00351     {
00352         ICMPv6Message *icmpMsg = (ICMPv6Message *)msg;
00353         type = icmpMsg->getType();
00354         code = -1; // FIXME this is dependent on getType()...
00355         IPv6Datagram *datagram = check_and_cast<IPv6Datagram *>(icmpMsg->decapsulate());
00356         localAddr = datagram->getSrcAddress();
00357         remoteAddr = datagram->getDestAddress();
00358         UDPPacket *packet = check_and_cast<UDPPacket *>(datagram->decapsulate());
00359         localPort = packet->getSourcePort();
00360         remotePort = packet->getDestinationPort();
00361         delete icmpMsg;
00362         delete datagram;
00363         delete packet;
00364     }
00365     EV << "ICMP error received: type=" << type << " code=" << code
00366        << " about packet " << localAddr << ":" << localPort << " > "
00367        << remoteAddr << ":" << remotePort << "\n";
00368 
00369     // identify socket and report error to it
00370     SocketsByPortMap::iterator it = socketsByPortMap.find(localPort);
00371     if (it==socketsByPortMap.end())
00372     {
00373         EV << "No socket on that local port, ignoring ICMP error\n";
00374         return;
00375     }
00376     SockDescList& list = it->second;
00377     SockDesc *srcSocket = NULL;
00378     for (SockDescList::iterator it=list.begin(); it!=list.end(); ++it)
00379     {
00380         SockDesc *sd = *it;
00381         if (sd->onlyLocalPortIsSet || matchesSocket(sd, localAddr, remoteAddr, remotePort))
00382         {
00383             srcSocket = sd; // FIXME what to do if there's more than one matching socket ???
00384         }
00385     }
00386     if (!srcSocket)
00387     {
00388         EV << "No matching socket, ignoring ICMP error\n";
00389         return;
00390     }
00391 
00392     // send UDP_I_ERROR to socket
00393     EV << "Source socket is sockId=" << srcSocket->sockId << ", notifying.\n";
00394     sendUpErrorNotification(srcSocket, UDP_I_ERROR, localAddr, remoteAddr, remotePort);
00395 }
00396 
00397 void AnsaUDP::sendUpErrorNotification(SockDesc *sd, int msgkind, const IPvXAddress& localAddr, const IPvXAddress& remoteAddr, short remotePort)
00398 {
00399     cPacket *notifyMsg = new cPacket("ERROR", msgkind);
00400     AnsaUDPControlInfo *udpCtrl = new AnsaUDPControlInfo();
00401     udpCtrl->setSockId(sd->sockId);
00402     udpCtrl->setUserId(sd->userId);
00403     udpCtrl->setSrcAddr(localAddr);
00404     udpCtrl->setDestAddr(remoteAddr);
00405     udpCtrl->setSrcPort(sd->localPort);
00406     udpCtrl->setDestPort(remotePort);
00407     notifyMsg->setControlInfo(udpCtrl);
00408 
00409     send(notifyMsg, "appOut", sd->appGateIndex);
00410 }
00411 
00412 void AnsaUDP::processUDPPacket(UDPPacket *udpPacket)
00413 {
00414     // simulate checksum: discard packet if it has bit error
00415     EV << "Packet " << udpPacket->getName() << " received from network, dest port " << udpPacket->getDestinationPort() << "\n";
00416     if (udpPacket->hasBitError())
00417     {
00418         EV << "Packet has bit error, discarding\n";
00419         delete udpPacket;
00420         numDroppedBadChecksum++;
00421         return;
00422     }
00423 
00424     int destPort = udpPacket->getDestinationPort();
00425     cPolymorphic *ctrl = udpPacket->removeControlInfo();
00426 
00427     // send back ICMP error if no socket is bound to that port
00428     SocketsByPortMap::iterator it = socketsByPortMap.find(destPort);
00429     if (it==socketsByPortMap.end())
00430     {
00431         EV << "No socket registered on port " << destPort << "\n";
00432         processUndeliverablePacket(udpPacket, ctrl);
00433         return;
00434     }
00435     SockDescList& list = it->second;
00436 
00437     int matches = 0;
00438 
00439     // deliver a copy of the packet to each matching socket
00440     cPacket *payload = udpPacket->getEncapsulatedMsg();
00441     if (dynamic_cast<IPControlInfo *>(ctrl)!=NULL)
00442     {
00443         IPControlInfo *ctrl4 = (IPControlInfo *)ctrl;
00444         for (SockDescList::iterator it=list.begin(); it!=list.end(); ++it)
00445         {
00446             SockDesc *sd = *it;
00447             if (sd->onlyLocalPortIsSet || matchesSocket(sd, udpPacket, ctrl4))
00448             {
00449                 EV << "Socket sockId=" << sd->sockId << " matches, sending up a copy.\n";
00450                 sendUp((cPacket*)payload->dup(), udpPacket, ctrl4, sd);
00451                 matches++;
00452             }
00453         }
00454     }
00455     else if (dynamic_cast<IPv6ControlInfo *>(udpPacket->getControlInfo())!=NULL)
00456     {
00457         IPv6ControlInfo *ctrl6 = (IPv6ControlInfo *)ctrl;
00458         for (SockDescList::iterator it=list.begin(); it!=list.end(); ++it)
00459         {
00460             SockDesc *sd = *it;
00461             if (sd->onlyLocalPortIsSet || matchesSocket(sd, udpPacket, ctrl6))
00462             {
00463                 EV << "Socket sockId=" << sd->sockId << " matches, sending up a copy.\n";
00464                 sendUp((cPacket*)payload->dup(), udpPacket, ctrl6, sd);
00465                 matches++;
00466             }
00467         }
00468     }
00469     else
00470     {
00471         error("(%s)%s arrived from lower layer without control info", udpPacket->getClassName(), udpPacket->getName());
00472     }
00473 
00474     // send back ICMP error if there is no matching socket
00475     if (matches==0)
00476     {
00477         EV << "None of the sockets on port " << destPort << " matches the packet\n";
00478         processUndeliverablePacket(udpPacket, ctrl);
00479         return;
00480     }
00481 
00482     delete udpPacket;
00483     delete ctrl;
00484 }
00485 
00486 
00487 void AnsaUDP::processMsgFromApp(cPacket *appData)
00488 {
00489     AnsaUDPControlInfo *udpCtrl = check_and_cast<AnsaUDPControlInfo *>(appData->removeControlInfo());
00490 
00491     UDPPacket *udpPacket = createUDPPacket(appData->getName());
00492     udpPacket->setByteLength(UDP_HEADER_BYTES);
00493     udpPacket->encapsulate(appData);
00494 
00495     // set source and destination port
00496     udpPacket->setSourcePort(udpCtrl->getSrcPort());
00497     udpPacket->setDestinationPort(udpCtrl->getDestPort());
00498 
00499     if (!udpCtrl->getDestAddr().isIPv6())
00500     {
00501         // send to IPv4
00502         EV << "Sending app packet " << appData->getName() << " over IPv4.\n";
00503         IPControlInfo *ipControlInfo = new IPControlInfo();
00504         ipControlInfo->setProtocol(IP_PROT_UDP);
00505         ipControlInfo->setSrcAddr(udpCtrl->getSrcAddr().get4());
00506         ipControlInfo->setDestAddr(udpCtrl->getDestAddr().get4());
00507         ipControlInfo->setInterfaceId(udpCtrl->getInterfaceId());
00508         ipControlInfo->setDiffServCodePoint(udpCtrl->getDiffServCodePoint());
00509         ipControlInfo->setTimeToLive(udpCtrl->getTimeToLive());
00510         udpPacket->setControlInfo(ipControlInfo);
00511         delete udpCtrl;
00512 
00513         send(udpPacket,"ipOut");
00514     }
00515     else
00516     {
00517         // send to IPv6
00518         EV << "Sending app packet " << appData->getName() << " over IPv6.\n";
00519         IPv6ControlInfo *ipControlInfo = new IPv6ControlInfo();
00520         ipControlInfo->setProtocol(IP_PROT_UDP);
00521         ipControlInfo->setSrcAddr(udpCtrl->getSrcAddr().get6());
00522         ipControlInfo->setDestAddr(udpCtrl->getDestAddr().get6());
00523         // ipControlInfo->setInterfaceId(udpCtrl->InterfaceId()); FIXME extend IPv6 with this!!!
00524         udpPacket->setControlInfo(ipControlInfo);
00525         delete udpCtrl;
00526 
00527         send(udpPacket,"ipv6Out");
00528     }
00529     numSent++;
00530 }
00531 
00532 UDPPacket *AnsaUDP::createUDPPacket(const char *name)
00533 {
00534     return new UDPPacket(name);
00535 }
00536 
00537 void AnsaUDP::processCommandFromApp(cMessage *msg)
00538 {
00539     AnsaUDPControlInfo *udpCtrl = check_and_cast<AnsaUDPControlInfo *>(msg->removeControlInfo());
00540     switch (msg->getKind())
00541     {
00542         case UDP_C_BIND:
00543             bind(msg->getArrivalGate()->getIndex(), udpCtrl);
00544             break;
00545         case UDP_C_CONNECT:
00546             connect(udpCtrl->getSockId(), udpCtrl->getDestAddr(), udpCtrl->getDestPort());
00547             break;
00548         case UDP_C_UNBIND:
00549             unbind(udpCtrl->getSockId());
00550             break;
00551         default:
00552             error("unknown command code (message kind) %d received from app", msg->getKind());
00553             break;
00554     }
00555 
00556     delete udpCtrl;
00557     delete msg;
00558 }
00559 
00560