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