|
INET Framework for OMNeT++/OMNEST
|
00001 // 00002 // Copyright (C) 2004 Andras Varga 00003 // 00004 // This program is free software; you can redistribute it and/or 00005 // modify it under the terms of the GNU Lesser General Public License 00006 // as published by the Free Software Foundation; either version 2 00007 // of the License, or (at your option) any later version. 00008 // 00009 // This program is distributed in the hope that it will be useful, 00010 // but WITHOUT ANY WARRANTY; without even the implied warranty of 00011 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00012 // GNU Lesser General Public License for more details. 00013 // 00014 // You should have received a copy of the GNU Lesser General Public License 00015 // along with this program; if not, see <http://www.gnu.org/licenses/>. 00016 // 00017 00018 00019 #include "TCP_old.h" 00020 #include "TCPConnection_old.h" 00021 #include "TCPSegment.h" 00022 #include "TCPCommand_m.h" 00023 #include "IPControlInfo.h" 00024 #include "IPv6ControlInfo.h" 00025 #include "ICMPMessage_m.h" 00026 #include "ICMPv6Message_m.h" 00027 00028 using namespace tcp_old; 00029 00030 Define_Module(TCP); 00031 00032 bool TCP::testing; 00033 bool TCP::logverbose; 00034 00035 #define EPHEMERAL_PORTRANGE_START 1024 00036 #define EPHEMERAL_PORTRANGE_END 5000 00037 00038 static std::ostream& operator<<(std::ostream& os, const TCP::SockPair& sp) 00039 { 00040 os << "loc=" << IPvXAddress(sp.localAddr) << ":" << sp.localPort << " " 00041 << "rem=" << IPvXAddress(sp.remoteAddr) << ":" << sp.remotePort; 00042 return os; 00043 } 00044 00045 static std::ostream& operator<<(std::ostream& os, const TCP::AppConnKey& app) 00046 { 00047 os << "connId=" << app.connId << " appGateIndex=" << app.appGateIndex; 00048 return os; 00049 } 00050 00051 static std::ostream& operator<<(std::ostream& os, const TCPConnection& conn) 00052 { 00053 os << "connId=" << conn.connId << " " << TCPConnection::stateName(conn.getFsmState()) 00054 << " state={" << const_cast<TCPConnection&>(conn).getState()->info() << "}"; 00055 return os; 00056 } 00057 00058 00059 void TCP::initialize() 00060 { 00061 lastEphemeralPort = EPHEMERAL_PORTRANGE_START; 00062 WATCH(lastEphemeralPort); 00063 00064 WATCH_PTRMAP(tcpConnMap); 00065 WATCH_PTRMAP(tcpAppConnMap); 00066 00067 recordStatistics = par("recordStats"); 00068 00069 cModule *netw = simulation.getSystemModule(); 00070 testing = netw->hasPar("testing") && netw->par("testing").boolValue(); 00071 logverbose = !testing && netw->hasPar("logverbose") && netw->par("logverbose").boolValue(); 00072 } 00073 00074 TCP::~TCP() 00075 { 00076 while (!tcpAppConnMap.empty()) 00077 { 00078 TcpAppConnMap::iterator i = tcpAppConnMap.begin(); 00079 delete (*i).second; 00080 tcpAppConnMap.erase(i); 00081 } 00082 } 00083 00084 void TCP::handleMessage(cMessage *msg) 00085 { 00086 if (msg->isSelfMessage()) 00087 { 00088 TCPConnection *conn = (TCPConnection *) msg->getContextPointer(); 00089 bool ret = conn->processTimer(msg); 00090 if (!ret) 00091 removeConnection(conn); 00092 } 00093 else if (msg->arrivedOn("ipIn") || msg->arrivedOn("ipv6In")) 00094 { 00095 if (dynamic_cast<ICMPMessage *>(msg) || dynamic_cast<ICMPv6Message *>(msg)) 00096 { 00097 tcpEV << "ICMP error received -- discarding\n"; // FIXME can ICMP packets really make it up to TCP??? 00098 delete msg; 00099 } 00100 else 00101 { 00102 // must be a TCPSegment 00103 TCPSegment *tcpseg = check_and_cast<TCPSegment *>(msg); 00104 00105 // get src/dest addresses 00106 IPvXAddress srcAddr, destAddr; 00107 if (dynamic_cast<IPControlInfo *>(tcpseg->getControlInfo())!=NULL) 00108 { 00109 IPControlInfo *controlInfo = (IPControlInfo *)tcpseg->removeControlInfo(); 00110 srcAddr = controlInfo->getSrcAddr(); 00111 destAddr = controlInfo->getDestAddr(); 00112 delete controlInfo; 00113 } 00114 else if (dynamic_cast<IPv6ControlInfo *>(tcpseg->getControlInfo())!=NULL) 00115 { 00116 IPv6ControlInfo *controlInfo = (IPv6ControlInfo *)tcpseg->removeControlInfo(); 00117 srcAddr = controlInfo->getSrcAddr(); 00118 destAddr = controlInfo->getDestAddr(); 00119 delete controlInfo; 00120 } 00121 else 00122 { 00123 error("(%s)%s arrived without control info", tcpseg->getClassName(), tcpseg->getName()); 00124 } 00125 00126 // process segment 00127 TCPConnection *conn = findConnForSegment(tcpseg, srcAddr, destAddr); 00128 if (conn) 00129 { 00130 bool ret = conn->processTCPSegment(tcpseg, srcAddr, destAddr); 00131 if (!ret) 00132 removeConnection(conn); 00133 } 00134 else 00135 { 00136 segmentArrivalWhileClosed(tcpseg, srcAddr, destAddr); 00137 } 00138 } 00139 } 00140 else // must be from app 00141 { 00142 TCPCommand *controlInfo = check_and_cast<TCPCommand *>(msg->getControlInfo()); 00143 int appGateIndex = msg->getArrivalGate()->getIndex(); 00144 int connId = controlInfo->getConnId(); 00145 00146 TCPConnection *conn = findConnForApp(appGateIndex, connId); 00147 00148 if (!conn) 00149 { 00150 conn = createConnection(appGateIndex, connId); 00151 00152 // add into appConnMap here; it'll be added to connMap during processing 00153 // the OPEN command in TCPConnection's processAppCommand(). 00154 AppConnKey key; 00155 key.appGateIndex = appGateIndex; 00156 key.connId = connId; 00157 tcpAppConnMap[key] = conn; 00158 00159 tcpEV << "TCP connection created for " << msg << "\n"; 00160 } 00161 bool ret = conn->processAppCommand(msg); 00162 if (!ret) 00163 removeConnection(conn); 00164 } 00165 00166 if (ev.isGUI()) 00167 updateDisplayString(); 00168 } 00169 00170 TCPConnection *TCP::createConnection(int appGateIndex, int connId) 00171 { 00172 return new TCPConnection(this, appGateIndex, connId); 00173 } 00174 00175 void TCP::segmentArrivalWhileClosed(TCPSegment *tcpseg, IPvXAddress srcAddr, IPvXAddress destAddr) 00176 { 00177 TCPConnection *tmp = new TCPConnection(); 00178 tmp->segmentArrivalWhileClosed(tcpseg, srcAddr, destAddr); 00179 delete tmp; 00180 delete tcpseg; 00181 } 00182 00183 void TCP::updateDisplayString() 00184 { 00185 if (ev.isDisabled()) 00186 { 00187 // in express mode, we don't bother to update the display 00188 // (std::map's iteration is not very fast if map is large) 00189 getDisplayString().setTagArg("t",0,""); 00190 return; 00191 } 00192 00193 //char buf[40]; 00194 //sprintf(buf,"%d conns", tcpAppConnMap.size()); 00195 //getDisplayString().setTagArg("t",0,buf); 00196 00197 int numINIT=0, numCLOSED=0, numLISTEN=0, numSYN_SENT=0, numSYN_RCVD=0, 00198 numESTABLISHED=0, numCLOSE_WAIT=0, numLAST_ACK=0, numFIN_WAIT_1=0, 00199 numFIN_WAIT_2=0, numCLOSING=0, numTIME_WAIT=0; 00200 00201 for (TcpAppConnMap::iterator i=tcpAppConnMap.begin(); i!=tcpAppConnMap.end(); ++i) 00202 { 00203 int state = (*i).second->getFsmState(); 00204 switch(state) 00205 { 00206 case TCP_S_INIT: numINIT++; break; 00207 case TCP_S_CLOSED: numCLOSED++; break; 00208 case TCP_S_LISTEN: numLISTEN++; break; 00209 case TCP_S_SYN_SENT: numSYN_SENT++; break; 00210 case TCP_S_SYN_RCVD: numSYN_RCVD++; break; 00211 case TCP_S_ESTABLISHED: numESTABLISHED++; break; 00212 case TCP_S_CLOSE_WAIT: numCLOSE_WAIT++; break; 00213 case TCP_S_LAST_ACK: numLAST_ACK++; break; 00214 case TCP_S_FIN_WAIT_1: numFIN_WAIT_1++; break; 00215 case TCP_S_FIN_WAIT_2: numFIN_WAIT_2++; break; 00216 case TCP_S_CLOSING: numCLOSING++; break; 00217 case TCP_S_TIME_WAIT: numTIME_WAIT++; break; 00218 } 00219 } 00220 char buf2[200]; 00221 buf2[0] = '\0'; 00222 if (numINIT>0) sprintf(buf2+strlen(buf2), "init:%d ", numINIT); 00223 if (numCLOSED>0) sprintf(buf2+strlen(buf2), "closed:%d ", numCLOSED); 00224 if (numLISTEN>0) sprintf(buf2+strlen(buf2), "listen:%d ", numLISTEN); 00225 if (numSYN_SENT>0) sprintf(buf2+strlen(buf2), "syn_sent:%d ", numSYN_SENT); 00226 if (numSYN_RCVD>0) sprintf(buf2+strlen(buf2), "syn_rcvd:%d ", numSYN_RCVD); 00227 if (numESTABLISHED>0) sprintf(buf2+strlen(buf2),"estab:%d ", numESTABLISHED); 00228 if (numCLOSE_WAIT>0) sprintf(buf2+strlen(buf2), "close_wait:%d ", numCLOSE_WAIT); 00229 if (numLAST_ACK>0) sprintf(buf2+strlen(buf2), "last_ack:%d ", numLAST_ACK); 00230 if (numFIN_WAIT_1>0) sprintf(buf2+strlen(buf2), "fin_wait_1:%d ", numFIN_WAIT_1); 00231 if (numFIN_WAIT_2>0) sprintf(buf2+strlen(buf2), "fin_wait_2:%d ", numFIN_WAIT_2); 00232 if (numCLOSING>0) sprintf(buf2+strlen(buf2), "closing:%d ", numCLOSING); 00233 if (numTIME_WAIT>0) sprintf(buf2+strlen(buf2), "time_wait:%d ", numTIME_WAIT); 00234 getDisplayString().setTagArg("t",0,buf2); 00235 } 00236 00237 TCPConnection *TCP::findConnForSegment(TCPSegment *tcpseg, IPvXAddress srcAddr, IPvXAddress destAddr) 00238 { 00239 SockPair key; 00240 key.localAddr = destAddr; 00241 key.remoteAddr = srcAddr; 00242 key.localPort = tcpseg->getDestPort(); 00243 key.remotePort = tcpseg->getSrcPort(); 00244 SockPair save = key; 00245 00246 // try with fully qualified SockPair 00247 TcpConnMap::iterator i; 00248 i = tcpConnMap.find(key); 00249 if (i!=tcpConnMap.end()) 00250 return i->second; 00251 00252 // try with localAddr missing (only localPort specified in passive/active open) 00253 key.localAddr = IPvXAddress(); 00254 i = tcpConnMap.find(key); 00255 if (i!=tcpConnMap.end()) 00256 return i->second; 00257 00258 // try fully qualified local socket + blank remote socket (for incoming SYN) 00259 key = save; 00260 key.remoteAddr = IPvXAddress(); 00261 key.remotePort = -1; 00262 i = tcpConnMap.find(key); 00263 if (i!=tcpConnMap.end()) 00264 return i->second; 00265 00266 // try with blank remote socket, and localAddr missing (for incoming SYN) 00267 key.localAddr = IPvXAddress(); 00268 i = tcpConnMap.find(key); 00269 if (i!=tcpConnMap.end()) 00270 return i->second; 00271 00272 // given up 00273 return NULL; 00274 } 00275 00276 TCPConnection *TCP::findConnForApp(int appGateIndex, int connId) 00277 { 00278 AppConnKey key; 00279 key.appGateIndex = appGateIndex; 00280 key.connId = connId; 00281 00282 TcpAppConnMap::iterator i = tcpAppConnMap.find(key); 00283 return i==tcpAppConnMap.end() ? NULL : i->second; 00284 } 00285 00286 ushort TCP::getEphemeralPort() 00287 { 00288 // start at the last allocated port number + 1, and search for an unused one 00289 ushort searchUntil = lastEphemeralPort++; 00290 if (lastEphemeralPort == EPHEMERAL_PORTRANGE_END) // wrap 00291 lastEphemeralPort = EPHEMERAL_PORTRANGE_START; 00292 00293 while (usedEphemeralPorts.find(lastEphemeralPort)!=usedEphemeralPorts.end()) 00294 { 00295 if (lastEphemeralPort == searchUntil) // got back to starting point? 00296 error("Ephemeral port range %d..%d exhausted, all ports occupied", EPHEMERAL_PORTRANGE_START, EPHEMERAL_PORTRANGE_END); 00297 lastEphemeralPort++; 00298 if (lastEphemeralPort == EPHEMERAL_PORTRANGE_END) // wrap 00299 lastEphemeralPort = EPHEMERAL_PORTRANGE_START; 00300 } 00301 00302 // found a free one, return it 00303 return lastEphemeralPort; 00304 } 00305 00306 void TCP::addSockPair(TCPConnection *conn, IPvXAddress localAddr, IPvXAddress remoteAddr, int localPort, int remotePort) 00307 { 00308 // update addresses/ports in TCPConnection 00309 SockPair key; 00310 key.localAddr = conn->localAddr = localAddr; 00311 key.remoteAddr = conn->remoteAddr = remoteAddr; 00312 key.localPort = conn->localPort = localPort; 00313 key.remotePort = conn->remotePort = remotePort; 00314 00315 // make sure connection is unique 00316 TcpConnMap::iterator it = tcpConnMap.find(key); 00317 if (it!=tcpConnMap.end()) 00318 { 00319 // throw "address already in use" error 00320 if (remoteAddr.isUnspecified() && remotePort==-1) 00321 error("Address already in use: there is already a connection listening on %s:%d", 00322 localAddr.str().c_str(), localPort); 00323 else 00324 error("Address already in use: there is already a connection %s:%d to %s:%d", 00325 localAddr.str().c_str(), localPort, remoteAddr.str().c_str(), remotePort); 00326 } 00327 00328 // then insert it into tcpConnMap 00329 tcpConnMap[key] = conn; 00330 00331 // mark port as used 00332 if (localPort>=EPHEMERAL_PORTRANGE_START && localPort<EPHEMERAL_PORTRANGE_END) 00333 usedEphemeralPorts.insert(localPort); 00334 } 00335 00336 void TCP::updateSockPair(TCPConnection *conn, IPvXAddress localAddr, IPvXAddress remoteAddr, int localPort, int remotePort) 00337 { 00338 // find with existing address/port pair... 00339 SockPair key; 00340 key.localAddr = conn->localAddr; 00341 key.remoteAddr = conn->remoteAddr; 00342 key.localPort = conn->localPort; 00343 key.remotePort = conn->remotePort; 00344 TcpConnMap::iterator it = tcpConnMap.find(key); 00345 ASSERT(it!=tcpConnMap.end() && it->second==conn); 00346 00347 // ...and remove from the old place in tcpConnMap 00348 tcpConnMap.erase(it); 00349 00350 // then update addresses/ports, and re-insert it with new key into tcpConnMap 00351 key.localAddr = conn->localAddr = localAddr; 00352 key.remoteAddr = conn->remoteAddr = remoteAddr; 00353 ASSERT(conn->localPort == localPort); 00354 key.remotePort = conn->remotePort = remotePort; 00355 tcpConnMap[key] = conn; 00356 00357 // localPort doesn't change (see ASSERT above), so there's no need to update usedEphemeralPorts[]. 00358 } 00359 00360 void TCP::addForkedConnection(TCPConnection *conn, TCPConnection *newConn, IPvXAddress localAddr, IPvXAddress remoteAddr, int localPort, int remotePort) 00361 { 00362 // update conn's socket pair, and register newConn (which'll keep LISTENing) 00363 updateSockPair(conn, localAddr, remoteAddr, localPort, remotePort); 00364 addSockPair(newConn, newConn->localAddr, newConn->remoteAddr, newConn->localPort, newConn->remotePort); 00365 00366 // conn will get a new connId... 00367 AppConnKey key; 00368 key.appGateIndex = conn->appGateIndex; 00369 key.connId = conn->connId; 00370 tcpAppConnMap.erase(key); 00371 key.connId = conn->connId = ev.getUniqueNumber(); 00372 tcpAppConnMap[key] = conn; 00373 00374 // ...and newConn will live on with the old connId 00375 key.appGateIndex = newConn->appGateIndex; 00376 key.connId = newConn->connId; 00377 tcpAppConnMap[key] = newConn; 00378 } 00379 00380 void TCP::removeConnection(TCPConnection *conn) 00381 { 00382 tcpEV << "Deleting TCP connection\n"; 00383 00384 AppConnKey key; 00385 key.appGateIndex = conn->appGateIndex; 00386 key.connId = conn->connId; 00387 tcpAppConnMap.erase(key); 00388 00389 SockPair key2; 00390 key2.localAddr = conn->localAddr; 00391 key2.remoteAddr = conn->remoteAddr; 00392 key2.localPort = conn->localPort; 00393 key2.remotePort = conn->remotePort; 00394 tcpConnMap.erase(key2); 00395 00396 // IMPORTANT: usedEphemeralPorts.erase(conn->localPort) is NOT GOOD because it 00397 // deletes ALL occurrences of the port from the multiset. 00398 std::multiset<ushort>::iterator it = usedEphemeralPorts.find(conn->localPort); 00399 if (it!=usedEphemeralPorts.end()) 00400 usedEphemeralPorts.erase(it); 00401 00402 delete conn; 00403 } 00404 00405 void TCP::finish() 00406 { 00407 tcpEV << getFullPath() << ": finishing with " << tcpConnMap.size() << " connections open.\n"; 00408 }