|
INET Framework for OMNeT++/OMNEST
|
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