INET Framework for OMNeT++/OMNEST
IGMP.cc
Go to the documentation of this file.
00001 // IGMP.cc
00002 // Petr Matelesko
00003 // 5. 5. 2010
00004 
00005 #include "IGMP.h"
00006 
00007 #ifndef WITHOUT_IPv4
00008 #include "IPv4InterfaceData.h"
00009 #endif
00010 
00011 Define_Module(IGMP);
00012 
00014 std::ostream& operator<<(std::ostream& os, const IGMPInterface& e)
00015 {
00016     os << "Internet address is " << e.ie->ipv4Data()->getIPAddress() << "/" << e.ie->ipv4Data()->getNetmask().getNetmaskLength() << endl;
00017     os << "IGMP is enabled on interface" << endl;
00018     os << "Curent IGMP version is 2" << endl;
00019 //     os << "IGMP query interval is " << IGMP::QUERY_INTERVAL << " seconds" << endl;
00020 //     os << "IGMP querier timeout is " << IGMP::OTHER_QUERIER_PRESENT_INTERVAL << " seconds" << endl;
00021 //     os << "IGMP max query response time is " << IGMP::QUERY_RESPONSE_INTERVAL_SEC << " seconds" << endl;
00022 //     os << "Last member query response interval is " << IGMP::QUERY_RESPONSE_INTERVAL_SEC / 1000 << " ms" << endl;
00023 //    os << "IGMP activity: " << e.join << " joins, " << e.leave << " leaves" << endl;
00024     os << "IGMP querying router is " << e.ipQuerier;
00025     if (e.querier)
00026         os << " (this system)";
00027     os << endl;
00028 
00029     return os;
00030 };
00031 
00039 bool IGMP::isRouter()
00040 {
00041     cModule *parentModule = this->getParentModule()->getParentModule();
00042 
00043     std::string moduleName = parentModule->getNedTypeName();
00044 
00045     if (moduleName.find("router") != std::string::npos || moduleName.find("Router") != std::string::npos)
00046         return true;
00047     else
00048         return false;
00049 }
00050 
00061 IPAddress IGMP::getQuerierAddress(IPAddress thisRouterAddress, IPAddress otherRouterAddress)
00062 {
00063     if (otherRouterAddress < thisRouterAddress)
00064         return otherRouterAddress;
00065     else
00066         return thisRouterAddress;
00067 }
00068 
00077 int IGMP::getIGMPInterfaceByID(int interfaceID)
00078 {
00079     for (int i = 0; i < (int)igmpIft.size(); i++)
00080     {
00081         if (igmpIft[i].intID == interfaceID)
00082             return i;
00083     }
00084     return -1;
00085 }
00086 
00096 int IGMP::getGroupMembershipPosition(IPAddress groupAddress, IGMPInterface * igmpInterface)
00097 {
00098 
00099     int n = igmpInterface->groupMembershipTable.size();
00100     for (int j = 0; j < n; j++)
00101     {
00102         if (groupAddress.equals(igmpInterface->groupMembershipTable[j].multicastGroup))
00103             return j;
00104     }
00105     return -1;
00106 }
00107 
00118 IGMPMessage *IGMP::createPacket(int type, int maxRespTime, IPAddress groupAddress)
00119 {
00120 
00121     IGMPMessage *msg = new IGMPMessage();
00122 
00123     switch (type) {
00124 
00125         case IGMP_MEMBERSHIP_QUERY:
00126             msg->setName("IGMP_MEMBERSHIP_QUERY");
00127             break;
00128 
00129         case IGMP_MEMBERSHIP_REPORT_V1:
00130             msg->setName("IGMP_MEMBERSHIP_REPORT_V1");
00131             break;
00132 
00133         case IGMP_MEMBERSHIP_REPORT_V2:
00134             msg->setName("IGMP_MEMBERSHIP_REPORT_V2");
00135             break;
00136 
00137         case IGMP_LEAVE_GROUP:
00138             msg->setName("IGMP_LEAVE_GROUP");
00139             break;
00140 
00141     }
00142     
00143     msg->setType(type);
00144     msg->setMaxRespTime(maxRespTime);
00145     msg->setGroupAddress(groupAddress);
00146 
00147     return msg;
00148 }
00149 
00150 
00163 void IGMP::sendMembershipGeneralQuery(int interfaceID)
00164 {
00165     IGMPMessage *msg = createPacket(IGMP_MEMBERSHIP_QUERY, QUERY_RESPONSE_INTERVAL_SEC, IPAddress::UNSPECIFIED_ADDRESS);
00166 
00167     IPControlInfo *controlInfo = new IPControlInfo();
00168     controlInfo->setDestAddr(IPAddress::ALL_HOSTS_MCAST);
00169     controlInfo->setProtocol(IP_PROT_IGMP);
00170     controlInfo->setTimeToLive(1);
00171     controlInfo->setInterfaceId(interfaceID);
00172     msg->setControlInfo(controlInfo);
00173 
00174     send(msg, "sendOut");
00175 }
00176 
00189 void IGMP::sendMembershipGroupSpecificQuery(IPAddress groupAddress, int interfaceID)
00190 {
00191     IGMPMessage *msg = createPacket(IGMP_MEMBERSHIP_QUERY, LAST_MEMBER_QUERY_INTERVAL_SEC, groupAddress);
00192 
00193     IPControlInfo *controlInfo = new IPControlInfo();
00194     controlInfo->setDestAddr(groupAddress);
00195     controlInfo->setProtocol(IP_PROT_IGMP);
00196     controlInfo->setTimeToLive(1);
00197     controlInfo->setInterfaceId(interfaceID);
00198     msg->setControlInfo(controlInfo);
00199 
00200     send(msg, "sendOut");
00201 }
00202 
00216 void IGMP::sendMembershipReportV2(IPAddress groupAddress, int interfaceID)
00217 {
00218     IGMPMessage *msg = createPacket(IGMP_MEMBERSHIP_REPORT_V2, 0, groupAddress);
00219 
00220     IPControlInfo *controlInfo = new IPControlInfo();
00221     controlInfo->setDestAddr(groupAddress);
00222     controlInfo->setProtocol(IP_PROT_IGMP);
00223     controlInfo->setTimeToLive(1);
00224     controlInfo->setInterfaceId(interfaceID);
00225     msg->setControlInfo(controlInfo);
00226 
00227     send(msg, "sendOut");
00228 }
00229 
00243 void IGMP::sendLeaveGroup(IPAddress groupAddress, int interfaceID)
00244 {
00245     IGMPMessage *msg = createPacket(IGMP_LEAVE_GROUP, 0, groupAddress);
00246 
00247     IPControlInfo *controlInfo = new IPControlInfo();
00248     controlInfo->setDestAddr(IPAddress::ALL_ROUTERS_MCAST);
00249     controlInfo->setProtocol(IP_PROT_IGMP);
00250     controlInfo->setTimeToLive(1);
00251     controlInfo->setInterfaceId(interfaceID);
00252     msg->setControlInfo(controlInfo);
00253 
00254     send(msg, "sendOut");    
00255 }
00256 
00266 void IGMP::addGroupToInterface(const int interfaceID, const IPAddress groupAddress)
00267 {
00268     IPv4InterfaceData::IPAddressVector addr;    // vektor IP adres
00269     int i = getIGMPInterfaceByID(interfaceID);
00270 
00271     // ziska ukazatel na ipv4 data rozhrani
00272     IPv4InterfaceData *ipv4 = igmpIft[i].ie->ipv4Data();
00273     
00274     // pokud neni adresa multicastove skupiny v rozhrani, zapiseme ji
00275     int n = ipv4->getMulticastGroups().size();
00276     for (int j = 0; j < n; j++)
00277     {
00278         if (groupAddress.equals(ipv4->getMulticastGroups()[j]))
00279             return;
00280     }
00281     addr = ipv4->getMulticastGroups();
00282     addr.push_back(groupAddress);
00283     ipv4->setMulticastGroups(addr);
00284 }
00285 
00295 void IGMP::removeGroupFromInterface(const int interfaceID, const IPAddress groupAddress)
00296 {
00297     IPv4InterfaceData::IPAddressVector addr;    // vektor IP adres
00298     int i = getIGMPInterfaceByID(interfaceID);
00299 
00300     // ziska ukazatel na ipv4 data rozhrani
00301     IPv4InterfaceData *ipv4 = igmpIft[i].ie->ipv4Data();
00302 
00303     // pokud nalezneme danou multicastovou adresu, odstranime ji
00304     addr = ipv4->getMulticastGroups();
00305     
00306     int n = addr.size();
00307     for (int j = 0; j < n; j++)
00308     {
00309         if (groupAddress.equals(addr[j]))
00310         {
00311             addr.erase(addr.begin() + j);
00312             ipv4->setMulticastGroups(addr);
00313             return;
00314         }          
00315     }
00316 
00317 }
00318 
00326 void IGMP::processMembershipReportV2(IGMPMessage *msg)
00327 {
00328     EV << "ProcessMembershipReportV2()" << endl;
00329 
00330     IPAddress groupAddress;     // skupinova adresa
00331     IPAddress lastReporter;     // zdrojova IP adresa klienta
00332     int intID;                  // ID rozhrani
00333     int i;
00334 
00335     /* Ziskani skupiny */
00336     groupAddress = msg->getGroupAddress();
00337 
00338     /* zjistit z ktereho rozhrani zprava prisla a IP adresa klienta */
00339     if (dynamic_cast<IPControlInfo *>(msg->getControlInfo())!=NULL)
00340     {
00341         IPControlInfo *controlInfo = (IPControlInfo *)msg->getControlInfo();
00342         lastReporter = controlInfo->getSrcAddr();
00343         intID = controlInfo->getInterfaceId();
00344     }
00345 
00346     // pridat info na dane rozrhrani o skupine
00347     addGroupToInterface(intID, groupAddress);
00348 
00349     i = getIGMPInterfaceByID(intID);
00350     // zapni casovac clenstvi na skupinach
00351     startGroupMembershipTimer(&igmpIft[i], groupAddress, lastReporter, GROUP_MEMBERSHIP_INTERVAL);
00352 
00353     // pokud existuje casovac Last Member, tak ho zrus
00354     int j = getGroupMembershipPosition(groupAddress, &igmpIft[i]);
00355     if (igmpIft[i].groupMembershipTable[j].lastMember != NULL && igmpIft[i].groupMembershipTable[j].lastMember->isScheduled())
00356         {
00357             cancelEvent(igmpIft[i].groupMembershipTable[j].lastMember);
00358             delete igmpIft[i].groupMembershipTable[j].lastMember;
00359             igmpIft[i].groupMembershipTable[j].lastMember = NULL;
00360         }
00361     
00362     // TODO notify routing - spoluprace s PIM
00363 
00364     delete msg;
00365 }
00366 
00367 
00368 void IGMP::processLeaveGroup(IGMPMessage *msg)
00369 {
00370     EV << "processLeaveGroup()" << endl;
00371 
00372     IPAddress groupAddress;     // skupinova adresa
00373     IPAddress lastReporter;     // zdrojova IP adresa klienta
00374     int intID;                  // ID rozhrani
00375     int i;
00376     int j;
00377 
00378     /* Ziskani skupiny */
00379     groupAddress = msg->getGroupAddress();
00380 
00381     /* zjistit z ktereho rozhrani zprava prisla a IP adresa klienta */
00382     if (dynamic_cast<IPControlInfo *>(msg->getControlInfo())!=NULL)
00383     {
00384         IPControlInfo *controlInfo = (IPControlInfo *)msg->getControlInfo();
00385         lastReporter = controlInfo->getSrcAddr();
00386         intID = controlInfo->getInterfaceId();
00387     }
00388 
00389     i = getIGMPInterfaceByID(intID);
00390 
00391     /* Pokud je rozhrani non-querier, tak zpravu zahodime */
00392     if (!igmpIft[i].querier) {
00393         delete msg;
00394         return;
00395     }
00396 
00397     // pozadovana skupina neni v tabulce, zpravu zahodime
00398     if ((j = getGroupMembershipPosition(groupAddress, &igmpIft[i])) == -1)
00399     {
00400         delete msg;
00401         return;
00402     }
00403     
00404     // - posle na dany inteface zpravu Membership Query - Group-Specific Query
00405     // - nastavi timer clenstvi ve skupine na LAST_MEMBER_QUERIER_INETERVAL
00406     // - nastavi timer pro opakovani Group-Specific Query
00407     startGroupMembershipTimer(&igmpIft[i], groupAddress, igmpIft[i].groupMembershipTable[j].lastReporter, LAST_MEMBER_QUERIER_INETERVAL);
00408     startLastMemberTimer(&igmpIft[i], groupAddress);
00409     sendMembershipGroupSpecificQuery(groupAddress, intID);
00410 
00411     delete msg;
00412 }
00413 
00414 
00422 void IGMP::processMembershipQuery(IGMPMessage *msg)
00423 {
00424     //EV << "ProcessMembershipQuery()" << endl; // DEBUG
00425 
00426     IPAddress srcAddr;
00427     IPAddress myAddr;
00428     IPAddress querierAddr;
00429     int intID;
00430     int i;
00431 
00432     /* zjistit z ktereho rozhrani zprava prisla a IP adresa klienta */
00433     if (dynamic_cast<IPControlInfo *>(msg->getControlInfo()) != NULL)
00434     {
00435         IPControlInfo *controlInfo = (IPControlInfo *)msg->getControlInfo();
00436         srcAddr = controlInfo->getSrcAddr();
00437         intID = controlInfo->getInterfaceId();
00438     }
00439 
00440     i = getIGMPInterfaceByID(intID);
00441     myAddr = igmpIft[i].ie->ipv4Data()->getIPAddress();
00442 
00443     // testuju, jestli jsem non-querier
00444     querierAddr = getQuerierAddress(myAddr, srcAddr);
00445     
00446     if (querierAddr != myAddr)
00447     {
00448         //EV << "non-querier" << endl; // DEBUG
00449 
00450         // zmenim stav na non-querier
00451         igmpIft[i].querier = false;
00452         igmpIft[i].ipQuerier = querierAddr;
00453 
00454         // pokud existuje, zrusime casovac General Query Init
00455         if (igmpIft[i].initGeneralQuery != NULL && igmpIft[i].initGeneralQuery->isScheduled())
00456         {
00457             cancelEvent(igmpIft[i].initGeneralQuery);
00458             delete igmpIft[i].initGeneralQuery;
00459             igmpIft[i].initGeneralQuery = NULL;
00460         }
00461 
00462         // pokud existuje, zrusime casovac General Query
00463         if (igmpIft[i].generalQuery != NULL && igmpIft[i].generalQuery->isScheduled())
00464         {
00465             cancelEvent(igmpIft[i].generalQuery);
00466             delete igmpIft[i].generalQuery;
00467             igmpIft[i].generalQuery = NULL;
00468         }
00469 
00470         // spustime casovac Other Querier Present
00471         startInterfaceTimer(TIMER_OTHER_QUERIER_PRESENT, &igmpIft[i]);
00472 
00473     }
00474 
00475    delete msg;
00476 }
00477 
00478 
00486 void IGMP::processIGMPMessage(IGMPMessage *igmpmsg)
00487 {
00488     switch (igmpmsg->getType())
00489     {
00490         case IGMP_MEMBERSHIP_QUERY:
00491             processMembershipQuery(igmpmsg);
00492             break;
00493 
00494         case IGMP_MEMBERSHIP_REPORT_V2:
00495             processMembershipReportV2(igmpmsg);
00496             break;
00497 
00498         case IGMP_LEAVE_GROUP:
00499             processLeaveGroup(igmpmsg);
00500             break;
00501         default:
00502             EV << "processIGMPMesage(): Unknow IGMP Message" << endl;
00503     }
00504 }
00505 
00513 void IGMP::processIGMPTimer(IGMPTimer *timer)
00514 {
00515     int i;      // index v tabulce IGMP rozhrani
00516     i = getIGMPInterfaceByID(timer->getIntID());
00517     
00518     switch (timer->getTimerKind())
00519     {
00520         case TIMER_INIT_GENERAL_QUERY: 
00521             // Casovac Init General Query vyprsel -
00522             // - posle General Query
00523             // - pokud jsme poslali vsechny Init General Query (STARTUP_QUERY_COUNT)
00524             // -- nastavi casovac General Query
00525             // - pokud jsme jeste vsechny Init General Query neposlali
00526             // -- nastavi casovac Init General Query
00527             sendMembershipGeneralQuery(timer->getIntID());
00528 
00529             if ((timer->getCount() - 1) > 0)
00530                 startInterfaceTimer(TIMER_INIT_GENERAL_QUERY, &igmpIft[i]);
00531             else
00532                 startInterfaceTimer(TIMER_GENERAL_QUERY, &igmpIft[i]);
00533             break;
00534 
00535         case TIMER_GENERAL_QUERY:
00536             // Casovac General Query vyprsel -
00537             // - posle zpravu General Query a nastavi casovac General Query
00538             sendMembershipGeneralQuery(timer->getIntID());
00539             startInterfaceTimer(TIMER_GENERAL_QUERY, &igmpIft[i]);
00540             break;
00541             
00542         case TIMER_OTHER_QUERIER_PRESENT:
00543             // Casovac pritomnosti jineho Querier routeru vyprsel -
00544             // - rozhrani se stava opet Querierem
00545             // - posle zpravu General Query a nastavi casovac General Query
00546             igmpIft[i].querier = true;
00547             igmpIft[i].ipQuerier = igmpIft[i].ie->ipv4Data()->getIPAddress();
00548             igmpIft[i].otherQuerierPresent = NULL;
00549             sendMembershipGeneralQuery(timer->getIntID());
00550             startInterfaceTimer(TIMER_GENERAL_QUERY, &igmpIft[i]);
00551             break;
00552 
00553         case TIMER_GROUP_MEMBERSHIP:
00554             // Casovac clenstvi vyprsel:
00555             // - odebereme multicasatovou skupiny z tabulky rozhrani
00556             // - odstranime zaznam ve vlastni tabulce clenstvi
00557             removeGroupFromInterface(timer->getIntID(), timer->getGroupAddress());
00558 
00559             int j;
00560             j = getGroupMembershipPosition(timer->getGroupAddress(), &igmpIft[i]);
00561 
00562             igmpIft[i].groupMembershipTable.erase(igmpIft[i].groupMembershipTable.begin() + j);
00563             
00564             // TODO - notify routing - spoluprace s PIM
00565             break;
00566 
00567         case TIMER_LAST_MEMBER:
00568 
00569             sendMembershipGroupSpecificQuery(timer->getGroupAddress(), timer->getIntID());
00570 
00571             if ((timer->getCount() - 1) > 0)
00572                 startLastMemberTimer(&igmpIft[i], timer->getGroupAddress());
00573 
00574             break;
00575     }
00576     delete timer;
00577 
00578 }
00579 
00588 void IGMP::handleMessage(cMessage *msg)
00589 {
00590     /* Implementace IGMP na routeru */
00591     if (isRouter())
00592     {
00593         //EV << "IGMP::handleMessage(): on router" << endl; // DEBUG
00594     
00595         /* zpracovani vlastnich zprav - timeru */
00596         if (msg->isSelfMessage())
00597         {
00598             processIGMPTimer(check_and_cast<IGMPTimer *>(msg));
00599            
00600           
00601         }
00602         /* zpracovani IGMP zprav */
00603         else
00604         {
00605             processIGMPMessage(check_and_cast<IGMPMessage *>(msg));
00606         }
00607 
00608     }
00609     /* Implementace IGMP na hostu */
00610     else
00611     {
00612         //EV << "IGMP::handleMessage(): on host" << endl; // DEBUG
00613 
00614         /* vlastni zpravy */
00615         if (msg->isSelfMessage())
00616         {
00617             // FIXME zatim zadne vlastni zpravy
00618         }
00619         /* IGMP zpravy */
00620         else
00621         {
00622             IGMPMessage  *mymsg = check_and_cast<IGMPMessage *>(msg);
00623 
00624             switch (mymsg->getType())
00625             {
00626                 case IGMP_MEMBERSHIP_QUERY:
00627 
00628                         if (dynamic_cast<IPControlInfo *>(mymsg->getControlInfo())!=NULL)
00629                         {
00630                             IPControlInfo *controlInfo = (IPControlInfo *)mymsg->removeControlInfo();
00631                             EV << "IGMP_MEMBERSHIP_QUERY from " << controlInfo->getSrcAddr() << " to " << controlInfo->getDestAddr() << endl; // FIXME destAddr nevzyplnuje
00632 
00633                             delete controlInfo;
00634                         }
00635                     
00636                     break;
00637             }
00638 
00639             delete mymsg;
00640             
00641         }
00642         
00643     }
00644 
00645 }
00646 
00657 IGMPTimer * IGMP::startGroupMembershipTimer(IGMPInterface * igmpInterface, IPAddress groupAddress, IPAddress lastReporter, int interval)
00658 {
00659     IGMPTimer *newTimer = new IGMPTimer();
00660     newTimer->setTimerKind(TIMER_GROUP_MEMBERSHIP);
00661     newTimer->setName("Timer Group Membership");
00662     newTimer->setIntID(igmpInterface->intID);
00663     newTimer->setGroupAddress(groupAddress);
00664     scheduleAt(simTime() + interval, newTimer);
00665     
00666     // prohledame tabulku  clenstvi, pokud uz clenstvi existuje:
00667     // - zrusime stary timer
00668     // - zapiseme novy
00669     // - zapiseme noveho Last Reportera
00670 
00671     int j = getGroupMembershipPosition(groupAddress, igmpInterface);
00672 
00673     if (j != -1)
00674     {
00675         cancelEvent(igmpInterface->groupMembershipTable[j].groupMembership);
00676         delete igmpInterface->groupMembershipTable[j].groupMembership;
00677         igmpInterface->groupMembershipTable[j].lastReporter = lastReporter;
00678         igmpInterface->groupMembershipTable[j].groupMembership = newTimer;
00679         igmpInterface->groupMembershipTable[j].lastMember = NULL;
00680         return newTimer;
00681     }
00682    
00683     // pokud timer neexistuje, vytvorime nove clenstvi
00684     // - zapiseme vsechny hodnoty
00685     // - vlozime do tabulky clenstvi
00686     IGMPGroupMembership newGroupMembership;
00687     newGroupMembership.multicastGroup = groupAddress;
00688     newGroupMembership.lastReporter = lastReporter;
00689     newGroupMembership.groupMembership = newTimer;
00690     newGroupMembership.lastMember = NULL;
00691     igmpInterface->groupMembershipTable.push_back(newGroupMembership);
00692     
00693     return newTimer;
00694 }
00695 
00704 IGMPTimer * IGMP::startLastMemberTimer(IGMPInterface * igmpInterface, IPAddress groupAddress)
00705 {
00706     IGMPTimer *newTimer = new IGMPTimer();
00707     newTimer->setTimerKind(TIMER_LAST_MEMBER);
00708     newTimer->setName("Timer Last Member");
00709     newTimer->setIntID(igmpInterface->intID);
00710     newTimer->setGroupAddress(groupAddress);
00711     scheduleAt(simTime() + LAST_MEMBER_QUERY_INTERVAL_SEC, newTimer);
00712 
00713     // vytvoreni prvotniho timeru -
00714     // - pocet Group-Specific Query dle LAST_MEMBER_QUERY_COUNT
00715 
00716     int j = getGroupMembershipPosition(groupAddress, igmpInterface);
00717 
00718     if (j != -1 && igmpInterface->groupMembershipTable[j].lastMember == NULL)
00719         newTimer->setCount(LAST_MEMBER_QUERY_COUNT - 1);
00720     // u dalsich timeru snizujeme pocet o 1
00721     else
00722         newTimer->setCount(igmpInterface->initGeneralQuery->getCount() - 1);
00723 
00724     igmpInterface->groupMembershipTable[j].lastMember = newTimer;
00725 
00726     return newTimer;
00727 }
00728 
00738 IGMPTimer * IGMP::startInterfaceTimer(int timerType, IGMPInterface * igmpInterface)
00739 {
00740     IGMPTimer *newTimer = new IGMPTimer();
00741     newTimer->setTimerKind(timerType);
00742     newTimer->setIntID(igmpInterface->intID);
00743 
00744     switch (timerType)
00745     {
00746         case TIMER_INIT_GENERAL_QUERY:
00747              
00748             // vytvoreni prvotniho timeru -
00749             // - pocet initializacnich General Query dle STARTUP_QUERY_COUNT
00750             if (igmpInterface->initGeneralQuery == NULL)
00751                 newTimer->setCount(STARTUP_QUERY_COUNT - 1);
00752             // u dalsich timeru snizujeme pocet o 1
00753             else
00754                 newTimer->setCount(igmpInterface->initGeneralQuery->getCount() - 1);
00755             
00756             newTimer->setName("Timer Init General Query");
00757             scheduleAt(simTime() + STARTUP_QUERY_INTERVAL, newTimer);
00758             igmpInterface->initGeneralQuery = newTimer;
00759             break;
00760 
00761         case TIMER_GENERAL_QUERY:
00762             newTimer->setName("Timer General Query");
00763             scheduleAt(simTime() + QUERY_INTERVAL, newTimer);
00764             igmpInterface->generalQuery = newTimer;
00765             break;
00766 
00767         case TIMER_OTHER_QUERIER_PRESENT:
00768             // pokud uz nejaky timer bezi, tak ho zrusime
00769             if (igmpInterface->otherQuerierPresent != NULL && igmpInterface->otherQuerierPresent->isScheduled())
00770             {
00771                 cancelEvent(igmpInterface->otherQuerierPresent);
00772                 delete igmpInterface->otherQuerierPresent;
00773             }
00774             // vytvorime novy timer
00775             newTimer->setName("Timer Other Querier Present");
00776             scheduleAt(simTime() + OTHER_QUERIER_PRESENT_INTERVAL, newTimer);
00777             igmpInterface->otherQuerierPresent = newTimer;
00778             break;
00779     }
00780     return newTimer;
00781 }
00782 
00790 void IGMP::initialize(int stage)
00791 {
00792     if (stage == 4)
00793     {
00794         /* IGMP modul routeru */
00795         if (isRouter())
00796         {
00797             /* pristup k tabulce rozhrani */
00798             ift = InterfaceTableAccess().get();
00799 
00800             /* inicializace timeru a promennych */
00801 
00802             ROBUSTNESS_VARIABLE = 2;                                            // default: 2
00803             QUERY_INTERVAL = 125;                                               // default: 125 s
00804             QUERY_RESPONSE_INTERVAL = 100;                                      // default: 100 = 10 s
00805             QUERY_RESPONSE_INTERVAL_SEC = QUERY_RESPONSE_INTERVAL / 10;         // prevod na sekundy
00806             LAST_MEMBER_QUERY_COUNT = ROBUSTNESS_VARIABLE;
00807             LAST_MEMBER_QUERY_INTERVAL = 10;    // default: 10 = 1 s
00808             LAST_MEMBER_QUERY_INTERVAL_SEC = LAST_MEMBER_QUERY_INTERVAL / 10;   // prevod na sekundy
00809             LAST_MEMBER_QUERIER_INETERVAL = LAST_MEMBER_QUERY_COUNT * LAST_MEMBER_QUERY_INTERVAL_SEC;
00810             GROUP_MEMBERSHIP_INTERVAL = (ROBUSTNESS_VARIABLE * QUERY_INTERVAL) + QUERY_RESPONSE_INTERVAL_SEC;
00811             STARTUP_QUERY_COUNT = ROBUSTNESS_VARIABLE;
00812             STARTUP_QUERY_INTERVAL = QUERY_INTERVAL / 4;
00813             OTHER_QUERIER_PRESENT_INTERVAL = (ROBUSTNESS_VARIABLE * QUERY_INTERVAL) + (QUERY_RESPONSE_INTERVAL_SEC / 2);
00814             
00815             /* naplneni vlastni tabulky rozhrani aktivni IGMP */
00816             // - neni loopback
00817             // - kazde rozhrani je automaticky Querier
00818             // - casovace nejsou nastaveny
00819             // TODO:
00820             // - ted je IGMP na vsech rozhranich defaultne zaple
00821             // - dodelat zapinani IGMP na rozhrani spolu s PIMem
00822             
00823             for (int i = 0; i < ift->getNumInterfaces(); i++)
00824             {
00825                 if (!ift->getInterface(i)->isLoopback())
00826                 {
00827                     IGMPInterface igmpInt;
00828                     igmpInt.intID = ift->getInterface(i)->getInterfaceId();     // interface ID
00829                     igmpInt.ie = ift->getInterface(i);                          // interface entry
00830                     igmpInt.querier = true;                                     // querier
00831                     igmpInt.ipQuerier = igmpInt.ie->ipv4Data()->getIPAddress(); // IP adresa Queriera
00832                     igmpInt.initGeneralQuery = NULL;                            // casovac init general query
00833                     igmpInt.generalQuery = NULL;                                // casovac general query
00834                     igmpInt.otherQuerierPresent = NULL;                         // casova other querier present
00835                     igmpIft.push_back(igmpInt);
00836 
00837                 }
00838             }
00839             
00840             /* sledovani promennych */
00841 
00842             //WATCH_VECTOR(igmpIft[i].groupMembershipTable);
00843             WATCH_VECTOR(igmpIft);
00844             
00845             /* startup query */
00846             // na vsechny rozhrani v tabulce IGMP rozhrani posle General Query a spusti casovac General Query Init
00847             for (int j = 0; j < (int)igmpIft.size(); j++)
00848             {
00849                 startInterfaceTimer(TIMER_INIT_GENERAL_QUERY, &igmpIft[j]);
00850                 //sendMembershipGeneralQuery(igmpIft[j].intID);
00851             }
00852                 
00853         }
00854 
00855 
00856         /* IGMP modul hostu */
00857         /*else
00858         {
00859             //EV << "IGMP::initialize() on client" << endl; // DEBUG
00860 
00861             // TEST: pro testovani chovani
00862             int intID;
00863             ift = InterfaceTableAccess().get();
00864 
00865 
00866             IPAddress ga1("225.0.0.1");
00867             IPAddress ga2("225.0.0.2");
00868             IPAddress ga3("225.0.0.3");
00869             IPAddress ga4("225.0.0.4");
00870 
00871             
00872             for (int i = 0; i < ift->getNumInterfaces(); i++)
00873             {
00874                 if (!ift->getInterface(i)->isLoopback())
00875                 {
00876                     intID = ift->getInterface(i)->getInterfaceId();
00877                     break;
00878                 }
00879             }
00880 
00881             // test 1: join 225.0.0.1
00882             sendMembershipReportV2(ga1, intID);
00883 
00884             // test 2. joing 225.0.0.2 - prihlaseni dalsi skupiny
00885             sendMembershipReportV2(ga2, intID); // join 225.0.0.2
00886             
00887             // test 3: join 225.0.0.2 - na skupinu, ktere uz je clenem
00888             sendMembershipReportV2(ga2, intID);
00889 
00890 
00891             // test 4: leave 225.0.0.1
00892             sendLeaveGroup(ga1, intID);         // leave 225.0.0.1
00893 
00894             // test 5: leave 225.0.0.3 - odhlaseni neprihlasene skupiny
00895             sendLeaveGroup(ga3, intID);         // leave 225.0.0.3
00896 
00897             //
00898 //          sendMembership
00899 
00900             // test 6: odhlaseni skupiny 225.0.0.2 po vyprseni casovace
00901             // - neposilame zadnou zpravu
00902 
00903         }*/
00904    }
00905    
00906 }