diff -Naur ns-allinone-2.29-old/ns-2.29/Makefile.in ns-allinone-2.29/ns-2.29/Makefile.in --- ns-allinone-2.29-old/ns-2.29/Makefile.in 2005-10-20 06:45:22.000000000 +0200 +++ ns-allinone-2.29/ns-2.29/Makefile.in 2007-08-03 22:23:40.000000000 +0200 @@ -70,8 +70,18 @@ -I./diffusion3/lib/nr -I./diffusion3/ns \ -I./diffusion3/filter_core -I./asim/ -I./qs \ -I./diffserv -I./satellite \ - -I./wpan - + -I./wpan \ + -I./clustering/common \ + -I./clustering/utility \ + -I./clustering/wuli \ + -I./clustering/mpr \ + -I./clustering/leader \ + -I./clustering/alzoubi \ + -I./clustering/connector \ + -I./clustering/dca_mastro \ + -I./clustering/wuli-sparsifier \ + -I./clustering/shiva \ + -I./clustering/rajaraman LIB = \ @V_LIBS@ \ @@ -139,7 +149,27 @@ diffusion3/filters/misc/srcrt.o \ diffusion3/filters/misc/tag.o \ diffusion3/filters/rmst/rmst.o \ - diffusion3/filters/rmst/rmst_filter.o + diffusion3/filters/rmst/rmst_filter.o \ + clustering/common/ClusteringModule.o \ + clustering/common/Separator.o \ + clustering/wuli/wuli.o \ + clustering/mpr/mpr.o \ + clustering/connector/connector_mastro.o \ + clustering/rajaraman/rajaraman.o \ + clustering/leader/leader.o \ + clustering/alzoubi/alzoubi.o \ + clustering/shiva/CyclesFinder.o \ + clustering/shiva/shiva.o \ + clustering/dca_mastro/dca_mastro.o \ + clustering/utility/Utility.o \ + clustering/utility/CommonUtility.o \ + clustering/utility/ClusteringUtility.o \ + clustering/utility/BackboneUtility.o \ + clustering/utility/StackUtility.o \ + clustering/utility/LeaderUtility.o \ + clustering/utility/ShivaUtility.o \ + clustering/utility/ConnectorUtility.o \ + clustering/utility/RajaramanUtility.o NS_TCL_LIB_STL = tcl/lib/ns-diffusion.tcl diff -Naur ns-allinone-2.29-old/ns-2.29/clustering/LICENSE ns-allinone-2.29/ns-2.29/clustering/LICENSE --- ns-allinone-2.29-old/ns-2.29/clustering/LICENSE 1970-01-01 01:00:00.000000000 +0100 +++ ns-allinone-2.29/ns-2.29/clustering/LICENSE 2007-08-03 22:23:31.000000000 +0200 @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff -Naur ns-allinone-2.29-old/ns-2.29/clustering/NOTICE ns-allinone-2.29/ns-2.29/clustering/NOTICE --- ns-allinone-2.29-old/ns-2.29/clustering/NOTICE 1970-01-01 01:00:00.000000000 +0100 +++ ns-allinone-2.29/ns-2.29/clustering/NOTICE 2007-08-03 22:23:31.000000000 +0200 @@ -0,0 +1,3 @@ + +Any use of this code for research purposes, should contain a reference to the following paper: +"Localized Protocols for Ad Hoc Clustering and Backbone Formation: A Performance Comparison.", S. Basagni, M. Mastrogiovanni, A. Panconesi, and C. Petrioli. IEEE Transactions on Parallel and Distributed Systems, Special Issue on Localized Communication and Topology Protocols for Ad Hoc Networks (S. Olariu, D. Simplot-Ryl, and I. Stojmenovic, editors), April 2006. diff -Naur ns-allinone-2.29-old/ns-2.29/clustering/alzoubi/.DS_Store ns-allinone-2.29/ns-2.29/clustering/alzoubi/.DS_Store --- ns-allinone-2.29-old/ns-2.29/clustering/alzoubi/.DS_Store 1970-01-01 01:00:00.000000000 +0100 +++ ns-allinone-2.29/ns-2.29/clustering/alzoubi/.DS_Store 2007-08-03 22:23:31.000000000 +0200 @@ -0,0 +1,2 @@ +Bud1ubi.cc +alzoubi.ccIlocblobđ!˙˙˙˙˙˙ alzoubi.hIlocblob!˙˙˙˙˙˙ MESSAGES.txtIlocblobPÓ˙˙˙˙˙˙ structure.hIlocblobÓ˙˙˙˙˙˙  @€ @€ @€ @ EDSDB `€ @€ @€ @ \ No newline at end of file diff -Naur ns-allinone-2.29-old/ns-2.29/clustering/alzoubi/alzoubi.cc ns-allinone-2.29/ns-2.29/clustering/alzoubi/alzoubi.cc --- ns-allinone-2.29-old/ns-2.29/clustering/alzoubi/alzoubi.cc 1970-01-01 01:00:00.000000000 +0100 +++ ns-allinone-2.29/ns-2.29/clustering/alzoubi/alzoubi.cc 2007-08-03 22:23:31.000000000 +0200 @@ -0,0 +1,1192 @@ + +/** + * Copyright (c) 2006 Michele Mastrogiovanni. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#include "alzoubi.h" +#include "Separator.h" +#include "BackboneUtility.h" + +int hdr_alzoubi::offset_; + +int ALZOUBI_Agent::_DEBUG_; + +double ALZOUBI_Agent::max_delay; + +int ALZOUBI_Agent::max_timeout_confirm; +double ALZOUBI_Agent::jitter_timeout_confirm; +double ALZOUBI_Agent::timeout_confirm; + +int ALZOUBI_Agent::max_timeout_cds; +double ALZOUBI_Agent::jitter_timeout_cds; +double ALZOUBI_Agent::timeout_cds; + +int ALZOUBI_Agent::max_timeout_last; +double ALZOUBI_Agent::jitter_timeout_last; +double ALZOUBI_Agent::timeout_last; + +static class AlzoubiHeaderClass : public PacketHeaderClass { +public: + AlzoubiHeaderClass() : PacketHeaderClass("PacketHeader/ALZOUBI", + sizeof(hdr_alzoubi)) { + bind_offset(&hdr_alzoubi::offset_); + } +} class_alzoubihdr; + +static class AlzoubiClass : public TclClass { +public: + AlzoubiClass() : TclClass("Agent/ALZOUBI") {} + TclObject* create(int , const char*const* ) { + return(new ALZOUBI_Agent()); + } +} class_alzoubi; + +ALZOUBI_Agent::ALZOUBI_Agent() : ClusteringModule(PT_ALZOUBI) +{ + timer = new AlzoubiTimer(this); + + bind("max-delay", &max_delay); + + bind_bool("debug", &_DEBUG_); + + bind("max-timeout-confirm", &max_timeout_confirm); + bind("jitter-timeout-confirm", &jitter_timeout_confirm); + bind("timeout-confirm", &timeout_confirm); + + bind("max-timeout-cds", &max_timeout_cds); + bind("jitter-timeout-cds", &jitter_timeout_cds); + bind("timeout-cds", &timeout_cds); + + bind("max-timeout-last", &max_timeout_last); + bind("jitter-timeout-last", &jitter_timeout_last); + bind("timeout-last", &timeout_last); + +} + +// +// Procedura di inizializzazione delle strutture dati +// della fase di Creazione del Backbone. +// +void +ALZOUBI_Agent::initializeCDSConstruction() +{ + // Iposta il numero di round. + cdscData.round = 0; + + cdscData.endFirstCDSBufferization = false; + + // Svuota il buffer dei messaggi ricevuti. + struct ColorMessage null_color_message; + null_color_message.round = -1; + for (NodeList::iterator i = neighbors.begin(); i != neighbors.end(); i++) { + cdscData.messages[0][*i] = null_color_message; + cdscData.messages[1][*i] = null_color_message; + } + + cdscData.myLastColor = COLOR_WHITE; +} + +// +// Funzione di ricezione di un pacchetto di clustering. +// +void +ALZOUBI_Agent::receive(Packet *p, Handler *h) +{ + struct hdr_alzoubi *alzoubih = HDR_ALZOUBI(p); + struct hdr_ip *iph = HDR_IP(p); + + NodeAddress sender_address = iph->saddr(); + // Destinazione. + NodeAddress destination_address = iph->daddr(); + + bool result; + + // Aggiorna le statistiche dei messaggi e dei mytes ricevuti. + switch (alzoubih->msg_type) { + + case ALZOUBI_COLOR : + + // + // Invia un messaggio diretto di conferma per la ricezione del messaggio + // + send_CONFIRM(sender_address, alzoubih->color_message.round, ALZOUBI_COLOR, false); + + // + // Se l'algoritmo e'terminato o e'nella fase finale si ignora il messaggio + // + if (status > ALZOUBI_STATUS_CDS) + return; + + // + // Bufferizza il messaggio: result vale true se il messaggio non e'mai arrivato prima. + // + result = bufferizeMessage(sender_address, alzoubih->color_message); + + // + // Se il messaggio e' vecchio, viene ignorato. + // + if (!result) + return; + + // + // Se non ci si trova nella fase di creazione del backbone, esce. + // + if (status == ALZOUBI_STATUS_END) + return; + + // + // E' arrivato un messaggio del primo round. + // + if (alzoubih->color_message.round == 0) { + // + // Riceve il messaggio + // + receive_COLOR(sender_address, alzoubih->color_message); + + // + // Forza lo svuotamento del buffer: ovvero se sono arrivati tutti i messaggi + // del primo round e non e' mai stato fatto lo svuotamento dei messaggi del + // secondo round allora, vengono svuotati i messaggi del secondo round. + // + emptyCDSBuffer(); + } + else if (alzoubih->color_message.round == 1) { + // + // Se il buffer dei messaggi del secondo round e'stato svuotato + // allora significa anche che sono arrivati tutti i messaggi del primo round + // Si puo'procedere a ricevere il messaggio + // + if (cdscData.endSecondCDSBufferization) + // + // Riceve il messaggio + // + receive_COLOR(sender_address, alzoubih->color_message); + } + break; + + case ALZOUBI_LAST : + + send_CONFIRM(sender_address, 0, ALZOUBI_LAST, false); + + // Se l'algoritmo e'terminato, allora non c'e'possibilita'di + // cambiare ricevendo un messaggio LAST. + if (status == ALZOUBI_STATUS_END) + return; + + // Se il messaggio e'un duplicato o sono arrivati + // gia'tutti i messaggi di LAST, ignora. + if (find(cdscData.last_messages.begin(), cdscData.last_messages.end(), sender_address) == cdscData.last_messages.end()) + return; + + // Riceve il messaggio + receive_LAST(sender_address, alzoubih->last_message); + + break; + + case ALZOUBI_REQUEST : + + receive_REQUEST(sender_address, alzoubih->request_message); + + break; + + case ALZOUBI_CONFIRM : + + receive_CONFIRM(sender_address, alzoubih->confirm_message); + + break; + + } +} + +/************************/ +/* Messages */ +/************************/ + +// +// Invia la conferma di ricezione per un certo messaggio di un certo round. +// Il messaggio viene utilizzato per confermare i messaggi di INFO, di FEEDBACK e di ACTION. +// Il flag "send" serve per indicare se la conferma fa parte di un invio o di una risposta. +// +void +ALZOUBI_Agent::send_CONFIRM(NodeAddress to, int round, AlzoubiMessageType type, bool send) +{ + Packet* p = allocpkt(); + struct hdr_alzoubi * alzoubih = HDR_ALZOUBI(p); + + // Common structures. + alzoubih->msg_type = ALZOUBI_CONFIRM; + + // Message. + alzoubih->confirm_message.send = send; + alzoubih->confirm_message.round = round; + alzoubih->confirm_message.type = type; + + size_t size = sizeof(ConfirmMessage) + sizeof(AlzoubiMessageType); + + // Invia il messaggio. + sendDown(p, size, to, ALZOUBI_Agent::max_delay); +} + +void +ALZOUBI_Agent::send_REQUEST(NodeAddress to, AlzoubiMessageType type, int round) +{ + Packet* p = allocpkt(); + struct hdr_alzoubi * alzoubih = HDR_ALZOUBI(p); + + // Common structures. + alzoubih->msg_type = ALZOUBI_REQUEST; + + // Message + alzoubih->request_message.type = type; + alzoubih->request_message.round = round; + + size_t size = sizeof(RequestMessage) + sizeof(AlzoubiMessageType); + + // Invia il messaggio. + sendDown(p, size, to, ALZOUBI_Agent::max_delay); +} + +void +ALZOUBI_Agent::emptyCDSBuffer() +{ + if (status != ALZOUBI_STATUS_CDS) { + // printf("ERROR: try to empty buffer while bufferizing\n"); + return; + } + + struct ColorMessage t1; + struct ColorMessage t2; + + // + // Flag che dice se sono arrivati tutti i messaggi del primo round. + // + bool all = true; + + // + // Se il buffer del primo round non  stato ancora svuotato allora provvede. + // + if (!cdscData.endFirstCDSBufferization) { + + cdscData.endFirstCDSBufferization = true; + + // NodeList mancano; + for (NodeList::iterator i = neighbors.begin(); i != neighbors.end(); i++) { + t1 = cdsFromBuffer(0, *i); + if (t1.round != -1) + receive_COLOR(*i, t1); + else + all = false; + } + + // + // Al momento di questo primo svuotamento, il nodo si rende conto di aver ricevuto correttamente + // tutti i messaggi del primo round: si accinge a svuotare il buffer per i messaggi del secondo + // round. + // + if (!(!cdscData.endSecondCDSBufferization && all)) + return; + + cdscData.endSecondCDSBufferization = true; + + all = true; + for (NodeList::iterator i = neighbors.begin(); i != neighbors.end(); i++) { + t2 = cdsFromBuffer(1, *i); + if (t2.round != -1) + receive_COLOR(*i, t2); + else + all = false; + } + + return; + } + + if (cdscData.endSecondCDSBufferization) + return; + + all = true; + // Verifica che siano arrivati tutti i messaggi del round 1 + for (NodeList::iterator i = neighbors.begin(); i != neighbors.end(); i++) { + t1 = cdsFromBuffer(1, *i); + if (t1.round == -1) { + all = false; + break; + } + } + + if (!all) + return; + + cdscData.endSecondCDSBufferization = true; + + all = true; + for (NodeList::iterator i = neighbors.begin(); i != neighbors.end(); i++) { + t2 = cdsFromBuffer(1, *i); + if (t2.round != -1) + receive_COLOR(*i, t2); + else + all = false; + } +} + +/****************************/ +/* Algorithm procedures and +/* events. +/****************************/ + +void +ALZOUBI_Agent::endModule() +{ + if (_DEBUG_) + printf("%d FINITO, colore = %s\n", myAddress, cdscData.myLastColor == COLOR_BLACK ? "BLACK" : "GRAY"); + + // Entra nello stato finale. + status = ALZOUBI_STATUS_END; + + // Memorizza il proprio clusterHead: + // se il nodo e'nero e'se stesso, altrimenti e'il vicino NERO maggiore. + NodeAddress CH = (cdscData.myLastColor == COLOR_BLACK) ? myAddress : greaterCluster(); + setClusterHead(myAddress, CH); + + if (utility) { + NodeList backboneNeighbors; + if (myAddress == CH) { + for (NodeList::iterator n = neighbors.begin(); n != neighbors.end(); n++) + if (cdscData.lastColor[*n] == COLOR_BLACK) + backboneNeighbors.insert(*n); + } + else { + backboneNeighbors.insert(CH); + } + ((BackboneUtility*)utility)->setBackbone(myAddress, backboneNeighbors); + ((BackboneUtility*)utility)->setColor(myAddress, myAddress == CH ? "black" : "white"); + } + + // Segnala la conclusione del processo di clustering. + ClusteringModule::endModule(); + + // Start upper module + if (upTarget) + Separator::instance().endCurrentModule(myAddress); +} + +// +// Inizia il processo di leader election. +// +void +ALZOUBI_Agent::startModule() +{ + // Inizializza le informazioni comuni del clustering. + ClusteringModule::startModule(); + + // + // Carica le informazioni di stato dal modulo sottostante. + // + if (!lowerModule && target()) { + ClusteringModule * bottom = (ClusteringModule*)target(); + if (bottom->supportProtocol("leader")) { + + cdscData.leader = *((NodeAddress*)bottom->getData("leader")); + cdscData.tree_size = *((int*)bottom->getData("tree_size")); + cdscData.parent = *((NodeAddress*)bottom->getData("parent")); + cdscData.childs = *((NodeList*)bottom->getData("childs")); + cdscData.level = *((int*)bottom->getData("level")); + cdscData.levels = *((map*)bottom->getData("levels")); + } + + // + // Load data from lower layer. + // + if (_DEBUG_) { + printf("\n%d [PARENT=%d, CHILDS=(", myAddress, cdscData.parent); + for (NodeList::iterator i = cdscData.childs.begin(); i != cdscData.childs.end(); i++) + printf("%d ", *i); + printf("), SIZE=%d, LEADER=%d, LEVEL=%d]\n\n", cdscData.tree_size, cdscData.leader, cdscData.level); + } + + } + + status = ALZOUBI_STATUS_CDS; + + // Initialize structures. + initializeCDSConstruction(); + + cdscData.last_messages = neighbors; + + // Vicini bianchi + cdscData.white_neighbors = neighbors; + + // Figli che non sono di tipo DOMINATEE + cdscData.childs_no_dominatee = cdscData.childs; + + // Vicini neri + cdscData.black_neighbors.clear(); + + // Imposta i nodi di rango inferiore. + for (NodeList::iterator i = neighbors.begin(); i != neighbors.end(); i++) { + int level = cdscData.levels[*i]; + if (level < cdscData.level) + cdscData.lower_rank.insert(*i); + else if ((level == cdscData.level) && ((*i) < myAddress)) + cdscData.lower_rank.insert(*i); + } + + // Vicini grigi + cdscData.gray_neighbors.clear(); + + // Figli neri o grigi. + cdscData.childs_gray_or_black.clear(); + + // Numero di nodi di rango inferiore. + cdscData.lower_rank_size = cdscData.lower_rank.size(); + + cdscData.color = COLOR_BLACK; + + if (cdscData.leader != myAddress) { + cdscData.color = COLOR_WHITE; + emptyCDSBuffer(); + return; + } + + send_COLOR(COLOR_BLACK); + + // + // Verifica se si puo'verificare la condizione di colorazione GRAY. + // Se le condizioni non ci sono allora il LEADER puo'liberamente + // concludere l'algoritmo. + // + if (cdscData.lower_rank_size != neighbors.size()) + init_LAST_cycle(); +} + +// +// Inizia la fase finale dell'algoritmo. Condizione necessaria all'invio +// del messaggio finale e'che tutti i nodi vicini abbiano ricevuto +// tutti i messaggi di tipo COLOR che sono stati inviati dal nodo. +// Quindi non e'permesso lanciare un messaggio di LAST se non qualora non ci +// siano timeout pendenti. +// +void +ALZOUBI_Agent::init_LAST_cycle() +{ + // Imposta l'ultimo colore selezionato. + cdscData.myLastColor = cdscData.color; + + // Imposta lo stato finale. + status = ALZOUBI_STATUS_LAST; + + // Se i messaggi di tipo COLOR sono gia'stati tutti ricevuti allora + // invia il messaggio LAST. + if (timer->CDSEmpty()) { + + // Comunica il proprio COLORE finale. + send_LAST(cdscData.myLastColor); + + // Lancia il timeout per la ricezione del messaggio + timer->launchLastTimeouts(neighbors); + } +} + +// +// Gestione dei messaggi di REQUEST +// +void +ALZOUBI_Agent::receive_REQUEST(NodeAddress from, struct RequestMessage rm) +{ + struct InfoMessage im; + struct FeedbackMessage fm; + + switch (rm.type) { + /* + case ALZOUBI_INFO : + // Viene richiesto un messaggio di INFO ma il nodo non lo ha ancora + // inviato. + // Quando sara'in grado di mandarlo lo inviera'e si aspettera' + // la ricevuta di ritorno. + if (!isInfoInBuffer(rm.round)) { + timer->addConfirmation(from, rm.round); + send_CONFIRM(from, rm.round, ALZOUBI_INFO, true); + return; + } + + // + // Il messaggio  in mio possesso: lo invio senza richiedere la conferma. + // + for (BufferInfoMessages::iterator i = leData.stored_messages.info.begin(); + i != leData.stored_messages.info.end(); + i++) { + + if (i->first == rm.round) { + im = i->second; + + send_INFO(im.fragment.ID, + im.new_fragment.ID, + im.new_fragment.size, + im.parent, + im.round, + from); + + } + } + break; + */ + } +} + +void +ALZOUBI_Agent::receive_CONFIRM(NodeAddress from, struct ConfirmMessage cm) +{ + switch (cm.type) { + + case ALZOUBI_COLOR : + /* + if (_DEBUG_) + printf("%d receive CONFIRM (COLOR) (ROUND=%d) from %d\n", myAddress, cm.round, from); + */ + + if (!timer->cancelCDS(from, cm.round)) + return; + + // Se ho ricevuto conferma da tutti i messaggi che ho inviato e sono nella fase + // di LAST, allora invia il messaggio LAST e aspetta che lo abbia ricevuto da tutti. + if ((status == ALZOUBI_STATUS_LAST) && (timer->CDSEmpty())) { + + // Comunica il proprio COLORE finale. + send_LAST(cdscData.myLastColor); + + // Lancia il timeout per la ricezione del messaggio + timer->launchLastTimeouts(neighbors); + + } + + break; + + case ALZOUBI_LAST : + /* + if (_DEBUG_) + printf("%d receive CONFIRM (LAST) (ROUND=%d) from %d\n", myAddress, cm.round, from); + */ + + if (!timer->cancelLast(from)) + return; + + // Se il nodo ricevuto conferma di ricezione da tutti i vicini + // del messaggio LAST che ho inviato e ho ricevuto le informazioni + // di LAST da ogni vicino, allora puo'concludere l'algoritmo. + if ((status == ALZOUBI_STATUS_LAST) && (timer->LastEmpty()) && (cdscData.last_messages.empty())) + endModule(); + + break; + } +} + +void +ALZOUBI_Agent::receive_LAST(NodeAddress from, struct LastMessage lm) +{ + if (_DEBUG_) + printf("%d receive LAST (FROM=%d, COLOR=%s)\n", myAddress, from, lm.color == COLOR_BLACK ? "BLACK" : "GRAY"); + + // Cancella la ricezione del messaggio + cdscData.last_messages.erase(from); + + // Memorizza il colore ultimo del nodo. + cdscData.lastColor[from] = lm.color; + + // Se il nodo e'nella fase finale e ha ricevuto tutti + // i messaggi LAST allora puo'concludere (se non l'ha gia'fatto). + if (!cdscData.last_messages.empty()) + return; + + // Se il nodo ha ricevuto messaggi di LAST da tutti i vicini + // ed e'ancora BLACK, allora significa che la condizione di + // decolorazione non si puo'piu'verificare e che il nodo puo' + // entrare nella fase finale (LAST). + if ((status != ALZOUBI_STATUS_LAST) && (cdscData.color == COLOR_BLACK)) { + init_LAST_cycle(); + return; + } + + // Se sono nella fase LAST, ho inviato il messaggio di LAST + // e ho ricevuto il messaggio di LAST da ogni vicini, allora + // concludo. + if ((cdscData.myLastColor != COLOR_WHITE) && (timer->LastEmpty()) && (timer->CDSEmpty())) + endModule(); +} + +void +ALZOUBI_Agent::processCDSStatus(NodeAddress from, struct ColorMessage cm) +{ + bool transformed = false; + + // + // Il nodo e' WHITE + // + if (cdscData.color == COLOR_WHITE) { + if (cm.dominator) { + // + // RULE 1) + // + // " Se un nodo WHITE riceve un messaggio DOMINATOR (BLACK) per la prima volta, + // esso diventa GRAY e invia in BROADCAST un messaggio DOMINATEE (GRAY) ". + // + if (_DEBUG_) + printf("%d applica REGOLA (1)\n", myAddress); + + cdscData.color = COLOR_GRAY; + + send_COLOR(COLOR_GRAY); + + transformed = true; + } + else { + // + // RULE 2) + // + // " Se un nodo WHITE riceve un messaggio DOMINATEE (GRAY) da ciascun vicino + // di rango inferiore, esso diventa BLACK e invia in broadcast un messaggio + // DOMINATOR (BLACK) ". + // + if (!cdscData.lower_rank.empty()) + return; + + if (_DEBUG_) + printf("%d applica REGOLA (2)\n", myAddress); + + cdscData.color = COLOR_BLACK; + + send_COLOR(COLOR_BLACK); + + transformed = true; + } + } + + // + // Il nodo e' GRAY + // + if (cdscData.color == COLOR_GRAY) { + // + // Se il nodo e'appena diventato GRAY da WHITE, verifica la possibilita' futura + // di poter cambiare colore in base alla REGOLA 3. + // Se non ci sono le basi per l'applicazione della REGOLA 3 allora il nodo + // termina la procedura. + // + if (transformed) { + // + // Se il nodo non ha figli oppure se gia'tutti i figli hanno inviato + // un messaggio di tipo DOMINATEE, allora termina. + // + if (cdscData.childs.empty()) { + init_LAST_cycle(); + return; + } + else if (cdscData.childs_no_dominatee.empty()) { + init_LAST_cycle(); + return; + } + return; + } + + // + // RULE 3) + // + // " Se un nodo GRAY riceve un messaggio DOMINATOR per la prima volta da un figlio + // che non ha mai inviato un messaggio di tipo DOMINATEE (GRAY), esso diventa BLACK + // e invia in broadcast un messaggio DOMINATOR (BLACK) ". + // + + // + // Se tutti i figli hanno ricevuto almeno un messaggio dominatee + // allora il nodo non puo'piu'applicare la "REGOLA (3)" e quindi + // conclude. + // + if (cdscData.childs_no_dominatee.empty()) { + init_LAST_cycle(); + return; + } + + // + // Se il messaggio appena arrivato e'di tipo DOMINATOR e questo proviene + // da un figlio che non ha mai inviato un messaggio di tipo DOMINATEE, + // allora il nodo applica la REGOLA 3. + // + if (!cm.dominator) + return; + + if (find(cdscData.childs_no_dominatee.begin(), cdscData.childs_no_dominatee.end(), from) == cdscData.childs_no_dominatee.end()) + return; + + if (_DEBUG_) + printf("%d applica REGOLA (3)\n", myAddress); + + cdscData.color = COLOR_BLACK; + + send_COLOR(COLOR_BLACK); + + // Inizia la fase finale + init_LAST_cycle(); + + return; + } + + // + // Il nodo e' BLACK + // + if (cdscData.color == COLOR_BLACK) { + + // + // RULE 4) + // + // " Se un nodo BLACK ha rango superiore al rango di tutti i vicini e tutti i vicini + // sono BLACK, esso diventa GRAY e invia in broadcast un messaggio DOMINATOR (BLACK) ". + // + if (cdscData.lower_rank_size != neighbors.size()) { + init_LAST_cycle(); + return; + } + + if (cdscData.black_neighbors.size() != neighbors.size()) + return; + + if (_DEBUG_) + printf("%d applica REGOLA (4)\n", myAddress); + + cdscData.color = COLOR_GRAY; + + send_COLOR(COLOR_BLACK); + + // Inizia la fase finale + init_LAST_cycle(); + + return; + } +} + +void +ALZOUBI_Agent::send_COLOR(NodeAddress to, struct ColorMessage cm) +{ + Color color = cm.dominator ? COLOR_BLACK : COLOR_GRAY; + send_COLOR(color, cm.round, to); +} + +void +ALZOUBI_Agent::send_COLOR(Color color) +{ + if (_DEBUG_) { + printf("%d send %s\n", myAddress, color == COLOR_GRAY ? "DOMINATEE" : "DOMINATOR"); + printf("%d is %s\n", myAddress, cdscData.color == COLOR_BLACK ? "BLACK" : "GRAY"); + } + + // Inizializza i timeout: li cancella solo se riceve la conferma di ricezione + timer->launchCDSTimeouts(neighbors, cdscData.round); + + send_COLOR(color, cdscData.round); + + struct ColorMessage cm; + cm.dominator = ((color == COLOR_BLACK) ? true : false); + cm.round = cdscData.round; + + // Bufferize + switch (cdscData.round) { + case 0 : cdscData.myFirstColor = cm; break; + case 1 : cdscData.mySecondColor = cm; break; + } + + cdscData.round++; +} + +void +ALZOUBI_Agent::send_LAST(Color color, NodeAddress to) +{ + /* + if (_DEBUG_ && (to == -1)) + printf("%d send LAST (%s)\n", myAddress, color == COLOR_BLACK ? "BLACK" : "GRAY"); + */ + + Packet* p = allocpkt(); + struct hdr_alzoubi * alzoubih = HDR_ALZOUBI(p); + + // Common structures. + alzoubih->msg_type = ALZOUBI_LAST; + + // Message + alzoubih->last_message.color = color; + + size_t size = sizeof(LastMessage) + sizeof(AlzoubiMessageType); + + sendDown(p, size, to, ALZOUBI_Agent::max_delay); +} + +void +ALZOUBI_Agent::send_COLOR(Color color, int round, NodeAddress to) +{ + /* + if (_DEBUG_) + printf("%d send %s to %d\n", myAddress, color == COLOR_BLACK ? "DOMINATOR" : "DOMINATEE", to); + */ + + Packet* p = allocpkt(); + struct hdr_alzoubi * alzoubih = HDR_ALZOUBI(p); + + // Common structures. + alzoubih->msg_type = ALZOUBI_COLOR; + + // Message + alzoubih->color_message.dominator = (color == COLOR_BLACK); + alzoubih->color_message.round = round; + + size_t size = sizeof(ColorMessage) + sizeof(AlzoubiMessageType); + + sendDown(p, size, to, ALZOUBI_Agent::max_delay); +} + +// +// Funzione di ricezione di un messaggio COLOR +// +void +ALZOUBI_Agent::receive_COLOR(NodeAddress from, struct ColorMessage cm) +{ + if (_DEBUG_) + printf("%d receive %s (FROM=%d, ROUND=%d)\n", myAddress, cm.dominator ? "DOMINATOR" : "DOMINATEE", from, cm.round); + + // + // Aggiorna le strutture dati + // + + // Il vicino non e'piu'un nodo bianco + cdscData.white_neighbors.erase(from); + + if (cm.dominator) { + // Se il messaggio e'di tipo dominator (BLACK): + + // Il vicino fa parte della lista dei vicini BLACK. + cdscData.black_neighbors.insert(from); + + // Se il vicino fa parte dei figli del nodo, allora entra a far parte dei nodi + // che sono GRAY o BLACK. + if (find(cdscData.childs.begin(), cdscData.childs.end(), from) != cdscData.childs.end()) + cdscData.childs_gray_or_black.insert(from); + + // Elimina il vicino dalla lista dei nodi GRAY. + cdscData.gray_neighbors.erase(from); + } + else { + // Se il messaggio e' di tipo dominatee (GRAY): + + // Il vicino entra a far parte dei nodi GRAY. + cdscData.gray_neighbors.insert(from); + + // Il vicino viene rimosso dalla lista dei vicini che non hanno + // mai inviato un messaggio di tipo DOMINATEE (GRAY). + cdscData.childs_no_dominatee.erase(from); + + // Se fa parte dei nodi di rango inferiore, allora viene eliminato + // dalla lista dei vicini di rango inferiore che devono inviare un + // messaggio dominatee (GRAY). + cdscData.lower_rank.erase(from); + + // Il vicino esce a far parte della lista dei nodi BLACK. + cdscData.black_neighbors.erase(from); + + // Se il vicino fa parte dei figli del nodo, allora entra a far parte dei nodi + // che sono GRAY o BLACK. + if (find(cdscData.childs.begin(), cdscData.childs.end(), from) != cdscData.childs.end()) + cdscData.childs_gray_or_black.insert(from); + } + + // Verifica il passaggio di fase + processCDSStatus(from, cm); +} + +bool +ALZOUBI_Agent::bufferizeMessage(NodeAddress from, struct ColorMessage cm) +{ + if ((cm.round != 0) && (cm.round != 1)) { + // printf("ERROR in round\n"); + return false; + } + + // Un messaggio gia'ricevuto viene scartato. + if (cdscData.messages[cm.round][from].round != -1) + return false; + + cdscData.messages[cm.round][from] = cm; + + if (cm.round == 1) { + // Arriva il secondo messaggio ma non  arrivato il primo. + if (cdscData.messages[cm.round - 1][from].round == -1) { + send_REQUEST(from, ALZOUBI_COLOR, cm.round - 1); + return false; + } + } + + return true; +} + +struct ColorMessage +ALZOUBI_Agent::cdsFromBuffer(int round, NodeAddress from) +{ + struct ColorMessage null_color_message; + null_color_message.round = -1; + if ((round != 0) && (round != 1)) + return null_color_message; + return cdscData.messages[round][from]; +} + +void +ALZOUBI_Agent::timeout(AlzoubiMessageType type, NodeAddress from, int round) +{ + switch (type) { + + case ALZOUBI_COLOR: + + if (_DEBUG_) + printf("%d TIMEOUT (CDS CONSTRUCTION) from %d [round=%d] (%f)\n", myAddress, from, round, Scheduler::instance().clock()); + + send_COLOR(from, (round == 0) ? cdscData.myFirstColor : cdscData.mySecondColor); + + break; + + case ALZOUBI_LAST: + + if (_DEBUG_) + printf("%d TIMEOUT (LAST) from %d (%f)\n", myAddress, from, Scheduler::instance().clock()); + + send_LAST(cdscData.myLastColor, from); + + break; + } +} + +void +ALZOUBI_Agent::timeoutConfirm(NodeAddress from, int round) +{ + /* + struct InfoMessage im; + for (BufferInfoMessages::iterator i = leData.stored_messages.info.begin(); i != leData.stored_messages.info.end(); i++) { + if (i->first == round) { + im = i->second; + if (_DEBUG_LEADER_) + printf("%d TIMEOUT (CONFIRM) from %d (round = %d) (%f)\n", myAddress, from, round, Scheduler::instance().clock()); + send_INFO(im.fragment.ID, + im.new_fragment.ID, + im.new_fragment.size, + im.parent, + im.round, + from); + } + } + */ +} + +void +ALZOUBI_Agent::lastTimeoutConfirm(NodeAddress from, int round) +{ + if (_DEBUG_) + printf("%d LAST TIMEOUT (CONFIRM) from %d [round = %d](%f)\n", myAddress, from, round, Scheduler::instance().clock()); +} + +void +ALZOUBI_Agent::lastTimeout(AlzoubiMessageType type, NodeAddress from, int round) +{ + switch (type) { + case ALZOUBI_COLOR : + if (_DEBUG_) + printf("%d LAST TIMEOUT (CDS CONSTRUCTION) from %d (round = %d) (%f)\n", myAddress, from, round, Scheduler::instance().clock()); + break; + case ALZOUBI_LAST : + if (_DEBUG_) + printf("%d LAST TIMEOUT (LAST) from %d (%f)\n", myAddress, from, Scheduler::instance().clock()); + break; + } +} + +NodeAddress +ALZOUBI_Agent::greaterCluster() +{ + // Ritorna il vicino clusterHead piu'grande. + NodeAddress max = -1; + for (map::iterator i = cdscData.lastColor.begin(); i != cdscData.lastColor.end(); i++) { + if (((i->first) > max) && ((i->second) == COLOR_BLACK)) + max = (i->first); + } + return max; +} + +// +// Gestione dello scadere dei timeout. +// +void +AlzoubiTimer::handle(Event* e) +{ + // + // Messaggio CDS. + // + for (map::iterator r = cds_timeouts.begin(); r != cds_timeouts.end(); r++) { + for (TimeoutMap::iterator m = (r->second).begin(); m != (r->second).end(); m++) { + if (m->second.timeout == e) { + m->second.num--; + if (m->second.num <= 0) { + agent->lastTimeout(ALZOUBI_COLOR, m->first, r->first); + } + else { + Scheduler::instance().schedule(this, e, ALZOUBI_Agent::timeout_cds + Random::uniform(ALZOUBI_Agent::jitter_timeout_cds)); + agent->timeout(ALZOUBI_COLOR, m->first, r->first); + } + return; + } + } + } + + // + // Messaggi LAST. + // + for (TimeoutMap::iterator i = last_timeouts.begin(); i != last_timeouts.end(); i++) { + if (i->second.timeout == e) { + i->second.num--; + if (i->second.num <= 0) + agent->lastTimeout(ALZOUBI_LAST, i->first, 0); + else { + Scheduler::instance().schedule(this, e, ALZOUBI_Agent::timeout_last + Random::uniform(ALZOUBI_Agent::jitter_timeout_last)); + agent->timeout(ALZOUBI_LAST, i->first, 0); + } + return; + } + } +} + +bool +AlzoubiTimer::CDSEmpty() +{ + return cds_timeouts.empty(); +} + +bool +AlzoubiTimer::LastEmpty() +{ + return last_timeouts.empty(); +} + +// +// Segnala la ricezione di conferma per l'invio del messaggio LAST. +// Ritorna true se il timeout e'stato eliminato. +// +bool +AlzoubiTimer::cancelLast(NodeAddress node) +{ + TimeoutMap::iterator i; + for (i = last_timeouts.begin(); i != last_timeouts.end(); i++) { + if (i->first == node) { + Scheduler::instance().cancel(i->second.timeout); + break; + } + } + if (i != last_timeouts.end()) { + last_timeouts.erase(i); + return true; + } + return false; +} + +// +// Lancia il timeout di LAST. +// +void +AlzoubiTimer::launchLastTimeouts(NodeList & last_neighbors) +{ + for (NodeList::iterator i = last_neighbors.begin(); i != last_neighbors.end(); i++) { + struct Timeout t; + t.timeout = new Event(); + t.num = ALZOUBI_Agent::max_timeout_last; + last_timeouts[*i] = t; + Scheduler::instance().schedule(this, t.timeout, ALZOUBI_Agent::timeout_last + Random::uniform(ALZOUBI_Agent::jitter_timeout_last)); + } +} + +// +// Lancia i timeout per i messaggi di CDS del round. +// +void +AlzoubiTimer::launchCDSTimeouts(NodeList & neighbors, int round) +{ + // Aggiunge i timeout: uno per ogni vicino. + for (NodeList::iterator i = neighbors.begin(); i != neighbors.end(); i++) { + struct Timeout t; + t.timeout = new Event(); + t.num = ALZOUBI_Agent::max_timeout_cds; + cds_timeouts[round][*i] = t; + Scheduler::instance().schedule(this, t.timeout, ALZOUBI_Agent::timeout_cds + Random::uniform(ALZOUBI_Agent::jitter_timeout_cds)); + } +} + +// +// Riceve un messaggio di INFO. +// Ritorna true se il messaggio e'stato cancellato. +// +bool +AlzoubiTimer::cancelCDS(NodeAddress node, int round) +{ + if ((round > 1) || (round < 0)) + return false; + + // Scorre la mappa round per round. + for (map::iterator r = cds_timeouts.begin(); + r != cds_timeouts.end(); + r++) { + + // Se esiste un TimeoutMap per quel round scorre il TimeoutMap. + if ((r->first) == round) { + for (TimeoutMap::iterator m = (r->second).begin(); + m != (r->second).end(); + m++) { + + // Se nel TimeoutMap contiene una entry per quel nodo, la elimina. + if ((m->first) == node) { + + // Cancella il timeout + Scheduler::instance().cancel((m->second).timeout); + + // Cancella la entry nel TimeoutMap + (r->second).erase(node); + + // Se non ci sono piu'timeout per quel round (mappa vuota), + // elimina tutta la mappa del round. + if ((r->second).empty()) + cds_timeouts.erase(round); + + return true; + } + } + } + } + return false; +} + +// Verifica che un pacchetto sia di tipo DATA. +bool +ALZOUBI_Agent::isDataPacket(Packet * p) +{ + struct hdr_alzoubi *alzoubih = HDR_ALZOUBI(p); + return (alzoubih->msg_type == ALZOUBI_DATA); +} + +// Preparazione all'invio di un messaggio al layer inferiore +void +ALZOUBI_Agent::prepareSendDataDown(Packet * p) +{ + struct hdr_alzoubi *alzoubih = HDR_ALZOUBI(p); + + // Marca il nodo come dato. + alzoubih->msg_type = ALZOUBI_DATA; +} diff -Naur ns-allinone-2.29-old/ns-2.29/clustering/alzoubi/alzoubi.h ns-allinone-2.29/ns-2.29/clustering/alzoubi/alzoubi.h --- ns-allinone-2.29-old/ns-2.29/clustering/alzoubi/alzoubi.h 1970-01-01 01:00:00.000000000 +0100 +++ ns-allinone-2.29/ns-2.29/clustering/alzoubi/alzoubi.h 2007-08-03 22:23:31.000000000 +0200 @@ -0,0 +1,223 @@ +/** + * Copyright (c) 2006 Michele Mastrogiovanni. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +// +// NOTE: +// Probabilmente bisogna aggiungere la gestione della richiesta o levarla. +// +// 1) Se un nodo riceve il secondo colore e non il primo ne fa richiesta. +// 2) Un nodo che invia un colore aspetta la conferma altrimenti ritrasmette. +// Finale: usare la 2. +// +// Nella fase di leader election memorizzare bene il numero di nodi della +// topologia: per ora non serve ma non  detto che non lo sia in futuro. +// + +#ifndef _ALZOUBI_H_ +#define _ALZOUBI_H_ + +#include "ClusteringModule.h" +#include "clustering/alzoubi/structure.h" + +#include +#include + +///////////////////// +/// Stato del nodo // +///////////////////// +typedef enum +{ + ALZOUBI_STATUS_CDS = 0x0, // Il nodo e'nella fase di creazine del backbone. + ALZOUBI_STATUS_LAST = 0x1, // Il nodo sta attendendo i messaggi finali da tutti. + ALZOUBI_STATUS_END = 0x2 +} AlzoubiStatus; + +////////////////////////// +// Header del pacchetto // +////////////////////////// +struct hdr_alzoubi +{ + AlzoubiMessageType msg_type; // Tipo di messaggio. + + union { + struct ColorMessage color_message; + struct RequestMessage request_message; + struct ConfirmMessage confirm_message; + struct LastMessage last_message; + }; + + ///////////////// + /// Addressing // + ///////////////// + static int offset_; + inline static int& offset() { return offset_; } + inline static hdr_alzoubi* access(const Packet* p) { + return (hdr_alzoubi*) p->access(offset_); + } +}; + +/////////// +// Timer // +/////////// +class AlzoubiTimer; + +/////////// +// Agent // +/////////// +class ALZOUBI_Agent : public ClusteringModule { +public: + + ALZOUBI_Agent(); + + // Funzione di ricezione dell'algoritmo di clustering. + virtual void receive(Packet * p, Handler * h); + + void timeout(AlzoubiMessageType type, NodeAddress from, int round); + void lastTimeout(AlzoubiMessageType type, NodeAddress from, int round); + + void timeoutConfirm(NodeAddress from, int round); + void lastTimeoutConfirm(NodeAddress from, int round); + + // Verifica che un pacchetto sia di tipo DATA. + virtual bool isDataPacket(Packet * p); + + // Preparazione all'invio di un messaggio al layer inferiore + virtual void prepareSendDataDown(Packet * p); + +protected: + + struct LeaderElectionData leData; // Dati della fase di leader election. + struct CDSConstructionData cdscData; // Dati della fase di creazione del backbone. + AlzoubiStatus status; // Stato dell'agente. + AlzoubiTimer * timer; // Gestore dei timeout. + +protected: + /////////////// + // Procedure // + /////////////// + + // Inizio dell'algoritmo (leader election). + virtual void startModule(); + + // Fine dell'algoritmo. + virtual void endModule(); + + // Procedura di inizializzazione delle variabili della Creazione dei Backbone. + void initializeCDSConstruction(); + + void emptyCDSBuffer(); // Svuota il buffer dei messaggi di CDS construction. + void processLEStatus(); // Gestione della fase di transizione durante la Leader Election. + void processCDSStatus(NodeAddress from, struct ColorMessage cm); // Gestione della fase di transizione + // durante la costruzione dei backbone. + + void init_LAST_cycle(); + + ///////////// + // Utility // + ///////////// + + NodeAddress greaterCluster(); // restituisce il vicino cluster maggiore. + + /////////////// + // Procedure // + /////////////// + + void send_COLOR(Color color); + void send_COLOR(Color color, int round, NodeAddress to = -1); + void send_COLOR(NodeAddress to, struct ColorMessage); + + void send_LAST(Color color, NodeAddress to = -1); + + // Invia una richiesta di un certo messaggio ad un vicino. + void send_REQUEST(NodeAddress to, AlzoubiMessageType type, int round); + + void send_CONFIRM(NodeAddress to, int round, AlzoubiMessageType type, bool send); + + void receive_COLOR(NodeAddress from, struct ColorMessage cm); + void receive_REQUEST(NodeAddress from, struct RequestMessage rm); + void receive_LAST(NodeAddress from, struct LastMessage lm); + void receive_CONFIRM(NodeAddress from, struct ConfirmMessage); + +public: + ///////////// + // Buffers // + ///////////// + + bool bufferizeMessage(NodeAddress from, struct ColorMessage cm); // Bufferize a message (CDS). + struct ColorMessage cdsFromBuffer(int round, NodeAddress from); // Ritorna un messaggio bufferizzato (se esiste). + +public: + + static int _DEBUG_; + + static double max_delay; + + static int max_timeout_confirm; + static double jitter_timeout_confirm; + static double timeout_confirm; + + static int max_timeout_cds; + static double jitter_timeout_cds; + static double timeout_cds; + + static int max_timeout_last; + static double jitter_timeout_last; + static double timeout_last; + +}; + +// +// Gestore dei timeout. +// +class AlzoubiTimer : public Handler { + +public: + + AlzoubiTimer(ALZOUBI_Agent * a) : Handler(), agent(a) {} + + // Funzione di gestione. + void handle(Event* e); + + // Lancia un timeout verso i vicini che ancora non hanno confermato un certo messaggio di CDS. + void launchCDSTimeouts(NodeList & cds_neighbors, int round); + + // Lancia il timeout di LAST. + void launchLastTimeouts(NodeList & info_neighbors); + + // Segnala la ricezione di conferma per l'invio del messaggio CDS. + bool cancelCDS(NodeAddress node, int round); + + // Segnala la ricezione di conferma per l'invio del messaggio LAST. + bool cancelLast(NodeAddress node); + + bool CDSEmpty(); + + bool LastEmpty(); + +public: + + ALZOUBI_Agent *agent; + + // Messaggi CDS (per round). + // round --> (vicino --> Timeout). + map cds_timeouts; + + // Messaggi LAST + TimeoutMap last_timeouts; + +}; + +#endif \ No newline at end of file diff -Naur ns-allinone-2.29-old/ns-2.29/clustering/alzoubi/structure.h ns-allinone-2.29/ns-2.29/clustering/alzoubi/structure.h --- ns-allinone-2.29-old/ns-2.29/clustering/alzoubi/structure.h 1970-01-01 01:00:00.000000000 +0100 +++ ns-allinone-2.29/ns-2.29/clustering/alzoubi/structure.h 2007-08-03 22:23:31.000000000 +0200 @@ -0,0 +1,255 @@ +/** + * Copyright (c) 2006 Michele Mastrogiovanni. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#ifndef _ALZOUBI_STRUCTURE_H_ +#define _ALZOUBI_STRUCTURE_H_ + +#include "clustering-header.h" +#include +#include + +//--------------------------------------------------------------------------------- +// Tipi di messaggio +//--------------------------------------------------------------------------------- +typedef enum +{ + ALZOUBI_COLOR = 0x0, // Messaggio per segnalare il colore di un nodo. + ALZOUBI_LAST = 0x1, + ALZOUBI_REQUEST = 0x2, // Richiesta di ritrasmissione. + ALZOUBI_CONFIRM = 0x3, // Mesaggio di conferma per l'avvenuta ricezione. + ALZOUBI_DATA = 0x4 +} AlzoubiMessageType; + +//--------------------------------------------------------------------------------- +// Informazioni sull'albero di appartenenza. +//--------------------------------------------------------------------------------- +struct TreeInfo { + NodeList childs; // Nodi figli. + NodeAddress parent; // Nodo genitore. +}; + +//--------------------------------------------------------------------------------- +// Informazioni su di un frammento. +//--------------------------------------------------------------------------------- +struct FragmentInfo { + NodeAddress ID; // Identita' del leader del frammento. + int size; // Dimensione del frammento. + + // Un frammento e'minore di un'altro se e'di dimensione minore + // oppure se e'delle stesse dimensioni e ha un ID minore. + bool operator< (const struct FragmentInfo & fragment) { + if (size < fragment.size) + return true; + return ((size == fragment.size) && + (ID < fragment.ID)); + } +}; + +//--------------------------------------------------------------------------------- +// Lista di nodi, per round che richiede la conferma dei messaggi INFO inviati. +//--------------------------------------------------------------------------------- +typedef map ConfirmationNodes; + +//--------------------------------------------------------------------------------- +// Messaggio INFO. +//--------------------------------------------------------------------------------- +struct InfoMessage { + struct FragmentInfo fragment; // Frammento a cui appartiene il nodo mittente. + struct FragmentInfo new_fragment; // Frammento a cui il nodo dello stesso frammento + // deve appartenere. + NodeAddress parent; // Genitore del mittente. + int round; // Round del messaggio. +}; + +//--------------------------------------------------------------------------------- +// Buffer per i messaggi di INFO inviati: uno per ogni round. +//--------------------------------------------------------------------------------- +typedef map BufferInfoMessages; + +//--------------------------------------------------------------------------------- +// Messaggio FEEDBACK. +//--------------------------------------------------------------------------------- +struct FeedbackMessage { + struct FragmentInfo fragment; // Frammento a cui appartiene il nodo mittente. + bool maximal_fragment_available; // Indica se il mittente conosce o no un frammento vicino massimale. + struct FragmentInfo maximal_fragment; // Informazioni sul frammento massimale. + int node_count; // Numero di nodi del sottoalbero radicato nel mittente. + int round; // Round del messaggio. +}; + +//--------------------------------------------------------------------------------- +// Buffer per i messaggi di FEEDBACK inviati: uno per ogni round. +//--------------------------------------------------------------------------------- +typedef map BufferFeedbackMessages; + +//--------------------------------------------------------------------------------- +// Messaggi memorizzati (per le ritrasmissioni). +//--------------------------------------------------------------------------------- +struct StoredMessages { + BufferInfoMessages info; // Messaggi di INFO. + BufferFeedbackMessages feedback; // Messaggi di FEEDBACK. +}; + +//--------------------------------------------------------------------------------- +// Messaggio ACTION. +//--------------------------------------------------------------------------------- +struct ActionMessage { + struct FragmentInfo current_fragment; // Frammento del messaggio di ACTION. + int round; +}; + +//--------------------------------------------------------------------------------- +// Messaggio LEADER. +//--------------------------------------------------------------------------------- +struct LeaderMessage { + struct FragmentInfo leader; // Informazioni sul leader e la grandezza del frammento globale. + NodeAddress parent; // Genitore del mittente. + int level; // Livello dell'albero del mittente. + bool confirm; // True indica un messaggio ritrasmesso, richiede la ritrasmissione. + // Non si usa il messaggio di request per specificare i dati del leader + // perche'in questo modo, posso inviare le informazioni sul leader. +}; + +//--------------------------------------------------------------------------------- +// Messaggio COLOR. +//--------------------------------------------------------------------------------- +struct ColorMessage { + bool dominator; // True = DOMINATOR, False = DOMINATEE + int round; // Round del messaggio +}; + +//--------------------------------------------------------------------------------- +// Messaggio LAST. +//--------------------------------------------------------------------------------- +struct LastMessage { + Color color; +}; + +//--------------------------------------------------------------------------------- +// Messaggio REQUEST. +//--------------------------------------------------------------------------------- +struct RequestMessage { + AlzoubiMessageType type; // Tipo i messaggio richiesto. + int round; // Round del messaggio. +}; + +//--------------------------------------------------------------------------------- +// Messaggio CONFIRM. +//--------------------------------------------------------------------------------- +struct ConfirmMessage { + AlzoubiMessageType type; // Tipo di messaggio da confermare. + bool send; // True se il messaggio e'l'invio, False se e'la risposta. + int round; // Round del messaggio. +}; + +//--------------------------------------------------------------------------------- +// Collezione principale di dati sulla leader election phase. +//--------------------------------------------------------------------------------- +struct LeaderElectionData { + bool candidate; // True se il nodo e'un candidato. + struct TreeInfo tree; // Informazioni sull'albero interno + // al frammento a cui il nodo appartiene. + struct FragmentInfo fragment; // Informazioni sul frammento a cui il nodo appartiene. + map maximal_fragment_available; // True se si conosce un frammento massimale + map maximal_fragment; // Il frammento massimale + map maximal_fragment_node; // Nodo a cui legarsi. + map stored_path; // Vicino verso il quale si raggiunge l'edge node massimale. + // -1 indica che il nodo corrente e'l'edge node. + + // Messaggio INFO proveniente dal nodo di JOIN memorizzato: serve perche'il messaggio di ACTION + // puo'giungere dopo la ricezione del messaggio di INFO da parte del nodo del frammento massimale + // che darebbe il via alla propagazione dell'INFO anche nel frammento del nodo. + map maximal_fragment_node_info_message; + + // Memorizza la ricezione di un messaggio di action per un certo round. + map action_for_round; + + NodeAddress old_fragment_identity; // Vecchia identita'del frammento. + NodeAddress new_fragment_identity; // Identita'del frammento a cui legarsi. + NodeList info_messages; // Vicini che ancora devono inviare il messaggio di INFO. + NodeList feedback_messages; // Vicini che ancora devono inviare il messaggio di FEEDBACK. + NodeList leader_messages; // Vicini che devono ancora inviare il messaggio di LEADER. + int sub_tree_partial_count; // Conteggio dei nodi del sottoalbero radicato nel nodo corrente. + + //------------------ + // Buffers. + //------------------ + list > buffer_info; // Messaggi di INFO inviati dai vicini. + list > buffer_feedback; // Messaggi di FEEDBACK inviati dai vicini. + map > buffer_action; + ConfirmationNodes confirmation_nodes_info; // Nodi dai quali ci si aspetta un INFO message. + + //------------------ + // Messaggi inviati. + //------------------ + struct StoredMessages stored_messages; + + //------------------ + // Round dell'algoritmo. + //------------------ + int round; + +}; + + + +struct CDSConstructionData { + + Color color; + + //==========================// + // Second phase of algorithm // + //==========================// + + NodeAddress parent; + NodeAddress leader; + int tree_size; + int level; + NodeList childs; + + NodeList white_neighbors; // Lista di vicini WHITE. + NodeList childs_no_dominatee; // Lista dei vicini che non hanno mai inviato un + // messaggio di tipo DOMINATEE. + NodeList black_neighbors; // Lista dei vicini BLACK. + NodeList lower_rank; // Lista dei vicini di rango inferiore che non hanno + // mai inviato un messaggio di tipo DOMINATEE. + int lower_rank_size; // Numero di vicini di rango inferiore. + NodeList gray_neighbors; // Vicini GRAY. + NodeList childs_gray_or_black; // Nodi figli GRAY o BLACK. + + map levels; // Livello di un vicino. + + map lastColor; // Ultimo colore di un vicino. + + //=========// + // Buffers // + //=========// + + map messages[2]; // Messaggi CDS dai vicini. + int round; // Numero di round. + struct ColorMessage myFirstColor; // Buffer di messaggi inviati. + struct ColorMessage mySecondColor; // Buffer di messaggi inviati. + Color myLastColor; // Ultimo colore del nodo. + + NodeList last_messages; // Vicini che devono inviare il messaggio di LAST. + + bool endFirstCDSBufferization; // E'true se il buffer  stato svuotato per i messaggi del primo round + bool endSecondCDSBufferization; // E'true se il buffer  stato svuotato per i messaggi del secondo round + +}; + +#endif \ No newline at end of file diff -Naur ns-allinone-2.29-old/ns-2.29/clustering/c-sparsifier/.DS_Store ns-allinone-2.29/ns-2.29/clustering/c-sparsifier/.DS_Store --- ns-allinone-2.29-old/ns-2.29/clustering/c-sparsifier/.DS_Store 1970-01-01 01:00:00.000000000 +0100 +++ ns-allinone-2.29/ns-2.29/clustering/c-sparsifier/.DS_Store 2007-08-03 22:23:31.000000000 +0200 @@ -0,0 +1 @@ +Bud1arsific-sparsifier.ccIlocblobZ!˙˙˙˙˙˙c-sparsifier.hIlocblob!˙˙˙˙˙˙  @€ @€ @€ @ EDSDB `€ @€ @€ @ \ No newline at end of file diff -Naur ns-allinone-2.29-old/ns-2.29/clustering/c-sparsifier/c-sparsifier.cc ns-allinone-2.29/ns-2.29/clustering/c-sparsifier/c-sparsifier.cc --- ns-allinone-2.29-old/ns-2.29/clustering/c-sparsifier/c-sparsifier.cc 1970-01-01 01:00:00.000000000 +0100 +++ ns-allinone-2.29/ns-2.29/clustering/c-sparsifier/c-sparsifier.cc 2007-08-03 22:23:31.000000000 +0200 @@ -0,0 +1,585 @@ + +/** + * Copyright (c) 2006 Michele Mastrogiovanni. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +//////////////// +// NS Headers // +//////////////// +#include "c-sparsifier.h" +#include "random.h" +#include "gridkeeper.h" +#include + +#include "Separator.h" + +/////////////////////////////////// +// Parte di dichiarazione comune // +/////////////////////////////////// + +int hdr_c_sparsifier::offset_; + +int CSPARSIFIER_Agent::_DEBUG_; // Attiva la modalita' di debug. + +int CSPARSIFIER_Agent::virtual_neighbors; +double CSPARSIFIER_Agent::max_delay; +int CSPARSIFIER_Agent::max_timeout_connect; +double CSPARSIFIER_Agent::jitter_timeout_connect; +double CSPARSIFIER_Agent::timeout_connect; +int CSPARSIFIER_Agent::max_timeout_candidate; +double CSPARSIFIER_Agent::jitter_timeout_candidate; +double CSPARSIFIER_Agent::timeout_candidate; + +static class CSparsifierClass : public TclClass { +public: + CSparsifierClass() : TclClass("Agent/CSPARSIFIER") {} + TclObject* create(int , const char*const* ) { + return(new CSPARSIFIER_Agent()); + } +} class_c_sparsifier; + +static class CSparsifierHeaderClass : public PacketHeaderClass { +public: + CSparsifierHeaderClass() : PacketHeaderClass("PacketHeader/CSPARSIFIER", + sizeof(hdr_c_sparsifier)) { + bind_offset(&hdr_c_sparsifier::offset_); + } +} class_c_sparsifierhdr; + +// +// Gestisce l'arrivo di un timeout segnalandolo +// opportunamente all'Agente. +// +void +CSparsifierTimer::handle(Event *e) +{ + // + // Timeout CONNECT. + // + for (TimeoutMap::iterator i = connect_timeouts.begin(); i != connect_timeouts.end(); i++) { + if (i->second.timeout == e) { + i->second.num--; + if (i->second.num <= 0) { + agent->lastTimeout(i->first, TIMEOUT_CONNECT); + } + else { + Scheduler::instance().schedule(this, e, + CSPARSIFIER_Agent::timeout_connect + Random::uniform(CSPARSIFIER_Agent::jitter_timeout_connect)); + agent->timeout(i->first, TIMEOUT_CONNECT); + } + } + } + + // + // Timeout CANDIDATE. + // + for (TimeoutMap::iterator i = candidate_timeouts.begin(); i != candidate_timeouts.end(); i++) { + if (i->second.timeout == e) { + i->second.num--; + if (i->second.num <= 0) { + agent->lastTimeout(i->first, TIMEOUT_CANDIDATE); + } + else { + Scheduler::instance().schedule(this, e, + CSPARSIFIER_Agent::timeout_connect + Random::uniform(CSPARSIFIER_Agent::jitter_timeout_connect)); + agent->timeout(i->first, TIMEOUT_CANDIDATE); + } + } + } + +} + +// +// Fa partire i timeout per i nodi che non hanno ancora risposto al +// messaggio di HELLO inviando la propria lista di vicini. +// +void +CSparsifierTimer::launchConnectTimeouts(NodeList & neighbors) +{ + for (NodeList::iterator i = neighbors.begin(); i != neighbors.end(); i++) { + // Definisce i Timeout di tipo HELLO + struct Timeout h; + h.timeout = new Event(); + h.num = CSPARSIFIER_Agent::max_timeout_connect; + connect_timeouts[*i] = h; + Scheduler::instance().schedule(this, h.timeout, + CSPARSIFIER_Agent::timeout_connect + Random::uniform(CSPARSIFIER_Agent::jitter_timeout_connect)); + } +} + +// +// L'agente segnala la ricezione di un messaggio di tipo HELLO: +// il timeout viene eliminato. +// +void +CSparsifierTimer::receivedConnect(NodeAddress from) +{ + TimeoutMap::iterator i; + for (i = connect_timeouts.begin(); i != connect_timeouts.end(); i++) { + if (i->first == from) { + Scheduler::instance().cancel(i->second.timeout); + break; + } + } + if (i != connect_timeouts.end()) + connect_timeouts.erase(i); +} + +// +// Fa partire i timeout per i nodi che non hanno ancora risposto al +// messaggio di HELLO inviando la propria lista di vicini. +// +void +CSparsifierTimer::launchCandidateTimeouts(NodeList & neighbors) +{ + for (NodeList::iterator i = neighbors.begin(); i != neighbors.end(); i++) { + // Definisce i Timeout di tipo CANDIDATE + struct Timeout h; + h.timeout = new Event(); + h.num = CSPARSIFIER_Agent::max_timeout_candidate; + candidate_timeouts[*i] = h; + Scheduler::instance().schedule(this, h.timeout, + CSPARSIFIER_Agent::timeout_candidate + Random::uniform(CSPARSIFIER_Agent::jitter_timeout_candidate)); + } +} + +// +// L'agente segnala la ricezione di un messaggio di tipo CONNECT: +// il timeout viene eliminato. +// +void +CSparsifierTimer::receivedCandidate(NodeAddress from) +{ + TimeoutMap::iterator i; + for (i = candidate_timeouts.begin(); i != candidate_timeouts.end(); i++) { + if (i->first == from) { + Scheduler::instance().cancel(i->second.timeout); + break; + } + } + if (i != candidate_timeouts.end()) + candidate_timeouts.erase(i); +} + +// +// Costruttore +// +CSPARSIFIER_Agent::CSPARSIFIER_Agent() : ClusteringModule(PT_CSPARSIFIER) +{ + timer = new CSparsifierTimer(this); + + bind_bool("debug", &_DEBUG_); + + bind("virtual-neighbors", &virtual_neighbors); + bind("max-delay", &max_delay); + + bind("max-timeout-connect", &max_timeout_connect); + bind("jitter-timeout-connect", &jitter_timeout_connect); + bind("timeout-connect", &timeout_connect); + + bind("max-timeout-candidate", &max_timeout_candidate); + bind("jitter-timeout-candidate", &jitter_timeout_candidate); + bind("timeout-candidate", &timeout_candidate); + +} + +void +CSPARSIFIER_Agent::receive(Packet *p, Handler *h) +{ + struct hdr_c_sparsifier *csparsifierh = HDR_CSPARSIFIER(p); + + // Mittente. + NodeAddress sender_address = csparsifierh->sender_address; + // Destinazione. + NodeAddress destination_address = csparsifierh->destination_address; + + switch (csparsifierh->msg_type) { + case CSPARSIFIER_CANDIDATE : + + if (status != CSPARISFIER_STATUS_CANDIDATE) + return; + + if (_DEBUG_) { + printf("%d receive CANDIDATE: FROM %d (", myAddress, sender_address); + for (NodeList::iterator node = (csparsifierh->selectedNodes)->begin(); node != (csparsifierh->selectedNodes)->end(); node++) + printf("%d ", *node); + printf(")\n"); + } + + // Memorizza i nodi selezionati dal vicino + selectedNodes[sender_address] = *(csparsifierh->selectedNodes); + + // Cancella il timeout. + timer->receivedCandidate(sender_address); + + if (selectedNodes.size() == neighbors.size()) { + if (_DEBUG_) + printf("%d receive ALL CANDIDATE\n", myAddress); + + status = CSPARISFIER_STATUS_CONNECT; + + // Crea la lista dei vicini finali aggiungendo a quelli candidati, + // i nodi vicini che hanno richiesto la connessione col nodo corrente. + sparseNeighbors = candidateNeighbors; + for (map::iterator it = selectedNodes.begin(); it != selectedNodes.end(); it++) { + if (find((it->second).begin(), (it->second).end(), myAddress) != (it->second).end()) + sparseNeighbors.insert(it->first); + } + + // Invia il messaggio di connessione a tutti i nodi a cui non l'ha gia'mandato. + for (NodeList::iterator it = sparseNeighbors.begin(); it != sparseNeighbors.end(); it++) { + if (find(connect_nodes.begin(), connect_nodes.end(), *it) == connect_nodes.end()) + send_CONNECT(*it); + } + + timer->launchConnectTimeouts(sparseNeighbors); + + // Elimina dai timeout i nodi che hanno gia'inviato il messaggio di connessione. + for (NodeList::iterator it = connect_nodes.begin(); it != connect_nodes.end(); it++) + timer->receivedConnect(*it); + + if (connect_nodes.size() == sparseNeighbors.size()) + endModule(); + + } + + break; + + case CSPARSIFIER_CONNECT : + + if (_DEBUG_) + printf("%d receive CONNECT: FROM %d\n", myAddress, sender_address); + + // Aggiunge il nodo alla lista di quelli che sono connessi + connect_nodes.insert(sender_address); + + // Risponde al messaggio di connessione. + if (status == CSPARISFIER_STATUS_CANDIDATE) + send_CONNECT(sender_address); + else { + timer->receivedConnect(sender_address); + if (connect_nodes.size() == sparseNeighbors.size()) + endModule(); + } + + break; + + case CSPARSIFIER_REQUEST : + + if (_DEBUG_) + printf("%d receive REQUEST: FROM %d ", myAddress, sender_address); + + switch (csparsifierh->request) { + + case CSPARISFIER_STATUS_CANDIDATE : + + if (_DEBUG_) + printf("[CANDIDATE]\n"); + + send_CANDIDATE(sender_address); + break; + + case CSPARISFIER_STATUS_CONNECT : + + if (_DEBUG_) + printf("[CONNECT]\n"); + + if ((status == CSPARISFIER_STATUS_CONNECT) || (status == CSPARISFIER_STATUS_END)) { + if (find(sparseNeighbors.begin(), sparseNeighbors.end(), sender_address) != sparseNeighbors.end()) + send_CONNECT(sender_address); + } + + break; + + } + + break; + + default: + break; + } + +} + +// +// Invia un messaggio di "Candidatura" ovvero la lista di vicini che +// il nodo propone. +// +void +CSPARSIFIER_Agent::send_CANDIDATE(NodeAddress to) +{ + Packet* p = allocpkt(); + + struct hdr_c_sparsifier * csparsifierh = HDR_CSPARSIFIER(p); + + csparsifierh->msg_type = CSPARSIFIER_CANDIDATE; + csparsifierh->sender_address = myAddress; + csparsifierh->destination_address = to; + + csparsifierh->selectedNodes = &candidateNeighbors; + + if (_DEBUG_) { + printf("%d send CANDIDATE: (", myAddress); + for (NodeList::iterator node = candidateNeighbors.begin(); node != candidateNeighbors.end(); node++) + printf("%d ", *node); + printf("\n"); + } + + sendDown(p, sizeof(CSparsifierMessageType) + sizeof(nsaddr_t) * (2 + CSPARSIFIER_Agent::virtual_neighbors), to, CSPARSIFIER_Agent::max_delay); +} + +// +// Invia un messaggio di "Candidatura" ovvero la lista di vicini che +// il nodo propone. +// +void +CSPARSIFIER_Agent::send_CONNECT(NodeAddress to) +{ + Packet* p = allocpkt(); + + struct hdr_c_sparsifier * csparsifierh = HDR_CSPARSIFIER(p); + + csparsifierh->msg_type = CSPARSIFIER_CONNECT; + csparsifierh->sender_address = myAddress; + csparsifierh->destination_address = to; + + if (_DEBUG_) + printf("%d send CONNECT to %d\n", myAddress, to); + + sendDown(p, sizeof(CSparsifierMessageType) + sizeof(nsaddr_t) * (2), to, CSPARSIFIER_Agent::max_delay); +} + +// +// Funzione richiamata allo scadere di un timeout per un certo tipo di messaggio: +// Il nodomanda la richiesta del dato al vicino interessato. +// +void +CSPARSIFIER_Agent::timeout(NodeAddress from, CSparsifierTimeoutType timeout) +{ + switch (timeout) { + + case TIMEOUT_CONNECT : + if (_DEBUG_) + printf("%d timeout connect\n", myAddress); + send_REQUEST(from, CSPARSIFIER_CONNECT); + break; + + case TIMEOUT_CANDIDATE : + if (_DEBUG_) + printf("%d timeout candidate\n", myAddress); + send_REQUEST(from, CSPARSIFIER_CANDIDATE); + break; + } +} + +// +// Funzione richiamata allo scadere dell'ultimo timeout. +// +void +CSPARSIFIER_Agent::lastTimeout(NodeAddress from, CSparsifierTimeoutType timeout) +{ + // TODO + /* + switch(type) { + case CSPARISFIER_STATUS_HELLO : + if (_DEBUG_) + printf("%d LAST TIMEOUT (HELLO) from %d (%f)\n", myAddress, from, Scheduler::instance().clock()); + break; + + case CSPARISFIER_STATUS_FIRST_DECISION : + if (_DEBUG_) + printf("%d LAST TIMEOUT (FIRST_DECISION) from %d (%f)\n", myAddress, from, Scheduler::instance().clock()); + break; + + case CSPARISFIER_STATUS_LAST_DECISION : + if (_DEBUG_) + printf("%d LAST TIMEOUT (LAST DECISION) from %d (%f)\n", myAddress, from, Scheduler::instance().clock()); + break; + } + */ +} + +// +// Procedura di partenza per l'algoritmo di clustering. +// +void +CSPARSIFIER_Agent::startModule() +{ + // Inizializza le informazioni comuni. + ClusteringModule::startModule(); + + // Stato dell'agente + status = CSPARISFIER_STATUS_CANDIDATE; + + // Svuota la lista dei vicini. + neighbors.clear(); + + // Svuota il buffer dei nodi che sono connessi. + connect_nodes.clear(); + + // + // Carica la lista dei vicini + // + GridKeeper * gk = GridKeeper::instance(); + MobileNode **output = new MobileNode *[gk->size_]; + + if (gk != NULL) { + + int num_neighbors = gk->get_neighbors(myMobileNode, output); + for (int i = 0; i < num_neighbors; i++) { + MobileNode * current = output[i]; + + // Initialize neighbor's info + NodeAddress neighborAddress = current->address(); + neighbors.insert(neighborAddress); + } + + } + + delete[] output; + + if (neighbors.size() == 0) + printf("CIAO"); + + // Svuota la lista dei candidati. + candidateNeighbors.clear(); + + // Sceglie in maniera random: "NUM_VICINI" vicini oppure tutti (se sono di meno). + NodeList::iterator node = neighbors.begin(); + for (int i = 0; i < (neighbors.size() < CSPARSIFIER_Agent::virtual_neighbors ? neighbors.size() : CSPARSIFIER_Agent::virtual_neighbors); i++) { + candidateNeighbors.insert(*node); + node++; + } + + // Svuota la mappa delle preferenze dei vicini. + selectedNodes.clear(); + + // Invia un messaggio di CONNESSIONE ai vicini. + send_CANDIDATE(-1); + + // Inizializza i timeout per i messaggi CANDIDATE. + timer->launchCandidateTimeouts(neighbors); +} + +// +// Procedura richiamata alla fine dell'algoritmo di clustering. +// +void +CSPARSIFIER_Agent::endModule() +{ + // L'algoritmo termina: il nodo puo'memorizzare il proprio clusterHead. + status = CSPARISFIER_STATUS_END; + + if (utility) + ((CSparsifierUtility*)utility)->setNeighbors(myAddress, sparseNeighbors); + + if (_DEBUG_) { + printf("END SPARSIFIER: %d ha vicini: ", myAddress); + for (NodeList::iterator i = sparseNeighbors.begin(); i != sparseNeighbors.end(); i++) + printf("%d ", *i); + printf("\n"); + } + + // Segnala la conclusione del processo di clustering. + ClusteringModule::endModule(); + + // Start upper module + if (upTarget) + Separator::instance().endCurrentModule(myAddress); +} + +// +// Procedura di ricezione dei messaggi HELLO. +// +void +CSPARSIFIER_Agent::receive_CANDIDATE(NodeAddress from, NodeList & selected) +{ + + // Memorizza la lista dei vicini scelta dal vicino. + selectedNodes[from] = selected; +} + +NodeList & +CSPARSIFIER_Agent::getNeighbors() +{ + return sparseNeighbors; +} + +void +CSPARSIFIER_Agent::send_REQUEST(NodeAddress to, CSparsifierMessageType type) +{ + Packet* p = allocpkt(); + + struct hdr_c_sparsifier * csparsifierh = HDR_CSPARSIFIER(p); + + csparsifierh->msg_type = CSPARSIFIER_REQUEST; + csparsifierh->sender_address = myAddress; + csparsifierh->destination_address = to; + + csparsifierh->request = type; + + if (_DEBUG_) + printf("%d send REQUEST %s to %d\n", myAddress, (type == CSPARSIFIER_CANDIDATE ? "CANDIDATE" : "CONNECT"), to); + + sendDown(p, sizeof(CSparsifierMessageType) * 2 + sizeof(nsaddr_t) * (2), to, CSPARSIFIER_Agent::max_delay); +} + +// Verifica che un pacchetto sia di tipo DATA. +bool +CSPARSIFIER_Agent::isDataPacket(Packet * p) +{ + struct hdr_c_sparsifier *csparsifierh = HDR_CSPARSIFIER(p); + return (csparsifierh->msg_type == CSPARSIFIER_DATA); +} + +// +// Preparazione all'invio di un messaggio al layer inferiore +// +void +CSPARSIFIER_Agent::prepareSendDataDown(Packet * p) +{ + struct hdr_c_sparsifier *csparsifierh = HDR_CSPARSIFIER(p); + hdr_ip* iph = hdr_ip::access(p); + + // Marca il nodo come dato. + csparsifierh->msg_type = CSPARSIFIER_DATA; +} + +/** + * Query if algorithm support a particular protocol: + * that method is probably called before a getData + * method. + */ +bool +CSPARSIFIER_Agent::supportProtocol(string protocol) +{ + if (protocol == "sparsification") + return true; + return false; +} + +/** + * That method is used to get data from an algorithm + * that was check to implements a particular protocol + */ +void * +CSPARSIFIER_Agent::getData(string data) +{ + if (data == "neighbors") { + return &sparseNeighbors; + } + return ClusteringModule::getData(data); +} diff -Naur ns-allinone-2.29-old/ns-2.29/clustering/c-sparsifier/c-sparsifier.h ns-allinone-2.29/ns-2.29/clustering/c-sparsifier/c-sparsifier.h --- ns-allinone-2.29-old/ns-2.29/clustering/c-sparsifier/c-sparsifier.h 1970-01-01 01:00:00.000000000 +0100 +++ ns-allinone-2.29/ns-2.29/clustering/c-sparsifier/c-sparsifier.h 2007-08-03 22:23:31.000000000 +0200 @@ -0,0 +1,206 @@ + +/** + * Copyright (c) 2006 Michele Mastrogiovanni. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#ifndef _C_SPARSIFIER_H_ +#define _C_SPARSIFIER_H_ + +#include "ClusteringModule.h" +#include "CSparsifierUtility.h" + +//////////////////// +// Stato del nodo // +//////////////////// +typedef enum { + CSPARISFIER_STATUS_CANDIDATE = 0x1, // Il nodo sta ricevendo informazioni dai vicini sulle loro preferenze. + CSPARISFIER_STATUS_CONNECT = 0x2, // Il nodo sta ricevendo la conferma di connessione dai vicini scelti. + CSPARISFIER_STATUS_END = 0x3 // Il nodo ha terminato l'algoritmo. +} CSparsifierStatus; + +////////////////////// +// Tipi di messaggi // +////////////////////// +typedef enum +{ + CSPARSIFIER_CANDIDATE = 0x1, // Messaggio di candidatura. + CSPARSIFIER_CONNECT = 0x2, // Messaggio di connessione. + CSPARSIFIER_REQUEST = 0x3, // Messaggio di richiesta. + CSPARSIFIER_DATA = 0x4 // Messaggio di DATI. +} CSparsifierMessageType; + +/////////////////// +/// Timeout type // +/////////////////// +typedef enum { + TIMEOUT_CONNECT = 0x1, // Timeout per il messaggio CONNECT. + TIMEOUT_CANDIDATE = 0x2 // Timeout per il messaggio CANDIDATE. +} CSparsifierTimeoutType; + +////////////////////////// +// Header del pacchetto // +////////////////////////// +struct hdr_c_sparsifier +{ + + CSparsifierMessageType msg_type; // Tipo di messaggio. + NodeAddress sender_address; // Mittente. + NodeAddress destination_address; // Destinatario: -1 per il broadcast. + CSparsifierMessageType request; + NodeList * selectedNodes; // Nodi selezionati (nel processo di candidatura). + + //////////////////// + // Accessibilita' // + //////////////////// + static int offset_; + inline static int& offset() { return offset_; } + inline static hdr_c_sparsifier* access(const Packet* p) { + return (hdr_c_sparsifier*) p->access(offset_); + } +}; + +/////////// +// Timer // +/////////// +class CSparsifierTimer; + +/////////// +// Agent // +/////////// +class CSPARSIFIER_Agent : public ClusteringModule +{ +public: + + CSPARSIFIER_Agent(); + + /** + * Query if algorithm support a particular protocol: + * that method is probably called before a getData + * method. + */ + virtual bool supportProtocol(string protocol); + + /** + * That method is used to get data from an algorithm + * that was check to implements a particular protocol + */ + virtual void * getData(string data); + + // Funzione di ricezione del modulo. + virtual void receive(Packet * p, Handler * h); + + // Fa partire il modulo. + virtual void startModule(); + + virtual NodeList & getNeighbors(); + + // Termine del lavoro del modulo. + virtual void endModule(); + + // Segnala lo scadere di un timeout per un messaggio. + void timeout(NodeAddress from, CSparsifierTimeoutType timeout); + + // Segnala il raggiungimento del massimo numero di timeout per un messaggio. + void lastTimeout(NodeAddress from, CSparsifierTimeoutType timeout); + + // Verifica che un pacchetto sia di tipo DATA. + virtual bool isDataPacket(Packet * p); + + // Preparazione all'invio di un messaggio al layer inferiore + virtual void prepareSendDataDown(Packet * p); + +protected: + + map selectedNodes; // Nodi Selezionati da ogni vicino. + NodeList neighbors; // Vicini. + NodeList candidateNeighbors; // Subset di vicini candidati. + NodeList sparseNeighbors; // Subset di vicini finali. + + NodeList connect_nodes; // Vicini che hanno inviato un messaggio CONNECT + // mentre il nodo era ancora in fase di candidatura. + + CSparsifierStatus status; // Stato dell'agente. + CSparsifierTimer * timer; // Gestore dei timeout. + +protected: + + /////////////// + // Procedure // + /////////////// + + // Invia un messaggio di saluto ai vicini per richiedere i loro vicini. + void send_CANDIDATE(NodeAddress to); + + // Invia un messaggio per confermare il link. + void send_CONNECT(NodeAddress to); + + // Invia un richiesta di ritrasmessione + void send_REQUEST(NodeAddress to, CSparsifierMessageType type); + + // Ricezione di un messaggio CANDIDATE. + void receive_CANDIDATE(NodeAddress from, NodeList & selected); + +public: + + static int _DEBUG_; + + static int virtual_neighbors; + static double max_delay; + static int max_timeout_connect; + static double jitter_timeout_connect; + static double timeout_connect; + static int max_timeout_candidate; + static double jitter_timeout_candidate; + static double timeout_candidate; + +}; + +///////////////////////////////// +// Timer per le ritrasmissioni // +///////////////////////////////// +class CSparsifierTimer: public Handler { +public: + + CSparsifierTimer(CSPARSIFIER_Agent * a) : Handler(), agent(a) {} + + void handle(Event* e); + + // Lancia tutti i timeout per i messaggi CANDIDATE. + void launchCandidateTimeouts(NodeList & neighbors); + + // Lancia tutti i timeout per i messaggi CONNECT. + void launchConnectTimeouts(NodeList & neighbors); + + // Viene segnalata la ricezione di un messaggio di CANDIDATE: si elimina il timeout. + void receivedCandidate(NodeAddress from); + + // Viene segnalata la ricezione di un messaggio di CONNECT: si elimina il timeout. + void receivedConnect(NodeAddress from); + +protected: + + // Timeout attivi per i messaggi CONNECT. + TimeoutMap connect_timeouts; + + // Timeout attivi per i messaggi CANDIDATE. + TimeoutMap candidate_timeouts; + + // Agente proprietario del Timer. + CSPARSIFIER_Agent * agent; +}; + +#endif + diff -Naur ns-allinone-2.29-old/ns-2.29/clustering/common/.DS_Store ns-allinone-2.29/ns-2.29/clustering/common/.DS_Store --- ns-allinone-2.29-old/ns-2.29/clustering/common/.DS_Store 1970-01-01 01:00:00.000000000 +0100 +++ ns-allinone-2.29/ns-2.29/clustering/common/.DS_Store 2007-08-03 22:23:31.000000000 +0200 @@ -0,0 +1 @@ +Bud1 rithm. Algorithm.hIlocblobZ!˙˙˙˙˙˙clustering-header.hIlocblob!˙˙˙˙˙˙ClusteringModule.ccIlocblobÂ!˙˙˙˙˙˙ClusteringModule.hIlocblobZ}˙˙˙˙˙˙ Separator.ccIlocblob}˙˙˙˙˙˙ Separator.hIlocblobÂ}˙˙˙˙˙˙  @€ @€ @€ @ E DSDB `€ @€ @€ @ \ No newline at end of file diff -Naur ns-allinone-2.29-old/ns-2.29/clustering/common/Algorithm.h ns-allinone-2.29/ns-2.29/clustering/common/Algorithm.h --- ns-allinone-2.29-old/ns-2.29/clustering/common/Algorithm.h 1970-01-01 01:00:00.000000000 +0100 +++ ns-allinone-2.29/ns-2.29/clustering/common/Algorithm.h 2007-08-03 22:23:31.000000000 +0200 @@ -0,0 +1,50 @@ + +/** + * Copyright (c) 2006 Michele Mastrogiovanni. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#ifndef _ALGORITHM_H_ +#define _ALGORITHM_H_ + +/** + * That class represent a generic algorithm. + * An algorithm is something that can be queried if support + * a particular kind of protocol and it's possible to ask + * some data to it. + * + * That class is used to provide to other layer information + * of a particular network layer + */ +class Algorithm { + + public: + + /** + * Query if algorithm support a particular protocol: + * that method is probably called before a getData + * method. + */ + virtual bool supportProtocol(string protocol) = 0; + + /** + * That method is used to get data from an algorithm + * that was check to implements a particular protocol + */ + virtual void * getData(string data) = 0; + +}; + +#endif \ No newline at end of file diff -Naur ns-allinone-2.29-old/ns-2.29/clustering/common/ClusteringModule.cc ns-allinone-2.29/ns-2.29/clustering/common/ClusteringModule.cc --- ns-allinone-2.29-old/ns-2.29/clustering/common/ClusteringModule.cc 1970-01-01 01:00:00.000000000 +0100 +++ ns-allinone-2.29/ns-2.29/clustering/common/ClusteringModule.cc 2007-08-03 22:23:31.000000000 +0200 @@ -0,0 +1,291 @@ + +/** + * Copyright (c) 2006 Michele Mastrogiovanni. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#include "ClusteringModule.h" + +#include "packet.h" +#include "agent.h" +#include "ip.h" +#include "mac.h" +#include "random.h" + +/** + * Create a new clustering module. + */ +ClusteringModule::ClusteringModule(enum packet_t pkttype) : Agent(pkttype), + statusModule(UNDEFINED), myAddress(-1), utility(NULL), upTarget(NULL), lowerModule(false) +{ +} + +/** + * Manage Tcl command. + */ +int +ClusteringModule::command(int argc, const char * const * argv) +{ + if (argc == 2) { + /** + * Start module + */ + if (strcmp (argv[1], "start") == 0) { + startModule(); + return (TCL_OK); + } + /** + * Set random seed: each simulation will be different. + */ + else if (strcmp (argv[1], "randomize") == 0) { + Random::seed_heuristically(); + return TCL_OK; + } + else if (strcmp (argv[1], "lower") == 0) { + lowerModule = true; + return TCL_OK; + } + } + else if (argc == 3) { + /** + * Set node address + */ + if (strcasecmp (argv[1], "addr") == 0) { + myAddress = Address::instance().str2addr(argv[2]); + return TCL_OK; + } + /** + * Set node mobile model. + */ + else if (strcasecmp (argv[1], "node") == 0) { + myMobileNode = (MobileNode*) TclObject::lookup (argv[2]); + return TCL_OK; + } + /** + * Set utility class. + */ + else if (strcasecmp (argv[1], "utility") == 0) { + utility = (CommonUtility *) TclObject::lookup(argv[2]); + return TCL_OK; + } + /** + * Set upper layer. + */ + else if (strcasecmp (argv[1], "up-target") == 0) { + upTarget=(Agent*) TclObject::lookup(argv[2]); + return TCL_OK; + } + } + + return Agent::command(argc, argv); +} + +/** + * Start a clustering module: save initial energy value, + * initial time and set internal state of module. + */ +void +ClusteringModule::startModule() +{ + initialEnergy = myMobileNode->energy_model()->energy(); + initialTime = NOW; + statusModule = RUNNING; + loadNeighbors(neighbors); +} + +/** + * Notify end of module execution: set internal state of module + * and enable packet management for upper layer. + * Set information for dumping. + */ +void +ClusteringModule::endModule() +{ + statusModule = CALCULATED; + + /** + * Set energy and time consumption. + */ + if (utility) { + utility->set(myAddress, initialEnergy - myMobileNode->energy_model()->energy(), ENERGY); + utility->set(myAddress, NOW - initialTime, TIME); + } +} + +/** + * Send a packet to lower layer in network stack. + * Size of packet must be specified. + * If a destination is no specified packet is broadcasted. + * Send action save information about bytes transmission + * in dumping utility. + */ +void +ClusteringModule::sendDown(Packet * p, size_t size, NodeAddress to, double maxDelay) +{ + hdr_ip* iph = HDR_IP(p); + hdr_cmn* cmh = HDR_CMN(p); + + // Common datas. + cmh->addr_type() = NS_AF_ILINK; + cmh->direction() = hdr_cmn::DOWN; + + // DEBUG + // printf("[UP] %d sent %d bytes\n", myAddress, size); + + cmh->size() += size; + iph->src_.addr_ = myAddress; + + if (to == -1) { + cmh->next_hop_ = MAC_BROADCAST; + iph->dst_.addr_ = IP_BROADCAST; + } + else { + cmh->next_hop_ = to; + iph->dst_.addr_ = to; + } + + if ((lowerModule) && (to == -1)) + Scheduler::instance().schedule(target_, p, Random::uniform(maxDelay)); + else + target_->recv(p, (Handler*)NULL); + + /** + * Save statistics about sent bytes and packets. + */ + if (utility) { + utility->add(myAddress, size, to != -1 ? TX_BYTE_UNICAST : TX_BYTE_BROADCAST); + utility->add(myAddress, 1, to != -1 ? TX_MSG_UNICAST : TX_MSG_BROADCAST); + } +} + +/** + * That method is called when node receive a message. + */ +void +ClusteringModule::recv(Packet * p, Handler * h) +{ + hdr_cmn *cmh = HDR_CMN(p); + hdr_ip *iph = HDR_IP(p); + + /** + * If packet is caming from upper layer and module ended execution + * of algorithm, it delivers to bottom target. + */ + if (cmh->direction() == hdr_cmn::DOWN) { + if (statusModule == CALCULATED) { + // Send packet to lower layer. + prepareSendDataDown(p); + target_->recv(p, (Handler*)NULL); + } + /** + * Discard packet. + */ + return; + } + + /** + * If packet is caming from bottom layer and packet is + * destined to current node, it call method to manage it. + */ + if (cmh->direction() == hdr_cmn::UP) { + /** + * Packet is destined to upper layer. + */ + if (isDataPacket(p)) { + /** + * If module algorithm is ended. + */ + if (statusModule == CALCULATED) { + // Send data to upper layer. + upTarget->recv(p, h); + } + } + else { + /** + * Packet is destined to current node: + * manage it. + */ + struct hdr_ip *iph = HDR_IP(p); + + if ((iph->daddr() != IP_BROADCAST) && (iph->daddr() != myAddress)) + return; + + struct hdr_cmn *cmh = HDR_CMN(p); + + if (utility) { + utility->add(myAddress, cmh->size(), iph->daddr() != IP_BROADCAST ? RX_BYTE_UNICAST : RX_BYTE_BROADCAST); + utility->add(myAddress, 1, iph->daddr() != IP_BROADCAST ? RX_MSG_UNICAST : RX_MSG_BROADCAST); + } + + receive(p, h); + } + } +} + +/** + * Load node list. + */ +void +ClusteringModule::loadNeighbors(NodeList & neighbors) +{ + neighbors.clear(); + + // To get information about neighborood + GridKeeper * gk = GridKeeper::instance(); + MobileNode **output = new MobileNode *[gk->size_]; + + if (gk != NULL) { + + int num_neighbors = gk->get_neighbors(myMobileNode, output); + for (int i = 0; i < num_neighbors; i++) { + MobileNode * current = output[i]; + + // Initialize neighbor's info + NodeAddress neighborAddress = current->address(); + neighbors.insert(neighborAddress); + } + + } + + delete[] output; +} + +/** + * Query if algorithm support a particular protocol: + * that method is probably called before a getData + * method. + */ +bool +ClusteringModule::supportProtocol(string protocol) +{ + /** + * That base class do not support any protocol. + */ + return false; +} + + +/** + * That method is used to get data from an algorithm + * that was check to implements a particular protocol + */ +void * +ClusteringModule::getData(string data) +{ + /** + * That base class do not provide any data + */ + return NULL; +} diff -Naur ns-allinone-2.29-old/ns-2.29/clustering/common/ClusteringModule.h ns-allinone-2.29/ns-2.29/clustering/common/ClusteringModule.h --- ns-allinone-2.29-old/ns-2.29/clustering/common/ClusteringModule.h 1970-01-01 01:00:00.000000000 +0100 +++ ns-allinone-2.29/ns-2.29/clustering/common/ClusteringModule.h 2007-08-03 22:23:31.000000000 +0200 @@ -0,0 +1,194 @@ + +/** + * Copyright (c) 2006 Michele Mastrogiovanni. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#ifndef _CLUSTERING_MODULE_H_ +#define _CLUSTERING_MODULE_H_ + +#include "random.h" +#include "agent.h" +#include "mobilenode.h" +#include "packet.h" + +#include "clustering-header.h" + +#include "CommonUtility.h" +#include "Algorithm.h" + +/** + * Module state. + */ +typedef enum { + UNDEFINED = 0x1, // Module is not initialized. + RUNNING = 0x2, // Module is working. + CALCULATED = 0x3 // Module end a task. +} StatusModule; + +/** + * + * That class represent a generic Clustering Module. + * It provide common methods to send messages to down/up network + * layer and exports module state. + * There are also some callback method like "endModule" to notify + * when a module ended its work. + * + */ +class ClusteringModule : public Agent, public Algorithm { + + public: + + /** + * Method to receive datas of module's algorithm + */ + virtual void receive(Packet * p, Handler * h) = 0; + + /** + * Callback to start module execution. + */ + virtual void startModule(); + + /** + * Callback to end module execution. + */ + virtual void endModule(); + + public: + + /** + * Query if algorithm support a particular protocol: + * that method is probably called before a getData + * method. + */ + virtual bool supportProtocol(string protocol); + + /** + * That method is used to get data from an algorithm + * that was check to implements a particular protocol + */ + virtual void * getData(string data); + + public: + + /** + * Specify type of managed packets. + */ + ClusteringModule(enum packet_t pkttype); + + /** + * Reception of a packet. + */ + virtual void recv(Packet * p, Handler * h); + + /** + * Wrapper for TCL commands. + */ + virtual int command(int argc, const char * const * argv); + + /** + * Return clusterHead status of a node (if known). + */ + virtual inline NodeAddress getClusterHead(NodeAddress node) { return clusterHead[node]; } + + /** + * Set a clusterhead for a node + */ + void setClusterHead(NodeAddress node, NodeAddress CH) { clusterHead[node] = CH; } + + protected: + + /** + * Load neighbors of a node. + */ + void loadNeighbors(NodeList & neighbors); + + /** + * Verify if a packet is a data packet for algorithm. + */ + virtual bool isDataPacket(Packet * p) = 0; + + /** + * Set a packet as a DATA packet for that algorithm. It is + * used to encapsulate an higher level network packet to send + * it down. + */ + virtual void prepareSendDataDown(Packet * p) = 0; + + /** + * That method is used to send a packet to lower network layer. + */ + void sendDown(Packet * p, size_t size, NodeAddress to = -1, double maxDelay = 0.0); + + /** + * Deliver a packet to upper level in network stack. + */ + inline void sendUp(Packet * p, Handler * h) { upTarget->recv(p, h); } + + protected: + + /** + * Module state. + */ + StatusModule statusModule; + + /** + * Node Address. + */ + NodeAddress myAddress; + + /** + * Utility class for information dump. + */ + CommonUtility * utility; + + /** + * Initial energy of node. + */ + double initialEnergy; + + /** + * Initial time. + */ + double initialTime; + + /** + * Up target. + */ + Agent * upTarget; + + /** + * Mobile Node Model. To access to internal information such energy. + */ + MobileNode *myMobileNode; + + /** + * That flag express if module is lower one. + */ + bool lowerModule; + + /** + * List of neighbors. + */ + NodeList neighbors; + + /** + * Clustering Status of node and neighbors. + */ + map clusterHead; + +}; + +#endif \ No newline at end of file diff -Naur ns-allinone-2.29-old/ns-2.29/clustering/common/Separator.cc ns-allinone-2.29/ns-2.29/clustering/common/Separator.cc --- ns-allinone-2.29-old/ns-2.29/clustering/common/Separator.cc 1970-01-01 01:00:00.000000000 +0100 +++ ns-allinone-2.29/ns-2.29/clustering/common/Separator.cc 2007-08-03 22:23:31.000000000 +0200 @@ -0,0 +1,105 @@ + +/** + * Copyright (c) 2006 Michele Mastrogiovanni. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#include "Separator.h" + +Separator* Separator::instance_; + +static class SeparatorClass : public TclClass { +public: + SeparatorClass() : TclClass("Utility/SEPARATOR") {} + TclObject* create(int , const char*const* ) { + return(new Separator()); + } +} class_separator_utility; + +void +Separator::recv(Packet *p, Handler *h) +{ +} + +Separator::Separator() : TclObject() +{ + indexCurrentModule = -1; + instance_ = this; +} + +// +// Lancia il modulo successivo: +// +void +Separator::startModule() +{ + indexCurrentModule++; + for (map >::iterator m = modules.begin(); m != modules.end(); m++) { + vector & v = (m->second); + if (indexCurrentModule < v.size()) + v[indexCurrentModule]->startModule(); + } +} + +int +Separator::command(int argc, const char * const * argv) +{ + if (argc == 2) { + if (strcmp (argv[1], "start") == 0) { + startModule(); + return TCL_OK; + } + } + else if (argc == 4) { + if (strcmp (argv[1], "register") == 0) { + NodeAddress node = atoi(argv[2]); + ClusteringModule * module = (ClusteringModule*)TclObject::lookup(argv[3]); + registerNode(node, module); + return TCL_OK; + } + } + + return TclObject::command(argc, argv); +} + +// +// Termina il modulo corrente. +// Se tutti i nodi hanno terminato, lancia il modulo +// superiore. +// +void +Separator::endCurrentModule(NodeAddress node) +{ + endedNodes.insert(node); + if (endedNodes.size() == modules.size()) { + endedNodes.clear(); + startModule(); + } +} + +// +// Registra un modulo per un nodo. +// +void +Separator::registerNode(NodeAddress node, ClusteringModule * module) +{ + modules[node].push_back(module); +} + +int +Separator::getIndexCurrentModule() +{ + return indexCurrentModule; +} diff -Naur ns-allinone-2.29-old/ns-2.29/clustering/common/Separator.h ns-allinone-2.29/ns-2.29/clustering/common/Separator.h --- ns-allinone-2.29-old/ns-2.29/clustering/common/Separator.h 1970-01-01 01:00:00.000000000 +0100 +++ ns-allinone-2.29/ns-2.29/clustering/common/Separator.h 2007-08-03 22:23:31.000000000 +0200 @@ -0,0 +1,91 @@ + +/** + * Copyright (c) 2006 Michele Mastrogiovanni. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#ifndef _SEPARATOR_UTILITY_H_ +#define _SEPARATOR_UTILITY_H_ + +#include +#include +#include + +#include "packet.h" +#include "ClusteringModule.h" + +// +// Questa classe permette la giustapposizione di due algoritmi +// modulari. +// +// Questa classe necessita la registrazione di un certo +// insieme di nodi e dei differenti algoritmi dello stack +// di cui loro sono responsabili. +// +// Avviando questa classe vengono avviati gli algoritmi di +// livello piĂš basso di ogni nodo simultaneamente. +// Ogni qualvolta uno degli algoritmi termina lo segnala +// alla classe che gestisce il sistema. +// +// Non appena ogni nodo registrato in origine ha terminato +// la propria procedura, vengono avviati simultaneamente i +// livelli superiori di tutti i nodi. +// +// Per la registrazione devono essere registrati i nodi in +// ordine: prima tutti quelli con il primo livello, poi tutti +// i nodi (li stessi) i loro secondi livelli e cosĂŹ via. +// + +class Separator : public TclObject { + + public: + + // Parsing dei comandi. + virtual int command(int argc, const char * const * argv); + virtual void recv(Packet *p, Handler *h); + virtual void recv(Packet *p, const char * h) { recv(p, (Handler*)NULL); } + + // Segnala che il modulo corrente di un nodo è terminato. + void endCurrentModule(NodeAddress node); + + Separator(); + + static Separator & instance() { + return (*instance_); + } + + int getIndexCurrentModule(); + + protected: + + static Separator * instance_; + + // Lancia il modulo successivo: + void startModule(); + + // Registra un nuovo layer per un nodo. + void registerNode(NodeAddress node, ClusteringModule * module); + + // Mappa dei moduli. + map > modules; + + // Indice del modulo corrente. + int indexCurrentModule; + + // Nodi che hanno terminato il livello corrente. + set endedNodes; +}; + +#endif \ No newline at end of file diff -Naur ns-allinone-2.29-old/ns-2.29/clustering/common/clustering-header.h ns-allinone-2.29/ns-2.29/clustering/common/clustering-header.h --- ns-allinone-2.29-old/ns-2.29/clustering/common/clustering-header.h 1970-01-01 01:00:00.000000000 +0100 +++ ns-allinone-2.29/ns-2.29/clustering/common/clustering-header.h 2007-08-03 22:23:31.000000000 +0200 @@ -0,0 +1,136 @@ + +/** + * Copyright (c) 2006 Michele Mastrogiovanni. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +// +// Definizioni di alcune funzioni di utilita' e tipi di dato +// comuni a tutti gli algoritmi di clustering. +// +#ifndef _CLUSTERING_COMMON_HEADER_ +#define _CLUSTERING_COMMON_HEADER_ + +#include "config.h" +#include "scheduler.h" + +#include +#include +#include +#include + +using namespace std; + +//////////////////// +/// ID di un nodo // +//////////////////// +typedef nsaddr_t NodeAddress; + +//////////////////// +/// Lista di nodi // +//////////////////// +typedef set NodeList; + +////////////// +/// Timeout // +////////////// +struct Timeout { + Event * timeout; + int num; +}; + +////////////////////////////////////////////// +/// Struttura di mantenimento di un timeout // +////////////////////////////////////////////// +struct TimeoutFrom { + NodeAddress from; + Event * timeout; + int num; +}; + +/////////////////////// +/// Mappa di timeout // +/////////////////////// +typedef map TimeoutMap; +typedef map TimeoutFromMap; + +//////////////////////////// +/// Print a list of nodes // +//////////////////////////// +static +void +printNodeList(NodeList & list) +{ + for (NodeList::iterator i = list.begin(); i != list.end(); i++) + printf("%d ", *i); +} + +// +// Mappa dei vicini: WULI +// +typedef map NodeNeighbors; + +// +// Colore del nodo +// +typedef enum { + NO_COLOR = 0x0, // Nessun colore + COLOR_WHITE = 0x1, // Colore BIANCO + COLOR_BLACK = 0x2, // Colore NERO + COLOR_GRAY = 0x3 // Colore GRIGIO +} Color; + +// +// Mappa dei colori dei vicini. +// +typedef map NodeColor; + +struct ReachPath { + int length; + + NodeAddress node1_ID; + int node1_WT; + + NodeAddress node2_ID; + int node2_WT; + + public: + ReachPath() { + length = -1; + node1_ID = -1; + node1_WT = -1; + node2_ID = -1; + node2_WT = -1; + } +}; + +// Mappa che indica, per ogni nodo il percorso per raggiungerlo. +typedef map Reachbility; + +// +// Percorso verso un nodo clusterHead memorizzato da un clusterHead. +// +struct Percorsi { + NodeAddress black_node; + struct ReachPath path; +}; + +// Combinazioni di liste di nodi. +typedef vector Combinations; + +typedef pair Arc; +typedef set Arcs; + +#endif diff -Naur ns-allinone-2.29-old/ns-2.29/clustering/connector/.DS_Store ns-allinone-2.29/ns-2.29/clustering/connector/.DS_Store --- ns-allinone-2.29-old/ns-2.29/clustering/connector/.DS_Store 1970-01-01 01:00:00.000000000 +0100 +++ ns-allinone-2.29/ns-2.29/clustering/connector/.DS_Store 2007-08-03 22:23:31.000000000 +0200 @@ -0,0 +1 @@ +Bud1ector_connector_mastro.ccIlocblobZ!˙˙˙˙˙˙connector_mastro.hIlocblob!˙˙˙˙˙˙  @€ @€ @€ @ EDSDB `€ @€ @€ @ \ No newline at end of file diff -Naur ns-allinone-2.29-old/ns-2.29/clustering/connector/connector_mastro.cc ns-allinone-2.29/ns-2.29/clustering/connector/connector_mastro.cc --- ns-allinone-2.29-old/ns-2.29/clustering/connector/connector_mastro.cc 1970-01-01 01:00:00.000000000 +0100 +++ ns-allinone-2.29/ns-2.29/clustering/connector/connector_mastro.cc 2007-08-03 22:23:31.000000000 +0200 @@ -0,0 +1,1174 @@ + +/** + * Copyright (c) 2006 Michele Mastrogiovanni. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +//////////////// +// NS Headers // +//////////////// +#include "connector_mastro.h" +#include "random.h" +#include "gridkeeper.h" +#include +#include + +/////////////////////////////////// +// Parte di dichiarazione comune // +/////////////////////////////////// + +int hdr_connector::offset_; + +int CONNECTOR_Agent::discovery; + +int CONNECTOR_Agent::_DEBUG_; + +double CONNECTOR_Agent::max_delay; +int CONNECTOR_Agent::max_timeout_signal; +double CONNECTOR_Agent::jitter_timeout_signal; +double CONNECTOR_Agent::timeout_signal; +int CONNECTOR_Agent::max_timeout_inter; +double CONNECTOR_Agent::jitter_timeout_inter; +double CONNECTOR_Agent::timeout_inter; +int CONNECTOR_Agent::max_timeout_forward_path; +double CONNECTOR_Agent::jitter_timeout_forward_path; +double CONNECTOR_Agent::timeout_forward_path; + +static class MyConnectorClass : public TclClass { +public: + MyConnectorClass() : TclClass("Agent/MYCONNECTOR") {} + TclObject* create(int , const char*const* ) { + return(new CONNECTOR_Agent()); + } +} class_my_connector; + +static class MyConnectorHeaderClass : public PacketHeaderClass { +public: + MyConnectorHeaderClass() : PacketHeaderClass("PacketHeader/CONNECTOR", + sizeof(hdr_connector)) { + bind_offset(&hdr_connector::offset_); + } +} class_my_connectorhdr; + +// +// Costruttore +// +CONNECTOR_Agent::CONNECTOR_Agent() : ClusteringModule(PT_CONNECTOR) +{ + timer = new ConnectorTimer(this); + + bind_bool("discovery", &discovery); + bind_bool("debug", &_DEBUG_); + + bind("max-delay", &max_delay); + bind("max-timeout-signal", &max_timeout_signal); + bind("jitter-timeout-signal", &jitter_timeout_signal); + bind("timeout-signal", &timeout_signal); + bind("max-timeout-inter", &max_timeout_inter); + bind("jitter-timeout-inter", &jitter_timeout_inter); + bind("timeout-inter", &timeout_inter); + bind("max-timeout-forward-path", &max_timeout_forward_path); + bind("jitter-timeout-forward-path", &jitter_timeout_forward_path); + bind("timeout-forward-path", &timeout_forward_path); +} + +void +CONNECTOR_Agent::receive(Packet *p, Handler *h) +{ + struct hdr_connector *connectorh = HDR_CONNECTOR(p); + struct hdr_ip *iph = HDR_IP(p); + + // Mittente. + NodeAddress sender_address = iph->saddr(); + // Destinazione. + NodeAddress destination_address = iph->daddr(); + + switch (connectorh->msg_type) { + + case CONNECTOR_SIGNAL : + + timer->receivedSignal(sender_address); + + if (status > CONNECTOR_STATUS_SIGNAL) + return; + + if (_DEBUG_) + printf("(%f) %d received SIGNAL from %d (%d)\n", NOW, myAddress, sender_address, connectorh->CH); + + setClusterHead(sender_address, connectorh->CH); + + knownedSituations.insert(sender_address); + + // + // Verifica il passaggio di fase. + // + processPhase(); + + break; + + case CONNECTOR_INTER : + + // + // I messaggi INTER vengono inviati dai nodi gateway + // ai vicini clusterhead. I gateway che ricevono tale + // messaggio lo scartano. + // + if (getClusterHead(myAddress) != myAddress) + return; + + // + // Invia la conferma di ricezione. + // + send_CONFIRM(sender_address, connectorh->msg_type); + + if (status > CONNECTOR_STATUS_INTER) + return; + + if (_DEBUG_) + printf("(%f) %d received INTER from %d\n", NOW, myAddress, sender_address); + + // + // Memorizza le rotte. + // + inter_received[sender_address] = *(connectorh->inter_info); + + // + // Elimina dai dati raccolti quelli legati al cluster corrente. + // + for (vector::iterator i = inter_received[sender_address].begin(); + i != inter_received[sender_address].end(); + i++) { + + if ((*i).node == myAddress) { + inter_received[sender_address].erase(i); + break; + } + } + + // + // Verifica il passaggio di fase. + // + processPhase(); + + break; + + case CONNECTOR_FORWARD_PATH: + + // + // I messaggi FORWARD_PATH sono inviati dai clusterHead ai vicini gateway + // solo in modalita' UNICAST: vanno sempre accettati. + // + + // + // Invia il messaggio di conferma + // + send_CONFIRM(sender_address, connectorh->msg_type); + + // + // Se si e'gia'passata la fase si passa + // + if (status > CONNECTOR_STATUS_PATH) + return; + + if (_DEBUG_) + printf("(%f) %d received FORWARD_PATH from %d\n", NOW, myAddress, sender_address); + + // + // Memorizza lo stato. + // + forward_path[sender_address] = *(connectorh->forward_path); + + // + // Verifica l'avanzamento. + // + processPhase(); + + break; + + case CONNECTOR_CONFIRM : + + // + // Ferma i timeout in ricezione + // + if (_DEBUG_) + printf("(%f) %d received CONFIRM from %d: ", NOW, myAddress, sender_address); + // Segnala la ricezione del messaggio. + switch (connectorh->confirm) { + case CONNECTOR_INTER : + if (_DEBUG_) + printf("INTER\n"); + timer->receivedInter(sender_address); + break; + case CONNECTOR_FORWARD_PATH : + if (_DEBUG_) + printf("FORWARD_PATH\n"); + timer->receivedForwardPath(sender_address); + break; + } + + processPhase(); + + return; + + break; + + case CONNECTOR_REQUEST : + + switch (connectorh->confirm) { + case CONNECTOR_SIGNAL : + if (_DEBUG_) + printf("SIGNAL\n"); + send_SIGNAL(-1); + break; + } + + break; + + return; + } +} + +// +// Funzione richiamata allo scadere di un timeout per un certo tipo di messaggio: +// Il nodo invia la richiesta del dato al vicino interessato. +// +void +CONNECTOR_Agent::timeout(ConnectorMessageType type, NodeAddress from) +{ + if (_DEBUG_) + printf("(%f) %d TIMEOUT ", NOW, myAddress); + switch (type) { + + case CONNECTOR_SIGNAL : + // ritrasmette lo stato del nodo in broadcast. + if (_DEBUG_) + printf("SIGNAL"); + + send_REQUEST(from, CONNECTOR_SIGNAL); + break; + + case CONNECTOR_INTER : + if (_DEBUG_) + printf("INTER"); + send_INTER(from); + break; + + case CONNECTOR_FORWARD_PATH : + if (_DEBUG_) + printf("FORWARD_PATH"); + send_FORWARD_PATH(from); + break; + + } + if (_DEBUG_) + printf(" from %d\n", from); +} + +// +// Funzione richiamata allo scadere dell'ultimo timeout. +// +void +CONNECTOR_Agent::lastTimeout(ConnectorMessageType type, NodeAddress from) +{ + if (_DEBUG_) { + printf("(%f) %d LAST TIMEOUT from %d ", NOW, myAddress, from); + switch (type) { + case CONNECTOR_SIGNAL : printf("SIGNAL\n"); break; + case CONNECTOR_INTER : printf("INTER\n"); break; + case CONNECTOR_FORWARD_PATH : printf("FORWARD_PATH\n"); break; + } + } +} + +// +// Procedura di partenza per l'algoritmo di clustering. +// +void +CONNECTOR_Agent::startModule() +{ + // Inizializza le informazioni comuni del clustering. + ClusteringModule::startModule(); + + // + // Carica le informazioni di stato dal modulo sottostante. + // + if (!lowerModule && target()) { + ClusteringModule * bottom = (ClusteringModule*)target(); + setClusterHead(myAddress, bottom->getClusterHead(myAddress)); + // Imposta lo stato iniziale che verrˆ poi sovrascritto, nel caso + // dei gateway, dai clusterhead sulle loro rotte. + /* + if (utility) + utility->setClusterHead(myAddress, getClusterHead(myAddress)); + */ + if (_DEBUG_) + printf("%d clusterhead is: %d\n", myAddress, getClusterHead(myAddress)); + for (NodeList::iterator i = neighbors.begin(); i != neighbors.end(); i++) { + setClusterHead(*i, bottom->getClusterHead(*i)); + if (_DEBUG_) + printf("--- %d --> (%d)\n", *i, getClusterHead(*i)); + } + } + + // + // Determina il proprio stato finale: ogni gateway si affilia al CH maggiore. + // + if (getClusterHead(myAddress) != myAddress) { + if (_DEBUG_) + printf("%d START: WHITE\n", myAddress); + if (discovery) { + NodeAddress node = -1; + for (NodeList::iterator n = neighbors.begin(); n != neighbors.end(); n++) + if (getClusterHead(*n) == (*n)) + if ((*n) > node) + node = (*n); + setClusterHead(myAddress, node); + } + } + else { + if (_DEBUG_) + printf("%d START: BLACK\n", myAddress); + } + + // Entra nella fase di segnalazione. + status = CONNECTOR_STATUS_SIGNAL; + + reach.clear(); + + if (discovery) { + // + // Go to phase after signalation. + // + knownedSituations = neighbors; + processPhase(); + } + else { + knownedSituations.clear(); + + // Invia il proprio stato a tutti i vicini. + send_SIGNAL(-1); + + // Aspetta il messaggi di stato da tutti i vicini. + timer->launchSignalTimeouts(neighbors); + } + +} + +// +// Procedura richiamata alla fine dell'algoritmo di clustering. +// +void +CONNECTOR_Agent::endModule() +{ + // L'algoritmo termina: il nodo puo'memorizzare il proprio clusterHead. + status = CONNECTOR_STATUS_END; + + // Memorizza il proprio clusterHead: + // se il nodo e'nero e'se stesso, altrimenti e'il vicino NERO maggiore. + + if (utility) { + NodeList backboneNeighbors; + if (myAddress == getClusterHead(myAddress)) { + for (Reachbility::iterator r = reach.begin(); r != reach.end(); r++) { + if ((r->second).length == 0) { + backboneNeighbors.insert(r->first); + } + else if (((r->second).length == 1) || ((r->second).length == 2)) { + backboneNeighbors.insert((r->second).node1_ID); + } + } + ((ConnectorUtility*)utility)->setConnectedClusterHeads(myAddress, reach.size()); + ((BackboneUtility*)utility)->setColor(myAddress, "black"); + } + else { + bool flag = false; + for (map::iterator f = forward_path.begin(); f != forward_path.end(); f++) { + backboneNeighbors.insert(f->first); + flag |= ((f->second).size() > 0); + for (NodeList::iterator n = (f->second).begin(); n != (f->second).end(); n++) + backboneNeighbors.insert(*n); + } + if (flag) + ((BackboneUtility*)utility)->setColor(myAddress, "gray"); + else + ((BackboneUtility*)utility)->setColor(myAddress, "white"); + } + ((BackboneUtility*)utility)->setBackbone(myAddress, backboneNeighbors); + } + + if (_DEBUG_) { + printf("%d CONNECTOR END\n", myAddress); + + if (getClusterHead(myAddress) == myAddress) { + printf("%d BLACK rotte:\n", myAddress); + for (Reachbility::iterator r = reach.begin(); r != reach.end(); r++) { + if ((r->second).length == 0) { + printf("{} ---> %d\n", r->first); + } + else if ((r->second).length == 1) { + printf("{ %d } ---> %d\n", (r->second).node1_ID, r->first); + } + else if ((r->second).length == 2) { + printf("{ %d , %d } ---> %d\n", (r->second).node1_ID, (r->second).node2_ID, r->first); + } + } + printf("\n"); + } + else { + printf("%d WHITE forward:\n", myAddress); + for (map::iterator f = forward_path.begin(); f != forward_path.end(); f++) + for (NodeList::iterator n = (f->second).begin(); n != (f->second).end(); n++) + printf("from %d ---()---> %d\n", (f->first), *n); + printf("\n"); + } + } + + // Segnala la conclusione del processo di clustering. + ClusteringModule::endModule(); + + // + // Avvia il livello superiore se ce ne e'uno. + // + if (upTarget) + Separator::instance().endCurrentModule(myAddress); +} + +// +// Verifica la condizione di cambio di fase. +// +void +CONNECTOR_Agent::processPhase() +{ + int max; + bool flag; + NodeList timeoutList; + + switch (status) { + + case CONNECTOR_STATUS_SIGNAL : + // + // Verifica se sono a conoscenza dello stato di ogni vicino. + // + if (knownedSituations.size() < neighbors.size()) + return; + + // + // Al termine della fase di segnalazione, i nodi + // gateway inviano i messaggi INTER a tutti i propri + // vicini. + // + if (getClusterHead(myAddress) != myAddress) { + + // + // Il nodo gateway prepara il messaggio INTER da inviare + // a tutti i vicini. + // + prepare_INTER_message(); + + // + // Invia il messaggio INTER. + // + send_INTER(-1); + + // + // Aspetta la conferma da tutti i vicini clusterhead. + // + timer->launchInterTimeouts(neighbors); + for (NodeList::iterator n = neighbors.begin(); n != neighbors.end(); n++) + if (getClusterHead(*n) != (*n)) + timer->receivedInter(*n); + } + else { + // + // Calcola il numero dei nodi dai quali aspettarsi il messaggio + // di INTER: tutti i vicini gateway. + // + expectedInterMessages = 0; + for (NodeList::iterator n = neighbors.begin(); n != neighbors.end(); n++) { + if (getClusterHead(*n) != (*n)) + expectedInterMessages++; + else { + // Aggiunge il nodo alla lista di quelli raggiungibili + // (i due nodi sono adiacenti). + reach[*n].length = 0; + } + } + + + } + + // + // Avanza di fase + // + status = CONNECTOR_STATUS_INTER; + + case CONNECTOR_STATUS_INTER : + + // + // Ci si trova in questa fase finche': + // 1) Se il nodo e'un clusterHead: + // Non si sono ricevuti tutti i messaggi INTER da ogni vicino + // gateway. + // 2) Se il nodo e'un gateway: + // passa direttamente alla fase successiva + // + + if (getClusterHead(myAddress) == myAddress) { + // + // Nodo CH. + // + + // + // Verifica che si e'ricevuto un messaggio INTER da ogni vicino. + // + if (inter_received.size() < expectedInterMessages) + return; + + if (_DEBUG_) + printf("%d receive ALL INTER\n", myAddress); + + // + // Calcola le rotte. + // + calculate_routes(); + + // + // Prepara i forward path. + // + prepare_FORWARD_PATH_message(); + + // + // Comunica le rotte ai vicini gateway (in UNICAST e in maniera diretta). + // + for (NodeList::iterator n = neighbors.begin(); n != neighbors.end(); n++) + if (getClusterHead(*n) != (*n)) + send_FORWARD_PATH(*n); + + // + // Aspetta le conferme dei messaggi di Forward Path da ogni + // vicino gateway. + // + timer->launchForwardPathTimeouts(neighbors); + for (NodeList::iterator n = neighbors.begin(); n != neighbors.end(); n++) + if (getClusterHead(*n) == (*n)) + timer->receivedForwardPath(*n); + } + else { + // + // Nodo gateway: passa alla fase successiva. + // + if (_DEBUG_) + printf("%d receive ALL INTER\n", myAddress); + } + + // + // Avanza di fase. + // + status = CONNECTOR_STATUS_PATH; + + case CONNECTOR_STATUS_PATH : + + // + // Ci si trova in questa fase finche': + // 1) Un nodo gateway non ha ricevuto tutti i messaggi di + // tipo FORWARD_PATH da ogni vicino clusterHead. + // 2) Un nodo clusterHead non ha ricevuto conferma del suo + // messaggio FORWARD_PATH da ogni vicino. + // + + if (getClusterHead(myAddress) == myAddress) { + // + // ClusterHead node. + // + if (!(timer->receivedAllForwardPath())) + return; + + if (_DEBUG_) + printf("%d receive ALL FORWARD PATH\n", myAddress); + } + else { + // + // Gateway node. + // + for (NodeList::iterator n = neighbors.begin(); n != neighbors.end(); n++) { + if (getClusterHead(*n) == (*n)) { + flag = false; + for (map::iterator f = forward_path.begin(); f != forward_path.end(); f++) { + if ((f->first) == (*n)) { + flag = true; + break; + } + } + if (!flag) + return; + } + } + + if (_DEBUG_) + printf("%d receive ALL FORWARD PATH\n", myAddress); + } + + break; + + default: + return; + + } + + // + // Termine dell'algoritmo + // + endModule(); +} + +// Verifica che un pacchetto sia di tipo DATA. +bool +CONNECTOR_Agent::isDataPacket(Packet * p) +{ + struct hdr_connector *connectorh = HDR_CONNECTOR(p); + return (connectorh->msg_type == CONNECTOR_DATA); +} + +// Preparazione all'invio di un messaggio al layer inferiore +void +CONNECTOR_Agent::prepareSendDataDown(Packet * p) +{ + struct hdr_connector *connectorh = HDR_CONNECTOR(p); + + // Marca il nodo come dato. + connectorh->msg_type = CONNECTOR_DATA; +} + +// +// Questa funzione viene utilizzata da un nodo CH per +// scegliere i migliori percorsi verso gli altri cluster. +// +void +CONNECTOR_Agent::calculate_routes() +{ + // + // I primi clusterHead ad essere aggiunti sono quelli raggiungibili dai vicini + // gateway affiliati ad un altro cluster e i clusterHead vicini ai gateway del mio + // cluster. + // + for (NodeList::iterator n = neighbors.begin(); n!= neighbors.end(); n++) { + + // + // Il vicino e' un gateway + // + if (getClusterHead(*n) != (*n)) { + // + // Il vicino e'affiliato ad un altro cluster + // + if (getClusterHead(*n) != getClusterHead(myAddress)) { + + // + // CH----(Y--->CH) + // + struct ReachPath new_path; + new_path.length = 1; + new_path.node1_ID = (*n); + + if (!isReachble(getClusterHead(*n))) { + // + // Imposta il percorso. + // + reach[getClusterHead(*n)] = new_path; + } + else { + // + // Il percorso verso il nodo esiste gia': + // si imposta con il percorso nuovo se questo passa per + // un vicino maggiore (e anche esso  lungo 1). + // + struct ReachPath old_path = reach[getClusterHead(*n)]; + if ((old_path.length == new_path.length) && (new_path.node1_ID > old_path.node1_ID)) + reach[getClusterHead(*n)] = new_path; + } + } + } + else { + // + // CH----CH + // + struct ReachPath newPath; + newPath.length = 0; + reach[*n] = newPath; + } + } + + // + // Aggiungo i percorsi lunghi 2 hop e quelli lunghi 3-hop presi dai messaggi inter. + // + for (map >::iterator m = inter_received.begin(); + m != inter_received.end(); + m++) { + + NodeAddress neighbor_ID = (m->first); + + // Scarta la connessione a distanza 2 per i nodi che non sono affiliati a me + if (getClusterHead(neighbor_ID) != getClusterHead(myAddress)) + continue; + + for (vector::iterator v = (m->second).begin(); v != (m->second).end(); v++) { + struct ConnectorInterInfo inter_info = (*v); + + NodeAddress clusterHead = inter_info.cluster; + + // + // Percorsi verso il nodo corrente non sono memorizzati. + // + if (clusterHead == myAddress) + continue; + + if (!isReachble(clusterHead)) { + // + // Aggiunge il percorso: puo'essere 1 o 2 hop. + // + struct ReachPath new_path; + + if (inter_info.node == inter_info.cluster) { + new_path.length = 1; + new_path.node1_ID = neighbor_ID; + } + else { + new_path.length = 2; + new_path.node1_ID = neighbor_ID; + new_path.node2_ID = inter_info.node; + } + + reach[clusterHead] = new_path; + + continue; + + } + + // + // Preleva il percorso memorizzato in passato. + // + struct ReachPath old_path = reach[clusterHead]; + + if (old_path.length == 1) { + // + // Se il nuovo percorso e'lungo 1. + // + if (inter_info.node == inter_info.cluster) { + // + // Se il nuovo percorso e'piu'pesante del vecchio memorizza quello + // + if (neighbor_ID > old_path.node1_ID) { + struct ReachPath new_path; + new_path.length = 1; + new_path.node1_ID = neighbor_ID; + reach[clusterHead] = new_path; + } + } + + continue; + } + + if (old_path.length == 2) { + // + // Se il nuovo percorso e'lungo 1 lo preferisce al vecchio + // + if (inter_info.node == inter_info.cluster) { + struct ReachPath new_path; + new_path.length = 1; + new_path.node1_ID = neighbor_ID; + reach[clusterHead] = new_path; + + continue; + } + + // + // Costruisce il percorso alternativo + // + struct ReachPath new_path; + new_path.length = 2; + new_path.node1_ID = neighbor_ID; + new_path.node2_ID = inter_info.node; + + // + // Sceglie fra due percorsi lunghi 2 il nodo maggiore + // e li confronta: + // Se il nodo maggiore di un percorso  maggiore di + // quello dell'altro percorso allora lo sceglie. + // Se i due nodi maggiori sono uguali allora sceglie + // quello che ha come secondo nodo il piu'grande. + // + NodeAddress max_old_path_ID = old_path.node2_ID; + NodeAddress max_old_path_ID_altro = old_path.node1_ID; + + if (old_path.node1_ID > old_path.node2_ID) { + max_old_path_ID = old_path.node1_ID; + max_old_path_ID_altro = old_path.node2_ID; + } + + NodeAddress max_new_path_ID = new_path.node2_ID; + NodeAddress max_new_path_ID_altro = new_path.node1_ID; + if (new_path.node1_ID > new_path.node2_ID) { + max_new_path_ID = new_path.node1_ID; + max_new_path_ID_altro = new_path.node2_ID; + } + + if (max_new_path_ID > max_old_path_ID) { + reach[clusterHead] = new_path; + continue; + } + + if (max_new_path_ID == max_old_path_ID) { + if (max_new_path_ID_altro > max_old_path_ID_altro) { + reach[clusterHead] = new_path; + continue; + } + } + } + } + } +} + +bool +CONNECTOR_Agent::isReachble(NodeAddress clusterHead) +{ + for (Reachbility::iterator r = reach.begin(); r != reach.end(); r++) + if ((r->first) == clusterHead) + return true; + + return false; +} + +// +// Questa procedura viene chiamata dopo il calcolo delle rotte per +// calcolare i messaggi FORWARD_PATH da inviare ai vicini gateway. +// Questa procedura deve essere chiamata solo dai nodi clusterHead. +// +// Si assume che ogni clusterHead non abbia vicini clusterHead. +// +void +CONNECTOR_Agent::prepare_FORWARD_PATH_message() +{ + forward_path.clear(); + + for (NodeList::iterator n = neighbors.begin(); n != neighbors.end(); n++) { + + for (Reachbility::iterator r = reach.begin(); r != reach.end(); r++) { + NodeAddress clusterHead = (r->first); + struct ReachPath path = (r->second); + + if (path.node1_ID != (*n)) + continue; + + /* + if (alone) { + if (forward_path[*n].size() > 0) + continue; + } + */ + + if (path.length == 1) + forward_path[*n].insert(clusterHead); + + if (path.length == 2) + forward_path[*n].insert(path.node2_ID); + } + } +} + +// +// Prepare il messaggio di INTER da inviare ai vicini gateway. +// +void +CONNECTOR_Agent::prepare_INTER_message() +{ + if (_DEBUG_) { + printf("%d is %s and have as neighbors:\n", myAddress, getClusterHead(myAddress) == myAddress ? "CH" : "GW"); + for (NodeList::iterator n = neighbors.begin(); n != neighbors.end(); n++) + printf("\t%d--->%d\n", *n, getClusterHead(*n)); + } + + // + // Il messaggio inter contiene il vettore di tutti i vicini clusterHead + // di un nodo (informazioni complete). + // + + cache_inter_message.clear(); + + // + // Accoda alla lista lo stato di tutti i vicini CH. + // + for (NodeList::iterator n = neighbors.begin(); n != neighbors.end(); n++) { + if (getClusterHead(*n) != getClusterHead(myAddress)) { + struct ConnectorInterInfo info; + info.node = (*n); + info.cluster = getClusterHead(*n); + cache_inter_message.push_back(info); + } + } +} + +// +// Richiede un messaggio che forse e'stato perduto. +// +void +CONNECTOR_Agent::send_SIGNAL(NodeAddress to) +{ + Packet* p = allocpkt(); + struct hdr_connector * connectorh = HDR_CONNECTOR(p); + connectorh->msg_type = CONNECTOR_SIGNAL; + connectorh->CH = getClusterHead(myAddress); + sendDown(p, sizeof(NodeAddress) + sizeof(ConnectorMessageType), to, CONNECTOR_Agent::max_delay); + if (_DEBUG_) + printf("%d send SIGNAL: %d\n", myAddress, getClusterHead(myAddress)); +} + +// +// Richiede un messaggio che forse e'stato perduto. +// +void +CONNECTOR_Agent::send_CONFIRM(NodeAddress to, ConnectorMessageType type) +{ + Packet* p = allocpkt(); + struct hdr_connector * connectorh = HDR_CONNECTOR(p); + connectorh->msg_type = CONNECTOR_CONFIRM; + connectorh->confirm = type; + sendDown(p, sizeof(ConnectorMessageType) * 2, to, CONNECTOR_Agent::max_delay); +} + +// +// Richiede un messaggio che forse e'stato perduto. +// +void +CONNECTOR_Agent::send_REQUEST(NodeAddress to, ConnectorMessageType type) +{ + Packet* p = allocpkt(); + struct hdr_connector * connectorh = HDR_CONNECTOR(p); + connectorh->msg_type = CONNECTOR_REQUEST; + connectorh->confirm = type; + sendDown(p, sizeof(ConnectorMessageType) * 2, to, CONNECTOR_Agent::max_delay); +} + +// +// Comunica ai vicini la forward path +// +void +CONNECTOR_Agent::send_FORWARD_PATH(NodeAddress to) +{ + Packet* p = allocpkt(); + struct hdr_connector * connectorh = HDR_CONNECTOR(p); + connectorh->msg_type = CONNECTOR_FORWARD_PATH; + connectorh->forward_path = &(forward_path[to]); + sendDown(p, sizeof(ConnectorMessageType) + sizeof(NodeAddress) * forward_path[to].size(), to, CONNECTOR_Agent::max_delay); +} + +// +// Invia INTER +// +void +CONNECTOR_Agent::send_INTER(NodeAddress to) +{ + Packet* p = allocpkt(); + struct hdr_connector * connectorh = HDR_CONNECTOR(p); + connectorh->msg_type = CONNECTOR_INTER; + connectorh->inter_info = &cache_inter_message; + sendDown(p, sizeof(ConnectorMessageType) + sizeof(NodeAddress) * 2 * cache_inter_message.size(), to, CONNECTOR_Agent::max_delay); + + if (_DEBUG_) { + if (to == -1) { + printf("%d send INTER:\n", myAddress); + for (vector::iterator i = cache_inter_message.begin(); i != cache_inter_message.end(); i++) { + struct ConnectorInterInfo info = *i; + printf("\t%d --> %d\n", info.node, info.cluster); + } + } + } +} + +// +// Gestisce i timeouts. +// +void +ConnectorTimer::handle(Event * e) +{ + // + // Verifica che l'evento sia un timeout di INTER. + // + for (TimeoutMap::iterator i = signal_timeouts.begin(); i != signal_timeouts.end(); i++) { + if ((i->second).timeout == e) { + (i->second).num--; + if ((i->second).num <= 0) + agent->lastTimeout(CONNECTOR_SIGNAL, i->first); + else { + Scheduler::instance().schedule(this, e, CONNECTOR_Agent::timeout_signal + Random::uniform(CONNECTOR_Agent::jitter_timeout_signal)); + agent->timeout(CONNECTOR_SIGNAL, i->first); + } + return; + } + } + + // + // Verifica che l'evento sia un timeout di INTER. + // + for (TimeoutMap::iterator i = inter_timeouts.begin(); i != inter_timeouts.end(); i++) { + if ((i->second).timeout == e) { + (i->second).num--; + if ((i->second).num <= 0) + agent->lastTimeout(CONNECTOR_INTER, i->first); + else { + Scheduler::instance().schedule(this, e, CONNECTOR_Agent::timeout_inter + Random::uniform(CONNECTOR_Agent::jitter_timeout_inter)); + agent->timeout(CONNECTOR_INTER, i->first); + } + return; + } + } + + // + // Verifica che l'evento sia un timeout di FORWARD_PATH. + // + for (TimeoutMap::iterator i = forward_path_timeouts.begin(); i != forward_path_timeouts.end(); i++) { + if ((i->second).timeout == e) { + (i->second).num--; + if ((i->second).num <= 0) + agent->lastTimeout(CONNECTOR_FORWARD_PATH, i->first); + else { + Scheduler::instance().schedule(this, e, CONNECTOR_Agent::timeout_forward_path + Random::uniform(CONNECTOR_Agent::jitter_timeout_forward_path)); + agent->timeout(CONNECTOR_FORWARD_PATH, i->first); + } + return; + } + } +} + +void +ConnectorTimer::launchForwardPathTimeouts(NodeList neighbors) +{ + forward_path_timeouts.clear(); + + for (NodeList::iterator i = neighbors.begin(); i != neighbors.end(); i++) { + // Inizializza solo quelli che non sono giˆ stati annullati + struct Timeout t; + t.timeout = new Event(); + t.num = CONNECTOR_Agent::max_timeout_forward_path; + forward_path_timeouts[*i] = t; + Scheduler::instance().schedule(this, t.timeout, CONNECTOR_Agent::timeout_forward_path + Random::uniform(CONNECTOR_Agent::jitter_timeout_forward_path)); + } +} + +void +ConnectorTimer::launchSignalTimeouts(NodeList neighbors) +{ + signal_timeouts.clear(); + + for (NodeList::iterator i = neighbors.begin(); i != neighbors.end(); i++) { + // Inizializza solo quelli che non sono giˆ stati annullati + struct Timeout t; + t.timeout = new Event(); + t.num = CONNECTOR_Agent::max_timeout_signal; + signal_timeouts[*i] = t; + Scheduler::instance().schedule(this, t.timeout, CONNECTOR_Agent::timeout_signal + Random::uniform(CONNECTOR_Agent::jitter_timeout_signal)); + } +} + +void +ConnectorTimer::launchInterTimeouts(NodeList neighbors) +{ + inter_timeouts.clear(); + + for (NodeList::iterator i = neighbors.begin(); i != neighbors.end(); i++) { + // Inizializza solo quelli che non sono giˆ stati annullati + struct Timeout t; + t.timeout = new Event(); + t.num = CONNECTOR_Agent::max_timeout_inter; + inter_timeouts[*i] = t; + Scheduler::instance().schedule(this, t.timeout, CONNECTOR_Agent::timeout_inter + Random::uniform(CONNECTOR_Agent::jitter_timeout_inter)); + } +} + +// Verifica l'arrivo di tutti i messaggi di forward. +bool +ConnectorTimer::receivedAllForwardPath() +{ + return forward_path_timeouts.empty(); +} + +void +ConnectorTimer::receivedForwardPath(NodeAddress node) +{ + TimeoutMap::iterator i; + for (i = forward_path_timeouts.begin(); i != forward_path_timeouts.end(); i++) { + if ((i->first) == node) { + Scheduler::instance().cancel((i->second).timeout); + break; + } + } + if (i != forward_path_timeouts.end()) + forward_path_timeouts.erase(i); +} + +void +ConnectorTimer::receivedSignal(NodeAddress node) +{ + TimeoutMap::iterator i; + for (i = signal_timeouts.begin(); i != signal_timeouts.end(); i++) { + if ((i->first) == node) { + Scheduler::instance().cancel((i->second).timeout); + break; + } + } + if (i != signal_timeouts.end()) + signal_timeouts.erase(i); +} + +void +ConnectorTimer::receivedInter(NodeAddress node) +{ + TimeoutMap::iterator i; + for (i = inter_timeouts.begin(); i != inter_timeouts.end(); i++) { + if ((i->first) == node) { + Scheduler::instance().cancel((i->second).timeout); + break; + } + } + if (i != inter_timeouts.end()) + inter_timeouts.erase(i); +} + +/** + * Query if algorithm support a particular protocol: + * that method is probably called before a getData + * method. + */ +bool +CONNECTOR_Agent::supportProtocol(string protocol) +{ + if (protocol == "reachbility") + return true; + return false; +} + +/** + * That method is used to get data from an algorithm + * that was check to implements a particular protocol + */ +void * +CONNECTOR_Agent::getData(string data) +{ + if (data == "reachPath") { + return &reach; + } + else if (data == "forwardPath") { + return &forward_path; + } + return NULL; +} diff -Naur ns-allinone-2.29-old/ns-2.29/clustering/connector/connector_mastro.h ns-allinone-2.29/ns-2.29/clustering/connector/connector_mastro.h --- ns-allinone-2.29-old/ns-2.29/clustering/connector/connector_mastro.h 1970-01-01 01:00:00.000000000 +0100 +++ ns-allinone-2.29/ns-2.29/clustering/connector/connector_mastro.h 2007-08-03 22:23:31.000000000 +0200 @@ -0,0 +1,336 @@ + +/** + * Copyright (c) 2006 Michele Mastrogiovanni. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#ifndef _CONNECTOR_H_ +#define _CONNECTOR_H_ + +/** + * That class implement a simple connection of clusterheads + * produced by a clustering algorithm: connect a couple of + * clusterhead if they are less that three hop away. + * + * Algorithm can be launched on a protocol that select a + * dominating set and in which each node known role of its + * neighbors. + */ + +#include "ClusteringModule.h" + +#include "Separator.h" +// #include "BackboneUtility.h" +#include "ConnectorUtility.h" + +#include + +/** + * Node state + */ +typedef enum { + CONNECTOR_STATUS_SIGNAL = 0x0, // Notification of node's rule to neighbors. + CONNECTOR_STATUS_INTER = 0x1, // Exchange of informations between gateways and CHs. + CONNECTOR_STATUS_FORWARD_PATH = 0x2, // Exchange of informations between CHs and gateways. + CONNECTOR_STATUS_PATH = 0x3, // Routes creation. + CONNECTOR_STATUS_END = 0x4 // Final state. +} ConnectorStatus; + +/** + * Message type. + */ +typedef enum +{ + CONNECTOR_SIGNAL = 0x0, // Notify rule to neighbor. + CONNECTOR_INTER = 0x1, // INTER message between a gateway and a CH. + CONNECTOR_FORWARD_PATH = 0x2, // FORWARD PATH message between a CH and a gateway. + CONNECTOR_CONFIRM = 0x3, // Confirm message. + CONNECTOR_REQUEST = 0x4, // Retransmission request. + CONNECTOR_DATA = 0x5 // Data message. +} ConnectorMessageType; + +/** + * Structure to mantain information of INTER + * messages and node status. + */ +struct ConnectorInterInfo { + NodeAddress node; // Node ID. + NodeAddress cluster; // Clusterhead ID. +}; + +/** + * Packet header + */ +struct hdr_connector +{ + ConnectorMessageType msg_type; // Message type + ConnectorMessageType confirm; // Confirmed message type. + NodeAddress CH; // CH in SIGNAL messages. + vector * inter_info; // Used in INTER messages. + NodeList * forward_path; // Forward node list. + + /** + * Accessibility. + */ + static int offset_; + inline static int& offset() { return offset_; } + inline static hdr_connector* access(const Packet* p) { + return (hdr_connector*) p->access(offset_); + } +}; + +/** + * Timer + */ +class ConnectorTimer; + +/** + * Agent + */ +class CONNECTOR_Agent : public ClusteringModule +{ + public: + + CONNECTOR_Agent(); + + /** + * Query if algorithm support a particular protocol: + * that method is probably called before a getData + * method. + */ + virtual bool supportProtocol(string protocol); + + /** + * That method is used to get data from an algorithm + * that was check to implements a particular protocol + */ + virtual void * getData(string data); + + /** + * Method to receive datas of module's algorithm + */ + virtual void receive(Packet * p, Handler * h); + + /** + * Callback to start module execution. + */ + virtual void startModule(); + + /** + * Callback to end module execution. + */ + virtual void endModule(); + + /** + * Timeout notification. + */ + void timeout(ConnectorMessageType type, NodeAddress from); + + /** + * Last timeout notification. + */ + void lastTimeout(ConnectorMessageType type, NodeAddress from); + + /** + * Verify if a packet is a data packet for algorithm. + */ + virtual bool isDataPacket(Packet * p); + + /** + * Set a packet as a DATA packet for that algorithm. It is + * used to encapsulate an higher level network packet to send + * it down. + */ + virtual void prepareSendDataDown(Packet * p); + + protected: + + /** + * Send status notification. + */ + void send_SIGNAL(NodeAddress to); + + /** + * Send route to clusters. + */ + void send_INTER(NodeAddress to); + + /** + * Send routes to gateways. + */ + void send_FORWARD_PATH(NodeAddress to); + + /** + * Send message request. + */ + void send_REQUEST(NodeAddress to, ConnectorMessageType type); + + /** + * Send confirmation. + */ + void send_CONFIRM(NodeAddress to, ConnectorMessageType type); + + protected: + + /** + * Verify phase. + */ + void processPhase(); + + /** + * Calculate routes. + */ + void calculate_routes(); + + /** + * Prepare INTER message. + */ + void prepare_INTER_message(); + + /** + * Prepare FORWARD PATH message. + */ + void prepare_FORWARD_PATH_message(); + + /** + * Verify if a path is already known. + */ + bool isReachble(NodeAddress clusterHead); + + /** + * Verify if first node is higher that second. + */ + bool higherThan(NodeAddress node, int nodeWT, NodeAddress other, int otherWT); + + protected: + + /** + * Number of inter message to receive. + */ + int expectedInterMessages; + + /** + * Algorithm status. + */ + ConnectorStatus status; + + /** + * Retransmission timer. + */ + ConnectorTimer * timer; + + /** + * Received INTER message. + */ + map > inter_received; + + /** + * Forward node. + */ + map forward_path; + + /** + * Final routes. + */ + Reachbility reach; + + private: + + /** + * Info for INTER message to send. + */ + vector cache_inter_message; + + /** + * Neighbors to send final knoledge. + */ + NodeList knownedSituations; + + public: + + /** + * Don't perform discovery phase: + * assume that each node known clustering status of each neighbor + */ + static int discovery; + + /** + * Enable debug mode. + */ + static int _DEBUG_; + + /** + * Algorithm datas + */ + static double max_delay; + static int max_timeout_signal; + static double jitter_timeout_signal; + static double timeout_signal; + static int max_timeout_inter; + static double jitter_timeout_inter; + static double timeout_inter; + static int max_timeout_forward_path; + static double jitter_timeout_forward_path; + static double timeout_forward_path; + +}; + +///////////////////////////////// +// Timer per le ritrasmissioni // +///////////////////////////////// +class ConnectorTimer: public Handler { +public: + + ConnectorTimer(CONNECTOR_Agent * a) : Handler(), agent(a) {} + + void handle(Event* e); + + // Lancia tutti i timeout per i messaggi SIGNAL. + void launchSignalTimeouts(NodeList neighbors); + + // Cencella un timeout per il messaggio SIGNAL. + void receivedSignal(NodeAddress from); + + // Lancia tutti i timeout per i messaggi INTER. + void launchInterTimeouts(NodeList neighbors); + + // Cencella un timeout per il messaggio INTER. + void receivedInter(NodeAddress from); + + // Lancia tutti i timeout per i messaggi FORWARD_PATH. + void launchForwardPathTimeouts(NodeList neighbors); + + // Cencella un timeout per il messaggio FORWARD_PATH. + void receivedForwardPath(NodeAddress from); + + // Verifica l'arrivo di tutti i messaggi di forward. + bool receivedAllForwardPath(); + +protected: + + // Messaggi di timeout. + TimeoutMap signal_timeouts; + + // Timeout attivi per i messaggi INTER. + TimeoutMap inter_timeouts; + + // Timeout attivi per i messaggi FORWARD_PATH. + TimeoutMap forward_path_timeouts; + + CONNECTOR_Agent * agent; + +}; + +#endif \ No newline at end of file diff -Naur ns-allinone-2.29-old/ns-2.29/clustering/dca_mastro/.DS_Store ns-allinone-2.29/ns-2.29/clustering/dca_mastro/.DS_Store --- ns-allinone-2.29-old/ns-2.29/clustering/dca_mastro/.DS_Store 1970-01-01 01:00:00.000000000 +0100 +++ ns-allinone-2.29/ns-2.29/clustering/dca_mastro/.DS_Store 2007-08-03 22:23:30.000000000 +0200 @@ -0,0 +1 @@ +Bud1‡mastro dca_mastro.ccIlocblobZ!˙˙˙˙˙˙ dca_mastro.hIlocblob!˙˙˙˙˙˙  @€ @€ @€ @ E‡DSDB ` @€ @€ @ \ No newline at end of file diff -Naur ns-allinone-2.29-old/ns-2.29/clustering/dca_mastro/dca_mastro.cc ns-allinone-2.29/ns-2.29/clustering/dca_mastro/dca_mastro.cc --- ns-allinone-2.29-old/ns-2.29/clustering/dca_mastro/dca_mastro.cc 1970-01-01 01:00:00.000000000 +0100 +++ ns-allinone-2.29/ns-2.29/clustering/dca_mastro/dca_mastro.cc 2007-08-03 22:23:30.000000000 +0200 @@ -0,0 +1,1115 @@ + +/** + * Copyright (c) 2006 Michele Mastrogiovanni. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +//////////////// +// NS Headers // +//////////////// +#include "dca_mastro.h" +#include "random.h" +#include "gridkeeper.h" +#include +#include + +#include "Separator.h" + + +/////////////////////////////////// +// Parte di dichiarazione comune // +/////////////////////////////////// + +int hdr_dca::offset_; + +int DCA_Agent::degree; + +int DCA_Agent::_DEBUG_; + +double DCA_Agent::max_delay; + +int DCA_Agent::max_timeout_hello; +double DCA_Agent::jitter_timeout_hello; +double DCA_Agent::timeout_hello; +int DCA_Agent::max_timeout_join; +double DCA_Agent::jitter_timeout_join; +double DCA_Agent::timeout_join; +int DCA_Agent::max_timeout_ch; +double DCA_Agent::jitter_timeout_ch; +double DCA_Agent::timeout_ch; +int DCA_Agent::max_timeout_signal; +double DCA_Agent::jitter_timeout_signal; +double DCA_Agent::timeout_signal; + +static class DcaClass : public TclClass { +public: + DcaClass() : TclClass("Agent/DCA") {} + TclObject* create(int , const char*const* ) { + return(new DCA_Agent()); + } +} class_dca; + +static class DcaHeaderClass : public PacketHeaderClass { +public: + DcaHeaderClass() : PacketHeaderClass("PacketHeader/DCA", + sizeof(hdr_dca)) { + bind_offset(&hdr_dca::offset_); + } +} class_dcahdr; + +// +// Costruttore +// +DCA_Agent::DCA_Agent() : ClusteringModule(PT_DCA) /*, msgClustering(0.0), bytesClustering(0.0), + msgBackbone(0.0), bytesBackbone(0.0) */ +{ + timer = new DcaTimer(this); + + bind_bool("degree", °ree); + + bind_bool("debug", &_DEBUG_); + + bind("max-delay", &max_delay); + + bind("max-timeout-join", &max_timeout_hello); + bind("jitter-timeout-join", &jitter_timeout_hello); + bind("timeout-join", &timeout_hello); + bind("max-timeout-join", &max_timeout_join); + bind("jitter-timeout-join", &jitter_timeout_join); + bind("timeout-join", &timeout_join); + bind("max-timeout-ch", &max_timeout_ch); + bind("jitter-timeout-ch", &jitter_timeout_ch); + bind("timeout-ch", &timeout_ch); + bind("max-timeout-signal", &max_timeout_signal); + bind("jitter-timeout-signal", &jitter_timeout_signal); + bind("timeout-signal", &timeout_signal); + +} + +void +DCA_Agent::receive(Packet *p, Handler *h) +{ + struct hdr_dca *dcah = HDR_DCA(p); + struct hdr_ip *iph = HDR_IP(p); + + // Mittente. + NodeAddress sender_address = iph->saddr(); + // Destinazione. + NodeAddress destination_address = iph->daddr(); + + // La richiesta pu˜ essere fatta solo di un messaggio + // di HELLO. + if (dcah->msg_type == DCA_REQUEST) { + if (_DEBUG_) + printf("%d receive REQUEST, resend HELLO\n", myAddress); + send_HELLO(-1); + return; + } + + // + // Ferma i timeout in ricezione + // + if (dcah->msg_type == DCA_CONFIRM) { + //if (_DEBUG_) + // printf("(%f) %d received CONFIRM from %d: ", NOW, myAddress, sender_address); + // Segnala la ricezione del messaggio. + switch (dcah->confirm) { + case DCA_CH : + //if (_DEBUG_) + // printf("CH\n"); + timer->receivedCh(sender_address); + break; + case DCA_JOIN : + //if (_DEBUG_) + // printf("JOIN\n"); + timer->receivedJoin(sender_address); + break; + case DCA_SIGNAL : + //if (_DEBUG_) + // printf("SIGNAL\n"); + timer->receivedSignal(sender_address); + break; + } + + processPhase(); + + return; + } + + int max; + bool flag; + NodeList::iterator n; + NodeAddress proposed_CH; + int largest_WT; + struct INTERInfo neigh; + + switch (dcah->msg_type) { + + case DCA_HELLO : + + timer->receivedHello(sender_address); + + // + // Se non si e'piu'nella fase di HELLO allora si scarta. + // + if (status > DCA_STATUS_HELLO) + return; + + if (_DEBUG_) + printf("(%f) %d received HELLO from %d (%d)\n", NOW, myAddress, sender_address, dcah->my_status.node_WT); + + // + // Memorizza il peso del vicino. + // + info[sender_address].WT = dcah->my_status.node_WT; + backbone_situation[sender_address].node_WT = dcah->my_status.node_WT; + + degrees[sender_address] = dcah->my_status.node_WT; + + // + // Verifica il passaggio di fase. + // + processPhase(); + + break; + + case DCA_CH : + + // + // Invia la conferma di ricezione. + // + send_CONFIRM(sender_address, dcah->msg_type); + + if (status > DCA_STATUS_SIGNAL) + return; + + if (_DEBUG_) + printf("(%f) %d received CH from %d (%d)\n", NOW, myAddress, sender_address, dcah->my_status.cluster_ID); + + // + // Aggiorna i dati. + // + info[sender_address].clusterHead = dcah->my_status.cluster_ID; + info[sender_address].clusterHeadWT = dcah->my_status.cluster_WT; + info[sender_address].CH = true; + + // + // Imposta lo stato di fine clustering. + // + neigh.node_ID = sender_address; + neigh.node_WT = info[sender_address].WT; + neigh.cluster_ID = info[sender_address].clusterHead; + neigh.cluster_WT = info[sender_address].clusterHeadWT; + backbone_situation[sender_address] = neigh; + + processClustering(); + + break; + + case DCA_JOIN : + + // + // Invia la conferma di ricezione. + // + send_CONFIRM(sender_address, dcah->msg_type); + + if (status > DCA_STATUS_SIGNAL) + return; + + if (_DEBUG_) + printf("(%f) %d received JOIN from %d (%d)\n", NOW, myAddress, sender_address, dcah->my_status.cluster_ID); + + // + // Aggiorna lo stato. + // + info[sender_address].JOIN = true; + info[sender_address].clusterHead = dcah->my_status.cluster_ID; + info[sender_address].clusterHeadWT = dcah->my_status.cluster_WT; + + // + // Imposta lo stato di fine clustering. + // + neigh.node_ID = sender_address; + neigh.node_WT = info[sender_address].WT; + neigh.cluster_ID = info[sender_address].clusterHead; + neigh.cluster_WT = info[sender_address].clusterHeadWT; + backbone_situation[sender_address] = neigh; + + // + // Aggiorna lo stato del cluster. + // + if (info[myAddress].clusterHead == myAddress) { + if (info[sender_address].clusterHead == myAddress) { + // + // Se il nodo e'entrato nel mio cluster: + // + info[myAddress].cluster.insert(sender_address); + if (_DEBUG_) + printf("(%f) %d il vicino %d e'entrato nel mio cluster\n", NOW, myAddress, sender_address); + } + } + + processClustering(); + + break; + + case DCA_SIGNAL : + + // + // Invia la conferma. + // + send_CONFIRM(sender_address, dcah->msg_type); + + // + // Se la fase e'passata si scarta. + // + if (status > DCA_STATUS_SIGNAL) + return; + + if (_DEBUG_) + printf("(%f) %d received SIGNAL from %d (%d)\n", NOW, myAddress, sender_address, dcah->my_status.cluster_ID); + + // + // Memorizza lo stato finale del vicino. + // + backbone_situation[sender_address] = dcah->my_status; + + // + // Verifica il passaggio di fase. + // + processPhase(); + + break; + } +} + +// +// Invia il messaggio CH +// +void +DCA_Agent::send_CH(NodeAddress to) +{ + Packet* p = allocpkt(); + + struct hdr_dca * dcah = HDR_DCA(p); + + dcah->msg_type = DCA_CH; + + // dcah->destination_address = to; + // dcah->my_status.node_ID = myAddress; + // dcah->my_status.node_WT = myAddress + dcah->my_status.cluster_ID = cache_ch_message_ID; + dcah->my_status.cluster_WT = cache_ch_message_WT; + + sendDown(p, sizeof(DcaMessageType) + sizeof(NodeAddress) + sizeof(int), to, DCA_Agent::max_delay); + /* + msgClustering += 1; + bytesClustering += (sizeof(DcaMessageType) + sizeof(NodeAddress) + sizeof(int)); + */ +} + +// +// Richiede un messaggio che forse e'stato perduto. +// +void +DCA_Agent::send_REQUEST(NodeAddress to) +{ + /* + if (_DEBUG_) + printf("%d send REQUEST\n", myAddress); + */ + + Packet* p = allocpkt(); + + struct hdr_dca * dcah = HDR_DCA(p); + + dcah->msg_type = DCA_REQUEST; + + sendDown(p, sizeof(DcaMessageType), to, DCA_Agent::max_delay); +} + +// +// Invia il messaggio HELLO +// +void +DCA_Agent::send_HELLO(NodeAddress to) +{ + Packet* p = allocpkt(); + + struct hdr_dca * dcah = HDR_DCA(p); + + dcah->msg_type = DCA_HELLO; + + dcah->my_status.node_WT = neighbors.size(); + + sendDown(p, sizeof(DcaMessageType) + sizeof(int), to, DCA_Agent::max_delay); +} + +// +// Invia JOIN +// +void +DCA_Agent::send_JOIN(NodeAddress to) +{ + Packet* p = allocpkt(); + + struct hdr_dca * dcah = HDR_DCA(p); + + dcah->msg_type = DCA_JOIN; + + // dcah->destination_address = to; + // dcah->my_status.node_ID = myAddress; + // dcah->my_status.node_WT = myAddress + + (dcah->my_status).cluster_ID = cache_join_message_ID; + (dcah->my_status).cluster_WT = cache_join_message_WT; + + sendDown(p, sizeof(DcaMessageType) + sizeof(NodeAddress) + sizeof(int), to, DCA_Agent::max_delay); + + /* + msgClustering += 1; + bytesClustering += (sizeof(DcaMessageType) + sizeof(NodeAddress) + sizeof(int)); + */ +} + +// +// Richiede un messaggio che forse e'stato perduto. +// +void +DCA_Agent::send_SIGNAL(NodeAddress to) +{ + Packet* p = allocpkt(); + + struct hdr_dca * dcah = HDR_DCA(p); + + dcah->msg_type = DCA_SIGNAL; + // dcah->destination_address = to; + + dcah->my_status.node_ID = backbone_situation[myAddress].node_ID; + dcah->my_status.node_WT = backbone_situation[myAddress].node_WT; + dcah->my_status.cluster_ID = backbone_situation[myAddress].cluster_ID; + dcah->my_status.cluster_WT = backbone_situation[myAddress].cluster_WT; + + sendDown(p, sizeof(DcaMessageType) + sizeof(NodeAddress) * 3 + sizeof(int) * 2, to, DCA_Agent::max_delay); +} + +// +// Richiede un messaggio che forse e'stato perduto. +// +void +DCA_Agent::send_CONFIRM(NodeAddress to, DcaMessageType type) +{ + //if (_DEBUG_) + // printf("(%f) %d send CONFIRM to %d (%d)\n", NOW, myAddress, to, type); + + Packet* p = allocpkt(); + + struct hdr_dca * dcah = HDR_DCA(p); + + dcah->msg_type = DCA_CONFIRM; + + // dcah->destination_address = to; + // dcah->my_status.node_ID = myAddress; + // dcah->my_status.node_WT = myAddress + // dcah->my_status.cluster_ID = cache_join_message_ID; + // dcah->my_status.cluster_WT = cache_join_message_WT; + + dcah->confirm = type; + + /* + if ((type == DCA_CH) || (type == DCA_JOIN)) { + msgClustering += 1; + bytesClustering += (sizeof(DcaMessageType) * 2); + } + else { + msgBackbone += 1; + bytesBackbone += (sizeof(DcaMessageType) * 2); + } + */ + + sendDown(p, sizeof(DcaMessageType) * 2, to, DCA_Agent::max_delay); +} + +map +DCA_Agent::getDegreeOfNeighbor() +{ + map degrees; + + // To get information about neighborood + GridKeeper * gk = GridKeeper::instance(); + MobileNode **output = new MobileNode *[gk->size_]; + MobileNode **degree = new MobileNode *[gk->size_]; + + if (gk != NULL) { + + int num_neighbors = gk->get_neighbors(myMobileNode, output); + for (int i = 0; i < num_neighbors; i++) { + + // Vicino. + MobileNode * current = output[i]; + + // Initialize neighbor's info + NodeAddress neighborAddress = current->address(); + + // Calcola il degree del nodo. + int _degree_ = gk->get_neighbors(current, degree); + + degrees[neighborAddress] = _degree_; + } + + } + + delete[] output; + delete[] degree; + + return degrees; +} + +// +// Procedura di partenza per l'algoritmo di clustering. +// +void +DCA_Agent::startModule() +{ + // Inizializza le informazioni comuni del clustering. + ClusteringModule::startModule(); + + //-------------------------------------- + // Imposta lo stato iniziale dei dati. + //-------------------------------------- + + if (DCA_Agent::degree != 1) + info[myAddress].WT = myAddress; + else + info[myAddress].WT = neighbors.size(); + + info[myAddress].clusterHead = -1; + info[myAddress].JOIN = false; + info[myAddress].CH = false; + + struct INTERInfo my_inter; + my_inter.node_ID = myAddress; + my_inter.node_WT = info[myAddress].WT; + my_inter.cluster_ID = -1; + my_inter.cluster_WT = -1; + backbone_situation[myAddress] = my_inter; + + for (NodeList::iterator n = neighbors.begin(); n != neighbors.end(); n++) { + if (DCA_Agent::degree != 1) + info[*n].WT = (*n); + + info[*n].clusterHead = -1; + info[*n].JOIN = false; + info[*n].CH = false; + + struct INTERInfo neigh_inter; + neigh_inter.node_ID = (*n); + + if (DCA_Agent::degree != 1) + neigh_inter.node_WT = (*n); + + neigh_inter.cluster_ID = -1; + neigh_inter.cluster_WT = -1; + backbone_situation[*n] = neigh_inter; + } + + if (_DEBUG_) + printf("(%f) %d my Weight is %d\n", NOW, myAddress, info[myAddress].WT); + + // Stato dell'agente + if (DCA_Agent::degree == 1) { + status = DCA_STATUS_HELLO; + degrees.clear(); + + send_HELLO(-1); + timer->launchHelloTimeouts(neighbors); + } + else { + status = DCA_STATUS_CLUSTERING; + processClustering(); + } +} + +void +DCA_Agent::endModule() +{ + if (_DEBUG_) + printf("%d DCA END\n", myAddress); + + setClusterHead(myAddress, backbone_situation[myAddress].cluster_ID); + for (NodeList::iterator n = neighbors.begin(); n != neighbors.end(); n++) + setClusterHead(*n, backbone_situation[*n].cluster_ID); + + // + // Imposta lo stato finale. + // + status = DCA_STATUS_END; + + if (utility) + ((ClusteringUtility*)utility)->setColor(myAddress, getClusterHead(myAddress) == myAddress ? "black" : "white"); + + // Segnala la conclusione del processo di clustering. + ClusteringModule::endModule(); + + // + // Avvia il livello superiore se ce ne e'uno. + // + if (upTarget) + Separator::instance().endCurrentModule(myAddress); +} + +void +DCA_Agent::timeout(DcaMessageType type, NodeAddress from) +{ + if (_DEBUG_) + printf("(%f) %d TIMEOUT ", NOW, myAddress); + switch (type) { + case DCA_HELLO : + if (_DEBUG_) + printf("HELLO"); + send_REQUEST(from); + break; + case DCA_CH : + if (_DEBUG_) + printf("CH"); + send_CH(from); + break; + case DCA_JOIN : + if (_DEBUG_) + printf("JOIN"); + send_JOIN(from); + break; + case DCA_SIGNAL : + if (_DEBUG_) + printf("SIGNAL"); + send_SIGNAL(from); + break; + } + if (_DEBUG_) + printf(" from %d\n", from); +} + +void +DCA_Agent::lastTimeout(DcaMessageType type, NodeAddress from) +{ + if (_DEBUG_) { + printf("(%f) %d LAST TIMEOUT from %d ", NOW, myAddress, from); + switch (type) { + case DCA_HELLO : printf("HELLO\n"); break; + case DCA_CH : printf("CH\n"); break; + case DCA_JOIN : printf("JOIN\n"); break; + case DCA_SIGNAL : printf("SIGNAL\n"); break; + } + } +} + +// Verifica che un pacchetto sia di tipo DATA. +bool +DCA_Agent::isDataPacket(Packet * p) +{ + struct hdr_dca *dcah = HDR_DCA(p); + return (dcah->msg_type == DCA_DATA); +} + +// Preparazione all'invio di un messaggio al layer inferiore +void +DCA_Agent::prepareSendDataDown(Packet * p) +{ + struct hdr_dca *dcah = HDR_DCA(p); + + // Marca il nodo come dato. + dcah->msg_type = DCA_DATA; +} + +// +// Restituisce true se il primo nodo e'maggiore del secondo. +// Il nodo A e'maggiore di B se: +// 1) Il peso di A e'maggiore. +// 2) Hanno peso uguale ma A ha un ID superiore. +// +bool +DCA_Agent::higherThan(NodeAddress node, int nodeWT, NodeAddress other, int otherWT) +{ + if (nodeWT > otherWT) + return true; + + if (nodeWT < otherWT) + return false; + + return (node > other); +} + +void +DCA_Agent::processClustering() +{ + if (status == DCA_STATUS_SIGNAL) { + processPhase(); + return; + } + + if (status != DCA_STATUS_CLUSTERING) + return; + + if (info[myAddress].clusterHead == myAddress) { + + // + // Se tutti i vicini con un peso minore del mio hanno un ruolo (gateway o clusterHead) + // allora termina. + // + for (NodeList::iterator n = neighbors.begin(); n != neighbors.end(); n++) + if (higherThan(myAddress, info[myAddress].WT, *n, info[*n].WT)) + if (info[*n].clusterHead == -1) + return; + + status = DCA_STATUS_SIGNAL; + + // + // Imposta lo stato di fine clustering. + // + struct INTERInfo my_inter; + my_inter.node_ID = myAddress; + my_inter.node_WT = info[myAddress].WT; + my_inter.cluster_ID = info[myAddress].clusterHead; + my_inter.cluster_WT = info[myAddress].clusterHeadWT; + backbone_situation[myAddress] = my_inter; + + // + // Verifica il passaggio di fase. + // + processPhase(); + + return; + + } + else { + // + // Se tutti i vicini di peso superiore hanno un ruolo allora termina. + // + for (NodeList::iterator n = neighbors.begin(); n != neighbors.end(); n++) + if (higherThan(*n, info[*n].WT, myAddress, info[myAddress].WT)) + if (info[*n].clusterHead == -1) + return; + + // + // Se tutti i vicini di peso superiore sono gateway allora diventa CH + // + bool flag = true; + + for (NodeList::iterator n = neighbors.begin(); n != neighbors.end(); n++) + if (higherThan(*n, info[*n].WT, myAddress, info[myAddress].WT)) + if (info[*n].clusterHead == (*n)) { + flag = false; + break; + } + + if (flag) { + // + // Tutti i vicini di peso superiore sono gateway (o non ce ne sono). + // + + // + // Divento CH + // + + info[myAddress].clusterHead = myAddress; + info[myAddress].clusterHeadWT = info[myAddress].WT; + info[myAddress].cluster.insert(myAddress); + info[myAddress].CH = true; + + // + // Diventa cluster. + // + cache_ch_message_ID = info[myAddress].clusterHead; + cache_ch_message_WT = info[myAddress].clusterHeadWT; + + // + // Invia il messaggio + // + send_CH(-1); + + // + // Invia i timeouts. + // + timer->launchChTimeouts(neighbors); + + status = DCA_STATUS_SIGNAL; + + // + // Imposta lo stato di fine clustering. + // + struct INTERInfo my_inter; + my_inter.node_ID = myAddress; + my_inter.node_WT = info[myAddress].WT; + my_inter.cluster_ID = info[myAddress].clusterHead; + my_inter.cluster_WT = info[myAddress].clusterHeadWT; + backbone_situation[myAddress] = my_inter; + + // + // Verifica il passaggio di fase. + // + processClustering(); + + return; + } + else { + // + // Esiste qualche vicino di peso superiore, CH: + // JOIN al CH maggiore. + // + int node_WT = -1; + NodeAddress node_ID = NodeAddress(-1); + + for (NodeList::iterator n = neighbors.begin(); n != neighbors.end(); n++) + if (higherThan(*n, info[*n].WT, myAddress, info[myAddress].WT)) + if (info[*n].clusterHead == (*n)) + if (higherThan(*n, info[*n].WT, node_ID, node_WT)) { + node_ID = *n; + node_WT = info[*n].WT; + } + + // + // Il nodo si lega al CH maggiore. + // + info[myAddress].clusterHead = node_ID; + info[myAddress].clusterHeadWT = node_WT; + + // + // Memorizza il messaggio da inviare. + // + cache_join_message_ID = info[myAddress].clusterHead; + cache_join_message_WT = info[myAddress].clusterHeadWT; + + // + // Invia il messaggio. + // + send_JOIN(-1); + + // + // Lancia i timeout. + // + timer->launchJoinTimeouts(neighbors); + + status = DCA_STATUS_SIGNAL; + + // + // Imposta la situazione del backbone: + // + struct INTERInfo my_inter; + my_inter.node_ID = myAddress; + my_inter.node_WT = info[myAddress].WT; + my_inter.cluster_ID = info[myAddress].clusterHead; + my_inter.cluster_WT = info[myAddress].clusterHeadWT; + backbone_situation[myAddress] = my_inter; + + // + // Invia la comunicazione finale del clustering. + // + send_SIGNAL(-1); + + // + // Avvia i timeout + // + timer->launchSignalTimeouts(neighbors); + + // + // Verifica l'avanzamento di fase. + // + processPhase(); + + return; + } + } +} + +// +// Verifica le condizioni per il cambio di fase. +// +void +DCA_Agent::processPhase() +{ + int max; + bool flag; + NodeList timeoutList; + + switch (status) { + + case DCA_STATUS_HELLO : + + if (degrees.size() < neighbors.size()) + return; + + status = DCA_STATUS_CLUSTERING; + processClustering(); + + return; + + case DCA_STATUS_CLUSTERING : + // + // Da questa fase si esce solo tramite la procedure processClustering() + // + return; + break; + + case DCA_STATUS_SIGNAL : + // + // Ci si trova in questa fase finche'non si e'deciso un ruolo finale nella fase di + // clustering per se stesso e ogni vicino ha segnalato il proprio. + // + if (backbone_situation[myAddress].cluster_ID == -1) + return; + + for (NodeList::iterator n = neighbors.begin(); n != neighbors.end(); n++) + if (backbone_situation[*n].cluster_ID == -1) + return; + + if (!timer->receivedAllSignal()) + return; + + if (_DEBUG_) + printf("(%f) %d received ALL CLUSTERING\n", NOW, myAddress); + + + + if (utility) { + /* + ((DcaUtility*)utility)->timeClustering[myAddress] = NOW - beginClusteringT; + ((DcaUtility*)utility)->energyClustering[myAddress] = beginClusteringE - myMobileNode->energy_model()->energy(); + beginBackboneE = myMobileNode->energy_model()->energy(); + beginBackboneT = NOW; + */ + } + + endModule(); + + return; + + default: + return; + + } + + // + // Termine dell'algoritmo + // + endModule(); + +} + +// +// TODO: manca la gestione dei messaggi INTER. +// +void +DcaTimer::handle(Event * e) +{ + // + // Verifica che l'evento sia un timeout di HELLO. + // + for (TimeoutMap::iterator i = hello_timeouts.begin(); i != hello_timeouts.end(); i++) { + if ((i->second).timeout == e) { + (i->second).num--; + if ((i->second).num <= 0) + agent->lastTimeout(DCA_HELLO, i->first); + else { + Scheduler::instance().schedule(this, e, DCA_Agent::timeout_hello + Random::uniform(DCA_Agent::jitter_timeout_hello)); + agent->timeout(DCA_HELLO, i->first); + } + return; + } + } + + // + // Verifica che l'evento sia un timeout di CH. + // + for (TimeoutMap::iterator i = ch_timeouts.begin(); i != ch_timeouts.end(); i++) { + if ((i->second).timeout == e) { + (i->second).num--; + if ((i->second).num <= 0) + agent->lastTimeout(DCA_CH, i->first); + else { + Scheduler::instance().schedule(this, e, DCA_Agent::timeout_ch + Random::uniform(DCA_Agent::jitter_timeout_ch)); + agent->timeout(DCA_CH, i->first); + } + return; + } + } + + // + // Verifica che l'evento sia un timeout di JOIN. + // + for (TimeoutMap::iterator i = join_timeouts.begin(); i != join_timeouts.end(); i++) { + if ((i->second).timeout == e) { + (i->second).num--; + if ((i->second).num <= 0) + agent->lastTimeout(DCA_JOIN, i->first); + else { + Scheduler::instance().schedule(this, e, DCA_Agent::timeout_join + Random::uniform(DCA_Agent::jitter_timeout_join)); + agent->timeout(DCA_JOIN, i->first); + } + return; + } + } + + // + // Verifica che l'evento sia un timeout di SIGNAL. + // + for (TimeoutMap::iterator i = signal_timeouts.begin(); i != signal_timeouts.end(); i++) { + if ((i->second).timeout == e) { + (i->second).num--; + if ((i->second).num <= 0) + agent->lastTimeout(DCA_SIGNAL, i->first); + else { + Scheduler::instance().schedule(this, e, DCA_Agent::timeout_signal + Random::uniform(DCA_Agent::jitter_timeout_signal)); + agent->timeout(DCA_SIGNAL, i->first); + } + return; + } + } + +} + +void +DcaTimer::launchJoinTimeouts(NodeList neighbors) +{ + join_timeouts.clear(); + + for (NodeList::iterator i = neighbors.begin(); i != neighbors.end(); i++) { + // Inizializza solo quelli che non sono giˆ stati annullati + struct Timeout t; + t.timeout = new Event(); + t.num = DCA_Agent::max_timeout_join; + join_timeouts[*i] = t; + } + + for (TimeoutMap::iterator i = join_timeouts.begin(); i != join_timeouts.end(); i++) + Scheduler::instance().schedule(this, (i->second).timeout, + DCA_Agent::timeout_join + Random::uniform(DCA_Agent::jitter_timeout_join)); +} + +void +DcaTimer::launchSignalTimeouts(NodeList neighbors) +{ + signal_timeouts.clear(); + + for (NodeList::iterator i = neighbors.begin(); i != neighbors.end(); i++) { + // Inizializza solo quelli che non sono giˆ stati annullati + struct Timeout t; + t.timeout = new Event(); + t.num = DCA_Agent::max_timeout_signal; + signal_timeouts[*i] = t; + Scheduler::instance().schedule(this, t.timeout, DCA_Agent::timeout_signal + Random::uniform(DCA_Agent::jitter_timeout_signal)); + } +} + +void +DcaTimer::launchChTimeouts(NodeList neighbors) +{ + ch_timeouts.clear(); + + for (NodeList::iterator i = neighbors.begin(); i != neighbors.end(); i++) { + // Inizializza solo quelli che non sono giˆ stati annullati + struct Timeout t; + t.timeout = new Event(); + t.num = DCA_Agent::max_timeout_ch; + ch_timeouts[*i] = t; + Scheduler::instance().schedule(this, t.timeout, DCA_Agent::timeout_ch + Random::uniform(DCA_Agent::jitter_timeout_ch)); + } +} + +void +DcaTimer::receivedCh(NodeAddress node) +{ + TimeoutMap::iterator i; + for (i = ch_timeouts.begin(); i != ch_timeouts.end(); i++) { + if ((i->first) == node) { + Scheduler::instance().cancel((i->second).timeout); + break; + } + } + if (i != ch_timeouts.end()) + ch_timeouts.erase(i); +} + +void +DcaTimer::receivedJoin(NodeAddress node) +{ + TimeoutMap::iterator i; + for (i = join_timeouts.begin(); i != join_timeouts.end(); i++) { + if ((i->first) == node) { + Scheduler::instance().cancel(i->second.timeout); + break; + } + } + if (i != join_timeouts.end()) + join_timeouts.erase(i); +} + +void +DcaTimer::receivedSignal(NodeAddress node) +{ + TimeoutMap::iterator i; + for (i = signal_timeouts.begin(); i != signal_timeouts.end(); i++) { + if ((i->first) == node) { + Scheduler::instance().cancel((i->second).timeout); + break; + } + } + if (i != signal_timeouts.end()) + signal_timeouts.erase(i); +} + +bool +DcaTimer::receivedAllSignal() +{ + return (signal_timeouts.size() == 0); +} + +// +// Fa partire i timeout per i nodi che non hanno ancora risposto al +// messaggio di HELLO inviando la propria lista di vicini. +// +void +DcaTimer::launchHelloTimeouts(NodeList neighbors) +{ + hello_timeouts.clear(); + + for (NodeList::iterator i = neighbors.begin(); i != neighbors.end(); i++) { + + struct Timeout t; + t.timeout = new Event(); + t.num = DCA_Agent::max_timeout_hello; + hello_timeouts[*i] = t; + + Scheduler::instance().schedule(this, t.timeout, + DCA_Agent::timeout_hello + Random::uniform(DCA_Agent::jitter_timeout_hello)); + } +} + +// +// L'agente segnala la ricezione di un messaggio di tipo HELLO: +// il timeout viene eliminato. +// +void +DcaTimer::receivedHello(NodeAddress from) +{ + TimeoutMap::iterator i; + for (i = hello_timeouts.begin(); i != hello_timeouts.end(); i++) { + if (i->first == from) { + Scheduler::instance().cancel(i->second.timeout); + break; + } + } + if (i != hello_timeouts.end()) + hello_timeouts.erase(i); +} diff -Naur ns-allinone-2.29-old/ns-2.29/clustering/dca_mastro/dca_mastro.h ns-allinone-2.29/ns-2.29/clustering/dca_mastro/dca_mastro.h --- ns-allinone-2.29-old/ns-2.29/clustering/dca_mastro/dca_mastro.h 1970-01-01 01:00:00.000000000 +0100 +++ ns-allinone-2.29/ns-2.29/clustering/dca_mastro/dca_mastro.h 2007-08-03 22:23:30.000000000 +0200 @@ -0,0 +1,322 @@ + +/** + * Copyright (c) 2006 Michele Mastrogiovanni. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#ifndef _DCA_MASTRO_H_ +#define _DCA_MASTRO_H_ + +#include "ClusteringModule.h" +#include "ClusteringUtility.h" + +#include + +//////////////////// +// Stato del nodo // +//////////////////// +typedef enum { + DCA_STATUS_HELLO = 0x1, // Invio il peso a miei vicini (HELLO) + DCA_STATUS_CLUSTERING = 0x2, // Decisione del clustering (JOIN, CH). + DCA_STATUS_SIGNAL = 0x3, // Fine della ricezione dello stato di ogni vicino (JOIN, CH). + DCA_STATUS_END = 0x4 // Fine dell'algoritmo. +} DcaStatus; + +////////////////////// +// Tipi di messaggi // +////////////////////// +typedef enum +{ + DCA_HELLO = 0x1, // Per comunicare il peso ai vicini + DCA_CH = 0x2, // Per la segnalazione dello stato di clusterHead + DCA_JOIN = 0x3, // Per segnalare il cluster a cui ci si lega. + DCA_SIGNAL = 0x4, // Per segnalare la propria situazione di fine clustering ai vicini. + DCA_CONFIRM = 0x5, // Per confermare la ricezione di un messaggio. + DCA_REQUEST = 0x6, // Request HELLO message. + DCA_DATA = 0x7 // Per inviare dati per il livello superiore. +} DcaMessageType; + +// +// Struttura utilizzata per mantenere le informazioni +// per l'invio di un messaggio di INTER e sul proprio stato. +// +struct INTERInfo { + NodeAddress node_ID; // ID nodo + int node_WT; // WT nodo + NodeAddress cluster_ID; // ID del suo clusterHead. + int cluster_WT; // WT del suo clusterHead. +}; + +// +// Informazioni sui vicini durante la fase di clustering. +// +struct NodeInfo { + int WT; // WT del nodo + NodeAddress clusterHead; // ID clusterHead del nodo + int clusterHeadWT; // WT clusterHead del nodo + NodeList cluster; // Nodi nel suo cluster. + bool JOIN; // True se ha inviato un messaggio di JOIN. + bool CH; // True se ha inviato un messaggio di CH. +}; + +////////////////////////// +// Header del pacchetto // +////////////////////////// +struct hdr_dca +{ + + DcaMessageType msg_type; // Tipo di messaggio. + DcaMessageType confirm; // Tipo di messaggio confermato. + + struct INTERInfo my_status; // Stato del mittente e del suo clusterHead. + + //////////////////// + // Accessibilita' // + //////////////////// + static int offset_; + inline static int& offset() { return offset_; } + inline static hdr_dca* access(const Packet* p) { + return (hdr_dca*) p->access(offset_); + } +}; + +/////////// +// Timer // +/////////// +class DcaTimer; + +/////////// +// Agent // +/////////// +class DCA_Agent : public ClusteringModule +{ +public: + + DCA_Agent(); + + /* + virtual inline NodeAddress getClusterHead(NodeAddress node) { + return backbone_situation[node].cluster_ID; + } + */ + + // Funzione di ricezione dell'algoritmo di clustering. + virtual void receive(Packet * p, Handler * h); + + // Fa partire il modulo. + virtual void startModule(); + + // Termine del lavoro del modulo. + virtual void endModule(); + + // Segnala lo scadere di un timeout per un messaggio. + void timeout(DcaMessageType type, NodeAddress from); + + // Segnala il raggiungimento del massimo numero di timeout per un messaggio. + void lastTimeout(DcaMessageType type, NodeAddress from); + + // Verifica che un pacchetto sia di tipo DATA. + virtual bool isDataPacket(Packet * p); + + // Preparazione all'invio di un messaggio al layer inferiore + virtual void prepareSendDataDown(Packet * p); + +protected: + + /////////////// + // Procedure // + /////////////// + + // Gestione della fase di transisione da uno stato all'altro + void processStatus(); + + // Invia il peso ai vicini (info[myAddress].WT). + void send_HELLO(NodeAddress to); + + // Invia richiesta di HELLO. + void send_REQUEST(NodeAddress to); + + // Invia il messaggio CH (cache_ch_message). + void send_CH(NodeAddress to); + + // Invia il messaggio JOIN (cache_join_message). + void send_JOIN(NodeAddress to); + + // Invia la conferma di ricezione (backbone_situation[myAddress]). + void send_SIGNAL(NodeAddress to); + + // Invia la conferma di ricezione. + void send_CONFIRM(NodeAddress to, DcaMessageType type); + +protected: + + // + // Verifica il passaggio di fase. + // + void processPhase(); + + // + // Verifica la terminazione del clustering + // + void processClustering(); + + // + // Restituisce true se il primo nodo e'maggiore del secondo. + // + bool higherThan(NodeAddress node, int nodeWT, NodeAddress other, int otherWT); + + // + // Restituisce il degree di un vicino. + // + map getDegreeOfNeighbor(); + +protected: + + // + // Stato dell'algoritmo + // + DcaStatus status; + + // + // Timer per le ritrasmissioni. + // + DcaTimer * timer; + + // Neighbors degree. + map degrees; + + // + // Informazioni sul nodo e i vicini nella fase di clustering. + // + map info; + + // + // Situazione al termine del clustering: dati su ogni vicino. + // + map backbone_situation; + + //-------------------------------------------------------- + // Messaggi inviati: utilizzati per le ritrasmissioni. + //-------------------------------------------------------- + + // + // Messaggio CH. + // + NodeAddress cache_ch_message_ID; + int cache_ch_message_WT; + + // + // Messaggio JOIN. + // + NodeAddress cache_join_message_ID; + int cache_join_message_WT; + +private: + + /* + float msgClustering; + float bytesClustering; + float msgBackbone; + float bytesBackbone; + + float beginClusteringE; + float beginClusteringT; + float beginBackboneE; + float beginBackboneT; + */ + +public: + + // + // Attiva la variante "degree": il peso di + // un nodo  pari al suo degree. + // + static int degree; + + static int _DEBUG_; + + static double max_delay; + + static int max_timeout_hello; + static double jitter_timeout_hello; + static double timeout_hello; + static int max_timeout_join; + static double jitter_timeout_join; + static double timeout_join; + static int max_timeout_ch; + static double jitter_timeout_ch; + static double timeout_ch; + static int max_timeout_signal; + static double jitter_timeout_signal; + static double timeout_signal; + +}; + +///////////////////////////////// +// Timer per le ritrasmissioni // +///////////////////////////////// +class DcaTimer: public Handler { +public: + + DcaTimer(DCA_Agent * a) : Handler(), agent(a) {} + + void handle(Event* e); + + // Lancia tutti i timeout per i messaggi HELLO. + void launchHelloTimeouts(NodeList neighbors); + + // Cencella un timeout per il messaggio HELLO. + void receivedHello(NodeAddress from); + + // Lancia tutti i timeout per i messaggi CH. + void launchChTimeouts(NodeList neighbors); + + // Cencella un timeout per il messaggio CH. + void receivedCh(NodeAddress from); + + // Lancia tutti i timeout per i messaggi CH. + void launchJoinTimeouts(NodeList neighbors); + + // Cencella un timeout per il messaggio CH. + void receivedJoin(NodeAddress from); + + // Lancia tutti i timeout per i messaggi SIGNAL. + void launchSignalTimeouts(NodeList neighbors); + + // Cencella un timeout per il messaggio SIGNAL. + void receivedSignal(NodeAddress from); + + // Verifica che tutti i Signal siano arrivati. + bool receivedAllSignal(); + +protected: + + // Timeout attivi per i messaggi HELLO. + TimeoutMap hello_timeouts; + + // Timeout attivi per i messaggi CH. + TimeoutMap ch_timeouts; + + // Timeout attivi per i messaggi JOIN. + TimeoutMap join_timeouts; + + // Timeout attivi per i messaggi SIGNAL. + TimeoutMap signal_timeouts; + + DCA_Agent * agent; + +}; + +#endif \ No newline at end of file diff -Naur ns-allinone-2.29-old/ns-2.29/clustering/initializer/.DS_Store ns-allinone-2.29/ns-2.29/clustering/initializer/.DS_Store --- ns-allinone-2.29-old/ns-2.29/clustering/initializer/.DS_Store 1970-01-01 01:00:00.000000000 +0100 +++ ns-allinone-2.29/ns-2.29/clustering/initializer/.DS_Store 2007-08-03 22:23:31.000000000 +0200 @@ -0,0 +1 @@ +Bud1‡ializeinitializer.ccIlocblobZ!˙˙˙˙˙˙ initializer.hIlocblob!˙˙˙˙˙˙  @€ @€ @€ @ E‡DSDB ` @€ @€ @ \ No newline at end of file diff -Naur ns-allinone-2.29-old/ns-2.29/clustering/initializer/initializer.cc ns-allinone-2.29/ns-2.29/clustering/initializer/initializer.cc --- ns-allinone-2.29-old/ns-2.29/clustering/initializer/initializer.cc 1970-01-01 01:00:00.000000000 +0100 +++ ns-allinone-2.29/ns-2.29/clustering/initializer/initializer.cc 2007-08-03 22:23:31.000000000 +0200 @@ -0,0 +1,993 @@ + +/** + * Copyright (c) 2006 Michele Mastrogiovanni. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +//////////////// +// NS Headers // +//////////////// +#include "BackboneUtility.h" +#include "Separator.h" + +#include "initializer.h" +#include "random.h" +#include "gridkeeper.h" +#include +#include + +/////////////////////////////////// +// Parte di dichiarazione comune // +/////////////////////////////////// + +int hdr_initializer::offset_; + +int INITIALIZER_Agent::degree; +int INITIALIZER_Agent::stojmenovic; +int INITIALIZER_Agent::_DEBUG_; + +int INITIALIZER_Agent::limit; +double INITIALIZER_Agent::max_delay; +int INITIALIZER_Agent::max_timeout_hello; +double INITIALIZER_Agent::jitter_timeout_hello; +double INITIALIZER_Agent::timeout_hello; +int INITIALIZER_Agent::max_timeout_first_decision; +double INITIALIZER_Agent::jitter_timeout_first_decision; +double INITIALIZER_Agent::timeout_first_decision; +int INITIALIZER_Agent::max_timeout_last_decision; +double INITIALIZER_Agent::jitter_timeout_last_decision; +double INITIALIZER_Agent::timeout_last_decision; + +static class InitializerClass : public TclClass { +public: + InitializerClass() : TclClass("Agent/INITIALIZER") {} + TclObject* create(int argc, const char*const* argv) { + return(new INITIALIZER_Agent()); + } +} class_initializer; + + +static class InitializerHeaderClass : public PacketHeaderClass { +public: + InitializerHeaderClass() : PacketHeaderClass("PacketHeader/INITIALIZER", + sizeof(hdr_initializer)) { + bind_offset(&hdr_initializer::offset_); + } +} class_initializerhdr; + +// +// Verifica che il timeout sia di tipo HELLO. +// +bool +InitializerTimer::isHelloTimeout(Event * e) +{ + for (TimeoutMap::iterator i = hello_timeouts.begin(); i != hello_timeouts.end(); i++) { + if (i->second.timeout == e) { + i->second.num--; + if (i->second.num <= 0) { + agent->lastTimeout(INITIALIZER_STATUS_HELLO, i->first); + } + else { + Scheduler::instance().schedule(this, e, + INITIALIZER_Agent::timeout_hello + Random::uniform(INITIALIZER_Agent::jitter_timeout_hello)); + agent->timeout(INITIALIZER_STATUS_HELLO, i->first); + } + return true; + } + } + return false; +} + +// +// Verifica che il timeout sia di tipo FIRST DECISION. +// +bool +InitializerTimer::isFirstDecisionTimeout(Event * e) +{ + for (TimeoutMap::iterator i = first_decision_timeouts.begin(); i != first_decision_timeouts.end(); i++) { + if (i->second.timeout == e) { + i->second.num--; + if (i->second.num <= 0) { + agent->lastTimeout(INITIALIZER_STATUS_FIRST_DECISION, i->first); + } + else { + Scheduler::instance().schedule(this, e, + INITIALIZER_Agent::timeout_first_decision + Random::uniform(INITIALIZER_Agent::jitter_timeout_first_decision)); + agent->timeout(INITIALIZER_STATUS_FIRST_DECISION, i->first); + } + return true; + } + } + return false; +} + +// +// Verifica che il timeout sia di tipo LAST DECISION. +// +bool +InitializerTimer::isLastDecisionTimeout(Event * e) +{ + for (TimeoutMap::iterator i = last_decision_timeouts.begin(); i != last_decision_timeouts.end(); i++) { + if (i->second.timeout == e) { + i->second.num--; + if (i->second.num <= 0) { + agent->lastTimeout(INITIALIZER_STATUS_LAST_DECISION, i->first); + } + else { + Scheduler::instance().schedule(this, e, + INITIALIZER_Agent::timeout_last_decision + Random::uniform(INITIALIZER_Agent::jitter_timeout_last_decision)); + agent->timeout(INITIALIZER_STATUS_LAST_DECISION, i->first); + } + return true; + } + } + return false; +} + +// +// Gestisce l'arrivo di un timeout segnalandolo +// opportunamente all'Agente. +// +void +InitializerTimer::handle(Event *e) +{ + if (isHelloTimeout(e)) + return; + + if (isFirstDecisionTimeout(e)) + return; + + if (isLastDecisionTimeout(e)) + return; +} + +// +// Inizializza i timeout che si possono lanciare in base ai vicini del nodo. +// +void +InitializerTimer::initTimeouts(NodeList & neighbors) +{ + for (NodeList::iterator i = neighbors.begin(); i != neighbors.end(); i++) { + + // Definisce i Timeout di tipo HELLO + struct Timeout h; + h.timeout = new Event(); + h.num = INITIALIZER_Agent::max_timeout_hello; + hello_timeouts[*i] = h; + + // Definisce i Timeout di tipo FIRST DECISION + struct Timeout f; + f.timeout = new Event(); + f.num = INITIALIZER_Agent::max_timeout_first_decision; + first_decision_timeouts[*i] = f; + + // Definisce i Timeout di tipo LAST DECISION + struct Timeout s; + s.timeout = new Event(); + s.num = INITIALIZER_Agent::max_timeout_last_decision; + last_decision_timeouts[*i] = s; + + } +} + +// +// Fa partire i timeout per i nodi che non hanno ancora risposto al +// messaggio di HELLO inviando la propria lista di vicini. +// +void +InitializerTimer::launchHelloTimeouts() +{ + for (TimeoutMap::iterator i = hello_timeouts.begin(); i != hello_timeouts.end(); i++) { + Scheduler::instance().schedule(this, i->second.timeout, + INITIALIZER_Agent::timeout_hello + Random::uniform(INITIALIZER_Agent::jitter_timeout_hello)); + } +} + +// +// Fa partire i timeout per i nodi che non hanno ancora inviato +// il proprio colore (iniziale). +// +void +InitializerTimer::launchFirstDecisionTimeouts() +{ + for (TimeoutMap::iterator i = first_decision_timeouts.begin(); i != first_decision_timeouts.end(); i++) { + Scheduler::instance().schedule(this, i->second.timeout, + INITIALIZER_Agent::timeout_first_decision + Random::uniform(INITIALIZER_Agent::jitter_timeout_first_decision)); + } +} + +// +// Fa partire i timeout per i nodi che non hanno ancora inviato +// il proprio colore (finale). +// +void +InitializerTimer::launchLastDecisionTimeouts() +{ + for (TimeoutMap::iterator i = last_decision_timeouts.begin(); i != last_decision_timeouts.end(); i++) { + Scheduler::instance().schedule(this, i->second.timeout, + INITIALIZER_Agent::timeout_last_decision + Random::uniform(INITIALIZER_Agent::jitter_timeout_last_decision)); + } +} + +// +// L'agente segnala la ricezione di un messaggio di tipo HELLO: +// il timeout viene eliminato. +// +void +InitializerTimer::receivedHello(NodeAddress from) +{ + TimeoutMap::iterator i; + for (i = hello_timeouts.begin(); i != hello_timeouts.end(); i++) { + if (i->first == from) { + Scheduler::instance().cancel(i->second.timeout); + break; + } + } + if (i != hello_timeouts.end()) + hello_timeouts.erase(i); +} + +// +// L'agente segnala la ricezione di un messaggio di tipo FIRST DECISION: +// il timeout viene eliminato. +// +void +InitializerTimer::receivedFirstDecision(NodeAddress from) +{ + TimeoutMap::iterator i; + for (i = first_decision_timeouts.begin(); i != first_decision_timeouts.end(); i++) { + if (i->first == from) { + Scheduler::instance().cancel(i->second.timeout); + break; + } + } + if (i != first_decision_timeouts.end()) + first_decision_timeouts.erase(i); +} + +// +// L'agente segnala la ricezione di un messaggio di tipo LAST DECISION: +// il timeout viene eliminato. +// +void +InitializerTimer::receivedLastDecision(NodeAddress from) +{ + TimeoutMap::iterator i; + for (i = last_decision_timeouts.begin(); i != last_decision_timeouts.end(); i++) { + if (i->first == from) { + Scheduler::instance().cancel(i->second.timeout); + break; + } + } + if (i != last_decision_timeouts.end()) + last_decision_timeouts.erase(i); +} + +// +// Costruttore +// +INITIALIZER_Agent::INITIALIZER_Agent() : ClusteringModule(PT_INITIALIZER) +{ + timer = new InitializerTimer(this); + + bind_bool("debug", &_DEBUG_); + bind_bool("degree", °ree); + bind_bool("stojmenovic", &stojmenovic); + + bind("limit", &limit); + + bind("max-delay", &max_delay); + bind("max-timeout-hello", &max_timeout_hello); + bind("jitter-timeout-hello", &jitter_timeout_hello); + bind("timeout-hello", &timeout_hello); + bind("max-timeout-first-decision", &max_timeout_first_decision); + bind("jitter-timeout-first-decision", &jitter_timeout_first_decision); + bind("timeout-first-decision", &timeout_first_decision); + bind("max-timeout-last-decision", &max_timeout_last_decision); + bind("jitter-timeout-last-decision", &jitter_timeout_last_decision); + bind("timeout-last-decision", &timeout_last_decision); + +} + +void +INITIALIZER_Agent::receive(Packet *p, Handler *h) +{ + struct hdr_initializer *initializerh = HDR_INITIALIZER(p); + struct hdr_ip *iph = HDR_IP(p); + + // Mittente. + NodeAddress sender_address = iph->saddr(); //dcah->my_status.node_ID; + // Destinazione. + NodeAddress destination_address = iph->daddr(); // dcah->destination_address; + + switch (initializerh->msg_type) { + case INITIALIZER_NEIGHBORS : + receive_NEIGHBORS(sender_address, *(initializerh->node_list)); + break; + + case INITIALIZER_COLOR : + receive_COLOR(sender_address, initializerh->status, initializerh->color); + break; + + case INITIALIZER_REQUEST : + receive_REQUEST(sender_address, initializerh->status); + break; + default: + break; + } + +} + +// +// Richiede un messaggio che forse e'stato perduto. +// +void +INITIALIZER_Agent::send_REQUEST(InitializerStatus _status_, NodeAddress to) +{ + if (_DEBUG_) + printf("%d send REQUEST\n", myAddress); + + Packet* p = allocpkt(); + + struct hdr_initializer * initializerh = HDR_INITIALIZER(p); + + initializerh->msg_type = INITIALIZER_REQUEST; + initializerh->status = _status_; + + sendDown(p, sizeof(InitializerMessageType) + sizeof(InitializerStatus), to, INITIALIZER_Agent::max_delay); +} + +// +// Messaggio usato per cumunicare la propria lista dei vicini ad un nodo vicino +// +void +INITIALIZER_Agent::send_NEIGHBORS(NodeAddress to) +{ + if (_DEBUG_) + printf("%d send NEIGHBORS\n", myAddress); + + Packet* p = allocpkt(); + + struct hdr_initializer * initializerh = HDR_INITIALIZER(p); + + initializerh->msg_type = INITIALIZER_NEIGHBORS; + initializerh->node_list = & neighbors; + + sendDown(p, sizeof(InitializerMessageType) + sizeof(nsaddr_t) * neighbors.size(), to, INITIALIZER_Agent::max_delay); +} + +// +// Messaggio usato per comunicare il colore del nodo in una certa fase dell'algoritmo. +// +void +INITIALIZER_Agent::send_COLOR(InitializerStatus _status_, NodeAddress to, Color color) +{ + if (_DEBUG_) + printf("%d send COLOR\n", myAddress); + + // Attention: set status of Agent BEFORE send GATEWAY message + Packet* p = allocpkt(); + + struct hdr_initializer * initializerh = HDR_INITIALIZER(p); + + initializerh->msg_type = INITIALIZER_COLOR; + initializerh->status = _status_; + initializerh->color = color; + + sendDown(p, sizeof(InitializerMessageType) + sizeof(InitializerStatus) + sizeof(Color), to, INITIALIZER_Agent::max_delay); +} + +//////////////////// +// Interrogazioni // +//////////////////// + +// +// Procedura per verificare se esistono due vicini del nodo +// non collegati fra loro. +// +bool +INITIALIZER_Agent::twoNeighborsAreUnlinked() +{ + NodeList tmp; + + // Il nodo A punta ad un vicino. + for (NodeList::iterator A = neighbors.begin(); A != neighbors.end(); A++) { + NodeList & nlA = nodeNeighbors[*A]; + // Il nodo B punta all'altro vicino. + for (NodeList::iterator B = A; B != neighbors.end(); B++) + // Se i vicini sono diversi + if (A != B) { + tmp.clear(); + tmp.insert(*B); + // Se fra i vicini di A non c'e' B allora i due vicini sono scollegati. + if (!includes(nlA.begin(), nlA.end(), tmp.begin(), tmp.end())) + return true; + } + } + + // Tutti i vicini sono collegati fra loro + return false; +} + +// +// Verifica se l'insieme dei vicini passato come parametro +// costituisce un insieme connesso. +// Viene effettuata una visita in profonditˆ dei nodi scelti. +// +bool +INITIALIZER_Agent::neighborsConnected(NodeList & nodes) +{ + map mappa; + + for (NodeList::iterator n = nodes.begin(); n != nodes.end(); n++) + mappa[*n] = 0; + + vector stack; + int size = nodes.size(); + NodeAddress currentNode; + + if (nodes.size() == 0) + return true; + + if (nodes.size() == 1) + return true; + + stack.push_back(*(nodes.begin())); + + while (stack.size() > 0) { + // + // 1) elimina il primo elemento dallo stack, + currentNode = stack.back(); + stack.pop_back(); + + // 2) lo colora, + mappa[currentNode] = 1; + + // 3) introduce tutti i vicini del nodo che + // sono parte dell'insieme e che non sono + // ancora marcati. + for (NodeList::iterator it = shortNeighbors[currentNode].begin(); + it != shortNeighbors[currentNode].end(); + it++) { + + // Se il vicino non  uno dei nodi da considerare. + if (find(nodes.begin(), nodes.end(), *it) == nodes.end()) + continue; + + if (mappa[*it] == 1) + continue; + + stack.push_back(*it); + } + } + + for (NodeList::iterator n = nodes.begin(); n != nodes.end(); n++) + if (mappa[*n] == 0) + return false; + return true; +} + +// +// Controlla se il vicino passato come parametro e'adiacente +// a tutti i vicini del nodo. +// +bool +INITIALIZER_Agent::neighborsCoversMyNeighbors(NodeList & nodes) +{ + int size = neighbors.size(); + + // + // Se i nodi scelti sono tanti quanti sono i vicini + // allora i vicini sono automaticamente coperti. + // + if (nodes.size() == size) + return true; + + // + // Se il nodo  uno solo e i suoi vicini, escluso il nodo corrente + // sono quanti sono i vicini del nodo - 1 allora ritorna true. + // + if (nodes.size() == 1) + return (shortNeighbors[*(nodes.begin())].size() == (size - 1)); + + NodeList covered; + + for (NodeList::iterator it = nodes.begin(); it != nodes.end(); it++) + copy(shortNeighbors[*it].begin(), shortNeighbors[*it].end(), inserter(covered, covered.begin())); + + return (covered.size() == size); +} + +// +// Verifica se esiste un sottoinsieme di nodi di grandezza specificata +// che abbia le seguenti caratteristiche: +// 1) L'insieme dei nodi  connesso. +// 2) Tutti i nodi sono marcati. +// 3) Tutti i nodi hanno ID maggiore del nodo. +// +bool +INITIALIZER_Agent::checkRule(int max) +{ + // Determina i nodi vicini che possono determinare il coloramento. + NodeList rightNodes; + for (NodeList::iterator n = neighbors.begin(); n != neighbors.end(); n++) { + if (INITIALIZER_Agent::degree == 1) { + if ((neighbors.size() < nodeNeighbors[*n].size()) || + ((neighbors.size() == nodeNeighbors[*n].size()) && (myAddress < (*n)))) + if (firstColorNeighbors[*n] == COLOR_BLACK) + rightNodes.insert(*n); + } + else { + if ((myAddress < (*n)) && (firstColorNeighbors[*n] == COLOR_BLACK)) + rightNodes.insert(*n); + } + } + + if (_DEBUG_) { + printf("%d BLACK NEIGHBORS: ", myAddress); + for (NodeList::iterator n = rightNodes.begin(); n != rightNodes.end(); n++) + printf("%d ", *n); + printf("\n"); + } + + max = (max < rightNodes.size() ? max : rightNodes.size()); + + if (_DEBUG_) + printf("%d max = %d\n", myAddress, max); + + // + // Estrae tutti i possibili accoppiamenti di nodi + // + int I = 0; + int A = 0; + int S = 0; + bool print = true; + + NodeList::iterator E = rightNodes.begin(); + + vector V; + NodeList empty; + V.push_back(empty); + + while (E != rightNodes.end()) { + A = 0; + S = V.size(); + while (A < S) { + + NodeList nodi = V[I]; + + if ((print) && (nodi.size() > 0)) { + + if (_DEBUG_) { + printf("%d verifica: (", myAddress); + for (NodeList::iterator n = nodi.begin(); n != nodi.end(); n++) + printf("%d ", *n); + printf(")\n"); + } + + // + // Verifica se la lista dei vicini  connessa + // + if (neighborsConnected(nodi)) { + + // + // e copre ogni vicino del nodo. + // + if (neighborsCoversMyNeighbors(nodi)) { + + return true; + + } + } + } + + NodeList tmp(V[A]); + tmp.insert(*E); + + if (tmp.size() <= max) { + V.push_back(tmp); + I++; + print = true; + } + else { + print = false; + } + + A++; + } + E++; + } + + while (I < V.size()) { + + if (_DEBUG_) { + printf("%d verifica: (", myAddress); + for (NodeList::iterator n = V[I].begin(); n != V[I].end(); n++) + printf("%d ", *n); + printf(")\n"); + } + + // + // Verifica se la lista dei vicini  connessa + // + if (neighborsConnected(V[I])) { + + // + // e copre ogni vicino del nodo. + // + if (neighborsCoversMyNeighbors(V[I])) { + + return true; + + } + } + + I++; + } + + return false; +} + +// +// Funzione richiamata allo scadere di un timeout per un certo tipo di messaggio: +// Il nodo invia la richiesta del dato al vicino interessato. +// +void +INITIALIZER_Agent::timeout(InitializerStatus type, NodeAddress from) +{ + send_REQUEST(type, from); +} + +// +// Funzione richiamata allo scadere dell'ultimo timeout. +// +void +INITIALIZER_Agent::lastTimeout(InitializerStatus type, NodeAddress from) +{ + /* + switch(type) { + case INITIALIZER_STATUS_HELLO : + if (_DEBUG_) + printf("%d LAST TIMEOUT (HELLO) from %d (%f)\n", myAddress, from, Scheduler::instance().clock()); + break; + + case INITIALIZER_STATUS_FIRST_DECISION : + if (_DEBUG_) + printf("%d LAST TIMEOUT (FIRST_DECISION) from %d (%f)\n", myAddress, from, Scheduler::instance().clock()); + break; + + case INITIALIZER_STATUS_LAST_DECISION : + if (_DEBUG_) + printf("%d LAST TIMEOUT (LAST DECISION) from %d (%f)\n", myAddress, from, Scheduler::instance().clock()); + break; + } + */ +} + +// +// Procedura di partenza per l'algoritmo di clustering. +// +void +INITIALIZER_Agent::startModule() +{ + // Inizializza le informazioni comuni del clustering. + ClusteringModule::startModule(); + + // + // Carica le informazioni di stato dal modulo sottostante. + // + if (!lowerModule && target()) { + ClusteringModule * bottom = (ClusteringModule*)target(); + if (bottom->supportProtocol("sparsification")) + neighbors = *((NodeList*)bottom->getData("neighbors")); + } + + // Inizializza le strutture dei timeout. + timer->initTimeouts(neighbors); + + lastColorNeighbors.clear(); + + // Stato dell'agente + status = INITIALIZER_STATUS_HELLO; + + // Se il nodo  isolato allora  un clusterHead. + if (neighbors.size() == 0) { + firstColor = COLOR_WHITE; + lastColor = COLOR_WHITE; + endModule(); + return; + } + + // Invia un HELLO per richiedere la lista dei vicini. + if (myAddress == 0) + send_NEIGHBORS(-1); + else + for (NodeList::iterator n = neighbors.begin(); n != neighbors.end(); n++) + send_NEIGHBORS(*n); + + // send_NEIGHBORS(-1); + + // Inizializza i timeout per i messaggi NEIGHBORS. + timer->launchHelloTimeouts(); +} + +// +// Procedura richiamata alla fine dell'algoritmo di clustering. +// +void +INITIALIZER_Agent::endModule() +{ + // L'algoritmo termina: il nodo puo'memorizzare il proprio clusterHead. + status = INITIALIZER_STATUS_END; + + // Memorizza il proprio clusterHead: + // se il nodo e'nero e'se stesso, altrimenti e'il vicino NERO maggiore. + NodeAddress CH = ((lastColor == COLOR_BLACK) ? myAddress : greaterCluster()); + + setClusterHead(myAddress, CH); + + if (utility) { + NodeList backboneNeighbors; + if (myAddress == CH) { + for (NodeList::iterator n = neighbors.begin(); n != neighbors.end(); n++) + if (lastColorNeighbors[*n] == COLOR_BLACK) + backboneNeighbors.insert(*n); + } + else { + backboneNeighbors.insert(CH); + } + ((BackboneUtility*)utility)->setBackbone(myAddress, backboneNeighbors); + ((BackboneUtility*)utility)->setColor(myAddress, myAddress == CH ? "black" : "white"); + } + + // Segnala la conclusione del processo di clustering. + ClusteringModule::endModule(); + + // Start upper module + if (upTarget) + Separator::instance().endCurrentModule(myAddress); +} + +// +// Procedura di ricezione del messaggio NEIGHBORS. +// +void +INITIALIZER_Agent::receive_NEIGHBORS(NodeAddress from, NodeList & neigh) +{ + if (_DEBUG_) + printf("%d receive NEIGHBORS\n", myAddress); + + // Se il messaggio e'di una fase passata, si scarta. + if (status > INITIALIZER_STATUS_HELLO) + return; + + // Cancella il timeout sulla ricezione di questo messaggio + timer->receivedHello(from); + + // Memorizza l'informazione. + nodeNeighbors[from] = neigh; + + // + // Assegna come lista di vicini di un nodo tutti i nodi che sono + // anche vicini del nodo corrrente. + // + for (NodeList::iterator i = neigh.begin(); i != neigh.end(); i++) + if (find(neighbors.begin(), neighbors.end(), *i) != neighbors.end()) + shortNeighbors[from].insert(*i); + + // Verifica se eventualemente si puo'avanzare di stato. + processStatus(); +} + +// +// Procedura di ricezione del messaggio di colore. +// +void +INITIALIZER_Agent::receive_COLOR(NodeAddress _from_, InitializerStatus _status_, Color color) +{ + if (_DEBUG_) + printf("%d receive COLOR\n", myAddress); + + // Se il messaggio e'di una fase passata, si scarta. + if (status > _status_) + return; + + // Cancella il timeout e memorizza le informazioni sul colore. + switch (_status_) { + case INITIALIZER_STATUS_FIRST_DECISION : + timer->receivedFirstDecision(_from_); + firstColorNeighbors[_from_] = color; + break; + case INITIALIZER_STATUS_LAST_DECISION : + timer->receivedLastDecision(_from_); + lastColorNeighbors[_from_] = color; + break; + } + + processStatus(); +} + +// +// Ricezione di un messaggio di richiesta. +// +void +INITIALIZER_Agent::receive_REQUEST(NodeAddress _from_, InitializerStatus _status_) +{ + if (_DEBUG_) + printf("%d receive REQUEST\n", myAddress); + + // Se il dato e'disponibile, si procede a soddisfare la richiesta + switch(_status_) { + + case INITIALIZER_STATUS_HELLO : + send_NEIGHBORS(-1); + break; + + case INITIALIZER_STATUS_FIRST_DECISION : + if (status > INITIALIZER_STATUS_HELLO) + send_COLOR(INITIALIZER_STATUS_FIRST_DECISION, _from_, firstColor); + break; + + case INITIALIZER_STATUS_LAST_DECISION : + if (status > INITIALIZER_STATUS_FIRST_DECISION) + send_COLOR(INITIALIZER_STATUS_LAST_DECISION, _from_, lastColor); + break; + + } +} + +// +// Restituisce il piu'grande vicino NERO. +// +NodeAddress +INITIALIZER_Agent::greaterCluster() +{ + // Ritorna il vicino clusterHead piu'grande. + NodeAddress max = -1; + for (NodeColor::iterator i = lastColorNeighbors.begin(); i != lastColorNeighbors.end(); i++) { + if (((i->second) == COLOR_BLACK) && ((i->first) > max)) + max = (i->first); + } + return max; +} + +// +// Questa procedura si occupa della valutazione dello stato attuale del nodo +// e della decisione di avanzare di fase. +// La procedura gestisce tutta la logica dell'algoritmo. +// +void +INITIALIZER_Agent::processStatus() +{ + switch (status) { + + case INITIALIZER_STATUS_HELLO : + + // Se un nodo NON ha collezionato tutte le informazioni sui vicini + // allora non avanza di fase + if (nodeNeighbors.size() != neighbors.size()) + return; + + // Hack: se due un nodo fa parte di un insieme completo di due nodi + // diventa allora tutti i nodi sono gateway. + if (neighbors.size() == 1) { + if (nodeNeighbors[*(neighbors.begin())].size() == 1) { + firstColor = COLOR_WHITE; + lastColor = COLOR_WHITE; + endModule(); + return; + } + } + + // Il nodo avanza di fase + status = INITIALIZER_STATUS_FIRST_DECISION; + + // Il nodo decide la sua prima colorazione in base al fatto che due suoi + // vicini siano scollegati oppure no. + firstColor = (twoNeighborsAreUnlinked() ? COLOR_BLACK : COLOR_WHITE); + + // + // Un valore di limit pari a zero oppure con la variazione di stojmenovic + // significa la mancanza di applicazione della regola di decolorazione. + // Pertanto viene saltata la parte di scambio + // di informazioni relative al primo colore e si procede direttamente alla + // comunicazione della colorazione finale. + // + if ((INITIALIZER_Agent::limit != 0) && (INITIALIZER_Agent::stojmenovic != 1)) { + + // Invia l'informazione sul proprio colore ai vicini. + send_COLOR(INITIALIZER_STATUS_FIRST_DECISION, -1, firstColor); + + // Fa partire il timeout sulla ricezione del primo colore da parte dei vicini. + timer->launchFirstDecisionTimeouts(); + } + + case INITIALIZER_STATUS_FIRST_DECISION : + + if ((INITIALIZER_Agent::limit != 0) && (INITIALIZER_Agent::stojmenovic != 1)) { + + // Se un nodo NON ha collezionato tutte le informazioni sulla prima + // colorazione dei vicini allora non avanza di fase + if (firstColorNeighbors.size() != neighbors.size()) + return; + + } + + // + // Simula che tutti i vicini siano neri. + // + if (INITIALIZER_Agent::stojmenovic == 1) { + + for (NodeList::iterator n = neighbors.begin(); n != neighbors.end(); n++) + firstColorNeighbors[*n] = COLOR_BLACK; + + } + + // Il nodo avanza di fase + status = INITIALIZER_STATUS_LAST_DECISION; + + // Imposta il secondo colore. + lastColor = firstColor; + + if (INITIALIZER_Agent::limit != 0) { + + // Applica le regole di decolorazione. + if (lastColor == COLOR_BLACK) { + if (_DEBUG_) + printf("%d e' BLACK: verifica decolorazione\n", myAddress); + + if (checkRule((INITIALIZER_Agent::limit < 0) ? neighbors.size() : INITIALIZER_Agent::limit) == true) + lastColor = COLOR_WHITE; + } + + if (_DEBUG_) + printf("%d E': %s\n", myAddress, (lastColor == COLOR_BLACK) ? "BLACK" : "WHITE"); + } + + // Invia l'informazione sul proprio colore ai vicini. + send_COLOR(INITIALIZER_STATUS_LAST_DECISION, -1, lastColor); + + // Fa partire il timeout sulla ricezione del secondo colore da parte dei vicini. + timer->launchLastDecisionTimeouts(); + + case INITIALIZER_STATUS_LAST_DECISION : + + // Se un nodo NON ha collezionato tutte le informazioni sull'ultima + // colorazione dei vicini allora non avanza di fase + if (lastColorNeighbors.size() != neighbors.size()) + return; + + endModule(); + } +} + +// Verifica che un pacchetto sia di tipo DATA. +bool +INITIALIZER_Agent::isDataPacket(Packet * p) +{ + struct hdr_initializer *initializerh = HDR_INITIALIZER(p); + return (initializerh->msg_type == INITIALIZER_DATA); +} + +// Preparazione all'invio di un messaggio al layer inferiore +void +INITIALIZER_Agent::prepareSendDataDown(Packet * p) +{ + struct hdr_initializer *initializerh = HDR_INITIALIZER(p); + + // Marca il nodo come dato. + initializerh->msg_type = INITIALIZER_DATA; +} + diff -Naur ns-allinone-2.29-old/ns-2.29/clustering/initializer/initializer.h ns-allinone-2.29/ns-2.29/clustering/initializer/initializer.h --- ns-allinone-2.29-old/ns-2.29/clustering/initializer/initializer.h 1970-01-01 01:00:00.000000000 +0100 +++ ns-allinone-2.29/ns-2.29/clustering/initializer/initializer.h 2007-08-03 22:23:31.000000000 +0200 @@ -0,0 +1,237 @@ + +/** + * Copyright (c) 2006 Michele Mastrogiovanni. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#ifndef _INITIALIZER_H_ +#define _INITIALIZER_H_ + +#include + +//////////////////// +// Stato del nodo // +//////////////////// +typedef enum { + INITIALIZER_STATUS_HELLO = 0x1, // Il nodo sta ricevendo informazioni dai vicini. + INITIALIZER_STATUS_FIRST_DECISION = 0x2, // Il nodo si e' colorato la prima volta. + INITIALIZER_STATUS_LAST_DECISION = 0x3, // Il nodo si e' colorato l'ultima volta. + INITIALIZER_STATUS_END = 0x4 // Il nodo ha terminato l'algoritmo di colorazione. +} InitializerStatus; + +////////////////////// +// Tipi di messaggi // +////////////////////// +typedef enum +{ + INITIALIZER_NEIGHBORS = 0x0, // Messaggio per comunicare la propria lista dei vicini. + INITIALIZER_COLOR = 0x1, // Messaggio per comunicare il colore. + INITIALIZER_REQUEST = 0x2, // Messaggio di richiesta di ritrasmissione. + INITIALIZER_DATA = 0x3 // Messaggio di dati. +} InitializerMessageType; + +////////////////////////// +// Header del pacchetto // +////////////////////////// +struct hdr_initializer +{ + + InitializerMessageType msg_type; // Tipo di messaggio. + InitializerStatus status; // Stato del nodo all'invio del messaggio (usato per le ritrasmissioni). + NodeList * node_list; // Lista dei vicini del mittente (solo per messaggio di tipo INITIALIZER_NEIGHBORS). + Color color; // Informazioni sul colore (messaggio INITIALIZER_COLOR). + + //////////////////// + // Accessibilita' // + //////////////////// + static int offset_; + inline static int& offset() { return offset_; } + inline static hdr_initializer* access(const Packet* p) { + return (hdr_initializer*) p->access(offset_); + } +}; + +/////////// +// Timer // +/////////// +class InitializerTimer; + +/////////// +// Agent // +/////////// +class INITIALIZER_Agent : public ClusteringModule +{ +public: + + INITIALIZER_Agent(); + + // Funzione di ricezione dell'algoritmo di clustering. + virtual void receive(Packet * p, Handler * h); + + // Fa partire il modulo. + virtual void startModule(); + + // Termine del lavoro del modulo. + virtual void endModule(); + + // Segnala lo scadere di un timeout per un messaggio. + void timeout(InitializerStatus type, NodeAddress from); + + // Segnala il raggiungimento del massimo numero di timeout per un messaggio. + void lastTimeout(InitializerStatus type, NodeAddress from); + + // Verifica che un pacchetto sia di tipo DATA. + virtual bool isDataPacket(Packet * p); + + // Preparazione all'invio di un messaggio al layer inferiore + virtual void prepareSendDataDown(Packet * p); + +protected: + + Color firstColor; // Primo colore del nodo (memorizzato per le ritrasmissioni). + Color lastColor; // Ultimo colore del nodo (memorizzato per le ritrasmissioni). + InitializerStatus status; // Stato dell'agente. + NodeColor firstColorNeighbors; // Mappa del primo colore dei vicini. + NodeColor lastColorNeighbors; // Mappa dell'ultimo colore dei vicini (e il clusterHead). + NodeNeighbors nodeNeighbors; // Vicini dei vicini. + NodeNeighbors shortNeighbors; // Vicini dei vicini che sono anche vicini del nodo. Il nodo escluso. + InitializerTimer * timer; // Gestore dei timeout. + +protected: + + /////////////// + // Procedure // + /////////////// + + // Gestione della fase di transisione da uno stato all'altro + void processStatus(); + + // Invia la propria lista dei vicini ad un nodo o a tutti. + void send_NEIGHBORS(NodeAddress to); + + // Invia la segnalazione di colore (BIANCO o NERO) per una fase dell'algoritmo. + void send_COLOR(InitializerStatus status, NodeAddress to, Color color); + + // Invia la richiesta di un certo messaggio ad un vicino. + void send_REQUEST(InitializerStatus message, NodeAddress to); + + // Ricezione della lista dei vicini di un vicino. + void receive_NEIGHBORS(NodeAddress from, NodeList & neighbors); + + // Ricezione del colore NERO di un vicino per una fase del protocollo. + void receive_COLOR(NodeAddress from, InitializerStatus status, Color color); + + // Ricezione di una richiesta di ritrasmissione per un messaggio da parte di un vicino. + void receive_REQUEST(NodeAddress from, InitializerStatus message); + + //////////////////// + // Interrogazioni // + //////////////////// + + // Verifica se due vicini del nodo solo NON connessi. + bool twoNeighborsAreUnlinked(); + + // Verifica se il nodo passato come parametro copre tutti i vicini del nodo (REGOLA 1). + bool neighborsCoversMyNeighbors(NodeList & nodes); + + // Verifica la REGOLA sulla base delle lunghezze specificate. + bool checkRule(int max); + + bool neighborsConnected(NodeList & nodes); + + // Crea un vettore di combinazioni. + void makeCombinations(NodeList & elements, Combinations & combinations, NodeList & lengths); + + void printDecoloredMessage(NodeList & nodi); + + // Restituisce il piu'grande vicino NERO. + NodeAddress greaterCluster(); + +public: + + static int degree; // Variante degree. + static int stojmenovic; // Variation Stojmenovic (no second communication phase). + static int _DEBUG_; + static int limit; + static double max_delay; + static int max_timeout_hello; + static double jitter_timeout_hello; + static double timeout_hello; + static int max_timeout_first_decision; + static double jitter_timeout_first_decision; + static double timeout_first_decision; + static int max_timeout_last_decision; + static double jitter_timeout_last_decision; + static double timeout_last_decision; + +}; + +///////////////////////////////// +// Timer per le ritrasmissioni // +///////////////////////////////// +class InitializerTimer: public Handler { +public: + + InitializerTimer(INITIALIZER_Agent * a) : Handler(), agent(a) {} + + void handle(Event* e); + + // Inizializza i timeout di un nodo + void initTimeouts(NodeList & neighbors); + + // Lancia tutti i timeout per i messaggi HELLO. + void launchHelloTimeouts(); + + // Lancia tutti i timeout per i messaggi FIRST DECISION. + void launchFirstDecisionTimeouts(); + + // Lancia tutti i timeout per i messaggi SECOND DECISION. + void launchLastDecisionTimeouts(); + + // Viene segnalata la ricezione di un messaggio di HELLO: si elimina il timeout. + void receivedHello(NodeAddress from); + + // Viene segnalata la ricezione di un messaggio di FIRST DECISION: si elimina il timeout. + void receivedFirstDecision(NodeAddress from); + + // Viene segnalata la ricezione di un messaggio di SECOND DECISION: si elimina il timeout. + void receivedLastDecision(NodeAddress from); + + // Verifica che il timeout sia per il messaggio di HELLO. + bool isHelloTimeout(Event * e); + + // Verifica che il timeout sia per il messaggio di FIRST DECISION. + bool isFirstDecisionTimeout(Event * e); + + // Verifica che il timeout sia per il messaggio di LAST DECISION. + bool isLastDecisionTimeout(Event * e); + +protected: + + // Timeout attivi per i messaggi HELLO. + TimeoutMap hello_timeouts; + + // Timeout attivi per i messaggi FIRST DECISION. + TimeoutMap first_decision_timeouts; + + // Timeout attivi per i messaggi LAST DECISION. + TimeoutMap last_decision_timeouts; + + // Agente proprietario del Timer. + INITIALIZER_Agent * agent; + +}; + +#endif \ No newline at end of file diff -Naur ns-allinone-2.29-old/ns-2.29/clustering/leader/.DS_Store ns-allinone-2.29/ns-2.29/clustering/leader/.DS_Store --- ns-allinone-2.29-old/ns-2.29/clustering/leader/.DS_Store 1970-01-01 01:00:00.000000000 +0100 +++ ns-allinone-2.29/ns-2.29/clustering/leader/.DS_Store 2007-08-03 22:23:30.000000000 +0200 @@ -0,0 +1 @@ +Bud1er.ccIl leader.ccIlocblobZ!˙˙˙˙˙˙leader.hIlocblob!˙˙˙˙˙˙ structure.hIlocblobÂ!˙˙˙˙˙˙  @€ @€ @€ @ EDSDB `€ @€ @€ @ \ No newline at end of file diff -Naur ns-allinone-2.29-old/ns-2.29/clustering/leader/leader.cc ns-allinone-2.29/ns-2.29/clustering/leader/leader.cc --- ns-allinone-2.29-old/ns-2.29/clustering/leader/leader.cc 1970-01-01 01:00:00.000000000 +0100 +++ ns-allinone-2.29/ns-2.29/clustering/leader/leader.cc 2007-08-03 22:23:31.000000000 +0200 @@ -0,0 +1,1858 @@ + +/** + * Copyright (c) 2006 Michele Mastrogiovanni. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#include "leader.h" +#include "Separator.h" + +int hdr_leader::offset_; + +int LEADER_Agent::_DEBUG_; +NodeAddress LEADER_Agent::fake_leader; + + +double LEADER_Agent::max_delay; + +int LEADER_Agent::max_timeout_confirm; +double LEADER_Agent::jitter_timeout_confirm; +double LEADER_Agent::timeout_confirm; + +int LEADER_Agent::max_timeout_info; +double LEADER_Agent::jitter_timeout_info; +double LEADER_Agent::timeout_info; + +int LEADER_Agent::max_timeout_action; +double LEADER_Agent::jitter_timeout_action; +double LEADER_Agent::timeout_action; + +int LEADER_Agent::max_timeout_feedback; +double LEADER_Agent::jitter_timeout_feedback; +double LEADER_Agent::timeout_feedback; + +int LEADER_Agent::max_timeout_leader; +double LEADER_Agent::jitter_timeout_leader; +double LEADER_Agent::timeout_leader; + +static class LeaderHeaderClass : public PacketHeaderClass { +public: + LeaderHeaderClass() : PacketHeaderClass("PacketHeader/LEADER", + sizeof(hdr_leader)) { + bind_offset(&hdr_leader::offset_); + } +} class_leaderhdr; + +static class LeaderClass : public TclClass { +public: + LeaderClass() : TclClass("Agent/LEADER") {} + TclObject* create(int , const char*const* ) { + return(new LEADER_Agent()); + } +} class_leader; + +LEADER_Agent::LEADER_Agent() : ClusteringModule(PT_LEADER) +{ + timer = new LeaderTimer(this); + + bind_bool("debug", &_DEBUG_); + + bind("fake-leader", &fake_leader); + + bind("max-delay", &max_delay); + + bind("max-timeout-confirm", &max_timeout_confirm); + bind("jitter-timeout-confirm", &jitter_timeout_confirm); + bind("timeout-confirm", &timeout_confirm); + + bind("max-timeout-info", &max_timeout_info); + bind("jitter-timeout-info", &jitter_timeout_info); + bind("timeout-info", &timeout_info); + + bind("max-timeout-action", &max_timeout_action); + bind("jitter-timeout-action", &jitter_timeout_action); + bind("timeout-action", &timeout_action); + + bind("max-timeout-feedback", &max_timeout_feedback); + bind("jitter-timeout-feedback", &jitter_timeout_feedback); + bind("timeout-feedback", &timeout_feedback); + + bind("max-timeout-leader", &max_timeout_leader); + bind("jitter-timeout-leader", &jitter_timeout_leader); + bind("timeout-leader", &timeout_leader); +} + +// +// Procedura di inizializzazione delle strutture dati +// della fase di Leader Election. +// +void +LEADER_Agent::initializeLeaderElection() +{ + // Ogni nodo inizialmente e'un candidato + leData.candidate = true; + + // Il frammento di appartenenza del nodo e'costituito dal nodo stesso. + leData.fragment.ID = myAddress; + leData.fragment.size = 1; + + // La struttura ad albero del frammento si limita al solo nodo, + // senza genitore e senza figli. + leData.tree.parent = -1; + leData.tree.childs.clear(); + + // Il nodo e'un nodo "edge" per il suo frammento. + leData.stored_path[0] = -1; + leData.maximal_fragment_node[0] = -1; + leData.maximal_fragment_available[0] = false; + + // L'identita'precedente del frammento di appartenenza e'indefinita. + leData.old_fragment_identity = -1; + + // Svuota i buffer dei messaggi ricevuti + leData.buffer_info.clear(); + leData.buffer_feedback.clear(); + leData.buffer_action.clear(); + + // Svuota i buffer dei messaggi inviati + leData.stored_messages.info.clear(); + leData.stored_messages.feedback.clear(); + + // Imposta il numero di round. + leData.round = 0; + + for (NodeList::iterator n = neighbors.begin(); n != neighbors.end(); n++) + leData.levels[*n] = -1; + + // Svuota l'elenco dei nodi ai quali deve confermare. + leData.confirmation_nodes_info.clear(); +} + +// +// Funzione di ricezione di un pacchetto di clustering. +// +void +LEADER_Agent::receive(Packet *p, Handler *h) +{ + struct hdr_leader *leaderh = HDR_LEADER(p); + struct hdr_ip *iph = HDR_IP(p); + + NodeAddress sender_address = iph->saddr(); + // Destinazione. + NodeAddress destination_address = iph->daddr(); + + bool result; + + switch (leaderh->msg_type) { + + case LEADER_INFO : + + // NUOVO CONFIRM: da modificare: + send_CONFIRM(sender_address, leaderh->info_message.round, LEADER_INFO, true); + + // Se l'algoritmo e'terminato si ignora il messaggio + if (status == LEADER_STATUS_END) + return; + + // + // Se non sono nella fase di ricezione dei messaggi di INFO, + // metto nel buffer il messaggio di INFO. + // + if (status != LEADER_STATUS_INFO) { + leData.buffer_info.push_back(pair(sender_address, leaderh->info_message)); + return; + } + + // Riceve il messaggio + recvInfoMessage(sender_address, leaderh->info_message); + + break; + + case LEADER_FEEDBACK : + + // Invia un messaggio di conferma. + send_CONFIRM(sender_address, leaderh->feedback_message.round, LEADER_FEEDBACK, true); + + // Se l'algoritmo e'terminato si ignora il messaggio + if (status == LEADER_STATUS_END) + return; + + // + // Se il messaggio è passato, viene ignorato. + // + if (leaderh->feedback_message.round < leData.round) + return; + + // + // Se non sono nella fase di ricezione dei messaggi di FEEDBACK, + // metto nel buffer il messaggio di FEEDBACK. + // + if (status != LEADER_STATUS_FEEDBACK) { + leData.buffer_feedback.push_back(pair(sender_address, leaderh->feedback_message)); + return; + } + + // Riceve il messaggio + recvFeedbackMessage(sender_address, leaderh->feedback_message); + + break; + + case LEADER_ACTION : + // Conferma la ricezione + send_CONFIRM(sender_address, leaderh->action_message.round, LEADER_ACTION, false); + + // Se il messaggio e'passato lo ignora. + if (leaderh->action_message.round < leData.round) + return; + + // Solo se si trova nella fase di INFO puo'ricevere messaggi di ACTION. + if (status != LEADER_STATUS_INFO) + return; + + // Se il messaggio e'gia'stato ricevuto viene scartato + if (leData.action_for_round[leData.round]) + return; + + // Riceve il messaggio di ACTION. + receive_ACTION(sender_address, leaderh->action_message); + break; + + case LEADER_LEADER : + + // Se il messaggio e' UNICAST allora puo'essere o una ritrasmissione + // oppure una risposta ad una ritrasmissione. + if (destination_address == myAddress) + // Se desidera che confermi il messaggio. + if (leaderh->leader_message.confirm) + // Invio nuovamente il mio messaggio di LEADER per conferma + // (se la fase e'la leader election o una successiva). + switch (status) { + case LEADER_STATUS_LEADER : + + case LEADER_STATUS_END : send_LEADER(leData.leader, + leData.tree_size, + leData.parent, + leData.level, + false, + sender_address); + break; + } + + // Se l'algoritmo e'terminato si ignora il messaggio + switch (status) { + case LEADER_STATUS_END : return; + default : break; + } + + // Se il nodo mi ha gia'inviato un messaggio LEADER. + if (status == LEADER_STATUS_LEADER) + if (leData.leader_messages.find(sender_address) == leData.leader_messages.end()) + return; + + receive_LEADER(sender_address, leaderh->leader_message, destination_address); + + break; + + case LEADER_REQUEST : + + receive_REQUEST(sender_address, leaderh->request_message); + + break; + + case LEADER_CONFIRM : + + receive_CONFIRM(sender_address, leaderh->confirm_message); + + break; + + } +} + +/********************/ +/* Messages */ +/********************/ + +// +// Funzione per inviare un nuovo messaggio di INFO. +// Fa partire i timeout per le conferme. +// +void +LEADER_Agent::send_INFO(NodeAddress fragment_identity, + NodeAddress new_fragment_identity, + int new_fragment_size, + NodeAddress parent) +{ + if (_DEBUG_) + printf("\t\t%d __send__ INFO (ID=%d, NEW_ID=%d, SIZE=%d, PARENT=%d, ROUND=%d, FROM=%d)\n", myAddress, + fragment_identity, new_fragment_identity, new_fragment_size, parent, leData.round, -1); + + // Invia il messaggio di INFO. + send_INFO(fragment_identity, new_fragment_identity, new_fragment_size, parent, leData.round, -1); + + // Lancia i timeout verso i nodi che devono ancora inviare messaggi di INFO. + // Puo'succedere che un nodo invii il proprio INFO dopo aver ricevuto alcuni messaggi di INFO. + // La variabile leData.info_messages indica il numero di vicini che devono ancora inviare messaggi di INFO + // per quel round. + + timer->launchInfoTimeouts(neighbors, leData.round); + + /* + if (!leData.info_messages.empty()) + timer->launchInfoTimeouts(leData.info_messages); + */ +} + +void +LEADER_Agent::send_INFO(NodeAddress fragment_identity, + NodeAddress new_fragment_identity, + int new_fragment_size, + NodeAddress parent, + int round, + NodeAddress to) +{ + Packet* p = allocpkt(); + struct hdr_leader * leaderh = HDR_LEADER(p); + + // Strutture comuni. + leaderh->msg_type = LEADER_INFO; + + // Imposta il contenuto del messaggio. + leaderh->info_message.fragment.ID = fragment_identity; + leaderh->info_message.new_fragment.ID = new_fragment_identity; + leaderh->info_message.new_fragment.size = new_fragment_size; + leaderh->info_message.parent = parent; + leaderh->info_message.round = round; + + // Calcola la dimensione del messaggio. + size_t size = sizeof(InfoMessage) + sizeof(LeaderMessageType); + + // Se sto inviando un messaggio di INFO mai inviato... + if (!isInfoInBuffer(round)) { + + // Lancia i timeout verso tutti i nodi che devono confermarmi + // l'arrivo del messaggio che sto per inviare. + // timer->launchConfirmation(round); + + // Memorizza il messaggio da inviare. + leData.stored_messages.info[round] = leaderh->info_message; + } + + // Invia il messaggio. + sendDown(p, size, to, LEADER_Agent::max_delay); + + /* + InfoMessage info = leaderh->info_message; + if (_DEBUG_) + printf("\t\t%d send INFO (ID=%d, NEW_ID=%d, SIZE=%d, PARENT=%d, ROUND=%d, TO=%d)\n", myAddress, + info.fragment.ID, info.new_fragment.ID, info.new_fragment.size, info.parent, info.round, to); + */ +} + +void +LEADER_Agent::send_FEEDBACK(NodeAddress to, + NodeAddress fragment_identity, + bool internal_flag, + NodeAddress maximal_fragment_identity, + int maximal_fragment_size, + int node_count) +{ + if (_DEBUG_) + printf("\t\t%d __send__ FEEDBACK (TO=%d, COUNT=%d, ROUND=%d)\n", myAddress, to, node_count, leData.round); + + send_FEEDBACK(to, fragment_identity, internal_flag, maximal_fragment_identity, maximal_fragment_size, node_count, leData.round); +} + +void +LEADER_Agent::send_FEEDBACK(NodeAddress to, + NodeAddress fragment_identity, + bool internal_flag, + NodeAddress maximal_fragment_identity, + int maximal_fragment_size, + int node_count, + int round) +{ + Packet* p = allocpkt(); + struct hdr_leader * leaderh = HDR_LEADER(p); + + // Common structure + leaderh->msg_type = LEADER_FEEDBACK; + + // Message + leaderh->feedback_message.fragment.ID = fragment_identity; + leaderh->feedback_message.maximal_fragment_available = internal_flag; + leaderh->feedback_message.maximal_fragment.ID = maximal_fragment_identity; + leaderh->feedback_message.maximal_fragment.size = maximal_fragment_size; + leaderh->feedback_message.node_count = node_count; + leaderh->feedback_message.round = round; + + + // Record message. + leData.stored_messages.feedback[round] = leaderh->feedback_message; + + size_t size = sizeof(FeedbackMessage) + sizeof(LeaderMessageType); + + // Invia il messaggio. + sendDown(p, size, to, LEADER_Agent::max_delay); + +} + +void +LEADER_Agent::send_LEADER(NodeAddress leader, + int fragment_size, + NodeAddress parent, + int level, + bool confirm, + NodeAddress to) +{ + Packet* p = allocpkt(); + struct hdr_leader * leaderh = HDR_LEADER(p); + + // Common structures. + leaderh->msg_type = LEADER_LEADER; + + // Message + leaderh->leader_message.leader.ID = leader; + leaderh->leader_message.leader.size = fragment_size; + leaderh->leader_message.parent = parent; + leaderh->leader_message.level = level; + leaderh->leader_message.confirm = confirm; + + size_t size = sizeof(LeaderMessage) + sizeof(LeaderMessageType); + + // Invia il messaggio. + sendDown(p, size, to, LEADER_Agent::max_delay); +} + +// +// Invia la conferma di ricezione per un certo messaggio di un certo round. +// Il messaggio viene utilizzato per confermare i messaggi di INFO, di FEEDBACK e di ACTION. +// Il flag "send" serve per indicare se la conferma fa parte di un invio o di una risposta. +// +void +LEADER_Agent::send_CONFIRM(NodeAddress to, int round, LeaderMessageType type, bool send) +{ + Packet* p = allocpkt(); + struct hdr_leader * leaderh = HDR_LEADER(p); + + // Common structures. + leaderh->msg_type = LEADER_CONFIRM; + + // Message. + leaderh->confirm_message.send = send; + leaderh->confirm_message.round = round; + leaderh->confirm_message.type = type; + + size_t size = sizeof(ConfirmMessage) + sizeof(LeaderMessageType); + + // Invia il messaggio. + sendDown(p, size, to, LEADER_Agent::max_delay); +} + +void +LEADER_Agent::send_ACTION(NodeAddress fragment_identity, NodeAddress to) +{ + // Invia il messaggio + send_ACTION(fragment_identity, to, leData.round); + + // Memorizza il messaggio lanciato + leData.buffer_action[leData.round] = pair(fragment_identity, to); + + // Fa partire il timeout. + timer->launchActionTimeouts(to, leData.round); +} + +void +LEADER_Agent::send_ACTION(NodeAddress fragment_identity, NodeAddress to, int round) +{ + Packet* p = allocpkt(); + struct hdr_leader * leaderh = HDR_LEADER(p); + + // Common structures. + leaderh->msg_type = LEADER_ACTION; + + // Message. + leaderh->action_message.current_fragment.ID = fragment_identity; + leaderh->action_message.round = round; + + size_t size = sizeof(ActionMessage) + sizeof(LeaderMessageType); + + // Invia il messaggio. + sendDown(p, size, to, LEADER_Agent::max_delay); +} + +void +LEADER_Agent::send_REQUEST(NodeAddress to, LeaderMessageType type, int round) +{ + Packet* p = allocpkt(); + struct hdr_leader * leaderh = HDR_LEADER(p); + + // Common structures. + leaderh->msg_type = LEADER_REQUEST; + + // Message + leaderh->request_message.type = type; + leaderh->request_message.round = round; + + size_t size = sizeof(RequestMessage) + sizeof(LeaderMessageType); + + // Invia il messaggio. + sendDown(p, size, to, LEADER_Agent::max_delay); +} + +/****************************/ +/* Utility. */ +/****************************/ + +void +LEADER_Agent::emptyInfoBuffer() +{ + // + // Effettua una copia di backup del buffer in modo che eventuali nuove bufferizzazioni + // non corrompano il processo di svuotamento. + // + list > tmp(leData.buffer_info); + + // Svuota il buffer. + leData.buffer_info.clear(); + + // Effettua la ricezione di tutti i messaggi bufferizzati. + for (list >::iterator i = tmp.begin(); i != tmp.end(); i++) { + if (_DEBUG_) + printf("\tFROM BUFFER\n"); + recvInfoMessage(i->first, i->second); + } +} + +void +LEADER_Agent::emptyFeedbackBuffer() +{ + // + // Effettua una copia di backup del buffer in modo che eventuali nuove bufferizzazioni + // non corrompano il processo di svuotamento. + // + list > tmp(leData.buffer_feedback); + + // Svuota il buffer. + leData.buffer_feedback.clear(); + + // Effettua la ricezione di tutti i messaggi bufferizzati. + for (list >::iterator i = tmp.begin(); i != tmp.end(); i++) { + if (_DEBUG_) + printf("\tFROM BUFFER\n"); + recvFeedbackMessage(i->first, i->second); + } +} + +/****************************/ +/* Algorithm procedures and +/* events. +/****************************/ + +void +LEADER_Agent::endModule() +{ + if (_DEBUG_) + printf("%d FINITO: leader = %d, nodi = %d\n", myAddress, leData.leader, leData.tree_size); + + // Entra nello stato finale. + status = LEADER_STATUS_END; + + if (utility) + if (leData.leader == myAddress) + ((LeaderUtility*)utility)->setLeader(myAddress); + + // Segnala la conclusione del processo di clustering. + ClusteringModule::endModule(); + + // Start upper module + if (upTarget) + Separator::instance().endCurrentModule(myAddress); +} + +// +// Inizia il processo di leader election. +// +void +LEADER_Agent::startModule() +{ + // Inizializza le informazioni comuni del clustering. + ClusteringModule::startModule(); + + if (_DEBUG_) { + printf("%d neighbors: ", myAddress); + for (NodeList::iterator n = neighbors.begin(); n != neighbors.end(); n++) + printf("%d ", *n); + printf("\n"); + } + + status = LEADER_STATUS_INIT; + + // Inizializza le strutture necessarie. + initializeLeaderElection(); + + if (fake_leader != -1) { + if (fake_leader == myAddress) { + beginLeaderPropagation(); + } + else { + } + } + else { + // Il nodo invia informazioni sul suo stato. + send_INFO(leData.fragment.ID, leData.fragment.ID, 1, -1); + + // Il nodo inizia un ciclo di INFO. + init_INFO_cycle(); + } +} + +// +// Procedura di gestione dei messaggi di INFO. +// Questa procedura viene chiamata con le seguenti assunzioni: +// 1) In ogni round ogni vicino invia uno e un solo messaggio di INFO. +// 2) Tutti i vicini inviano quel messaggio. +// 3) Non vengono ricevuti altri messaggi prima di aver ricevuto ogni messaggio di INFO per quel round. +// +void +LEADER_Agent::receive_INFO(NodeAddress from, struct InfoMessage info) +{ + if (_DEBUG_) + printf("%d receive INFO (ID=%d, NEW_ID=%d, SIZE=%d, PARENT=%d, ROUND=%d, FROM=%d)\n", myAddress, + info.fragment.ID, info.new_fragment.ID, info.new_fragment.size, info.parent, info.round, from); + + // Elimina il timeout del messaggio di INFO. + // timer->cancelInfo(from, .seq); + + // Elimina il nodo dalla lista di coloro che devono inviare un messaggio INFO. + leData.info_messages.erase(from); + + // FIXME: + // Se il messaggio di questo round proviene dal vicino che nel round + // precedente e'stato il "maximal_fragment_node", memorizza il messaggio proveniente + // da questo nodo nel caso il messaggio di ACTION giunga al nodo dopo il messaggio di INFO. + // Questo fenomeno puo'accadere solo ai nodi che hanno come "stored_path" in quel round -1 + // (e quindi erano degli "edge_node"). + if (leData.round != 0) + if (leData.stored_path[leData.round - 1] == -1) + if (leData.maximal_fragment_node[leData.round - 1] == from) + leData.maximal_fragment_node_info_message[leData.round] = info; + + if (belongToAnotherFragment(from, info)) { + // Il mittente appartiene ad un frammento differente: + // Aggiorna la conoscenza del vicino massimale. + updateMaximalFragment(from, info); + if (_DEBUG_) + if (leData.maximal_fragment_available[leData.round]) + printf("\t%d [MAXID=%d, SIZE=%d, PATH=%d, NODE=%d]\n", myAddress, + leData.maximal_fragment[leData.round].ID, + leData.maximal_fragment[leData.round].size, + leData.stored_path[leData.round], + leData.maximal_fragment_node[leData.round]); + } + else { + // Il mittente appartiene allo stesso frammento. + + if (leData.tree.parent != -1) { + // Il nodo conosce il suo genitore. + if (leData.tree.parent == from) { + // Il nodo genitore ha inviato il messaggio di INFO. + if (!isInfoInBuffer(info.round)) { + // Il nodo non aveva ancora mai inviato il messaggio di INFO per + // questo round: il nodo nel round precendente si e'legato al frammento di + // quel nodo tramite esso. + // La vecchia identita'del nodo e'gia'impostata correttamente. + // La nuova identita'viene agggiornata per quanto riguarda la dimensione del + // frammento. + // Il nodo edge legato invia un messaggio di INFO con la dimensione dettatagli + // dal frammento a cui e'legato. + leData.fragment = info.new_fragment; + send_INFO(leData.old_fragment_identity, + leData.fragment.ID, + leData.fragment.size, + from); + } + else { + // Il genitore mi sta inviando un messaggio duplicato: + // lo scarto ma, viste le ipotesi, questa parte non verra'mai + // chiamata. + } + } + else { + // Un nodo mio vicino dello stesso frammento ha inviato un messaggio di INFO. + if (info.parent == myAddress) { + // Il nodo ha impostato il nodo corrente come genitore: + // imposto il nodo mittente come figlio. + leData.tree.childs.insert(from); + if (_DEBUG_) + printf("\t\t%d ADD CHILD %d\n", myAddress, from); + } + else { + // Il messaggio proviene da un nodo vicino, dello stesso + // frammento ma che non mi ha scelto come genitore. + // printf("ERROR\n"); + } + } + } + else { + if (leData.candidate) { + if (info.parent == myAddress) { + // Il nodo ha impostato il nodo corrente come genitore: + // imposto il nodo mittente come figlio. + leData.tree.childs.insert(from); + if (_DEBUG_) + printf("\t\t%d ADD CHILD %d\n", myAddress, from); + } + else { + // Il nodo appartiene allo stesso frammento ma non sta inviando informazioni + // diretamente al nodo corrente. + // Ignora. + } + } + else { + if (info.parent == myAddress) { + // Errore: un nodo non puo'ricevere un messaggio da un + // figlio se prima non conosce il padre. + } + else { + // Se il nodo non e'candidato allora vuol dire che non conosce ancora il suo genitore: + // Ricevuto il messaggio di INFO lo propaga. + leData.tree.parent = from; + leData.old_fragment_identity = leData.fragment.ID; + leData.fragment = info.new_fragment; + send_INFO(leData.old_fragment_identity, + leData.fragment.ID, + leData.fragment.size, + from); + } + } + } + } + + if (!leData.info_messages.empty()) + return; + + // Ho ricevuto il messaggio di info da tutti i miei vicini + // (e ho inviato il mio messaggio per questo round). + // Comincia il ciclo di feedback + + init_FEEDBACK_cycle(); +} + +// +// La funzione inizializza un ciclo di FEEDBACK: +// +void +LEADER_Agent::init_FEEDBACK_cycle() +{ + if (_DEBUG_) + printf("%d BEGIN FEEDBACK CYCLE\n", myAddress); + + // Imposta lo stato che caratterizza il ciclo di FEEDBACK. + status = LEADER_STATUS_FEEDBACK; + + // Imposta la lista dei vicini che devono inviare un messaggio di FEEDBACK + // ovvero tutti i figli del nodo nello stesso frammento. + leData.feedback_messages = leData.tree.childs; + + // Imposta a zero la conoscenza della grandezza del frammento. + leData.sub_tree_partial_count = 0; + + // + // Effettua i calcoli per avanzare di fase. + // Necessario nel caso in cui non si abbiano nodi figli. + // + if (leData.feedback_messages.empty()) { + processLEStatus(); + return; + } + + // Svuota il buffer dei messaggi FEEDBACK. + emptyFeedbackBuffer(); + + +} + +// +// Questa funzione viene lanciata dopo aver inviato il messaggio di INFO per un round: +// prepara le strutture di dati per poter ricevere i messaggi di INFO da tutti i vicini. +// I timeout verso i nodi che non hanno ancora risposto vanno inviati dopo l'invio del +// messaggio di INFO. +// +void +LEADER_Agent::init_INFO_cycle(bool initialize) { + if (_DEBUG_) + printf("%d BEGIN INFO CYCLE\n", myAddress); + + // Imposta lo stato che caratterizza il ciclo di ricezione di INFO. + status = LEADER_STATUS_INFO; + + // Imposta la lista dei vicini che devono ancora mandare messaggi di INFO. + leData.info_messages = neighbors; + + // Resetta la conoscenza di frammenti vicini massimali. + leData.maximal_fragment_available[leData.round] = false; + + // Resetta la conoscenza di frammenti vicini massimali. + leData.maximal_fragment_node[leData.round] = -1; + + // Imposta a zero la conoscenza della struttura del frammento. + // Il genitore va resettato solo se non e'stato ricevuto un messaggio di ACTION. + if (initialize) + leData.tree.parent = -1; + + leData.tree.childs.clear(); + + // Svuota il buffer dei messaggi INFO. + emptyInfoBuffer(); +} + +// +// Questa funzione viene lanciata dopo aver inviato il messaggio di INFO per un round: +// prepara le strutture di dati per poter ricevere i messaggi di INFO da tutti i vicini. +// I timeout verso i nodi che non hanno ancora risposto vanno inviati dopo l'invio del +// messaggio di INFO. +// +void +LEADER_Agent::init_LEADER_cycle() { + // Imposta lo stato che caratterizza il ciclo di ricezione di INFO. + status = LEADER_STATUS_LEADER; + + // Imposta la lista dei vicini che devono ancora mandare messaggi di INFO. + leData.leader_messages = neighbors; + + // Imposta a zero la conoscenza della struttura del frammento + leData.parent = -1; + leData.tree_size = 0; + leData.level = 0; + leData.leader = myAddress; +} + +void +LEADER_Agent::receive_FEEDBACK(NodeAddress from, struct FeedbackMessage feedback) +{ + if (_DEBUG_) + printf("%d receive FEEDBACK (FROM=%d, MAX=%d, SIZE=%d, ROUND=%d)\n", myAddress, from, feedback.maximal_fragment.ID, feedback.maximal_fragment.size, feedback.round); + // Elimina il nodo dalla lista di coloro che devono inviare un messaggio FEEDBACK. + leData.feedback_messages.erase(from); + + // Aggiorna il conteggio del frammento corrente + leData.sub_tree_partial_count += feedback.node_count; + + // Aggiorna la situazione sul frammento massimale. + updateMaximalFragment(from, feedback); + if (_DEBUG_) + if (leData.maximal_fragment_available[leData.round]) + printf("\t%d [MAXID=%d, SIZE=%d, PATH=%d, NODE=%d]\n", myAddress, leData.maximal_fragment[leData.round].ID, + leData.maximal_fragment[leData.round].size, leData.stored_path[leData.round], leData.maximal_fragment_node[leData.round]); + + if (!leData.feedback_messages.empty()) + return; + + // Sono giunti tutti i messaggi di FEEDBACK: si decide lo stato del nodo. + processLEStatus(); +} + +// +// Gestione dei messaggi di REQUEST +// +void +LEADER_Agent::receive_REQUEST(NodeAddress from, struct RequestMessage rm) +{ + struct InfoMessage im; + struct FeedbackMessage fm; + + switch (rm.type) { + /* + case LEADER_INFO : + // Viene richiesto un messaggio di INFO ma il nodo non lo ha ancora + // inviato. + // Quando sara'in grado di mandarlo lo inviera'e si aspettera' + // la ricevuta di ritorno. + if (!isInfoInBuffer(rm.round)) { + timer->addConfirmation(from, rm.round); + send_CONFIRM(from, rm.round, LEADER_INFO, true); + return; + } + + // + // Il messaggio è in mio possesso: lo invio senza richiedere la conferma. + // + for (BufferInfoMessages::iterator i = leData.stored_messages.info.begin(); + i != leData.stored_messages.info.end(); + i++) { + + if (i->first == rm.round) { + im = i->second; + + send_INFO(im.fragment.ID, + im.new_fragment.ID, + im.new_fragment.size, + im.parent, + im.round, + from); + + } + } + break; + */ + } +} + +void +LEADER_Agent::receive_CONFIRM(NodeAddress from, struct ConfirmMessage cm) +{ + switch (cm.type) { + case LEADER_INFO : + if (_DEBUG_) + printf("%d receive CONFIRM (INFO) from %d (ROUND=%d)\n", myAddress, from, cm.round); + // Nuovo CONFIRM: da modificare: + timer->cancelInfo(from, cm.round); + + /* + if (cm.send) { + timer->cancelInfo(from); + leData.confirmation_nodes_info[cm.round].insert(from); + } + else + timer->cancelConfirmation(from, cm.round); + */ + + break; + + case LEADER_FEEDBACK : + if (_DEBUG_) + printf("%d receive CONFIRM (FEEDBACK) from %d\n", myAddress, from); + timer->cancelFeedback(from, cm.round); + + break; + + case LEADER_ACTION : + timer->cancelAction(from, cm.round); + break; + + } +} + +// +// Procedura di gestione del messaggio ACTION. +// +void +LEADER_Agent::receive_ACTION(NodeAddress from, struct ActionMessage action) +{ + if (_DEBUG_) + printf("%d receive ACTION (FROM=%d)\n", myAddress, from); + + // Azzera l'identita'del nuovo frammento a cui legarsi. + leData.action_for_round[leData.round] = true; + + // Il nodo non e'piu'candidato + leData.candidate = false; + + // + // Se lo stored path non e'impostato, il nodo e'di tipo edge e deve legarsi + // al frammento massimale precedentemente calcolato. + // + // FIXME: non sono sicuro se ci va il -1 + if (leData.stored_path[leData.round - 1] == -1) { + // Imposta il genitore + + // FIXME insieme a quello a processLEStatus + // leData.old_fragment_identity = leData.fragment.ID; + + // FIXME: Non sono sicuro se ci deve stare il -1 + leData.tree.parent = leData.maximal_fragment_node[leData.round - 1]; + leData.fragment.ID = leData.maximal_fragment[leData.round - 1].ID; + + if (_DEBUG_) + printf("%d JOIN to %d\n", myAddress, leData.maximal_fragment_node[leData.round - 1]); + + // + // Se il messaggio di INFO da parte del genitore a cui un "edge_node" + // si e'legato e'stato ricevuto prima dell'arrivo del messaggio di ACTION, + // da parte del candidato per il proprio frammento, + // viene simulata la ricezione. + // Il criterio non si applica al round 0. + // + // if (leData.round != 0) { + if (leData.maximal_fragment_node_info_message[leData.round].round != -1) + if (!isInfoInBuffer(leData.round)) { + // Il nodo non aveva ancora mai inviato il messaggio di INFO per + // questo round: il nodo nel round precendente si e'legato al frammento di + // quel nodo tramite esso. + // La vecchia identita'del nodo e'gia'impostata correttamente. + // La nuova identita'viene agggiornata per quanto riguarda la dimensione del + // frammento. + // Il nodo edge legato invia un messaggio di INFO con la dimensione dettatagli + // dal frammento a cui e'legato. + leData.fragment = leData.maximal_fragment_node_info_message[leData.round].new_fragment; + send_INFO(leData.old_fragment_identity, + leData.fragment.ID, + leData.fragment.size, + leData.stored_path[leData.round - 1]); + } + // } + } + else { + // Se il nodo che riceve il messaggio di ACTION + // lo deve propagare allora non deve memorizzare il genitore. + leData.tree.parent = -1; + send_ACTION (leData.fragment.ID, leData.stored_path[leData.round - 1]); + // leData.stored_path = -1; + } +} + +// +// Procedura di gestione dei messaggi LEADER: +// +void +LEADER_Agent::receive_LEADER(NodeAddress from, struct LeaderMessage lm, NodeAddress to) +{ + if (_DEBUG_) + printf("%d receive LEADER (FROM=%d, PARENT=%d, SIZE=%d, LEVEL=%d)\n", myAddress, from, lm.parent, lm.leader.size, lm.level); + + // + // Se il nodo e'gia'in fase di leader election. + // + if (status == LEADER_STATUS_LEADER) { + + // Elimina il timeout del messaggio LEADER. + timer->cancelLeader(from); + + // Elimina il nodo dalla lista di coloro che devono inviare un messaggio INFO. + leData.leader_messages.erase(from); + + // Memorizza il livello del vicino. + leData.levels[from] = lm.level; + + // Il mittente imposta il nodo come genitore. + + if (lm.parent == myAddress) + // Aggiorna la lista dei figli. + leData.childs.insert(from); + } + else { + // Il nodo riceve il primo messaggio di LEADER: imposta lo stato + status = LEADER_STATUS_LEADER; + + // Memorizza il livello del vicino. + leData.levels[from] = lm.level; + + // Forza a non essere candidato: FIXME + leData.candidate = false; + + // Imposta la lista dei vicini dai quali deve ricevere messaggi di Leader. + leData.leader_messages = neighbors; + leData.leader_messages.erase(from); + + // Genitore + leData.parent = from; + // Numero di nodi della topologia. + leData.tree_size = lm.leader.size; + // Livello nell'albero + leData.level = lm.level + 1; + // Leader. + leData.leader = lm.leader.ID; + // Childs + leData.childs.clear(); + + // Invia il messaggio di LEADER. + send_LEADER(leData.leader, leData.tree_size, leData.parent, leData.level); + + // Inizializza i timeout verso i vicini restanti (escluso il genitore) + timer->launchLeaderTimeouts(leData.leader_messages); + } + + if (!leData.leader_messages.empty()) + return; + + // End Procedure. + endModule(); +} + +// +// Questa procedura viene chiamata al termine del ciclo di FEEDBACK: +// il nodo, se non e'leader propaga l'informazione sui frammenti massimali adiacenti +// al proprio genitore; se e'leader decide la sorte del frammento (legarsi al frammento +// vicino massimale oppure no). +// +void +LEADER_Agent::processLEStatus() +{ + if (_DEBUG_) + printf("%d -- PROCESS --\n", myAddress); + + int X = 2; + + // + // Per il primo round, ogni nodo che sia il piu'piccolo del suo vicinato, + // si lega al piu'grande vicino. Tutti gli altri rimangono leader. + // + if (leData.round == 0) { + if (_DEBUG_) + printf("%d (SIZE=%d == MAX=%d)\n", myAddress, leData.fragment.size, leData.maximal_fragment[leData.round].size); + + NodeAddress minimo = *min_element(neighbors.begin(), neighbors.end()); + if (myAddress < minimo) { + // Il nodo si lega al nodo massimo. + + // Se la grandezza del frammento corrente e'minore al frammento + // vicino massimale, allora il frammento si lega al frammento massimale. + + if (utility) + ((LeaderUtility*)utility)->addJoin(leData.fragment.ID, leData.maximal_fragment[leData.round].ID); + + // Avanza di round. + leData.round++; + + // Memorizza un messaggio nullo. + struct InfoMessage im; + im.round = -1; + leData.maximal_fragment_node_info_message[leData.round] = im; + leData.action_for_round[leData.round] = false; + + // Invia il messaggio di ACTION. + struct ActionMessage am; + am.current_fragment = leData.fragment; + receive_ACTION(myAddress, am); + + // Inizia un nuovo ciclo di ricezione dei messaggi INFO. + init_INFO_cycle(false); + + return; + } + else { + // Rimane leader + if (_DEBUG_) + printf("%d rimane LEADER\n", myAddress); + + // Avanza di round. + leData.round++; + + // Memorizza un messaggio nullo. + struct InfoMessage im; + im.round = -1; + leData.maximal_fragment_node_info_message[leData.round] = im; + leData.action_for_round[leData.round] = false; + + // Invia il nuovo messaggio di INFO. + leData.old_fragment_identity = leData.fragment.ID; + send_INFO(leData.fragment.ID, leData.fragment.ID, leData.fragment.size, -1); + + // Inizia un nuovo ciclo di ricezione dei messaggi INFO. + init_INFO_cycle(); + + return; + } + } + + if (leData.candidate) { + // Il nodo e'un candidato + + // Aggiorna la descrizione del frammento. + leData.fragment.size = leData.sub_tree_partial_count + 1; + + if (!leData.maximal_fragment_available[leData.round]) { + + if (_DEBUG_) + printf("\t\t\t%d e'il LEADER\n", myAddress); + + beginLeaderPropagation(); + + return; + } + + if (leData.fragment.size >= X * leData.maximal_fragment[leData.round].size) { + if (_DEBUG_) + printf("%d (SIZE=%d > MAX=%d)\n", myAddress, leData.fragment.size, leData.maximal_fragment[leData.round].size); + // Se la grandezza del frammento corrente e'maggiore o uguale al frammento + // vicino massimale, allora il nodo rimane candidato. + + if (_DEBUG_) + printf("%d rimane LEADER\n", myAddress); + + // Avanza di round. + leData.round++; + + // Memorizza un messaggio nullo. + struct InfoMessage im; + im.round = -1; + leData.maximal_fragment_node_info_message[leData.round] = im; + leData.action_for_round[leData.round] = false; + + // Invia il nuovo messaggio di INFO. + leData.old_fragment_identity = leData.fragment.ID; + send_INFO(leData.fragment.ID, leData.fragment.ID, leData.fragment.size, -1); + + // Inizia un nuovo ciclo di ricezione dei messaggi INFO. + init_INFO_cycle(); + + return; + } + else if (leData.fragment < leData.maximal_fragment[leData.round]) { + if (_DEBUG_) + printf("%d (SIZE=%d < MAX=%d)\n", myAddress, leData.fragment.size, leData.maximal_fragment[leData.round].size); + + // Se la grandezza del frammento corrente e'minore al frammento + // vicino massimale, allora il frammento si lega al frammento massimale. + + if (utility) + ((LeaderUtility*)utility)->addJoin(leData.fragment.ID, leData.maximal_fragment[leData.round].ID); + + // Avanza di round. + leData.round++; + + // Memorizza un messaggio nullo. + struct InfoMessage im; + im.round = -1; + leData.maximal_fragment_node_info_message[leData.round] = im; + leData.action_for_round[leData.round] = false; + + // Propaga un messaggio di ACTION verso il nodo di JOIN + struct ActionMessage am; + am.current_fragment = leData.fragment; + am.round = leData.round; + receive_ACTION(myAddress, am); + + // Inizia un nuovo ciclo di ricezione dei messaggi INFO. + init_INFO_cycle(false); + + return; + } + else { + if (_DEBUG_) + printf("%d (MAX=%d <= SIZE=%d <= X*MAX )\n", myAddress, leData.maximal_fragment[leData.round].size, leData.fragment.size); + + // In tutti gli altri casi il frammento rimane candidato. + if (_DEBUG_) + printf("%d rimane LEADER\n", myAddress); + + // Avanza di round. + leData.round++; + + // Memorizza un messaggio nullo. + struct InfoMessage im; + im.round = -1; + leData.maximal_fragment_node_info_message[leData.round] = im; + leData.action_for_round[leData.round] = false; + + // Invia il nuovo messaggio di INFO. + leData.old_fragment_identity = leData.fragment.ID; + send_INFO(leData.fragment.ID, leData.fragment.ID, leData.fragment.size, -1); + + // Inizia un nuovo ciclo di ricezione dei messaggi INFO. + init_INFO_cycle(); + + return; + } + } + else { + // Il nodo non e'candidato invia al genitore le informazioni + // sul frammento adiacente massimale. + send_FEEDBACK (leData.tree.parent, + leData.fragment.ID, + leData.maximal_fragment_available[leData.round], + leData.maximal_fragment[leData.round].ID, + leData.maximal_fragment[leData.round].size, + leData.sub_tree_partial_count + 1); + + timer->launchFeedbackTimeouts(leData.tree.parent, leData.round); + + // Avanza di round. + leData.round++; + + // Memorizza un messaggio nullo. + struct InfoMessage im; + im.round = -1; + leData.maximal_fragment_node_info_message[leData.round] = im; + leData.action_for_round[leData.round] = false; + + // Inizia un nuovo ciclo di ricezione dei messaggi INFO. + // FIXME: e'necessario impostare il vecchio ? + leData.old_fragment_identity = leData.fragment.ID; + init_INFO_cycle(); + + return; + } + +} + +// +// Aggiorna la situazione del frammento vicino massimale: +// +void +LEADER_Agent::updateMaximalFragment(NodeAddress from, struct FeedbackMessage feedback) +{ + // Il messaggio di feedback segnala che il nodo mittente non conosce alcun frammento massimale. + if (!feedback.maximal_fragment_available) + return; + + // Se il nodo non possiede alcuna informazione su frammenti massimali: + // il frammento descritto dal messaggio FEEDBACK diventa il frammento vicino massimale. + if (!leData.maximal_fragment_available[leData.round]) { + leData.maximal_fragment_available[leData.round] = true; + leData.maximal_fragment[leData.round] = feedback.maximal_fragment; + // FIXME non so se si deve impostare + leData.maximal_fragment_node[leData.round] = -1; + leData.stored_path[leData.round] = from; + return; + } + + // Il nodo ha gia'un frammento massimale memorizzato: + // se il frammento massimale che conosce e'minore di quello inviato + // allora memorizza il frammento inviato. + if (leData.maximal_fragment[leData.round] < feedback.maximal_fragment) { + leData.maximal_fragment[leData.round] = feedback.maximal_fragment; + // FIXME non so se si deve impostare + leData.maximal_fragment_node[leData.round] = -1; + leData.stored_path[leData.round] = from; + return; + } +} + +// +// Aggiorna la situazione del frammento vicino massimale: +// Si assume che il messaggio di info provenga da un frammento differente. +// +void +LEADER_Agent::updateMaximalFragment(NodeAddress from, struct InfoMessage info) +{ + // Se il nodo non possiede alcuna informazione su frammenti massimali: + // il frammento descritto dal messaggio INFO diventa il frammento vicino massimale. + if (!leData.maximal_fragment_available[leData.round]) { + leData.maximal_fragment_available[leData.round] = true; + leData.maximal_fragment[leData.round] = info.new_fragment; + leData.maximal_fragment_node[leData.round] = from; + leData.stored_path[leData.round] = -1; + return; + } + + // Il nodo ha gia'un frammento massimale memorizzato: + // se il frammento massimale che conosce e'minore di quello inviato + // allora memorizza il frammento inviato. + if (leData.maximal_fragment[leData.round] < info.new_fragment) { + leData.maximal_fragment[leData.round] = info.new_fragment; + leData.maximal_fragment_node[leData.round] = from; + leData.stored_path[leData.round] = -1; + return; + } +} + +void +LEADER_Agent::timeout(LeaderMessageType type, NodeAddress from, int round) +{ + switch (type) { + case LEADER_INFO: + + if (_DEBUG_) + printf("------ %d timeout INFO (ROUND=%d) from %d ------\n", myAddress, round, from); + + // Nuovo CONFIRM: da modificare. + send_INFO(leData.stored_messages.info[round].fragment.ID, + leData.stored_messages.info[round].new_fragment.ID, + leData.stored_messages.info[round].new_fragment.size, + leData.stored_messages.info[round].parent, + leData.stored_messages.info[round].round, + from); + /* + send_REQUEST(from, LEADER_INFO, leData.round); + */ + break; + case LEADER_FEEDBACK: + if (_DEBUG_) + printf("------ %d timeout FEEDBACK (ROUND=%d) from %d ------\n", myAddress, round, from); + + // Invia nuovamente il feedback bufferizzato. + struct FeedbackMessage fm; + for (BufferFeedbackMessages::iterator i = leData.stored_messages.feedback.begin(); i != leData.stored_messages.feedback.end(); i++) { + + if (i->first == round) { + fm = i->second; + + send_FEEDBACK(from, + fm.fragment.ID, + fm.maximal_fragment_available, + fm.maximal_fragment.ID, + fm.maximal_fragment.size, + fm.node_count, + round); + } + } + break; + + case LEADER_ACTION: + + send_ACTION(leData.buffer_action[round].first, leData.buffer_action[round].second, round); + + break; + + case LEADER_LEADER: + + if (_DEBUG_) + printf("%d timeout LEADER from %d\n", myAddress, from); + + send_LEADER(leData.leader, + leData.tree_size, + leData.parent, + leData.level, + true, + from); + + break; + } +} + +void +LEADER_Agent::timeoutConfirm(NodeAddress from, int round) +{ + /* + struct InfoMessage im; + for (BufferInfoMessages::iterator i = leData.stored_messages.info.begin(); i != leData.stored_messages.info.end(); i++) { + if (i->first == round) { + im = i->second; + if (_DEBUG_) + printf("%d TIMEOUT (CONFIRM) from %d (round = %d) (%f)\n", myAddress, from, round, Scheduler::instance().clock()); + send_INFO(im.fragment.ID, + im.new_fragment.ID, + im.new_fragment.size, + im.parent, + im.round, + from); + } + } + */ +} + +// +// Verifica se il messaggio di INFO e'stato gia'mandato per un certo round. +// +bool +LEADER_Agent::isInfoInBuffer(int round) +{ + for (BufferInfoMessages::iterator i = leData.stored_messages.info.begin(); i != leData.stored_messages.info.end(); i++) + if (i->first == round) + return true; + + return false; +} + +// +// Verifica se il messaggio di FEEDBACK e'stato gia'mandato per un certo round. +// +bool +LEADER_Agent::isFeedbackInBuffer(int round) +{ + for (BufferFeedbackMessages::iterator i = leData.stored_messages.feedback.begin(); i != leData.stored_messages.feedback.end(); i++) + if (i->first == round) + return true; + + return false; +} + +void +LEADER_Agent::lastTimeoutConfirm(NodeAddress from, int round) +{ + if (_DEBUG_) + printf("%d LAST TIMEOUT (CONFIRM) from %d [round = %d](%f)\n", myAddress, from, round, Scheduler::instance().clock()); + +} + +void +LEADER_Agent::lastTimeout(LeaderMessageType type, NodeAddress from, int round) +{ + switch (type) { + case LEADER_INFO : + if (_DEBUG_) + printf("%d LAST TIMEOUT (INFO) from %d (round = %d) (%f)\n", myAddress, from, leData.round, Scheduler::instance().clock()); + break; + case LEADER_FEEDBACK: + if (_DEBUG_) + printf("%d LAST TIMEOUT (FEEDBACK) from %d (round = %d) (%f)\n", myAddress, from, leData.round, Scheduler::instance().clock()); + break; + case LEADER_ACTION: + if (_DEBUG_) + printf("%d LAST TIMEOUT (ACTION) from %d (round = %d) (%f)\n", myAddress, from, leData.round, Scheduler::instance().clock()); + break; + case LEADER_LEADER : + if (_DEBUG_) + printf("%d LAST TIMEOUT (LEADER) from %d (%f)\n", myAddress, from, Scheduler::instance().clock()); + break; + } +} + +// +// Ricezione del messaggio di INFO (anche da buffer). +// +void +LEADER_Agent::recvInfoMessage(NodeAddress from, struct InfoMessage info) +{ + // + // Se il messaggio è passato, viene ignorato. + // + if (info.round < leData.round) + return; + + // + // Se il messaggio è futuro viene bufferizzato. + // + if (info.round > leData.round) { + leData.buffer_info.push_back(pair(from, info)); + return; + } + + // + // Se il messaggio e'il secondo ad arrivare da un nodo allora lo si scarta. + // + if (leData.info_messages.find(from) == leData.info_messages.end()) + return; + + // + // Riceve effettivamente il messaggio + // + receive_INFO(from, info); +} + +// +// Ricezione del messaggio di INFO. +// +void +LEADER_Agent::recvFeedbackMessage(NodeAddress from, struct FeedbackMessage feedback) +{ + // + // Se il messaggio è un messaggio futuro si bufferizza. + // + if (feedback.round > leData.round) { + leData.buffer_feedback.push_back(pair(from, feedback)); + return; + } + + // + // Se il messaggio e'il secondo ad arrivare da un nodo allora lo si scarta. + // + if (leData.feedback_messages.find(from) == leData.feedback_messages.end()) + return; + + // + // Riceve il messaggio (round corrente). + // + receive_FEEDBACK(from, feedback); +} + +bool +LEADER_Agent::belongToAnotherFragment(NodeAddress node, struct InfoMessage info) +{ + // Se non ho ancora inviato un messaggio di INFO per questo round il mio + // "fragment.ID" rappresenta il mio frammento corrente, + // altrimenti il mio vecchio frammento e' memorizzato in "old_fragment_identity". + //if (!isInfoInBuffer(info.round)) { + if (info.fragment.ID == leData.fragment.ID) + return false; + // Il messaggio portava un ID che non apparteneva al mio frammento. + // Cio'nonostante il messaggio puo'indicare un cambiamento di frammento. + // Effettuo gli stessi controlli sulla variabile info.new_fragment.ID + return (info.new_fragment.ID != leData.fragment.ID); + /* + } + else { + if (info.fragment.ID == leData.old_fragment_identity) + return false; + // Il messaggio portava un ID che non apparteneva al mio frammento. + // Cio'nonostante il messaggio puo'indicare un cambiamento di frammento. + // Effettuo gli stessi controlli sulla variabile info.new_fragment.ID + return (info.new_fragment.ID != leData.old_fragment_identity); + } + */ +} + +// +// Gestione dello scadere dei timeout. +// +void +LeaderTimer::handle(Event* e) +{ + // + // Verifica che l'evento sia un timeout di INFO. + // + for (map::iterator rr = info_timeouts.begin(); rr != info_timeouts.end(); rr++) { + // rr->first e' il round' + // rr->second e'la mappa dei timeout. + for (TimeoutMap::iterator i = rr->second.begin(); i != rr->second.end(); i++) { + if ((i->second).timeout == e) { + (i->second).num--; + if ((i->second).num <= 0) + agent->lastTimeout(LEADER_INFO, i->first, rr->first); + else { + Scheduler::instance().schedule(this, e, LEADER_Agent::timeout_info + Random::uniform(LEADER_Agent::jitter_timeout_info)); + agent->timeout(LEADER_INFO, i->first, rr->first); + } + return; + } + } + } + + // + // Verify if is a FEEDBACK timeout + // + for (TimeoutFromMap::iterator i = feedback_timeouts.begin(); i != feedback_timeouts.end(); i++) { + if (i->second.timeout == e) { + i->second.num--; + if (i->second.num <= 0) + agent->lastTimeout(LEADER_FEEDBACK, i->second.from, i->first); + else { + Scheduler::instance().schedule(this, e, LEADER_Agent::timeout_feedback + Random::uniform(LEADER_Agent::jitter_timeout_feedback)); + agent->timeout(LEADER_FEEDBACK, i->second.from, i->first); + } + return; + } + } + + // + // Messaggi ACTION. + // + for (map::iterator i = action_timeouts.begin(); i != action_timeouts.end(); i++) { + if (i->second.timeout == e) { + i->second.num--; + if (i->second.num <= 0) + agent->lastTimeout(LEADER_ACTION, i->second.from, i->first); + else { + Scheduler::instance().schedule(this, e, LEADER_Agent::timeout_action + Random::uniform(LEADER_Agent::jitter_timeout_action)); + agent->timeout(LEADER_ACTION, i->second.from, i->first); + } + return; + } + } + + // + // Messaggi LEADER. + // + for (TimeoutMap::iterator i = leader_timeouts.begin(); i != leader_timeouts.end(); i++) { + if (i->second.timeout == e) { + i->second.num--; + if (i->second.num <= 0) + agent->lastTimeout(LEADER_LEADER, i->first, 0); + else { + Scheduler::instance().schedule(this, e, LEADER_Agent::timeout_leader + Random::uniform(LEADER_Agent::jitter_timeout_leader)); + agent->timeout(LEADER_LEADER, i->first, 0); + } + return; + } + } + +} + +// +// Lancia i timeout per i messaggi di INFO del round. +// +void +LeaderTimer::launchInfoTimeouts(NodeList & info_neighbors, int round) +{ + for (NodeList::iterator i = info_neighbors.begin(); i != info_neighbors.end(); i++) { + // Inizializza solo quelli che non sono giĂ  stati annullati + struct Timeout t; + t.timeout = new Event(); + t.num = LEADER_Agent::max_timeout_info; + info_timeouts[round][*i] = t; + Scheduler::instance().schedule(this, t.timeout, LEADER_Agent::timeout_info + Random::uniform(LEADER_Agent::jitter_timeout_info)); + } +} + +// +// Lancia i timeout per i messaggi di FEEDBACK del round. +// +void +LeaderTimer::launchFeedbackTimeouts(NodeAddress parent, int round) +{ + struct TimeoutFrom t; + t.timeout = new Event(); + t.num = LEADER_Agent::max_timeout_feedback; + t.from = parent; + feedback_timeouts[round] = t; + Scheduler::instance().schedule(this, t.timeout, LEADER_Agent::timeout_feedback + Random::uniform(LEADER_Agent::jitter_timeout_feedback)); +} + +// +// Lancia il timeout per la ricezione del messaggio ACTION per il round. +// +void +LeaderTimer::launchActionTimeouts(NodeAddress to, int round) +{ + struct TimeoutFrom tf; + tf.from = to; + tf.timeout = new Event(); + tf.num = LEADER_Agent::max_timeout_action; + action_timeouts[round] = tf; + Scheduler::instance().schedule(this, tf.timeout, LEADER_Agent::timeout_action + Random::uniform(LEADER_Agent::jitter_timeout_action)); +} + +// +// Lancia i timeout per i messaggi di LEADER del round. +// +void +LeaderTimer::launchLeaderTimeouts(NodeList & leader_neighbors) +{ + for (NodeList::iterator i = leader_neighbors.begin(); i != leader_neighbors.end(); i++) { + struct Timeout t; + t.timeout = new Event(); + t.num = LEADER_Agent::max_timeout_leader; + leader_timeouts[*i] = t; + Scheduler::instance().schedule(this, t.timeout, LEADER_Agent::timeout_leader + Random::uniform(LEADER_Agent::jitter_timeout_leader)); + } +} + +// +// Riceve un messaggio di INFO +// +void +LeaderTimer::cancelInfo(NodeAddress node, int round) +{ + TimeoutMap::iterator i; + for (i = info_timeouts[round].begin(); i != info_timeouts[round].end(); i++) { + if (i->first == node) { + Scheduler::instance().cancel((i->second).timeout); + break; + } + } + if (i != info_timeouts[round].end()) + info_timeouts[round].erase(i); +} + +void +LeaderTimer::cancelAction(NodeAddress node, int round) +{ + map::iterator i; + for (i = action_timeouts.begin(); i != action_timeouts.end(); i++) + if (((i->first) == round) && ((i->second.from) == node)) + break; + if (i != action_timeouts.end()) + action_timeouts.erase(i); +} + +// +// Riceve un messaggio di INFO +// +void +LeaderTimer::cancelFeedback(NodeAddress node, int round) +{ + TimeoutFromMap::iterator i; + for (i = feedback_timeouts.begin(); i != feedback_timeouts.end(); i++) { + if (((i->first) == round) && ((i->second.from) == node)) { + Scheduler::instance().cancel(i->second.timeout); + break; + } + } + if (i != feedback_timeouts.end()) { + feedback_timeouts.erase(i); + } +} + +// +// Riceve un messaggio di LEADER +// +void +LeaderTimer::cancelLeader(NodeAddress node) +{ + TimeoutMap::iterator i; + for (i = leader_timeouts.begin(); i != leader_timeouts.end(); i++) { + if (i->first == node) { + Scheduler::instance().cancel(i->second.timeout); + break; + } + } + if (i != leader_timeouts.end()) + leader_timeouts.erase(i); +} + +// Verifica che un pacchetto sia di tipo DATA. +bool +LEADER_Agent::isDataPacket(Packet * p) +{ + struct hdr_leader *leaderh = HDR_LEADER(p); + return (leaderh->msg_type == LEADER_DATA); +} + +// Preparazione all'invio di un messaggio al layer inferiore +void +LEADER_Agent::prepareSendDataDown(Packet * p) +{ + struct hdr_leader *leaderh = HDR_LEADER(p); + + // Marca il nodo come dato. + leaderh->msg_type = LEADER_DATA; +} + +/** +* Query if algorithm support a particular protocol: +* that method is probably called before a getData +* method. +*/ +bool +LEADER_Agent::supportProtocol(string protocol) +{ + if (protocol == "leader") + return true; + return false; +} + +/** +* That method is used to get data from an algorithm +* that was check to implements a particular protocol +*/ +void * +LEADER_Agent::getData(string data) +{ + if (data == "leader") { + return &(leData.leader); + } + else if (data == "tree_size") { + return &(leData.tree_size); + } + else if (data == "parent") { + return &(leData.parent); + } + else if (data == "childs") { + return &(leData.childs); + } + else if (data == "level") { + return &(leData.level); + } + else if (data == "levels") { + return &(leData.levels); + } + return NULL; +} + +void +LEADER_Agent::beginLeaderPropagation() +{ + // Se il nodo non conosce nessun frammento adiacente massimale, allora + // vuol dire che e'l'unico: viene eletto LEADER. + + // Genitore + leData.parent = -1; + // Numero di nodi della topologia. + leData.tree_size = leData.fragment.size; + // Livello nell'albero + leData.level = 0; + // Leader. + leData.leader = myAddress; + // Childs + leData.childs.clear(); + + init_LEADER_cycle(); + + send_LEADER (myAddress, leData.tree_size, -1, 0); + + // Imposta i timeout verso i nodi che devono inviare un messaggio LEADER. + timer->launchLeaderTimeouts(leData.leader_messages); +} \ No newline at end of file diff -Naur ns-allinone-2.29-old/ns-2.29/clustering/leader/leader.h ns-allinone-2.29/ns-2.29/clustering/leader/leader.h --- ns-allinone-2.29-old/ns-2.29/clustering/leader/leader.h 1970-01-01 01:00:00.000000000 +0100 +++ ns-allinone-2.29/ns-2.29/clustering/leader/leader.h 2007-08-03 22:23:31.000000000 +0200 @@ -0,0 +1,294 @@ + +/** + * Copyright (c) 2006 Michele Mastrogiovanni. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#ifndef _LEADER_H_ +#define _LEADER_H_ + +#include "ClusteringModule.h" +#include "clustering/leader/structure.h" +#include "LeaderUtility.h" + +#include +#include + +///////////////////// +/// Stato del nodo // +///////////////////// +typedef enum +{ + LEADER_STATUS_INIT = 0x1, // Stato iniziale. + LEADER_STATUS_INFO = 0x2, // Fase di riceazione dei messaggi di INFO. + LEADER_STATUS_FEEDBACK = 0x3, // Fase di riceazione dei messaggi di FEEDBACK. + LEADER_STATUS_LEADER = 0x4, // Sono in fase di ricezione dei messaggi LEADER. + LEADER_STATUS_END = 0x5 +} LeaderStatus; + +////////////////////////// +// Header del pacchetto // +////////////////////////// +struct hdr_leader +{ + LeaderMessageType msg_type; // Tipo di messaggio. + + union { + struct InfoMessage info_message; + struct FeedbackMessage feedback_message; + struct ActionMessage action_message; + struct LeaderMessage leader_message; + struct RequestMessage request_message; + struct ConfirmMessage confirm_message; + }; + + ///////////////// + /// Addressing // + ///////////////// + static int offset_; + inline static int& offset() { return offset_; } + inline static hdr_leader* access(const Packet* p) { + return (hdr_leader*) p->access(offset_); + } +}; + +/////////// +// Timer // +/////////// +class LeaderTimer; + +/////////// +// Agent // +/////////// +class LEADER_Agent : public ClusteringModule { +public: + + LEADER_Agent(); + + // Funzione di ricezione dell'algoritmo di clustering. + virtual void receive(Packet * p, Handler * h); + + // Funzione di ricezione dei messaggi di INFO. + void recvInfoMessage(NodeAddress from, struct InfoMessage info); + + // Funzione di ricezione dei messaggi di FEEDBACK. + void recvFeedbackMessage(NodeAddress from, struct FeedbackMessage info); + + void timeout(LeaderMessageType type, NodeAddress from, int round); + void lastTimeout(LeaderMessageType type, NodeAddress from, int round); + + void timeoutConfirm(NodeAddress from, int round); + void lastTimeoutConfirm(NodeAddress from, int round); + + void beginLeaderPropagation(); + + // Verifica che un pacchetto sia di tipo DATA. + virtual bool isDataPacket(Packet * p); + + // Preparazione all'invio di un messaggio al layer inferiore + virtual void prepareSendDataDown(Packet * p); + +protected: + + struct LeaderElectionData leData; // Dati della fase di leader election. + LeaderStatus status; // Stato dell'agente. + LeaderTimer * timer; // Gestore dei timeout. + +protected: + /////////////// + // Procedure // + /////////////// + + // Inizio dell'algoritmo (leader election). + virtual void startModule(); + + // Fine dell'algoritmo. + virtual void endModule(); + + virtual void * getData(string data); + virtual bool supportProtocol(string protocol); + + // Procedura di inizializzazione delle variabili della Leader Election Phase. + void initializeLeaderElection(); + + void emptyInfoBuffer(); // Svuota il buffer dei messaggi di INFO. + void emptyFeedbackBuffer(); // Svuota il buffer dei messaggi di FEEDBACK. + void processLEStatus(); // Gestione della fase di transizione durante la Leader Election. + + void init_INFO_cycle(bool initialize = true); + void init_FEEDBACK_cycle(); + void init_LEADER_cycle(); + + ///////////// + // Utility // + ///////////// + + // + // Verifica se il messaggio di INFO proviene da un nodo che appartiene + // ad un frammento vicino. + // + bool belongToAnotherFragment(NodeAddress node, struct InfoMessage info); + + void updateMaximalFragment(NodeAddress from, struct InfoMessage info); + void updateMaximalFragment(NodeAddress from, struct FeedbackMessage info); + + /////////////// + // Procedure // + /////////////// + + void send_INFO(NodeAddress fragment_identity, + NodeAddress new_fragment_identity, + int new_fragment_size, + NodeAddress parent, + int round, + NodeAddress to); + + void send_INFO(NodeAddress fragment_identity, + NodeAddress new_fragment_identity, + int new_fragment_size, + NodeAddress parent); + + // Invia una richiesta di un certo messaggio ad un vicino. + void send_REQUEST(NodeAddress to, LeaderMessageType type, int round); + + void send_LEADER(NodeAddress leader, + int size, + NodeAddress parent, + int level, + bool confirm = false, + NodeAddress to = -1); + + void send_FEEDBACK(NodeAddress to, + NodeAddress fragment_identity, + bool internal_flag, + NodeAddress maximal_fragment_identity, + int maximal_fragment_size, + int node_count, + int round); + void send_FEEDBACK(NodeAddress to, + NodeAddress fragment_identity, + bool internal_flag, + NodeAddress maximal_fragment_identity, + int maximal_fragment_size, + int node_count); + + void send_ACTION(NodeAddress fragment_identity, NodeAddress to); + void send_ACTION(NodeAddress fragment_identity, NodeAddress to, int round); + + void send_CONFIRM(NodeAddress to, int round, LeaderMessageType type, bool send); + + void receive_LEADER(NodeAddress from, struct LeaderMessage lm, NodeAddress to); + + void receive_REQUEST(NodeAddress from, struct RequestMessage rm); + void receive_INFO(NodeAddress from, struct InfoMessage im); + void receive_FEEDBACK(NodeAddress from, struct FeedbackMessage fm); + void receive_ACTION(NodeAddress from, struct ActionMessage am); + void receive_CONFIRM(NodeAddress from, struct ConfirmMessage); + +public: + ///////////// + // Buffers // + ///////////// + + bool isInfoInBuffer(int round); + bool isFeedbackInBuffer(int round); + +public: + + static NodeAddress fake_leader; + + static int _DEBUG_; + + static double max_delay; + + static int max_timeout_confirm; + static double jitter_timeout_confirm; + static double timeout_confirm; + + static int max_timeout_info; + static double jitter_timeout_info; + static double timeout_info; + + static int max_timeout_action; + static double jitter_timeout_action; + static double timeout_action; + + static int max_timeout_feedback; + static double jitter_timeout_feedback; + static double timeout_feedback; + + static int max_timeout_leader; + static double jitter_timeout_leader; + static double timeout_leader; + +}; + +// +// Gestore dei timeout. +// +class LeaderTimer : public Handler { + +public: + + LeaderTimer(LEADER_Agent * a) : Handler(), agent(a) {} + + // Funzione di gestione. + void handle(Event* e); + + // Lancia il timeout di INFO verso i nodi che devono ancora inviare un messaggio di INFO per il round corrente. + void launchInfoTimeouts(NodeList & info_neighbors, int round); + + // Lancia il timeout verso il genitore che deve ricevere il messaggio di FEEDBACK. + void launchFeedbackTimeouts(NodeAddress parent, int round); + + // Lancia il timeout verso il nodo che deve ricevere il messaggio di ACTION. + void launchActionTimeouts(NodeAddress to, int round); + + // Lancia un timeout verso i vicini che ancora non hanno inviato il messaggio di LEADER. + void launchLeaderTimeouts(NodeList & leader_neighbors); + + // Segnala la ricezione di un messaggio di INFO. + void cancelInfo(NodeAddress node, int round); + + // Segnala la ricezione della conferma ad un messaggio di FEEDBACK. + void cancelFeedback(NodeAddress node, int round); + + // Segnala la ricezione di un messaggio di ACTION. + void cancelAction(NodeAddress node, int round); + + // Segnala la ricezione di conferma per l'invio del messaggio LEADER. + void cancelLeader(NodeAddress node); + +public: + + LEADER_Agent *agent; + + // Timeout INFO per round. + map info_timeouts; + + // Timeout FEEDBACK. + TimeoutFromMap feedback_timeouts; + + // Messaggi ACTION. + map action_timeouts; + + // Messaggi LEADER. + TimeoutMap leader_timeouts; + + map buffer_received_info; + +}; + +#endif \ No newline at end of file diff -Naur ns-allinone-2.29-old/ns-2.29/clustering/leader/structure.h ns-allinone-2.29/ns-2.29/clustering/leader/structure.h --- ns-allinone-2.29-old/ns-2.29/clustering/leader/structure.h 1970-01-01 01:00:00.000000000 +0100 +++ ns-allinone-2.29/ns-2.29/clustering/leader/structure.h 2007-08-03 22:23:31.000000000 +0200 @@ -0,0 +1,217 @@ + +/** + * Copyright (c) 2006 Michele Mastrogiovanni. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#ifndef _LEADER_STRUCTURE_H_ +#define _LEADER_STRUCTURE_H_ + +#include "clustering-header.h" + +#include +#include + +//--------------------------------------------------------------------------------- +// Tipi di messaggio +//--------------------------------------------------------------------------------- +typedef enum +{ + LEADER_INFO = 0x1, // Messaggio per comunicare informazioni sul frammento + // ai propri vicini. + LEADER_FEEDBACK = 0x2, // Messaggio per comunicare informazioni sui frammenti + // vicini massimali al proprio genitore. + LEADER_ACTION = 0x3, // Messaggio interno a un frammento per legarsi ad un + // frammento vicino. + LEADER_LEADER = 0x4, // Messaggio finale della Leader Election. + + LEADER_REQUEST = 0x7, // Richiesta di ritrasmissione. + + LEADER_CONFIRM = 0x8, // Mesaggio di conferma per l'avvenuta ricezione. + + LEADER_DATA +} LeaderMessageType; + +//--------------------------------------------------------------------------------- +// Informazioni sull'albero di appartenenza. +//--------------------------------------------------------------------------------- +struct TreeInfo { + NodeList childs; // Nodi figli. + NodeAddress parent; // Nodo genitore. +}; + +//--------------------------------------------------------------------------------- +// Informazioni su di un frammento. +//--------------------------------------------------------------------------------- +struct FragmentInfo { + NodeAddress ID; // Identita' del leader del frammento. + int size; // Dimensione del frammento. + + // + // Un frammento e'minore di un'altro se e'di dimensione minore + // oppure se e'delle stesse dimensioni e ha un ID minore. + // + bool operator< (const struct FragmentInfo & fragment) { + if (size < fragment.size) + return true; + return ((size == fragment.size) && + (ID < fragment.ID)); + } +}; + +//--------------------------------------------------------------------------------- +// Lista di nodi, per round che richiede la conferma dei messaggi INFO inviati. +//--------------------------------------------------------------------------------- +typedef map ConfirmationNodes; + +//--------------------------------------------------------------------------------- +// Messaggio INFO. +//--------------------------------------------------------------------------------- +struct InfoMessage { + struct FragmentInfo fragment; // Frammento a cui appartiene il nodo mittente. + struct FragmentInfo new_fragment; // Frammento a cui il nodo dello stesso frammento + // deve appartenere. + NodeAddress parent; // Genitore del mittente. + int round; // Round del messaggio. +}; + +//--------------------------------------------------------------------------------- +// Buffer per i messaggi di INFO inviati: uno per ogni round. +//--------------------------------------------------------------------------------- +typedef map BufferInfoMessages; + +//--------------------------------------------------------------------------------- +// Messaggio FEEDBACK. +//--------------------------------------------------------------------------------- +struct FeedbackMessage { + struct FragmentInfo fragment; // Frammento a cui appartiene il nodo mittente. + bool maximal_fragment_available; // Indica se il mittente conosce o no un frammento vicino massimale. + struct FragmentInfo maximal_fragment; // Informazioni sul frammento massimale. + int node_count; // Numero di nodi del sottoalbero radicato nel mittente. + int round; // Round del messaggio. +}; + +//--------------------------------------------------------------------------------- +// Buffer per i messaggi di FEEDBACK inviati: uno per ogni round. +//--------------------------------------------------------------------------------- +typedef map BufferFeedbackMessages; + +//--------------------------------------------------------------------------------- +// Messaggi memorizzati (per le ritrasmissioni). +//--------------------------------------------------------------------------------- +struct StoredMessages { + BufferInfoMessages info; // Messaggi di INFO. + BufferFeedbackMessages feedback; // Messaggi di FEEDBACK. +}; + +//--------------------------------------------------------------------------------- +// Messaggio ACTION. +//--------------------------------------------------------------------------------- +struct ActionMessage { + struct FragmentInfo current_fragment; // Frammento del messaggio di ACTION. + int round; +}; + +//--------------------------------------------------------------------------------- +// Messaggio LEADER. +//--------------------------------------------------------------------------------- +struct LeaderMessage { + struct FragmentInfo leader; // Informazioni sul leader e la grandezza del frammento globale. + NodeAddress parent; // Genitore del mittente. + int level; // Livello dell'albero del mittente. + bool confirm; // True indica un messaggio ritrasmesso, richiede la ritrasmissione. + // Non si usa il messaggio di request per specificare i dati del leader + // perche'in questo modo, posso inviare le informazioni sul leader. +}; + +//--------------------------------------------------------------------------------- +// Messaggio REQUEST. +//--------------------------------------------------------------------------------- +struct RequestMessage { + LeaderMessageType type; // Tipo i messaggio richiesto. + int round; // Round del messaggio. +}; + +//--------------------------------------------------------------------------------- +// Messaggio CONFIRM. +//--------------------------------------------------------------------------------- +struct ConfirmMessage { + LeaderMessageType type; // Tipo di messaggio da confermare. + bool send; // True se il messaggio e'l'invio, + // False se e'la risposta. + int round; // Round del messaggio. +}; + +//--------------------------------------------------------------------------------- +// Collezione principale di dati sulla leader election phase. +//--------------------------------------------------------------------------------- +struct LeaderElectionData { + bool candidate; // True se il nodo e'un candidato. + struct TreeInfo tree; // Informazioni sull'albero interno + // al frammento a cui il nodo appartiene. + struct FragmentInfo fragment; // Informazioni sul frammento a cui il nodo appartiene. + map maximal_fragment_available; // True se si conosce un frammento massimale + map maximal_fragment; // Il frammento massimale + map maximal_fragment_node; // Nodo a cui legarsi. + map stored_path; // Vicino verso il quale si raggiunge l'edge node massimale. + // -1 indica che il nodo corrente e'l'edge node. + + NodeAddress leader; + NodeAddress parent; + int tree_size; + int level; + map levels; + NodeList childs; + + // + // Messaggio INFO proveniente dal nodo di JOIN memorizzato: serve perche'il messaggio di ACTION + // puo'giungere dopo la ricezione del messaggio di INFO da parte del nodo del frammento massimale + // che darebbe il via alla propagazione dell'INFO anche nel frammento del nodo. + // + map maximal_fragment_node_info_message; + + // + // Memorizza la ricezione di un messaggio di action per un certo round. + // + map action_for_round; + + NodeAddress old_fragment_identity; // Vecchia identita'del frammento. + NodeAddress new_fragment_identity; // Identita'del frammento a cui legarsi. + NodeList info_messages; // Vicini che ancora devono inviare il messaggio di INFO. + NodeList feedback_messages; // Vicini che ancora devono inviare il messaggio di FEEDBACK. + NodeList leader_messages; // Vicini che devono ancora inviare il messaggio di LEADER. + int sub_tree_partial_count; // Conteggio dei nodi del sottoalbero radicato nel nodo corrente. + + //------------------ + // Buffers. + //------------------ + list > buffer_info; // Messaggi di INFO inviati dai vicini. + list > buffer_feedback; // Messaggi di FEEDBACK inviati dai vicini. + map > buffer_action; + ConfirmationNodes confirmation_nodes_info; // Nodi dai quali ci si aspetta un INFO message. + + //------------------ + // Messaggi inviati. + //------------------ + struct StoredMessages stored_messages; + + //------------------ + // Round dell'algoritmo. + //------------------ + int round; + +}; + +#endif \ No newline at end of file diff -Naur ns-allinone-2.29-old/ns-2.29/clustering/mpr/.DS_Store ns-allinone-2.29/ns-2.29/clustering/mpr/.DS_Store --- ns-allinone-2.29-old/ns-2.29/clustering/mpr/.DS_Store 1970-01-01 01:00:00.000000000 +0100 +++ ns-allinone-2.29/ns-2.29/clustering/mpr/.DS_Store 2007-08-03 22:23:30.000000000 +0200 @@ -0,0 +1 @@ +Bud1‡ccIlocblobmpr.ccIlocblobZ!˙˙˙˙˙˙mpr.hIlocblob!˙˙˙˙˙˙  @€ @€ @€ @ E‡DSDB ` @€ @€ @ \ No newline at end of file diff -Naur ns-allinone-2.29-old/ns-2.29/clustering/mpr/mpr.cc ns-allinone-2.29/ns-2.29/clustering/mpr/mpr.cc --- ns-allinone-2.29-old/ns-2.29/clustering/mpr/mpr.cc 1970-01-01 01:00:00.000000000 +0100 +++ ns-allinone-2.29/ns-2.29/clustering/mpr/mpr.cc 2007-08-03 22:23:30.000000000 +0200 @@ -0,0 +1,965 @@ + +/** + * Copyright (c) 2006 Michele Mastrogiovanni. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +//////////////// +// NS Headers // +//////////////// +#include "Separator.h" +#include "BackboneUtility.h" + +#include "mpr.h" +#include "random.h" +#include "gridkeeper.h" +#include +#include + +/////////////////////////////////// +// Parte di dichiarazione comune // +/////////////////////////////////// + +int hdr_mpr::offset_; + +int MPR_Agent::_DEBUG_; +int MPR_Agent::enhanced; +int MPR_Agent::enhanced_2; + +double MPR_Agent::max_delay; +int MPR_Agent::max_timeout_hello; +double MPR_Agent::jitter_timeout_hello; +double MPR_Agent::timeout_hello; +int MPR_Agent::max_timeout_first_decision; +double MPR_Agent::jitter_timeout_first_decision; +double MPR_Agent::timeout_first_decision; +int MPR_Agent::max_timeout_last_decision; +double MPR_Agent::jitter_timeout_last_decision; +double MPR_Agent::timeout_last_decision; + +static class MprClass : public TclClass { +public: + MprClass() : TclClass("Agent/MPR") {} + TclObject* create(int argc, const char*const* argv) { + return(new MPR_Agent()); + } +} class_mpr; + + +static class MprHeaderClass : public PacketHeaderClass { +public: + MprHeaderClass() : PacketHeaderClass("PacketHeader/MPR", + sizeof(hdr_mpr)) { + bind_offset(&hdr_mpr::offset_); + } +} class_mprhdr; + +// +// Verifica che il timeout sia di tipo HELLO. +// +bool +MprTimer::isHelloTimeout(Event * e) +{ + for (TimeoutMap::iterator i = hello_timeouts.begin(); i != hello_timeouts.end(); i++) { + if (i->second.timeout == e) { + i->second.num--; + if (i->second.num <= 0) { + agent->lastTimeout(MPR_STATUS_HELLO, i->first); + } + else { + Scheduler::instance().schedule(this, e, + MPR_Agent::timeout_hello + Random::uniform(MPR_Agent::jitter_timeout_hello)); + agent->timeout(MPR_STATUS_HELLO, i->first); + } + return true; + } + } + return false; +} + +// +// Verifica che il timeout sia di tipo FIRST DECISION. +// +bool +MprTimer::isFirstDecisionTimeout(Event * e) +{ + for (TimeoutMap::iterator i = first_decision_timeouts.begin(); i != first_decision_timeouts.end(); i++) { + if (i->second.timeout == e) { + i->second.num--; + if (i->second.num <= 0) { + agent->lastTimeout(MPR_STATUS_FIRST_DECISION, i->first); + } + else { + Scheduler::instance().schedule(this, e, + MPR_Agent::timeout_first_decision + Random::uniform(MPR_Agent::jitter_timeout_first_decision)); + agent->timeout(MPR_STATUS_FIRST_DECISION, i->first); + } + return true; + } + } + return false; +} + +// +// Verifica che il timeout sia di tipo LAST DECISION. +// +bool +MprTimer::isLastDecisionTimeout(Event * e) +{ + for (TimeoutMap::iterator i = last_decision_timeouts.begin(); i != last_decision_timeouts.end(); i++) { + if (i->second.timeout == e) { + i->second.num--; + if (i->second.num <= 0) { + agent->lastTimeout(MPR_STATUS_LAST_DECISION, i->first); + } + else { + Scheduler::instance().schedule(this, e, + MPR_Agent::timeout_last_decision + Random::uniform(MPR_Agent::jitter_timeout_last_decision)); + agent->timeout(MPR_STATUS_LAST_DECISION, i->first); + } + return true; + } + } + return false; +} + +// +// Gestisce l'arrivo di un timeout segnalandolo +// opportunamente all'Agente. +// +void +MprTimer::handle(Event *e) +{ + if (isHelloTimeout(e)) + return; + + if (isFirstDecisionTimeout(e)) + return; + + if (isLastDecisionTimeout(e)) + return; +} + +// +// Inizializza i timeout che si possono lanciare in base ai vicini del nodo. +// +void +MprTimer::initTimeouts(NodeList & neighbors) +{ + for (NodeList::iterator i = neighbors.begin(); i != neighbors.end(); i++) { + + // Definisce i Timeout di tipo HELLO + struct Timeout h; + h.timeout = new Event(); + h.num = MPR_Agent::max_timeout_hello; + hello_timeouts[*i] = h; + + // Definisce i Timeout di tipo LAST DECISION + struct Timeout s; + s.timeout = new Event(); + s.num = MPR_Agent::max_timeout_last_decision; + last_decision_timeouts[*i] = s; + + } +} + +// +// Fa partire i timeout per i nodi che non hanno ancora risposto al +// messaggio di HELLO inviando la propria lista di vicini. +// +void +MprTimer::launchHelloTimeouts() +{ + for (TimeoutMap::iterator i = hello_timeouts.begin(); i != hello_timeouts.end(); i++) { + Scheduler::instance().schedule(this, i->second.timeout, + MPR_Agent::timeout_hello + Random::uniform(MPR_Agent::jitter_timeout_hello)); + } +} + +// +// Fa partire i timeout per i nodi che non hanno ancora inviato +// il proprio colore (iniziale). +// +void +MprTimer::launchFirstDecisionTimeout(NodeAddress node) +{ + // Definisce i Timeout di tipo FIRST DECISION + struct Timeout f; + f.timeout = new Event(); + f.num = MPR_Agent::max_timeout_first_decision; + first_decision_timeouts[node] = f; + + Scheduler::instance().schedule(this, f.timeout, MPR_Agent::timeout_first_decision + Random::uniform(MPR_Agent::jitter_timeout_first_decision)); +} + +// +// Fa partire i timeout per i nodi che non hanno ancora inviato +// il proprio colore (finale). +// +void +MprTimer::launchLastDecisionTimeouts() +{ + for (TimeoutMap::iterator i = last_decision_timeouts.begin(); i != last_decision_timeouts.end(); i++) { + Scheduler::instance().schedule(this, i->second.timeout, + MPR_Agent::timeout_last_decision + Random::uniform(MPR_Agent::jitter_timeout_last_decision)); + } +} + +// +// L'agente segnala la ricezione di un messaggio di tipo HELLO: +// il timeout viene eliminato. +// +void +MprTimer::receivedHello(NodeAddress from) +{ + TimeoutMap::iterator i; + for (i = hello_timeouts.begin(); i != hello_timeouts.end(); i++) { + if (i->first == from) { + Scheduler::instance().cancel(i->second.timeout); + break; + } + } + if (i != hello_timeouts.end()) + hello_timeouts.erase(i); +} + +// +// L'agente segnala la ricezione di un messaggio di tipo FIRST DECISION: +// il timeout viene eliminato. +// +void +MprTimer::receivedFirstDecision(NodeAddress from) +{ + TimeoutMap::iterator i; + for (i = first_decision_timeouts.begin(); i != first_decision_timeouts.end(); i++) { + if (i->first == from) { + Scheduler::instance().cancel(i->second.timeout); + break; + } + } + if (i != first_decision_timeouts.end()) + first_decision_timeouts.erase(i); +} + +// +// L'agente segnala la ricezione di un messaggio di tipo LAST DECISION: +// il timeout viene eliminato. +// +void +MprTimer::receivedLastDecision(NodeAddress from) +{ + TimeoutMap::iterator i; + for (i = last_decision_timeouts.begin(); i != last_decision_timeouts.end(); i++) { + if (i->first == from) { + Scheduler::instance().cancel(i->second.timeout); + break; + } + } + if (i != last_decision_timeouts.end()) + last_decision_timeouts.erase(i); +} + +// +// Costruttore +// +MPR_Agent::MPR_Agent() : ClusteringModule(PT_MPR) +{ + timer = new MprTimer(this); + + bind_bool("debug", &_DEBUG_); + bind_bool("enhanced", &enhanced); + bind_bool("enhanced-2", &enhanced_2); + + bind("max-delay", &max_delay); + bind("max-timeout-hello", &max_timeout_hello); + bind("jitter-timeout-hello", &jitter_timeout_hello); + bind("timeout-hello", &timeout_hello); + bind("max-timeout-first-decision", &max_timeout_first_decision); + bind("jitter-timeout-first-decision", &jitter_timeout_first_decision); + bind("timeout-first-decision", &timeout_first_decision); + bind("max-timeout-last-decision", &max_timeout_last_decision); + bind("jitter-timeout-last-decision", &jitter_timeout_last_decision); + bind("timeout-last-decision", &timeout_last_decision); + +} + +void +MPR_Agent::receive(Packet *p, Handler *h) +{ + struct hdr_mpr *mprh = HDR_MPR(p); + struct hdr_ip *iph = HDR_IP(p); + + // Mittente. + NodeAddress sender_address = iph->saddr(); //dcah->my_status.node_ID; + // Destinazione. + NodeAddress destination_address = iph->daddr(); // dcah->destination_address; + + switch (mprh->msg_type) { + case MPR_NEIGHBORS : + receive_NEIGHBORS(sender_address, *(mprh->node_list)); + break; + + case MPR_COLOR : + receive_COLOR(sender_address, mprh->color); + break; + + case MPR_SELECTION : + receive_MPR(sender_address, mprh->mpr_selected); + break; + + case MPR_REQUEST : + receive_REQUEST(sender_address, mprh->status); + break; + default: + break; + } + +} + +// +// Richiede un messaggio che forse e'stato perduto. +// +void +MPR_Agent::send_REQUEST(MprStatus _status_, NodeAddress to) +{ + /* + if (_DEBUG_) + printf("%d send REQUEST\n", myAddress); + */ + + Packet* p = allocpkt(); + + struct hdr_mpr * mprh = HDR_MPR(p); + + mprh->msg_type = MPR_REQUEST; + mprh->status = _status_; + + sendDown(p, sizeof(MprMessageType) + sizeof(MprStatus), to, MPR_Agent::max_delay); +} + +// +// Messaggio usato per cumunicare la propria lista dei vicini ad un nodo vicino +// +void +MPR_Agent::send_NEIGHBORS(NodeAddress to) +{ + /* + if (_DEBUG_) + printf("%d send NEIGHBORS\n", myAddress); + */ + + Packet* p = allocpkt(); + + struct hdr_mpr * mprh = HDR_MPR(p); + + mprh->msg_type = MPR_NEIGHBORS; + mprh->node_list = & neighbors; + + sendDown(p, sizeof(MprMessageType) + sizeof(nsaddr_t) * neighbors.size(), to, MPR_Agent::max_delay); +} + +// +// Messaggio usato per comunicare il colore del nodo in una certa fase dell'algoritmo. +// +void +MPR_Agent::send_COLOR(NodeAddress to, Color color) +{ + /* + if (_DEBUG_) + printf("%d send COLOR\n", myAddress); + */ + + Packet* p = allocpkt(); + + struct hdr_mpr * mprh = HDR_MPR(p); + + mprh->msg_type = MPR_COLOR; + mprh->color = color; + + sendDown(p, sizeof(MprMessageType) + sizeof(Color), to, MPR_Agent::max_delay); +} + +// +// Messaggio usato per comunicare il colore del nodo in una certa fase dell'algoritmo. +// +void +MPR_Agent::send_MPR(NodeAddress to, bool selected) +{ + /* + if (_DEBUG_) + printf("%d send MPR to %d: %d\n", myAddress, to, selected ? 1 : 0); + */ + + Packet* p = allocpkt(); + + struct hdr_mpr * mprh = HDR_MPR(p); + + mprh->msg_type = MPR_SELECTION; + mprh->mpr_selected = selected; + + sendDown(p, sizeof(MprMessageType) + sizeof(bool), to, MPR_Agent::max_delay); +} + +//////////////////// +// Interrogazioni // +//////////////////// + +// +// Procedura per verificare se esistono due vicini del nodo +// non collegati fra loro. +// +bool +MPR_Agent::twoNeighborsAreUnlinked() +{ + NodeList tmp; + + // Il nodo A punta ad un vicino. + for (NodeList::iterator A = neighbors.begin(); A != neighbors.end(); A++) { + NodeList & nlA = nodeNeighbors[*A]; + // Il nodo B punta all'altro vicino. + for (NodeList::iterator B = A; B != neighbors.end(); B++) + // Se i vicini sono diversi + if (A != B) { + tmp.clear(); + tmp.insert(*B); + // Se fra i vicini di A non c'e' B allora i due vicini sono scollegati. + if (!includes(nlA.begin(), nlA.end(), tmp.begin(), tmp.end())) + return true; + } + } + + // Tutti i vicini sono collegati fra loro + return false; +} + +// +// Verifica se esiste un sottoinsieme di nodi di grandezza specificata +// che abbia le seguenti caratteristiche: +// 1) L'insieme dei nodi  connesso. +// 2) Tutti i nodi sono marcati. +// 3) Tutti i nodi hanno ID maggiore del nodo. +// +void +MPR_Agent::applyRules() +{ + if (_DEBUG_) + printf("%d have smallest neighbors: %d\n", myAddress, smallerNeighbor); + + // + // Apply Rule 1 and Enhanced Rule 1. + // + if (smallerNeighbor == myAddress) { + + if ((MPR_Agent::enhanced == 0) || ((MPR_Agent::enhanced == 1) && twoNeighborsAreUnlinked())) { + finalColor[myAddress] = COLOR_BLACK; + return; + } + + } + + finalColor[myAddress] = (selection == 1 ? COLOR_BLACK : COLOR_WHITE); +} + +// +// Funzione richiamata allo scadere di un timeout per un certo tipo di messaggio: +// Il nodo invia la richiesta del dato al vicino interessato. +// +void +MPR_Agent::timeout(MprStatus type, NodeAddress from) +{ + send_REQUEST(type, from); +} + +// +// Funzione richiamata allo scadere dell'ultimo timeout. +// +void +MPR_Agent::lastTimeout(MprStatus type, NodeAddress from) +{ + if (_DEBUG_) + printf("%d LAST TIMEOUT %d from %d\n", myAddress, type, from); +} + +// +// Procedura di partenza per l'algoritmo di clustering. +// +void +MPR_Agent::startModule() +{ + // Inizializza le informazioni comuni del clustering. + ClusteringModule::startModule(); + + // + // Carica le informazioni di stato dal modulo sottostante. + // + if (!lowerModule && target()) { + ClusteringModule * bottom = (ClusteringModule*)target(); + if (bottom->supportProtocol("sparsification")) + neighbors = *((NodeList*)bottom->getData("neighbors")); + } + + // Inizializza le strutture dei timeout. + timer->initTimeouts(neighbors); + + finalColor.clear(); + + selection = -1; + + // Stato dell'agente + status = MPR_STATUS_HELLO; + + smallerNeighbor = myAddress; + for (NodeList::iterator n = neighbors.begin(); n != neighbors.end(); n++) + if ((*n) < smallerNeighbor) + smallerNeighbor = (*n); + + // Invia un HELLO per richiedere la lista dei vicini. + send_NEIGHBORS(-1); + + // Inizializza i timeout per i messaggi NEIGHBORS. + timer->launchHelloTimeouts(); +} + +// +// Procedura richiamata alla fine dell'algoritmo di clustering. +// +void +MPR_Agent::endModule() +{ + if (_DEBUG_) + printf("%d END\n", myAddress); + + // L'algoritmo termina: il nodo puo'memorizzare il proprio clusterHead. + status = MPR_STATUS_END; + + // Memorizza il proprio clusterHead: + // se il nodo e'nero e'se stesso, altrimenti e'il vicino NERO maggiore. + NodeAddress CH = ((finalColor[myAddress] == COLOR_BLACK) ? myAddress : greaterCluster()); + + setClusterHead(myAddress, CH); + if (utility) { + NodeList backboneNeighbors; + if (myAddress == CH) { + for (NodeList::iterator n = neighbors.begin(); n != neighbors.end(); n++) + if (finalColor[*n] == COLOR_BLACK) + backboneNeighbors.insert(*n); + } + else { + backboneNeighbors.insert(CH); + } + ((BackboneUtility*)utility)->setBackbone(myAddress, backboneNeighbors); + ((BackboneUtility*)utility)->setColor(myAddress, myAddress == CH ? "black" : "white"); + } + + // Segnala la conclusione del processo di clustering. + ClusteringModule::endModule(); + + // Start upper module + if (upTarget) + Separator::instance().endCurrentModule(myAddress); +} + +// +// Procedura di ricezione del messaggio NEIGHBORS. +// +void +MPR_Agent::receive_NEIGHBORS(NodeAddress from, NodeList & neigh) +{ + /* + if (_DEBUG_) + printf("%d receive NEIGHBORS\n", myAddress); + */ + + // Se il messaggio e'di una fase passata, si scarta. + if (status > MPR_STATUS_HELLO) + return; + + // Cancella il timeout sulla ricezione di questo messaggio + timer->receivedHello(from); + + // Memorizza l'informazione. + nodeNeighbors[from] = neigh; + + // Add two hop neighbors. + set_union(twoHopNeighbors.begin(), twoHopNeighbors.end(), neigh.begin(), neigh.end(), insert_iterator(twoHopNeighbors, twoHopNeighbors.begin())); + + // Verifica se eventualemente si puo'avanzare di stato. + processStatus(); +} + +// +// Calculate MPR set. +// +void +MPR_Agent::calculateMPRSet() +{ + NodeList tmp; + + if (_DEBUG_) + printf("%d is calculating MPR set\n", myAddress); + + NodeList neighborsToConsider = neighbors; + + // + // Calculate correct two hop neighborhood + // + NodeList nodeToRemove = neighborsToConsider; + nodeToRemove.insert(myAddress); + + // + // Erase from two hop neighbors: current node and direct neighbors. + // + tmp.clear(); + set_difference(twoHopNeighbors.begin(), twoHopNeighbors.end(), nodeToRemove.begin(), nodeToRemove.end(), insert_iterator(tmp, tmp.begin())); + twoHopNeighbors = tmp; + + if ((MPR_Agent::enhanced == 1) || (MPR_Agent::enhanced_2 == 1)) { + + // + // Enhanced Algorithm + // + for (NodeNeighbors::iterator nn = nodeNeighbors.begin(); nn != nodeNeighbors.end(); nn++) { + + // + // Verify if a neighbor is "free". + // A neighbor is considered "free" if its smallest neighbor is not + // current node. + // + bool isFree = false; + + // + // Select smaller neighbor of neighbor. + // + NodeAddress min = nn->first; + + for (NodeList::iterator n = (nn->second).begin(); n != (nn->second).end(); n++) { + + if ((MPR_Agent::enhanced == 1) || (MPR_Agent::enhanced_2 == 1)) { + + if ((*n) < myAddress) { + isFree = true; + break; + } + + } + + if (MPR_Agent::enhanced_2 == 1) { + + if ((*n) < min) { + min = (*n); + break; + } + + } + + } + + // + // Add a "free" node to MPR set (if requested). + // + if ((MPR_Agent::enhanced == 1) || (MPR_Agent::enhanced_2 == 1)) + if (isFree) { + mprNeighbors.insert(nn->first); + if (_DEBUG_) + printf("- free node: %d\n", nn->first); + } + + // + // Add node smallest in its neighborhood. + // + if (MPR_Agent::enhanced_2 == 1) + if (min >= nn->first) { + mprNeighbors.insert(nn->first); + if (_DEBUG_) + printf("- neighbor smaller that its neighbors: %d\n", nn->first); + } + + } + + } + + // + // Erase already choosen MPR nodes. + // + for (NodeList::iterator n = mprNeighbors.begin(); n != mprNeighbors.end(); n++) { + tmp.clear(); + set_difference(twoHopNeighbors.begin(), twoHopNeighbors.end(), nodeNeighbors[*n].begin(), nodeNeighbors[*n].end(), insert_iterator(tmp, tmp.begin())); + twoHopNeighbors = tmp; + } + tmp.clear(); + set_difference(neighborsToConsider.begin(), neighborsToConsider.end(), mprNeighbors.begin(), mprNeighbors.end(), insert_iterator(tmp, tmp.begin())); + neighborsToConsider = tmp; + + // + // Add to MPR set neighbors that are alone in connection with some node in + // two hop neighborhood + // + map reachCount; + for (NodeNeighbors::iterator nn = nodeNeighbors.begin(); nn != nodeNeighbors.end(); nn++) + for (NodeList::iterator n = (nn->second).begin(); n != (nn->second).end(); n++) + reachCount[*n].insert(nn->first); + + NodeList toErase; + for (NodeList::iterator n = twoHopNeighbors.begin(); n != twoHopNeighbors.end(); n++) + if (reachCount[*n].size() == 1) { + mprNeighbors.insert(*reachCount[*n].begin()); + neighborsToConsider.erase(*reachCount[*n].begin()); + set_union(toErase.begin(), toErase.end(), nodeNeighbors[*reachCount[*n].begin()].begin(), nodeNeighbors[*reachCount[*n].begin()].end(), insert_iterator(toErase, toErase.begin())); + + if (_DEBUG_) + printf("- unque connection: %d to reach node:%d \n", *reachCount[*n].begin(), *n); + } + + // + // Cover other nodes. + // + tmp.clear(); + set_difference(twoHopNeighbors.begin(), twoHopNeighbors.end(), toErase.begin(), toErase.end(), insert_iterator(tmp, tmp.begin())); + twoHopNeighbors = tmp; + + NodeList countNodes; + while (twoHopNeighbors.size() > 0) { + + // + // Add to MPR set neighbor node that cover most two hop neighbors + // choosen between neighbors to consider. + // + int max = -1; + NodeAddress node = -1; + + // + // Choose neighbor to consider that cover most two hop neighbors. + // + for (NodeList::iterator n = neighborsToConsider.begin(); n != neighborsToConsider.end(); n++) { + countNodes.clear(); + set_intersection(nodeNeighbors[*n].begin(), nodeNeighbors[*n].end(), twoHopNeighbors.begin(), twoHopNeighbors.end(), insert_iterator(countNodes, countNodes.begin())); + if ((int)countNodes.size() > max) { + node = (*n); + max = countNodes.size(); + } + else if (((int)countNodes.size() == max) && ((*n) < node)) { + node = (*n); + max = countNodes.size(); + } + } + + if (_DEBUG_) + printf("- greater group by: %d touch %d nodes\n", node, max); + + neighborsToConsider.erase(node); + mprNeighbors.insert(node); + + // + // Erase two hop neighbors from list. + // + tmp.clear(); + set_difference(twoHopNeighbors.begin(), twoHopNeighbors.end(), nodeNeighbors[node].begin(), nodeNeighbors[node].end(), insert_iterator(tmp, tmp.begin())); + twoHopNeighbors = tmp; + + } + + if (_DEBUG_) { + printf("%d MPR: ", myAddress); + for (NodeList::iterator n = mprNeighbors.begin(); n != mprNeighbors.end(); n++) + printf("%d ", *n); + printf("\n"); + } + +} + + +// +// Procedura di ricezione del messaggio di colore. +// +void +MPR_Agent::receive_COLOR(NodeAddress _from_, Color color) +{ + /* + if (_DEBUG_) + printf("%d receive COLOR\n", myAddress); + */ + + // Se il messaggio e'di una fase passata, si scarta. + if (status > MPR_STATUS_LAST_DECISION) + return; + + timer->receivedLastDecision(_from_); + finalColor[_from_] = color; + + processStatus(); +} + +void +MPR_Agent::receive_MPR(NodeAddress _from_, bool selected) +{ + /* + if (_DEBUG_) + printf("%d receive MPR from %d: %d\n", myAddress, _from_, selected ? 1 : 0); + */ + + timer->receivedFirstDecision(_from_); + + selection = (selected ? 1 : 0); + + processStatus(); +} + +// +// Ricezione di un messaggio di richiesta. +// +void +MPR_Agent::receive_REQUEST(NodeAddress _from_, MprStatus _status_) +{ + /* + if (_DEBUG_) + printf("%d receive REQUEST\n", myAddress); + */ + + // Se il dato e'disponibile, si procede a soddisfare la richiesta + switch(_status_) { + + case MPR_STATUS_HELLO : + send_NEIGHBORS(-1); + break; + + case MPR_STATUS_FIRST_DECISION : + if (status > MPR_STATUS_HELLO) + send_MPR(_from_, mprSelection[_from_]); + break; + + case MPR_STATUS_LAST_DECISION : + if (status > MPR_STATUS_FIRST_DECISION) + send_COLOR(_from_, finalColor[myAddress]); + break; + + } +} + +// +// Restituisce il piu'grande vicino NERO. +// +NodeAddress +MPR_Agent::greaterCluster() +{ + // Ritorna il vicino clusterHead piu'grande. + NodeAddress max = -1; + for (NodeColor::iterator i = finalColor.begin(); i != finalColor.end(); i++) { + if (((i->second) == COLOR_BLACK) && ((i->first) > max) && ((i->first) != myAddress)) + max = (i->first); + } + return max; +} + +// +// Questa procedura si occupa della valutazione dello stato attuale del nodo +// e della decisione di avanzare di fase. +// La procedura gestisce tutta la logica dell'algoritmo. +// +void +MPR_Agent::processStatus() +{ + NodeAddress minimumNode = -1; + for (NodeList::iterator n = neighbors.begin(); n != neighbors.end(); n++) + if (minimumNode == -1) + minimumNode = (*n); + else if ((*n) < minimumNode) + minimumNode = (*n); + + switch (status) { + + case MPR_STATUS_HELLO : + + // Se un nodo NON ha collezionato tutte le informazioni sui vicini + // allora non avanza di fase + if (nodeNeighbors.size() != neighbors.size()) + return; + + // Il nodo avanza di fase + status = MPR_STATUS_FIRST_DECISION; + + // Calculate MPR set of node. + calculateMPRSet(); + + for (NodeNeighbors::iterator nn = nodeNeighbors.begin(); nn != nodeNeighbors.end(); nn++) { + NodeAddress min = myAddress; + for (NodeList::iterator n = (nn->second).begin(); n != (nn->second).end(); n++) + if ((*n) < min) { + min = (*n); + break; + } + if (min == myAddress) { + mprSelection[nn->first] = (find(mprNeighbors.begin(), mprNeighbors.end(), nn->first) != mprNeighbors.end()); + } + } + + // + // Send MPR selection to neighbors + // + for (map::iterator n = mprSelection.begin(); n != mprSelection.end(); n++) { + send_MPR(n->first, n->second); + } + + if (selection == -1) + timer->launchFirstDecisionTimeout(minimumNode); + + case MPR_STATUS_FIRST_DECISION : + + if (selection == -1) + return; + + // Il nodo avanza di fase + status = MPR_STATUS_LAST_DECISION; + + // Apply Rules. + applyRules(); + + if (_DEBUG_) + printf("%d E': %s\n", myAddress, (finalColor[myAddress] == COLOR_BLACK) ? "BLACK" : "WHITE"); + + // Invia l'informazione sul proprio colore ai vicini. + send_COLOR(-1, finalColor[myAddress]); + + // Fa partire il timeout sulla ricezione del secondo colore da parte dei vicini. + timer->launchLastDecisionTimeouts(); + + case MPR_STATUS_LAST_DECISION : + + // Se un nodo NON ha collezionato tutte le informazioni sull'ultima + // colorazione dei vicini allora non avanza di fase + if (finalColor.size() != (neighbors.size() + 1)) + return; + + endModule(); + } +} + +// Verifica che un pacchetto sia di tipo DATA. +bool +MPR_Agent::isDataPacket(Packet * p) +{ + struct hdr_mpr *mprh = HDR_MPR(p); + return (mprh->msg_type == MPR_DATA); +} + +// Preparazione all'invio di un messaggio al layer inferiore +void +MPR_Agent::prepareSendDataDown(Packet * p) +{ + struct hdr_mpr *mprh = HDR_MPR(p); + + // Marca il nodo come dato. + mprh->msg_type = MPR_DATA; +} + diff -Naur ns-allinone-2.29-old/ns-2.29/clustering/mpr/mpr.h ns-allinone-2.29/ns-2.29/clustering/mpr/mpr.h --- ns-allinone-2.29-old/ns-2.29/clustering/mpr/mpr.h 1970-01-01 01:00:00.000000000 +0100 +++ ns-allinone-2.29/ns-2.29/clustering/mpr/mpr.h 2007-08-03 22:23:30.000000000 +0200 @@ -0,0 +1,246 @@ + +/** + * Copyright (c) 2006 Michele Mastrogiovanni. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#ifndef _MPR_H_ +#define _MPR_H_ + +#include + +////////////////// +// Node's state // +////////////////// +typedef enum { + MPR_STATUS_HELLO = 0x1, // Node is collecting neighbors information. + MPR_STATUS_FIRST_DECISION = 0x2, // Node is waiting information about MPR set. + MPR_STATUS_LAST_DECISION = 0x3, // Node is waiting last color from neighbors. + MPR_STATUS_END = 0x4 // Node ended coloration algorithm. +} MprStatus; + +////////////////////// +// Tipi di messaggi // +////////////////////// +typedef enum +{ + MPR_NEIGHBORS = 0x0, // Node send its neighbors list. + MPR_SELECTION = 0x1, // A Node communicate to a neighbor its selection about MPR set. + MPR_COLOR = 0x2, // A Node communicate final color to neighbors. + MPR_REQUEST = 0x3, // Request of retransmission. + MPR_DATA = 0x4 // Data message. +} MprMessageType; + +////////////////////////// +// Header del pacchetto // +////////////////////////// +struct hdr_mpr +{ + + MprMessageType msg_type; // Message Type. + MprStatus status; // Request message. + NodeList * node_list; // Neighbors list. + bool mpr_selected; // Notify if a node was selected as MPR. + Color color; // Used to notify last color. + + //////////////////// + // Accessibilita' // + //////////////////// + static int offset_; + inline static int& offset() { return offset_; } + inline static hdr_mpr* access(const Packet* p) { + return (hdr_mpr*) p->access(offset_); + } +}; + +/////////// +// Timer // +/////////// +class MprTimer; + +/////////// +// Agent // +/////////// +class MPR_Agent : public ClusteringModule +{ +public: + + MPR_Agent(); + + // Funzione di ricezione dell'algoritmo di clustering. + virtual void receive(Packet * p, Handler * h); + + // Fa partire il modulo. + virtual void startModule(); + + // Termine del lavoro del modulo. + virtual void endModule(); + + // Segnala lo scadere di un timeout per un messaggio. + void timeout(MprStatus type, NodeAddress from); + + // Segnala il raggiungimento del massimo numero di timeout per un messaggio. + void lastTimeout(MprStatus type, NodeAddress from); + + // Verifica che un pacchetto sia di tipo DATA. + virtual bool isDataPacket(Packet * p); + + // Preparazione all'invio di un messaggio al layer inferiore + virtual void prepareSendDataDown(Packet * p); + +protected: + + MprStatus status; // Agent's state. + + NodeNeighbors nodeNeighbors; // Neighbors of node's neighbors. + NodeList mprNeighbors; // MPR Set of node. + NodeList twoHopNeighbors; // Two Hop Neighbors. + + map mprSelection; // Final MPR selection for interested nodes. + + MprTimer * timer; // Timeout manager. + + NodeColor finalColor; // Final color of node and neighbors. + + int selection; // MPR selection of smallest neighbor. + + NodeAddress smallerNeighbor; // Smaller Neighbors between its neighbors and current node. + +protected: + + /////////////// + // Procedure // + /////////////// + + // Manage phase change. + void processStatus(); + + // Send neighbors list to neighbors. + void send_NEIGHBORS(NodeAddress to); + + // Notify final color. + void send_COLOR(NodeAddress to, Color color); + + // Notify MPR selection. + void send_MPR(NodeAddress to, bool selection); + + // Invia la richiesta di un certo messaggio ad un vicino. + void send_REQUEST(MprStatus message, NodeAddress to); + + // Ricezione della lista dei vicini di un vicino. + void receive_NEIGHBORS(NodeAddress from, NodeList & neighbors); + + // Ricezione del colore NERO di un vicino per una fase del protocollo. + void receive_COLOR(NodeAddress from, Color color); + + // Ricezione del colore NERO di un vicino per una fase del protocollo. + void receive_MPR(NodeAddress from, bool selected); + + // Ricezione di una richiesta di ritrasmissione per un messaggio da parte di un vicino. + void receive_REQUEST(NodeAddress from, MprStatus message); + + //////////////////// + // Interrogazioni // + //////////////////// + + // Verifica se due vicini del nodo solo NON connessi. + bool twoNeighborsAreUnlinked(); + + // Verifica la REGOLA sulla base delle lunghezze specificate. + void applyRules(); + + // Calculate MPR set (rule 1 and 2). + void calculateMPRSet(); + + // Restituisce il piu'grande vicino NERO. + NodeAddress greaterCluster(); + +public: + + static int enhanced; // Enanched Rule. + static int enhanced_2; // Enhanced Rule 2. + + static int _DEBUG_; + + static double max_delay; + static int max_timeout_hello; + static double jitter_timeout_hello; + static double timeout_hello; + static int max_timeout_first_decision; + static double jitter_timeout_first_decision; + static double timeout_first_decision; + static int max_timeout_last_decision; + static double jitter_timeout_last_decision; + static double timeout_last_decision; + +}; + +///////////////////////////////// +// Timer per le ritrasmissioni // +///////////////////////////////// +class MprTimer: public Handler { +public: + + MprTimer(MPR_Agent * a) : Handler(), agent(a) {} + + void handle(Event* e); + + // Inizializza i timeout di un nodo + void initTimeouts(NodeList & neighbors); + + // Lancia tutti i timeout per i messaggi HELLO. + void launchHelloTimeouts(); + + // Lancia tutti i timeout per i messaggi FIRST DECISION. + void launchFirstDecisionTimeout(NodeAddress node); + + // Lancia tutti i timeout per i messaggi SECOND DECISION. + void launchLastDecisionTimeouts(); + + // Viene segnalata la ricezione di un messaggio di HELLO: si elimina il timeout. + void receivedHello(NodeAddress from); + + // Viene segnalata la ricezione di un messaggio di FIRST DECISION: si elimina il timeout. + void receivedFirstDecision(NodeAddress from); + + // Viene segnalata la ricezione di un messaggio di SECOND DECISION: si elimina il timeout. + void receivedLastDecision(NodeAddress from); + + // Verifica che il timeout sia per il messaggio di HELLO. + bool isHelloTimeout(Event * e); + + // Verifica che il timeout sia per il messaggio di FIRST DECISION. + bool isFirstDecisionTimeout(Event * e); + + // Verifica che il timeout sia per il messaggio di LAST DECISION. + bool isLastDecisionTimeout(Event * e); + +protected: + + // Timeout attivi per i messaggi HELLO. + TimeoutMap hello_timeouts; + + // Timeout attivi per i messaggi FIRST DECISION (MPR Selection). + TimeoutMap first_decision_timeouts; + + // Timeout attivi per i messaggi LAST DECISION (Color). + TimeoutMap last_decision_timeouts; + + // Agente proprietario del Timer. + MPR_Agent * agent; + +}; + +#endif \ No newline at end of file diff -Naur ns-allinone-2.29-old/ns-2.29/clustering/rajaraman/.DS_Store ns-allinone-2.29/ns-2.29/clustering/rajaraman/.DS_Store --- ns-allinone-2.29-old/ns-2.29/clustering/rajaraman/.DS_Store 1970-01-01 01:00:00.000000000 +0100 +++ ns-allinone-2.29/ns-2.29/clustering/rajaraman/.DS_Store 2007-08-03 22:23:30.000000000 +0200 @@ -0,0 +1 @@ +Bud1 nitiondefinitions_raj.hIlocblobZ!˙˙˙˙˙˙LinkedStatus.ccIlocblobÂ!˙˙˙˙˙˙LinkedStatus.hIlocblobZ}˙˙˙˙˙˙ rajaraman.ccIlocblob}˙˙˙˙˙˙ rajaraman.hIlocblobÂ}˙˙˙˙˙˙  @€ @€ @€ @ E DSDB `€ @€ @€ @ \ No newline at end of file diff -Naur ns-allinone-2.29-old/ns-2.29/clustering/rajaraman/LinkedStatus.cc ns-allinone-2.29/ns-2.29/clustering/rajaraman/LinkedStatus.cc --- ns-allinone-2.29-old/ns-2.29/clustering/rajaraman/LinkedStatus.cc 1970-01-01 01:00:00.000000000 +0100 +++ ns-allinone-2.29/ns-2.29/clustering/rajaraman/LinkedStatus.cc 2007-08-03 22:23:30.000000000 +0200 @@ -0,0 +1,79 @@ + +/** + * Copyright (c) 2006 Michele Mastrogiovanni. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#include "LinkedStatus.h" + +template +void +LinkedStatus<_DataNode, _DataTime>::addState(_DataNode data, const _DataTime & time) +{ + // + // Verifica se il messaggio è giĂ  presente e ordina l'inserimento. + // + for (_myList::iterator i = l.begin(); i != l.end(); i++) { + // Se il dato da inserire esiste, si scarta + if ((i->time) == time) + return; + + if ((i->dataTime) < time) { + _myStruct d; + d.dataNode = data; + d.dataTime = time; + l.insert(i, d); + return; + } + } + + _myStruct d; + d.dataNode = data; + d.dataTime = time; + + l.push_back(d); + if (history == -1) + return; + if (l.size() > history) + l.pop_back(); +} + +template +_DataNode & +LinkedStatus<_DataNode, _DataTime>::getState(const _DataTime time) +{ + for (_myList::iterator i = l.begin(); i != l.end(); i++) + if (i->dataTime == time) + return i->dataNode; + return empty; +} + +template +_DataTime & +LinkedStatus<_DataNode, _DataTime>::getLast() +{ + return (*(l.begin())); +} + + +template +bool +LinkedStatus<_DataNode, _DataTime>::isPresent(const _DataTime time) +{ + for (_myList::iterator i = l.begin(); i != l.end(); i++) + if (i->dataTime == time) + return true; + return false; +} diff -Naur ns-allinone-2.29-old/ns-2.29/clustering/rajaraman/LinkedStatus.h ns-allinone-2.29/ns-2.29/clustering/rajaraman/LinkedStatus.h --- ns-allinone-2.29-old/ns-2.29/clustering/rajaraman/LinkedStatus.h 1970-01-01 01:00:00.000000000 +0100 +++ ns-allinone-2.29/ns-2.29/clustering/rajaraman/LinkedStatus.h 2007-08-03 22:23:30.000000000 +0200 @@ -0,0 +1,64 @@ + +/** + * Copyright (c) 2006 Michele Mastrogiovanni. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +// +// Questa classe rappresenta lo stato di un nodo: +// è una lista di stati che si susseguono temporalmente in cui +// vengono mantenute 2 tipi di informazioni: +// 1) I dati relativi a un nodo. +// 2) I dati relativi allo stato. +// +// E'possibile solo memorizzare informazioni successive +// oppure richiedere informazioni passate. +// La storia del nodo è ridotta ad un certo numero di istanti +// prefissati. +// + +#include + +using namespace std; + +template +struct LinkedData { + _DataNode dataNode; + _DataTime dataTime; +}; + +template +class LinkedStatus +{ + public: + LinkedStatus(int history) : history(abs(history)) {} + LinkedStatus() : history(-1) {} + + void addState(_DataNode data, const _DataTime & time); + + _DataNode & getState(const _DataTime time); + + bool isPresent(const _DataTime time); + + _DataTime & getLast(); + + protected: + typedef struct LinkedData<_DataNode, _DataTime> _myStruct; + typedef list<_myStruct> _myList; + + _myList l; + int history; + _DataNode empty; +}; diff -Naur ns-allinone-2.29-old/ns-2.29/clustering/rajaraman/definitions_raj.h ns-allinone-2.29/ns-2.29/clustering/rajaraman/definitions_raj.h --- ns-allinone-2.29-old/ns-2.29/clustering/rajaraman/definitions_raj.h 1970-01-01 01:00:00.000000000 +0100 +++ ns-allinone-2.29/ns-2.29/clustering/rajaraman/definitions_raj.h 2007-08-03 22:25:02.000000000 +0200 @@ -0,0 +1,114 @@ + +/** + * Copyright (c) 2006 Michele Mastrogiovanni. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +/** + * Questo file contiene alcune definizioni utilizzate nell' + * algoritmo rajaraman (e forse nel vezirani). + */ + + //------------------------------------------------------ +// Tempo dell'algoritmo. +//------------------------------------------------------ +typedef struct _AlgorithmTime { + // Round. + int round; + // Fase. + int fase; + // Valore massimo di fase. + int last_fase; + + public: + + _AlgorithmTime() { + round = 0; + fase = 0; + last_fase = 0; + } + + // Costruttore. + _AlgorithmTime(int r, int f, int l) { + round = r; + fase = f; + last_fase = l; + } + + // Costruttore. + _AlgorithmTime(const _AlgorithmTime & t) { + round = t.round; + fase = t.fase; + last_fase = t.last_fase; + } + + // Operatore di uguaglianza. + bool operator== (struct _AlgorithmTime & t) { + return ((t.fase == fase) && (t.round == round)); + } + + // Operatore minore. + bool operator < (struct _AlgorithmTime & t) { + if (round < t.round) + return true; + if (round > t.round) + return false; + if (fase < t.fase) + return true; + return false; + } + + // Operatore maggiore. + bool operator > (struct _AlgorithmTime & t) { + if (round > t.round) + return true; + if (round < t.round) + return false; + if (fase > t.fase) + return true; + return false; + } + + void operator++ () { + if (fase == last_fase) { + round++; + fase = 0; + return; + } + fase++; + } + + void operator-- () { + if (fase == 0) { + round--; + fase = last_fase; + return; + } + fase--; + } +} AlgorithmTime; + +template<> +bool +std::less::operator()(const AlgorithmTime & t1, const AlgorithmTime & t2) const +{ + if (t1.round < t2.round) + return true; + if (t1.round > t2.round) + return false; + if (t1.fase < t2.fase) + return true; + return false; +} diff -Naur ns-allinone-2.29-old/ns-2.29/clustering/rajaraman/rajaraman.cc ns-allinone-2.29/ns-2.29/clustering/rajaraman/rajaraman.cc --- ns-allinone-2.29-old/ns-2.29/clustering/rajaraman/rajaraman.cc 1970-01-01 01:00:00.000000000 +0100 +++ ns-allinone-2.29/ns-2.29/clustering/rajaraman/rajaraman.cc 2007-08-03 22:23:30.000000000 +0200 @@ -0,0 +1,1182 @@ + +/** + * Copyright (c) 2006 Michele Mastrogiovanni. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +// Ricorda sempre di rendere concordi l'assegnazione del clusterHead e la cover: +// un nodo clusterHead e'anche cevered. + +//////////////// +// NS Headers // +//////////////// +#include "rajaraman.h" +#include "random.h" +#include "gridkeeper.h" + +#include "Separator.h" + +#include + +/////////////////////////////////// +// Parte di dichiarazione comune // +/////////////////////////////////// + +int hdr_rajaraman::offset_; + +int RAJARAMAN_Agent::_DEBUG_; + +int RAJARAMAN_Agent::rounded_span; +int RAJARAMAN_Agent::fraction; + +double RAJARAMAN_Agent::max_delay; +int RAJARAMAN_Agent::max_timeout_message; +double RAJARAMAN_Agent::jitter_timeout_message; +double RAJARAMAN_Agent::timeout_message; + +int RAJARAMAN_Agent::b_param; + +static class RajaramanClass : public TclClass { +public: + RajaramanClass() : TclClass("Agent/RAJARAMAN") {} + TclObject* create(int , const char*const* ) { + return(new RAJARAMAN_Agent()); + } +} class_rajaraman; + +static class RajaramanHeaderClass : public PacketHeaderClass { +public: + RajaramanHeaderClass() : PacketHeaderClass("PacketHeader/RAJARAMAN", + sizeof(hdr_rajaraman)) { + bind_offset(&hdr_rajaraman::offset_); + } +} class_rajaramanhdr; + +void +RajaramanTimer::clearAll() +{ + message_timeouts.clear(); +} + +// Definizione del timer. +void +RajaramanTimer::handle(Event * e) +{ + // + // Timeout MESSAGE. + // + for (TimeoutMap::iterator i = message_timeouts.begin(); i != message_timeouts.end(); i++) { + if (i->second.timeout == e) { + i->second.num--; + if (i->second.num <= 0) { + agent->lastTimeout(i->first, RAJARAMAN_Agent::max_timeout_message - i->second.num); + } + else { + Scheduler::instance().schedule(this, e, + RAJARAMAN_Agent::timeout_message + Random::uniform(RAJARAMAN_Agent::jitter_timeout_message)); + agent->timeout(i->first, RAJARAMAN_Agent::max_timeout_message - i->second.num); + } + } + } + + // + // Timeout TERMINATION. + // + for (TimeoutMap::iterator i = termination_timeouts.begin(); i != termination_timeouts.end(); i++) { + if (i->second.timeout == e) { + i->second.num--; + if (i->second.num <= 0) { + agent->lastTimeoutTermination(i->first, RAJARAMAN_Agent::max_timeout_message - i->second.num); + } + else { + Scheduler::instance().schedule(this, e, + RAJARAMAN_Agent::timeout_message + Random::uniform(RAJARAMAN_Agent::jitter_timeout_message)); + agent->timeoutTermination(i->first, RAJARAMAN_Agent::max_timeout_message - i->second.num); + } + } + } +} + +// +// Lancia un timeout verso una lista di vicini. +// +void +RajaramanTimer::launchMessageTimeout(NodeList & neighbors) +{ + for (NodeList::iterator i = neighbors.begin(); i != neighbors.end(); i++) { + // + // Definisce i Timeout di tipo MESSAGE + // + struct Timeout h; + h.timeout = new Event(); + h.num = RAJARAMAN_Agent::max_timeout_message; + message_timeouts[*i] = h; + Scheduler::instance().schedule(this, h.timeout, RAJARAMAN_Agent::timeout_message + Random::uniform(RAJARAMAN_Agent::jitter_timeout_message)); + } +} + +// +// Lancia un timeout verso una lista di vicini. +// +void +RajaramanTimer::launchTerminationTimeout(NodeList & neighbors) +{ + for (NodeList::iterator i = neighbors.begin(); i != neighbors.end(); i++) { + // + // Definisce i Timeout di tipo MESSAGE + // + struct Timeout h; + h.timeout = new Event(); + h.num = RAJARAMAN_Agent::max_timeout_message; + termination_timeouts[*i] = h; + Scheduler::instance().schedule(this, h.timeout, RAJARAMAN_Agent::timeout_message + Random::uniform(RAJARAMAN_Agent::jitter_timeout_message)); + } +} + +// +// Elimina un timeout. +// +void +RajaramanTimer::receivedMessage(NodeAddress from) +{ + TimeoutMap::iterator i; + for (i = message_timeouts.begin(); i != message_timeouts.end(); i++) { + if ((i->first) == from) { + Scheduler::instance().cancel((i->second).timeout); + break; + } + } + if (i != message_timeouts.end()) + message_timeouts.erase(i); +} + +// +// Elimina un timeout. +// +void +RajaramanTimer::receivedTermination(NodeAddress from) +{ + TimeoutMap::iterator i; + for (i = termination_timeouts.begin(); i != termination_timeouts.end(); i++) { + if ((i->first) == from) { + Scheduler::instance().cancel((i->second).timeout); + break; + } + } + if (i != termination_timeouts.end()) + termination_timeouts.erase(i); +} + +// +// Costruttore dell'agente. +// +RAJARAMAN_Agent::RAJARAMAN_Agent() : ClusteringModule(PT_RAJARAMAN), currentTime(0, RAJARAMAN_PHASE_SPAN_1, RAJARAMAN_PHASE_DECISION_2), ended(false) +{ + timer = new RajaramanTimer(this); + + bind_bool("debug", &_DEBUG_); + bind_bool("rounded-span", &rounded_span); + bind_bool("fraction", &fraction); + + bind("b-param", &b_param); + + bind("max-delay", &max_delay); + bind("max-timeout-message", &max_timeout_message); + bind("jitter-timeout-message", &jitter_timeout_message); + bind("timeout-message", &timeout_message); +} + +// +// Determina il rounded_span in base al parametro B. +// Si assume che il valore passato come SPAN sia +// maggiore o uguale a 0. +// Il rounded span di 0  0. +// Qualunque valore negativo viene restituito uguale. +// +int +RAJARAMAN_Agent::roundedSpan(int span) +{ + + if (!RAJARAMAN_Agent::rounded_span) + return span; + + if (span < 0) + return span; + if (span == 0) + return 0; + int value = 1; + while (value < span) + value *= b_param; + return value; +} + +// +// Riceve un messaggio di tipo VALUE. +// Possono essere ricevuti i messaggi di tipo +// VALUE normali oppure i messaggi TERMINATE. +// In entrambi i casi la procedura di ricezione  +// la stessa. Si tenga solo conto che il messaggio +// TERMINATE una volta ricevuto viene utilizzato per +// memorizzare lo stato finale di un nodo e per +// inviare la conferma. Non  necessario farlo in +// questa procedura. +// +void +RAJARAMAN_Agent::receive_MSG(NodeAddress from, AlgorithmTime time, DataNode d) +{ + if (ended) { + // + // Avvia il livello superiore se ce ne e'uno + // e se tutti i nodi vicini hanno terminato. + // + for (NodeList::iterator n = neighbors.begin(); n != neighbors.end(); n++) + if (finalState[*n] == RAJARAMAN_STATUS_UNKNOWN) + return; + + reallyEnd(); + + return; + } + + // + // Se il messaggio  di un round successivo al corrente + // viene bufferizzato. + // + if (currentTime < time) { + DataBuffer db; + db.sender = from; + db.data = d; + db.time = time; + buffer.push_back(db); + return; + } + + // + // Se il messaggio appartiene a un round passato + // viene scartato. + // + if (time < currentTime) + return; + + // + // Il messaggio appartiene al round corrente. + // + + // + // Verifica se il nodo  uno di quelli attivi. + // + if (!belongToActiveNeighbors(from)) + return; + + // + // Se  giˆ noto lo stato per quel nodo allora + // il messaggio  giˆ giunto e viene pertanto + // scartato. + // + if (data[currentTime][from].state != RAJARAMAN_STATUS_UNKNOWN) + return; + + // + // Elimina il timeout per la ricezione di quel + // messaggio. + // + timer->receivedMessage(from); + + // + // Memorizza lo stato e il valore associati + // al nodo mittente. + // + data[currentTime][from] = d; + + // + // Stampa il messaggio ricevuto. + // + if (_DEBUG_) { + if (d.value == RAJARAMAN_TERMINATION) { + printf("(%f.2) %d received TERMINATE from %d\n", NOW, myAddress, from); + } + else { + printf("(%f.2) - %d received ", NOW, myAddress); + switch (time.fase) { + case RAJARAMAN_PHASE_SPAN_1 : + printf("SPAN_1 (%d)", d.value); + break; + case RAJARAMAN_PHASE_SPAN_2 : + printf("SPAN_2 (%d)", d.value); + break; + case RAJARAMAN_PHASE_CANDIDATE : + printf("CANDIDATE %s", d.value == RAJARAMAN_VALUE_YES ? "YES" : "NO"); + break; + case RAJARAMAN_PHASE_SUPPORT : + printf("SUPPORT (%d)", d.value); + break; + case RAJARAMAN_PHASE_DECISION_1 : + switch (d.state) { + case RAJARAMAN_STATUS_IN : printf("DECISION_1 BLACK"); break; + case RAJARAMAN_STATUS_OUT : printf("DECISION_1 GRAY"); break; + case RAJARAMAN_STATUS_UNDECIDED : printf("DECISION_1 WHITE"); break; + } + break; + case RAJARAMAN_PHASE_DECISION_2 : + switch (d.state) { + case RAJARAMAN_STATUS_IN : printf("DECISION_2 BLACK"); break; + case RAJARAMAN_STATUS_OUT : printf("DECISION_2 GRAY"); break; + case RAJARAMAN_STATUS_UNDECIDED : printf("DECISION_2 WHITE"); break; + } + break; + } + printf(" from %d\n", from); + } + } + + // + // Se non sono stati ancora ricevuti tutti i messaggi + // del round corrente allora ritorna. + // + if (!receivedAllMessages(currentTime)) + return; + + // + // Decide se avanzare di fase. + // + processStatus(); +} + +bool +RAJARAMAN_Agent::belongToActiveNeighbors(NodeAddress from) +{ + for (DataNodes::iterator n = data[currentTime].begin(); n != data[currentTime].end(); n++) + if ((n->first) == from) + return true; + + return false; +} + +// +// Riceve un messaggio. +// +void +RAJARAMAN_Agent::receive(Packet *p, Handler *h) +{ + struct hdr_rajaraman *rajaramanh = HDR_RAJARAMAN(p); + struct hdr_ip *iph = HDR_IP(p); + + // Mittente. + NodeAddress sender_address = iph->saddr(); + // Destinazione. + NodeAddress destination_address = iph->daddr(); + + switch (rajaramanh->msg_type) { + + case RAJARAMAN_MSG_VALUE : + + // + // Se un nodo comunica il suo stato finale, lo memorizza + // e invia la conferma. + // + if ((rajaramanh->data).value == RAJARAMAN_TERMINATION) { + finalState[sender_address] = (rajaramanh->data).state; + send_CONFIRM(sender_address); + } + + // + // Processa il messaggio. + // + receive_MSG(sender_address, rajaramanh->time, rajaramanh->data); + + break; + + case RAJARAMAN_MSG_REQUEST : + + if ((rajaramanh->data).value != myAddress) + break; + + // + // Se il messaggio  disponibile viene inviato + // nuovamente. + // + if (((rajaramanh->time) < currentTime) || + ((rajaramanh->time) == currentTime)) { + + send_VALUE(data[rajaramanh->time][myAddress], rajaramanh->time, sender_address); + + } + + // + // Le richieste di messaggi non disponibili + // vengono scartate. + // + break; + + case RAJARAMAN_MSG_CONFIRM : + + if ((rajaramanh->data).value != myAddress) + break; + + // + // Elimina il timeout per la ricezione di quel + // messaggio. + // Non viene controllata la terminazione perch questa + // dipende solo dalla ricezione del messaggio TERMINATE + // di ogni nodo e non dalla effettiva ricezione dell'ACK + // ad esso correlato. + // + timer->receivedTermination(sender_address); + + break; + + } + + // Packet::free(p); +} + +// +// Imposta i valori per un nuovo round: crea una lista di nodi +// che  uguale a quella del round precedente e in cui i nodi +// che nel round precedente avevano inviato un messaggio di +// TERMINAZIONE sono assenti. +// Ciascun nodo viene posto nello stato UNKNOWN e ha un valore +// di default pari a 0 (neutro). +// Un messaggio si considera arrivato se lo stato di un nodo +//  diverso da UNKNOWN (e contiene lo stato del nodo). +// Se nel round precedente il nodo corrente aveva inviato un +// messaggio di terminazione allora richiama la procedura di +// fine. +// +void +RAJARAMAN_Agent::initializeRound(AlgorithmTime t) +{ + // + // Determina il tempo precedente. + // + AlgorithmTime previouseTime(t); + --previouseTime; + + for (DataNodes::iterator n = data[previouseTime].begin(); + n != data[previouseTime].end(); + n++) { + // + // Se il nodo nel round precedente ha terminato + // (ha come "value" "RAJARAMAN_TERMINATION") allora + // nono viene aggiunto alla lista successiva. + // Viene considerato un messaggio di terminazione + // anche il messaggio RAJARAMAN_STATUS_IN inviato + // nel round "RAJARAMAN_PHASE_DECISION_1". + // + if ((n->second).value != RAJARAMAN_TERMINATION) { + data[t][n->first].state = RAJARAMAN_STATUS_UNKNOWN; + data[t][n->first].value = RAJARAMAN_NO_VALUE; + } + } +} + +// +// Verifica che siano giunti tutti i messaggi per un certo +// round. La procedura controlla se qualcuno dei nodi del +// round  ancora nello stato UNKNOWN. +// +bool +RAJARAMAN_Agent::receivedAllMessages(AlgorithmTime time) +{ + bool ret = true; + for (DataNodes::iterator n = data[time].begin(); n != data[time].end(); n++) + if ((n->second).state == RAJARAMAN_STATUS_UNKNOWN) + return false; + + return true; +} + +void +RAJARAMAN_Agent::reallyEnd() +{ + // + // Imposta i clusterHeads.+ + // + for (NodeList::iterator n = neighbors.begin(); n != neighbors.end(); n++) + if (finalState[*n] == RAJARAMAN_STATUS_IN) + setClusterHead(*n, myAddress); + else + setClusterHead(*n, -1); + if (finalState[myAddress] == RAJARAMAN_STATUS_IN) + setClusterHead(myAddress, myAddress); + else { + NodeAddress node = -1; + for (NodeList::iterator n = neighbors.begin(); n != neighbors.end(); n++) { + setClusterHead(*n, finalState[*n] == RAJARAMAN_STATUS_IN ? *n : -1); + if (finalState[*n] == RAJARAMAN_STATUS_IN) + if ((*n) > node) + node = (*n); + } + setClusterHead(myAddress, node); + } + + if (_DEBUG_) { + printf("RAJARAMAN %d is %s\n", myAddress, getClusterHead(myAddress) == myAddress ? "BLACK" : "WHITE"); + // printf("\t- %d  %s\n", *n, finalState[*n] == RAJARAMAN_STATUS_IN ? "BLACK" : (finalState[*n] == RAJARAMAN_STATUS_OUT ? "WHITE" : "UNCOLORED")); + } + + if (statusModule == CALCULATED) + return; + + if (utility) + ((RajaramanUtility*)utility)->setCycles(myAddress, currentTime.round * 6 + currentTime.fase); + + // statusModule = CALCULATED; + + if (_DEBUG_) + printf("(%f.2) - %d REALLY END: %s\n", NOW, myAddress, finalState[myAddress] == RAJARAMAN_STATUS_IN ? "BLACK" : (finalState[myAddress] == RAJARAMAN_STATUS_OUT ? "WHITE": "UNCOLORED")); + + // + // Imposta il colore finale. + // + if (utility) + ((ClusteringUtility*)utility)->setColor(myAddress, finalState[myAddress] == RAJARAMAN_STATUS_IN ? "black" : "white"); + + ClusteringModule::endModule(); + + if (upTarget) + Separator::instance().endCurrentModule(myAddress); +} + +// +// Termine dell'algoritmo. +// +void +RAJARAMAN_Agent::endModule() +{ + if (_DEBUG_) + printf("(%f.2) - %d CHOOSE: %s\n", NOW, myAddress, finalState[myAddress] == RAJARAMAN_STATUS_IN ? "BLACK" : (finalState[myAddress] == RAJARAMAN_STATUS_OUT ? "WHITE": "UNCOLORED")); + + // + // Segnala che l'algoritmo  terminato + // + ended = true; + + // + // Avvia il livello superiore se ce ne e'uno + // e se tutti i nodi vicini hanno terminato. + // + for (NodeList::iterator n = neighbors.begin(); n != neighbors.end(); n++) + if (finalState[*n] == RAJARAMAN_STATUS_UNKNOWN) + return; + + reallyEnd(); +} + +// +// Lancia l'algoritmo. +// +void +RAJARAMAN_Agent::startModule() +{ + ended = false; + + // + // Avvia l'algoritmo. + // + ClusteringModule::startModule(); + + // + // Imposta lo stato di tutti i vicini a UNKNOWN. + // + for (NodeList::iterator n = neighbors.begin(); n != neighbors.end(); n++) { + data[currentTime][*n].state = RAJARAMAN_STATUS_UNKNOWN; + setClusterHead(*n, -2); + finalState[*n] = RAJARAMAN_STATUS_UNKNOWN; + } + + // + // ... e del nodo corrente. + // + data[currentTime][myAddress].state = RAJARAMAN_STATUS_UNDECIDED; + finalState[myAddress] = RAJARAMAN_STATUS_UNKNOWN; + + // + // Il valore di SPAN_1 in partenza  prefissato. + // + data[currentTime][myAddress].value = roundedSpan(neighbors.size() + 1); + + // + // Invia il proprio SPAN_1 in broadcast a tutti i vicini. + // + send_VALUE(data[currentTime][myAddress], currentTime, -1); + + // Lancia il timeout verso tutti i vicini. + // + NodeList nodes; + for (DataNodes::iterator n = data[currentTime].begin(); + n != data[currentTime].end(); + n++) { + + nodes.insert(n->first); + } + nodes.erase(myAddress); + timer->launchMessageTimeout(nodes); +} + +// +// Avanza di fase in base al valore di decisione estratto +// dalla fase corrente: +// 1) Incremente il contatore del round. +// 2) Inizializza il round successivo (ed eventualmente termina). +// 3) Memorizza il suo nuovo stato. +// 4) Fa partire i timeout. +// 5) Riceve tutti i messaggi bufferizzati. +// +void +RAJARAMAN_Agent::advancePhase(DataNode & nextDataNode) +{ + // + // Avanza di round. + // + ++currentTime; + + // + // Inizializza il round successivo (ed + // eventualmente termina). + // + initializeRound(currentTime); + + // + // Memorizza le informazioni del nodo. + // + data[currentTime][myAddress] = nextDataNode; + + // + // Invia il proprio valore. + // + send_VALUE(nextDataNode, currentTime, -1); + + // + // Se il nodo non ha terminato allora il messaggio + // deve essere confermato dai messaggi dei nodi + // sopravvissuti. + // Il messaggio di terminazione deve essere confermato + // esplicitamente da tutti. + // + if (nextDataNode.value != RAJARAMAN_TERMINATION) { + NodeList nodes; + for (DataNodes::iterator n = data[currentTime].begin(); n != data[currentTime].end(); n++) + if ((n->first) != myAddress) + nodes.insert(n->first); + + timer->launchMessageTimeout(nodes); + + // + // Svuota il buffer dei messaggi. + // + emptyBuffer(); + + // + // Se non sono stati ancora ricevuti tutti i messaggi + // del round corrente allora ritorna. + // + if (!receivedAllMessages(currentTime)) + return; + + // + // Verifica lo stato di terminazione. + // + processStatus(); + } + else { + // + // Memorizza lo stato finale + // + finalState[myAddress] = data[currentTime][myAddress].state; + + // + // E' stato inviato il messaggio TERMINATE: + // lancia il timeout verso tutti i vicini e + // + timer->launchTerminationTimeout(neighbors); + + // + // Termina la procedura. + // + endModule(); + } + + +} + +// +// Avanza di fase: effettua i calcoli per inviare il +// messaggio della fase successiva. +// +void +RAJARAMAN_Agent::processStatus() +{ + if (_DEBUG_) + printf("----------- PROCESS ---------\n"); + + // + // Variabili ausiliarie: + // + int max, count; + float fraction_count; + bool flag; + + // + // Informazioni del round successivo: + // Il valore viene impostato a "NO_VALUE" e lo stato + // al valore di stato corrente. + // + DataNode nextDataNode; + nextDataNode.value = RAJARAMAN_NO_VALUE; + nextDataNode.state = data[currentTime][myAddress].state; + + // + // Determina il turno passato. + // + AlgorithmTime previouseTime(currentTime); + --previouseTime; + + // + // Funzione di debug per stampare le informazioni in + // possesso di un nodo. + // + if (_DEBUG_) + printValues(); + + // + // A seconda del round corrente viene determinato lo + // stato successivo del nodo. + // + switch (currentTime.fase) { + + case RAJARAMAN_PHASE_SPAN_1 : + + // + // Il nodo possiede il rounded_span di tutti i + // vicini calcola il massimo e lo invia + // ai vicini rimasti. Eventuali messaggi di + // terminazione non alterano il calcolo in + // quanto vagono -1. + // + max = 0; + for (DataNodes::iterator n = data[currentTime].begin(); + n != data[currentTime].end(); + n++) { + + if ((n->second).value > max) + max = (n->second).value; + } + + // + // Imposta il nuovo stato e il valore da propagare. + // + nextDataNode.value = max; + + // + // Verifica lo stato di terminazione. + // + if (nextDataNode.value == 0) { + nextDataNode.value = RAJARAMAN_TERMINATION; + } + + break; + + case RAJARAMAN_PHASE_SPAN_2 : + // + // Il nodo possiede il massimo span inviato da + // ogni vicino: pu˜ determinare lo span massimo + // a distanza 2 hop e verificare se  in possesso + // dello span pi alto (o uguale). + // In questo modo pu˜ determinare la sua + // candidatura. + // + max = data[previouseTime][myAddress].value; + for (DataNodes::iterator n = data[currentTime].begin(); + n != data[currentTime].end(); + n++) { + + if ((n->second).value > max) + max = (n->second).value; + } + + // + // Imposta il nuovo stato: se lo span di livello + // 1 del nodo corrente  maggiore o uguale al + // massimo span di livello 2 (calcolato + // considerando il nodo corrente e ogni suo + // vicino) allora il nodo  un candidato (1). + // + if (data[previouseTime][myAddress].value >= max) + nextDataNode.value = RAJARAMAN_VALUE_YES; + else + nextDataNode.value = RAJARAMAN_VALUE_NO; + + break; + + case RAJARAMAN_PHASE_CANDIDATE : + // + // Il nodo possiede il valore di candidatura di + // ogni vicino e il suo. + // Se il nodo non  coperto, il supporto di un + // nodo  pari al numero di candidati incluso se + // stesso. + // Se il nodo  coperto invia come valore + // di supporto il valore 0. Sarˆ il nodo + // destinatario a non considerare tale nodo + // nei calcoli successivi. + // Invia poi il suo supporto ad ogni vicino. + // + count = 0; + if (data[currentTime][myAddress].state == RAJARAMAN_STATUS_UNDECIDED) + for (DataNodes::iterator n = data[currentTime].begin(); + n != data[currentTime].end(); + n++) { + + if ((n->second).value == RAJARAMAN_VALUE_YES) { + count++; + } + } + + // Imposta il proprio valore di supporto. + nextDataNode.value = count; + + break; + + case RAJARAMAN_PHASE_SUPPORT : + + // + // Il nodo possiede il supporto e lo stato + // inviati da tutti i vicini. + // Pu˜ calcolare quindi la media dei supporti + // dei nodi non coperti e stabilire se + // diventare o no un nodo IN. + // + max = 0; + count = 0; + fraction_count = 0.0; + + if (data[previouseTime][myAddress].value == RAJARAMAN_VALUE_YES) { + // + // Il nodo  un candidato: determina la media + // dei supporti dei nodi non coperti che il + // nodo copre. + // + for (DataNodes::iterator n = data[currentTime].begin(); + n != data[currentTime].end(); + n++) { + + if (((n->second).state == RAJARAMAN_STATUS_UNDECIDED) && + ((n->second).value != RAJARAMAN_TERMINATION)) { + max++; + count += (n->second).value; + fraction_count += (1.0 / (float)((n->second).value)); + } + } + + if (fraction) { + // + // Il nodo decide in maniera randomica se + // diventare un clusterhead. + // + if (Random::uniform(1.0) <= (fraction_count / (float)(max))) { + nextDataNode.state = RAJARAMAN_STATUS_IN; + } + } + else { + // + // Il nodo decide in maniera randomica se + // diventare un clusterhead. + // + if (Random::uniform(1.0) <= (1.0 / ((float)(count) / (float)(max)))) { + nextDataNode.state = RAJARAMAN_STATUS_IN; + } + } + } + + break; + + case RAJARAMAN_PHASE_DECISION_1 : + + // + // Il nodo conosce lo stato finale di tutti i nodi + // vicini e pu˜ decidere per il suo secondo stato. + // Un nodo grigio non altererˆ il suo stato + // mentre un nodo UNDECIDED potrˆ diventare + // GRAY. + // Nel caso il nodo sia IN, dopo il ciclo + // invierˆ un messaggio TERMINATE. + // + if (data[currentTime][myAddress].state != RAJARAMAN_STATUS_IN) { + for (DataNodes::iterator n = data[currentTime].begin(); + n != data[currentTime].end(); + n++) { + + if ((n->second).state == RAJARAMAN_STATUS_IN) { + nextDataNode.state = RAJARAMAN_STATUS_OUT; + break; + } + } + } + else { + // + // Se il nodo  diventato clusterhead al round + // precedente allora invia un messaggio di + // terminazione. + // + nextDataNode.value = RAJARAMAN_TERMINATION; + } + + break; + + case RAJARAMAN_PHASE_DECISION_2 : + + // + // Il nodo conosce lo stato finale di ogni + // vicino: quelli che sono diventati IN e quelli + // che di conseguenza sono diventati OUT. + // Determina il suo rounded_span ed eventualmente + // termina (nel caso si renda conto di non avere + // pi nodi UNDECIDED intorno e di non esserlo + // lui stesso. + // + count = 0; + for (DataNodes::iterator n = data[currentTime].begin(); + n != data[currentTime].end(); + n++) { + + if (((n->second).state == RAJARAMAN_STATUS_UNDECIDED) && + ((n->second).value != RAJARAMAN_TERMINATION)) { + count++; + } + } + + if (count == 0) + nextDataNode.value = RAJARAMAN_TERMINATION; + else + nextDataNode.value = roundedSpan(count); + + break; + } + + // + // Avanza di fase. + // + advancePhase(nextDataNode); + + if (_DEBUG_) + printf("-------------------------------\n"); +} + +// +// Svuota il buffer dei messaggi. +// +void +RAJARAMAN_Agent::emptyBuffer() +{ + while (buffer.size() > 0) { + DataBuffer bufferizedMessage = buffer.front(); + buffer.pop_front(); + receive_MSG(bufferizedMessage.sender, bufferizedMessage.time, bufferizedMessage.data); + } +} + +void +RAJARAMAN_Agent::send_CONFIRM(NodeAddress to) +{ + Packet* p = allocpkt(); + struct hdr_rajaraman * rajaramanh = HDR_RAJARAMAN(p); + rajaramanh->msg_type = RAJARAMAN_MSG_CONFIRM; + (rajaramanh->data).value = to; + sendDown(p, sizeof(RajaramanMessage), -1, RAJARAMAN_Agent::max_delay); +} + +void +RAJARAMAN_Agent::send_REQUEST(AlgorithmTime time, + NodeAddress to) +{ + Packet* p = allocpkt(); + struct hdr_rajaraman * rajaramanh = HDR_RAJARAMAN(p); + rajaramanh->msg_type = RAJARAMAN_MSG_REQUEST; + (rajaramanh->time) = time; + (rajaramanh->data).value = to; + sendDown(p, sizeof(RajaramanMessage) + sizeof(AlgorithmTime) + sizeof(NodeAddress), -1, RAJARAMAN_Agent::max_delay); +} + +void +RAJARAMAN_Agent::send_VALUE(DataNode data, + AlgorithmTime time, + NodeAddress to) +{ + Packet* p = allocpkt(); + struct hdr_rajaraman * rajaramanh = HDR_RAJARAMAN(p); + rajaramanh->msg_type = RAJARAMAN_MSG_VALUE; + (rajaramanh->time) = time; + (rajaramanh->data) = data; + sendDown(p, sizeof(RajaramanMessage) + sizeof(AlgorithmTime) + sizeof(DataNode), to, RAJARAMAN_Agent::max_delay); + + if (_DEBUG_) { + if (data.value == RAJARAMAN_TERMINATION) { + printf("(%f.2) - %d sent TERMINATED\n", NOW, myAddress); + } + else { + printf("(%f.2) - %d sent ", NOW, myAddress); + switch (time.fase) { + case RAJARAMAN_PHASE_SPAN_1 : + printf("SPAN_1 (%d)", data.value); + break; + case RAJARAMAN_PHASE_SPAN_2 : + printf("SPAN_2 (%d)", data.value); + break; + case RAJARAMAN_PHASE_CANDIDATE : + printf("CANDIDATE %s", data.value == RAJARAMAN_VALUE_YES ? "YES" : "NO"); + break; + case RAJARAMAN_PHASE_SUPPORT : + printf("SUPPORT (%d)", data.value); + break; + case RAJARAMAN_PHASE_DECISION_1 : + printf("DECISION_1 %s", data.state == RAJARAMAN_STATUS_IN ? "BLACK" : (data.state == RAJARAMAN_STATUS_OUT ? "GRAY" : "WHITE")); + break; + case RAJARAMAN_PHASE_DECISION_2 : + printf("DECISION_2 %s", data.state == RAJARAMAN_STATUS_IN ? "BLACK" : (data.state == RAJARAMAN_STATUS_OUT ? "GRAY" : "WHITE")); + break; + } + printf("\n"); + } + } +} + +// +// Verifica che un pacchetto sia di tipo DATA. +// +bool +RAJARAMAN_Agent::isDataPacket(Packet * p) +{ + struct hdr_rajaraman *rajaramanh = HDR_RAJARAMAN(p); + return (rajaramanh->msg_type == RAJARAMAN_DATA); +} + +// +// Preparazione all'invio di un messaggio al layer inferiore +// +void +RAJARAMAN_Agent::prepareSendDataDown(Packet * p) +{ + struct hdr_rajaraman *rajaramanh = HDR_RAJARAMAN(p); + hdr_ip* iph = hdr_ip::access(p); + + // + // Marca il nodo come dato. + // + rajaramanh->msg_type = RAJARAMAN_DATA; +} + +void +RAJARAMAN_Agent::timeoutTermination(NodeAddress from, int num) +{ + /* + if (utility) + ((RajaramanUtility*)utility)->setMaxTimeout(myAddress, num); + */ + + // + // Invia nuovamente il messaggio di terminazione. + // + send_VALUE(data[currentTime][myAddress], currentTime, from); +} + +// +// Scade il timeout per un nodo: richiede il dato. +// +void +RAJARAMAN_Agent::timeout(NodeAddress from, int num) +{ + /* + if (utility) + ((RajaramanUtility*)utility)->setMaxTimeout(myAddress, num); + */ + + if (_DEBUG_) { + printf("(%f.2) - %d received TIMEOUT from %d (", NOW, myAddress, from); + switch (currentTime.fase) { + case RAJARAMAN_PHASE_SPAN_1 : printf("SPAN_1"); break; + case RAJARAMAN_PHASE_SPAN_2 : printf("SPAN_2"); break; + case RAJARAMAN_PHASE_CANDIDATE : printf("CANDIDATE"); break; + case RAJARAMAN_PHASE_SUPPORT : printf("SUPPORT"); break; + case RAJARAMAN_PHASE_DECISION_1 : printf("DECISION_1"); break; + case RAJARAMAN_PHASE_DECISION_2 : printf("DECISION_2"); break; + } + printf(")\n"); + } + + // + // Invia la richiesta del dato per il round corrente + // al nodo in questione. + // + send_REQUEST(currentTime, from); +} + +void +RAJARAMAN_Agent::lastTimeoutTermination(NodeAddress from, int num) +{ + /* + if (utility) + ((RajaramanUtility*)utility)->setMaxTimeout(myAddress, num); + */ + + if (_DEBUG_) + printf("(%f.2) - %d received LAST TIMEOUT TERMINATION from %d\n", NOW, myAddress, from); +} + +void +RAJARAMAN_Agent::lastTimeout(NodeAddress from, int num) +{ + /* + if (utility) + ((RajaramanUtility*)utility)->setMaxTimeout(myAddress, num); + */ + + if (_DEBUG_) + printf("(%f.2) - %d received LAST TIMEOUT from %d\n", NOW, myAddress, from); +} + +// +// Funzione di debug per stampare i valori posseduti da +// un nodo. +// +void +RAJARAMAN_Agent::printValues() +{ + switch (currentTime.fase) { + case RAJARAMAN_PHASE_SPAN_1 : printf("%d: SPAN 1:\n", myAddress); break; + case RAJARAMAN_PHASE_SPAN_2 : printf("%d: SPAN 2:\n", myAddress); break; + case RAJARAMAN_PHASE_CANDIDATE : printf("%d: CANDIDATE:\n", myAddress); break; + case RAJARAMAN_PHASE_SUPPORT : printf("%d: SUPPORT:\n", myAddress); break; + case RAJARAMAN_PHASE_DECISION_1 : printf("%d: DECISION 1:\n", myAddress); break; + case RAJARAMAN_PHASE_DECISION_2 : printf("%d: DECISION 2:\n", myAddress); break; + } + + for (DataNodes::iterator n = data[currentTime].begin(); n != data[currentTime].end(); n++) { + if ((n->second).value == RAJARAMAN_TERMINATION) { + printf("\t%d - TERMINATED\n", n->first); + } + else { + printf("\t%d - state='", n->first); + switch ((n->second).state) { + case RAJARAMAN_STATUS_UNKNOWN : printf("?"); break; + case RAJARAMAN_STATUS_UNDECIDED : printf("undecided"); break; + case RAJARAMAN_STATUS_IN : printf("BLACK"); break; + case RAJARAMAN_STATUS_OUT : printf("GRAY"); break; + } + printf("', value='%d'\n", (n->second).value); + } + } + +} diff -Naur ns-allinone-2.29-old/ns-2.29/clustering/rajaraman/rajaraman.h ns-allinone-2.29/ns-2.29/clustering/rajaraman/rajaraman.h --- ns-allinone-2.29-old/ns-2.29/clustering/rajaraman/rajaraman.h 1970-01-01 01:00:00.000000000 +0100 +++ ns-allinone-2.29/ns-2.29/clustering/rajaraman/rajaraman.h 2007-08-03 22:23:30.000000000 +0200 @@ -0,0 +1,333 @@ + +/** + * Copyright (c) 2006 Michele Mastrogiovanni. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +// L'algoritmo si basa sullo scambio di messaggi verso i +// vicini ad ogni round. +// I messaggi scambiati sono descritti dal protocollo e +// sono scambiati solo fra i vicini che non hanno ancora +// inviato un messaggio di terminazione. +// Un nodo esce dall'esecuzione dell'algoritmo +// semplicemente inviando il messaggio di terminazione. +// Gli unici messaggi scambiati sono i messaggi per la +// comunicazione del valore. +// + +#ifndef _RAJARAMAN_H_ +#define _RAJARAMAN_H_ + +#include "ClusteringModule.h" +#include "definitions_raj.h" +// #include "ClusteringUtility.h" +#include "RajaramanUtility.h" + +// +// Fasi dell'algoritmo. +// +#define RAJARAMAN_PHASE_SPAN_1 0 +#define RAJARAMAN_PHASE_SPAN_2 1 +#define RAJARAMAN_PHASE_CANDIDATE 2 +#define RAJARAMAN_PHASE_SUPPORT 3 +#define RAJARAMAN_PHASE_DECISION_1 4 +#define RAJARAMAN_PHASE_DECISION_2 5 + +// YES +#define RAJARAMAN_VALUE_YES 1 +// NO +#define RAJARAMAN_VALUE_NO 0 +// TERMINATE. +#define RAJARAMAN_TERMINATION -1 +// NO VALUE. +#define RAJARAMAN_NO_VALUE 0 + + +// Stato Sconosciuto +#define RAJARAMAN_STATUS_UNKNOWN 10 +// Stato indeciso +#define RAJARAMAN_STATUS_UNDECIDED 20 +// Stato IN +#define RAJARAMAN_STATUS_IN 30 +// Stato OUT. +#define RAJARAMAN_STATUS_OUT 40 + +//------------------------------------------------------ +// Tipo di messaggio +//------------------------------------------------------ +typedef enum { + + // Messaggio per la comunicazione di un valore. + RAJARAMAN_MSG_VALUE = 0x0, + // Messaggio di richiesta + RAJARAMAN_MSG_REQUEST = 0x1, + // Messaggio di conferma ricezione terminazione + RAJARAMAN_MSG_CONFIRM = 0x2, + // Messaggio di tipo DATA. + RAJARAMAN_DATA = 0x3 + +} RajaramanMessage; + +//------------------------------------------------------ +// Informazioni su un nodo. +//------------------------------------------------------ +typedef struct _DataNode { + // Valore associato alla fase. + int value; + // Stato del nodo. + int state; +} DataNode; + +//------------------------------------------------------ +// Informazioni sui nodi. +//------------------------------------------------------ +typedef map DataNodes; + +//------------------------------------------------------ +// Informazioni bufferizzate di un nodo. +//------------------------------------------------------ +typedef struct _DataBuffer { + // Mittente. + NodeAddress sender; + // Dato nel nodo + DataNode data; + // Time + AlgorithmTime time; +} DataBuffer; + +//------------------------------------------------------ +// Informazioni dell'algoritmo. +//------------------------------------------------------ +typedef map DataAlgorithm; + +//------------------------------------------------------ +// Header del pacchetto +//------------------------------------------------------ +struct hdr_rajaraman +{ + RajaramanMessage msg_type; // Tipo di messaggio. + AlgorithmTime time; // Tempo del messaggio. + DataNode data; // Valore e stato di un nodo. + + static int offset_; + inline static int& offset() { return offset_; } + inline static hdr_rajaraman* access(const Packet* p) { + return (hdr_rajaraman*) p->access(offset_); + } +}; + +class RajaramanTimer; + +//////////// +// Agente // +//////////// +class RAJARAMAN_Agent : public ClusteringModule +{ +public: + RAJARAMAN_Agent(); + +public: + + // Ricezione di un pacchetto. + virtual void receive(Packet *p, Handler *h); + + // Riceve un messaggio di tipo MSG. + void receive_MSG(NodeAddress from, AlgorithmTime time, DataNode data); + + // Inizia il modulo. + virtual void startModule(); + + // Terminazione del modulo. + virtual void endModule(); + + // Timeout di un nodo. + void timeout(NodeAddress from, int num); + void timeoutTermination(NodeAddress from, int num); + + // Ultimo timeout di un nodo. + void lastTimeout(NodeAddress from, int num); + void lastTimeoutTermination(NodeAddress from, int num); + + // Verifica che un pacchetto sia di tipo DATA. + virtual bool isDataPacket(Packet * p); + + // Preparazione all'invio di un messaggio al layer inferiore + virtual void prepareSendDataDown(Packet * p); + + // Verifica se il nodo  uno di quelli attivi. + bool belongToActiveNeighbors(NodeAddress from); + + ////////////// + // Messaggi // + ////////////// + + // + // Invia un messaggio specificando: + // 1) La fase alla quale il messaggio  legato. + // 2) Il valore associato alla fase + // 3) Il destinatario del messaggio (-1 per il broadcast). + // + void send_VALUE(DataNode data, + AlgorithmTime t, + NodeAddress to); + + // + // Invia la richiesta di un dato per un round. + // + void send_REQUEST(AlgorithmTime t, + NodeAddress to); + + // + // Invia un messaggio di conferma della ricezione del + // messaggio TERMINATE. + // + void send_CONFIRM(NodeAddress to); + + // + // Funzione di debug per stampare i valori posseduti da + // un nodo. + // + void printValues(); + +protected: + + void reallyEnd(); + + // Verifica se il nodo pu˜ concludere l'algoritmo + // + void advancePhase(DataNode & nextDataNode); + + // Inizializza i dati per un nuovo round. + // + void initializeRound(AlgorithmTime t); + + // Calcola il rounded span. + // + int roundedSpan(int span); + + // Svuota il buffer dei messaggi. + // + void emptyBuffer(); + + // Verifica che siano giunti tutti i messaggi per un + // determinato round. + // + bool receivedAllMessages(AlgorithmTime t); + + // Ritorna il vicino clusterhead maggiore. + // + NodeAddress greaterCluster(); + + // Verifica l'avanzamento di fase. + // + void processStatus(); + +protected: + + bool ended; + + // Istante corrente di esecuzione. + // + AlgorithmTime currentTime; + + // Dati dell'algoritmo. + // + DataAlgorithm data; + + // + // Stato finale dei nodi vicini e del nodo corrente. + // + map finalState; + + // + // Messaggi di avvenuta ricezione provenienti dai vicini + // + NodeList receivedConfirm; + + // Buffer di messaggi. + // + list buffer; + +protected: + + // Timer per le ritrasmissioni. + // + RajaramanTimer * timer; + +public: + + // Variabile di debug + // + static int _DEBUG_; + + // Disattiva il rounded span. + // + static int rounded_span; + + // Attiva la variante proposta da Rajaraman + // + static int fraction; + + static double max_delay; + static int max_timeout_message; + static double jitter_timeout_message; + static double timeout_message; + + // + // Valore "b" descritto nell'algoritmo per il calcolo del + // "rounded_span". + // + static int b_param; + +}; + +// +// Timer. +// +class RajaramanTimer : public Handler { + +public: + + RajaramanTimer(RAJARAMAN_Agent * a) : Handler(), agent(a) {} + + void handle(Event * e); + + // Invia un timeout verso una lista di vicini. + void launchMessageTimeout(NodeList & neighbors); + + // Invia un timeout verso una lista di vicini. + void launchTerminationTimeout(NodeList & neighbors); + + // Elimina un timeout per un vicino. + void receivedMessage(NodeAddress from); + + // Elimina un timeout per un vicino. + void receivedTermination(NodeAddress from); + + // Elimina tutti i timeout. + void clearAll(); + +protected: + // Mappa dei timeout. + TimeoutMap message_timeouts; + + // Mappa dei timeout. + TimeoutMap termination_timeouts; + + // Agent. + RAJARAMAN_Agent * agent; +}; + +#endif diff -Naur ns-allinone-2.29-old/ns-2.29/clustering/shiva/.DS_Store ns-allinone-2.29/ns-2.29/clustering/shiva/.DS_Store --- ns-allinone-2.29-old/ns-2.29/clustering/shiva/.DS_Store 1970-01-01 01:00:00.000000000 +0100 +++ ns-allinone-2.29/ns-2.29/clustering/shiva/.DS_Store 2007-08-03 22:23:30.000000000 +0200 @@ -0,0 +1 @@ +Bud1esFindCyclesFinder.ccIlocblobZ!˙˙˙˙˙˙CyclesFinder.hIlocblob!˙˙˙˙˙˙shiva.ccIlocblobÂ!˙˙˙˙˙˙shiva.hIlocblobZ}˙˙˙˙˙˙  @€ @€ @€ @ EDSDB `€ @€ @€ @ \ No newline at end of file diff -Naur ns-allinone-2.29-old/ns-2.29/clustering/shiva/CyclesFinder.cc ns-allinone-2.29/ns-2.29/clustering/shiva/CyclesFinder.cc --- ns-allinone-2.29-old/ns-2.29/clustering/shiva/CyclesFinder.cc 1970-01-01 01:00:00.000000000 +0100 +++ ns-allinone-2.29/ns-2.29/clustering/shiva/CyclesFinder.cc 2007-08-03 22:23:30.000000000 +0200 @@ -0,0 +1,170 @@ + +/** + * Copyright (c) 2006 Michele Mastrogiovanni. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#include "CyclesFinder.h" + +#include + +CyclesFinder::CyclesFinder(Paths paths) { + + table = paths; + + H = table.size(); + W = table[0].size(); + + next.resize(H + 1); + for (int y = 0; y <= H; y++) + next[y].resize(W); + + calculated = false; +} + +void +CyclesFinder::find_cycle(int k, Cycles & cycles) { + + if (!calculated) { + sort(table.begin(), table.end(), PathsCompare()); + calculate_next(); + calculated = true; + } + + if (k % 2 == 0) + coppie(k / 2, k / 2, cycles); + else + coppie(k / 2, k / 2 + 1, cycles); + +} + +/* + Nota: le coppie (1,2) e (2,1) sono differenti a meno che x = y. + in quel caso la coppia ripetuta va eliminata. + Si elimina quella che ha il primo valore piu' grande. +*/ +void +CyclesFinder::print_ciclo(int x, int y, int x_, int y_, Cycles & cycles) +{ + set s; + int i; + for (i = 0; i < x; i++) + s.insert(table[x_][W-i-1]); + for (i = 1; i < y; i++) + s.insert(table[y_][W-y+i]); + if (s.size() != (unsigned int)(x + y - 1)) + return; + + Path v(s.size()); + + for (i = 0; i < x; i++) { + v[i] = table[x_][W-i-1]; + } + for (i = 1; i < y; i++) { + v[x + i - 1] = table[y_][W-y+i]; + } + + // print_path(v); + + Cycles::iterator i_; + for (i_ = cycles.begin(); i_ != cycles.end(); i_++) { + Path & pp = (Path&)(*i_); + if (isPathEqual(pp, v)) + break; + } + if (i_ != cycles.end()) + return; + cycles.insert(v); + +} + +void +CyclesFinder::coppie (int x, int y, Cycles & cycles) +{ + //printf("Cicli lunghi %d [x = %d, y = %d]\n", x+y, x, y); + for (int x_ = 0; next[x_][W-x] != -1; x_ = next[x_][W-x]) + for (int y_ = 0; next[y_][W-y] != -1; y_ = next[y_][W-y]) + if (x_ != y_) + if (table[x_][W-x] == table[y_][W-y]) { + if (table[y_][W-x] == table[x_][W-y]) { + if (x_ > y_) + print_ciclo(x, y, x_, y_, cycles); + } + else + print_ciclo(x, y, x_, y_, cycles); + } +} + +void +CyclesFinder::calculate_next() +{ + next.resize(next.size() + 1); + next[H].resize(W); + + for (int x = 0; x < W; x++) + next[0][x] = 0; + + for (int y = 1; y < H; y++) { + + int x; + for (x = 0; (x < W) && (table[y][W-x-1] == table[y-1][W-x-1]); x++) + next[y][W-x-1] = next[y-1][W-x-1]; + for (int tmp = 0; tmp < W-x; tmp++) { + next[next[y-1][tmp]][tmp] = y; + next[y][tmp] = y; + } + + } + + for (int x = 0; x < W; x++) { + next[next[H-1][x]][x] = H; + next[H][x] = -1; + } + +} + +void +CyclesFinder::print_paths(Paths & t) +{ + /* + for (unsigned int y = 0; y < t.size(); y++) { + printf("(%d) ", y); + for (unsigned int x = 0; x < t[y].size(); x++) + printf("%d ", t[y][x]); + printf("\n"); + } + // printf("--------------------\n"); + */ +} + +void +CyclesFinder::print_path(const Path & t) +{ + for (unsigned int x = 0; x < t.size(); x++) + printf("%d ", t[x]); + printf("\n"); + printf("--------------------\n"); +} + +bool +CyclesFinder::isPathEqual(Path & a, Path & b) +{ + unsigned i; + for (i = 0; i < a.size() && a[i] == b[i]; i++); + if (i == a.size()) + return true; + for (i = 0; i < a.size() && a[i] == b[b.size()-i-1]; i++); + return i == a.size(); +} diff -Naur ns-allinone-2.29-old/ns-2.29/clustering/shiva/CyclesFinder.h ns-allinone-2.29/ns-2.29/clustering/shiva/CyclesFinder.h --- ns-allinone-2.29-old/ns-2.29/clustering/shiva/CyclesFinder.h 1970-01-01 01:00:00.000000000 +0100 +++ ns-allinone-2.29/ns-2.29/clustering/shiva/CyclesFinder.h 2007-08-03 22:23:30.000000000 +0200 @@ -0,0 +1,94 @@ + +/** + * Copyright (c) 2006 Michele Mastrogiovanni. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#ifndef _CYCLESFINDER_H_ +#define _CYCLESFINDER_H_ + +#include +#include "clustering-header.h" + +/* + Definizione di Path: +*/ +typedef vector Path; + +// Confronta fra due percorsi: +// Il percorso a e' minore di b se: +// 1) Il percorso a e' piu' corto di b oppure +// 2) I due percorsi sono diversi e a e'lessicograficamente minore. +// +struct PathsCompare : public binary_function +{ + bool operator()(const Path & a, const Path & b) const { + + if (a.size() != b.size()) + return a.size() < b.size(); + + Path::const_reverse_iterator ri_a = a.rbegin(); + Path::const_reverse_iterator ri_b = b.rbegin(); + + for (ri_a = a.rbegin(); ri_a != a.rend(); ri_a++) { + if ((*ri_a) != (*ri_b)) + break; + ri_b++; + } + if (ri_a == a.rend()) + return false; + + return (*ri_a) < (*ri_b); + + } +}; + +/* + Definizione di insieme di percorsi +*/ +typedef vector Paths; + +// Definizione di cicli. +// +typedef set Cycles; + +// +// +class CyclesFinder { + + public: + CyclesFinder(Paths paths); + + void find_cycle(int MAX, Cycles & cycles); + void print_paths(Paths & t); + void print_path(const Path & t); + + protected: + + void print_ciclo(int x, int y, int x_, int y_, Cycles & cycles); + void coppie (int x, int y, Cycles & cycles); + void calculate_next(); + bool isPathEqual(Path & a, Path & b); + + protected: + int W; + int H; + Paths table; + Paths next; + bool calculated; + +}; + +#endif \ No newline at end of file diff -Naur ns-allinone-2.29-old/ns-2.29/clustering/shiva/shiva.cc ns-allinone-2.29/ns-2.29/clustering/shiva/shiva.cc --- ns-allinone-2.29-old/ns-2.29/clustering/shiva/shiva.cc 1970-01-01 01:00:00.000000000 +0100 +++ ns-allinone-2.29/ns-2.29/clustering/shiva/shiva.cc 2007-08-03 22:23:30.000000000 +0200 @@ -0,0 +1,1449 @@ + +/** + * Copyright (c) 2006 Michele Mastrogiovanni. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + + +#include "shiva.h" + +#include "random.h" +#include "gridkeeper.h" + +int hdr_shiva::offset_; + +// int SHIVA_Agent::with_bottom_router; +int SHIVA_Agent::_DEBUG_; + +int SHIVA_Agent::max_length; // 3; // Lunghezza massima dei cicli + // (di nodi BLACK) da tagliare + +double SHIVA_Agent::max_delay; // 0.2; // Delay di una broadcast + +double SHIVA_Agent::jitter_timeout_destruction; +double SHIVA_Agent::timeout_destruction; + +int SHIVA_Agent::max_timeout_discover; // 4; // Numero massimo di timeout al messaggio DISCOVER +double SHIVA_Agent::jitter_timeout_discover; // 0.2; // Jitter per il messaggio DISCOVER. +double SHIVA_Agent::timeout_discover; // 1.0; // Durata timeout messaggio DISCOVER. + +int SHIVA_Agent::max_timeout_turn_on; // 4; // Numero massimo di timeout al messaggio DISCOVER +double SHIVA_Agent::jitter_timeout_turn_on; // 0.2; // Jitter per il messaggio DISCOVER. +double SHIVA_Agent::timeout_turn_on; // 1.0; // Durata timeout messaggio DISCOVER. + +static class ShivaClass : public TclClass { +public: + ShivaClass() : TclClass("Agent/SHIVA") {} + TclObject* create(int , const char*const* ) { + return(new SHIVA_Agent()); + } +} class_shiva; + +static class ShivaHeaderClass : public PacketHeaderClass { +public: + ShivaHeaderClass() : PacketHeaderClass("PacketHeader/SHIVA", + sizeof(hdr_shiva)) { + bind_offset(&hdr_shiva::offset_); + } +} class_shivahdr; + +SHIVA_Agent::SHIVA_Agent() : ClusteringModule(PT_SHIVA), seq(0) +{ + timer = new ShivaTimer(this); + + // bind_bool("with-bottom-router", &with_bottom_router); + bind_bool("debug", &_DEBUG_); + + bind("max-length", &max_length); + + bind("max-delay", &max_delay); + + bind("jitter-timeout-destruction", &jitter_timeout_destruction); + bind("timeout-destruction", &timeout_destruction); + + bind("max-timeout-discover", &max_timeout_discover); + bind("jitter-timeout-discover", &jitter_timeout_discover); + bind("timeout-discover", &timeout_discover); + + bind("max-timeout-turn-on", &max_timeout_turn_on); + bind("jitter-timeout-turn-on", &jitter_timeout_turn_on); + bind("timeout-turn-on", &timeout_turn_on); +} + +/* +int +SHIVA_Agent::command(int argc, const char * const * argv) +{ + if (argc == 2) { + if (strcmp (argv[1], "ended") == 0) { + if (status != SHIVA_STATUS_END) + endModule(); + return (TCL_OK); + } + else if (strcmp (argv[1], "destruction") == 0) { + timer->beginDestruction(); + return (TCL_OK); + } + } + + return ClusteringModule::command(argc, argv); +} +*/ + +// +// Questa procedura parte dalla lista dei nodi contenuta in black_neighbors +// ed elimina tutti i nodi che fanno parte dei cicli. +// Successivamente passa alla fase di colorazione dei nodi vicini che sono +// interessati con i legami verso gli altri nodi BLACK. +// +void +SHIVA_Agent::endCycleDiscover() +{ + // + // Se la funzione viene chiamata e il nodo  bianco, allora non si deve curare + // di alcun ciclo ma solo dare il via alla fase di creazione del backbone + // + + // + // Elimina tutti i timeout della fase precedente + // + timer->cancelAllDiscover(); + + // + // Un nodo gateway attende di ricevere da tutti i nodi clusterHead vicini + // che hanno presso di lui almeno una rotta il messaggio di TURN ON/OFF. + // + if (getClusterHead(myAddress) != myAddress) { + beginBackboneFormation(); + return; + } + + // + // Se non ci sono percorsi, allora si procede alla fase di creazione + // del backbone. + // + if (paths.empty()) { + beginBackboneFormation(); + return; + } + + CyclesFinder finder(paths); + + if (_DEBUG_) + printf("%d-----\n", myAddress); + + // + // Per ogni ciclo di lunghezza k, se il nodo e'uno degli estremi + // dell'arco di cardinalita' minima, allora sconnette il vicino + // sullo stesso ciclo. + // + for (int k = 3; k <= max_length; k++) { + Cycles cycles; + finder.find_cycle(k, cycles); + for (Cycles::iterator i = cycles.begin(); i != cycles.end(); i++) { + + Path p = (*i); + p.push_back(myAddress); + + // Stampa il ciclo. + if (_DEBUG_) + finder.print_path(p); + + ShivaArc better; + + for (int i = 0; i < p.size(); i++) { + ShivaArc arc; + arc.length = reachComplete[p[i]][p[(i + 1) % p.size()]].length; + arc.begin = p[i]; + arc.end = p[(i + 1) % p.size()]; + if (i == 0) + better = arc; + else if (isBetterThan(arc, better)) + better = arc; + } + + NodeList::iterator it; + + if (utility) + ((ShivaUtility*)utility)->eraseVirtualArc(better.begin, better.end, better.length); + + if (myAddress == better.begin) { + if (_DEBUG_) + printf("Elimino l'arco: %d - %d\n", better.begin, better.end); + node_to_turn_off.insert(better.end); + } + else if (myAddress == better.end) { + if (_DEBUG_) + printf("Elimino l'arco: %d - %d\n", better.begin, better.end); + node_to_turn_off.insert(better.begin); + } + } + } + if (_DEBUG_) + printf("-------\n"); + + beginBackboneFormation(); +} + +// +// Cerca di colorare di BLACK tutti i nodi WHITE che si trovano nel percorso verso +// i nodi BLACK sopravvissuti all'eliminazione dei cicli. +// +void +SHIVA_Agent::beginBackboneFormation() +{ + // + // Imposta lo stato. + // + status = SHIVA_STATUS_CONNECTING; + + // + // Un nodo gateway termina la fase di backbone quando ha ricevuto tutti i messaggi + // di tipo TURN ON/OFF dai vicini che hanno una rotta presso di lui. + // + if (getClusterHead(myAddress) != myAddress) { + processPhase(); + return; + } + + if (_DEBUG_) + printf("%d BEGIN BACKBONE\n", myAddress); + + // + // Il nodo tenta di accendere tutti i vicini che sono sulle rotte tranne quelle da + // eliminare. + // + reachComplete[myAddress].erase(myAddress); + + for (NodeList::iterator n = neighbors.begin(); n != neighbors.end(); n++) + if (getClusterHead(*n) != (*n)) + neighborTurnOn[*n] = false; + + for (NodeList::iterator n = node_to_turn_off.begin(); n != node_to_turn_off.end(); n++) + reachComplete[myAddress].erase(*n); + + for (Reachbility::iterator r = reachComplete[myAddress].begin(); r != reachComplete[myAddress].end(); r++) { + struct ReachPath path = (r->second); + if ((r->second).length > 0) { + neighborTurnOn[path.node1_ID] = true; + } + } + + // + // Invia il messaggio ai vicini Bianchi. + // + + // + // Invia il messaggio + // + for (NodeList::iterator n = neighbors.begin(); n != neighbors.end(); n++) { + + /* + if (_DEBUG_) + printf("%d neighbors: %d -> %d\n", myAddress, *n, getClusterHead(*n)); + */ + + if (getClusterHead(*n) != (*n)) { + + send_TURN_ON(*n); + // + // Invia il timeout + // + timer->launchTurnOn(*n); + } + } + + processPhase(); +} + +// +// Funzione di ricezione dei pacchetti +// +void +SHIVA_Agent::receive(Packet *p, Handler *h) +{ + struct hdr_shiva *shivah = HDR_SHIVA(p); + struct hdr_ip *iph = HDR_IP(p); + + // Mittente. + NodeAddress sender_address = iph->saddr(); + // Destinazione. + NodeAddress destination_address = iph->daddr(); + + switch (shivah->msg_type) { + + case SHIVA_DISCOVER : + + // + // Se il messaggio di discover e'stato generato da un mio precedente + // allora elimina il timeout per quel messaggio e lo scarta. + // + if (shivah->discovery_message.parent == myAddress) { + // + // Per ogni messaggio in risposta ad uno inviato da me + // va eliminato il timeout. + // + timer->cancelDiscover(sender_address, (shivah->discovery_message).ack_seq); + } + + // + // Scarta i messaggi inviati solo per conferma. + // + if (shivah->discovery_message.dummy) + return; + + // + // Se il messaggio e'stato gia'ricevuto, lo scarta e + // invia una conferma di ricezione. + // + if (find(receivedMessagesFrom[sender_address].begin(), + receivedMessagesFrom[sender_address].end(), + (shivah->discovery_message).ack_seq) != receivedMessagesFrom[sender_address].end()) { + + struct DiscoveryMessage msg = createDummyDiscover((shivah->discovery_message).my_seq, sender_address); + send_DISCOVER(sender_address, msg); + + /* + if (_DEBUG_) + printf("%d riceve un DISCOVER from %d ma scarta perche'gia'ricevuto\n", myAddress, sender_address); + */ + + return; + } + + // + // Aggiunge il messaggio alla lista dei ricevuti + // + receivedMessagesFrom[sender_address].insert((shivah->discovery_message).ack_seq); + + // + // Processa il messaggio (solo se si e'nella fase di discover). + // + if (status == SHIVA_STATUS_DISCOVER) { + receive_DISCOVER(sender_address, shivah->discovery_message); + } + else { + // + // Invia un messaggio dummy. + // + struct DiscoveryMessage msg = createDummyDiscover((shivah->discovery_message).my_seq, sender_address); + send_DISCOVER(sender_address, msg); + } + + // + // Verifica il passaggio alla fase successiva. + // + processPhase(); + + break; + + case SHIVA_TURN_ON : + // + // Invia un messaggio di avvenuta ricezione + // + send_CONFIRM_TURN_ON(sender_address); + + if (status == SHIVA_STATUS_END) + return; + + // + // Riceve il messaggio + // + receive_TURN_ON(sender_address, true); + + // + // Verifica il passaggio alla fase successiva. + // + processPhase(); + + break; + + case SHIVA_TURN_OFF : + // + // Invia un messaggio di avvenuta ricezione + // + send_CONFIRM_TURN_ON(sender_address); + + if (status == SHIVA_STATUS_END) + return; + + // + // Riceve il messaggio + // + receive_TURN_ON(sender_address, false); + + // + // Verifica il passaggio alla fase successiva. + // + processPhase(); + + break; + + case SHIVA_CONFIRM : + + switch (shivah->confirm) { + + case SHIVA_DISCOVER : + // + // Elimina il timeout di DISCOVER. + // + timer->cancelDiscover(sender_address, (shivah->discovery_message).ack_seq); + + break; + + case SHIVA_TURN_ON : + // + // Se era l'ultimo messaggio di TURN ON da confermare, + // e si e'ricevuta risposta da tutti i vicini allora termina + // + timer->cancelTurnOn(sender_address); + + break; + } + } +} + +void +SHIVA_Agent::processPhase() +{ + bool colored; + + switch (status) { + + case SHIVA_STATUS_DISCOVER : + // + // La fase di discover termina solo richiamando la funzione + // endCycleDiscover. + // + return; + break; + + case SHIVA_STATUS_CONNECTING : + // + // Un clusterHead termina nel momento in cui si trova in questa fase. + // + if (getClusterHead(myAddress) == myAddress) + break; + + // + // Un gateway presente in qualche rotta termina nel momento in cui + // riceve un messaggio di TURN ON/OFF da ogni vicino clusterHead + // da cui parte almeno una rotta che passa per il nodo stesso. + // + if (turnOnMessages.size() > 0) + return; + + // + // Se almeno uno dei vicini ha inviato TURN ON allora + // il nodo viene acceso. + // + colored = false; + for (map::iterator n = turnOnValues.begin(); n != turnOnValues.end(); n++) { + if (n->second == true) { + colored = true; + break; + } + } + if (colored) { + finalClusterHead = myAddress; + if (utility) + ((ShivaUtility*)utility)->colorNode(myAddress); + } + + break; + + default: + return; + break; + } + + endModule(); +} + +// +// Questo messaggio serve per scoprire i vicini BLACK a distanza minore uguale a 3 +// e per rilevare i cicli di nodi BLACK. +// +void +SHIVA_Agent::send_DISCOVER(NodeAddress to, struct DiscoveryMessage message) +{ + Packet* p = allocpkt(); + struct hdr_shiva * shivah = HDR_SHIVA(p); + + shivah->msg_type = SHIVA_DISCOVER; + + shivah->discovery_message = message; + + size_t pkt_size = 0; + + /* + if (_DEBUG_) { + printf("%d send DISCOVER%s to %d\n", myAddress, message.dummy ? " DUMMY" : "", to); + for (int i = 0; i < message.path1.size(); i++) { + if (i != 0) + printf("-"); + printf("[%d]", message.path1[i]); + } + printf("---"); + for (int i = 0; i < message.path2.size(); i++) { + if (i != 0) + printf("-"); + printf("[%d]", message.path2[i]); + } + printf("\n"); + } + */ + + pkt_size = sizeof(ShivaMessageType); + pkt_size += sizeof(int) * 2 + sizeof(NodeAddress); + pkt_size += (message.dummy ? 0 : sizeof(NodeAddress) * (message.path1.size() + message.path2.size())); + + sendDown(p, pkt_size , to, SHIVA_Agent::max_delay); +} + +struct DiscoveryMessage +SHIVA_Agent::createDiscover(int ack_seq, Path path1, Path path2, NodeAddress parent) +{ + struct DiscoveryMessage message; + + seq++; + message.my_seq = seq; + message.ack_seq = ack_seq; + message.parent = parent; + message.path1 = path1; + message.path2 = path2; + message.dummy = false; + + // Bufferizza il messaggio + myDiscoveryMessages[message.my_seq] = message; + + return message; +} + +struct DiscoveryMessage +SHIVA_Agent::createDummyDiscover(int ack_seq, NodeAddress parent) +{ + struct DiscoveryMessage message; + + seq++; + message.my_seq = seq; + message.ack_seq = ack_seq; + message.parent = parent; + message.dummy = true; + + // Bufferizza il messaggio + myDiscoveryMessages[message.my_seq] = message; + + return message; +} + + + +// +// Conferma un messaggio di TURN ON. +// +void +SHIVA_Agent::send_CONFIRM_TURN_ON(NodeAddress to) +{ + Packet* p = allocpkt(); + struct hdr_shiva * shivah = HDR_SHIVA(p); + + shivah->msg_type = SHIVA_CONFIRM; + + shivah->confirm = SHIVA_TURN_ON; + + size_t pkt_size = sizeof(ShivaMessageType) * 2; + sendDown(p, pkt_size, to, SHIVA_Agent::max_delay); +} + +void +SHIVA_Agent::send_TURN_ON(NodeAddress to) +{ + bool on = neighborTurnOn[to]; + + /* + if (_DEBUG_) + printf("%d send TURN %s to %d\n", myAddress, on ? "ON" : "OFF", to); + */ + + // + // Siccome quando si memorizzano i percorsi si mette in testa + // l'ultimo nodo visitato, il vicino del nodo corrente sarˆ sempre + // quello in testa. + // + + Packet* p = allocpkt(); + struct hdr_shiva * shivah = HDR_SHIVA(p); + + shivah->msg_type = (on ? SHIVA_TURN_ON : SHIVA_TURN_OFF); + + //if (_DEBUG_) + // printf("(%f.2) %d send TURN ON (%d, %s)\n", NOW, myAddress, to, on ? "ON" : "OFF"); + + // I messaggio di accensione  un messaggio UNICAST + sendDown(p, sizeof(ShivaMessageType), to, SHIVA_Agent::max_delay); +} + +/****************************/ +/* Algorithm procedures and +/* events. +/****************************/ + +void +SHIVA_Agent::timeout(ShivaMessageType type, NodeAddress from, int seq) +{ + switch (type) { + case SHIVA_DISCOVER : + + /* + if (_DEBUG_) + printf("(%f.2) %d TIMEOUT DISCOVER from %d\n", NOW, myAddress, from); + */ + + // + // Il vicino puo'non aver ricevutoil mio messaggio di DISCOVER. + // Lo invio nuovamente. + // + send_DISCOVER(from, myDiscoveryMessages[seq]); + + break; + + case SHIVA_TURN_ON : + + /* + if (_DEBUG_) + printf("(%f.2) %d TIMEOUT TURN ON from %d\n", NOW, myAddress, from); + */ + + // + // Avvia nuovamente il messaggio. + // + send_TURN_ON(from); + + break; + } +} + +void +SHIVA_Agent::savePaths(Path path1, Path path2) +{ + int start = 0; + for (int i = 1; i < path2.size(); i++) { + NodeAddress begin = path1[start]; + NodeAddress end = path1[path2[i]]; + ReachPath path; + path.length = (path2[i] - start - 1); + if (path.length > 0) { + path.node1_ID = path1[start + 1]; + path.node1_WT = path1[start + 1]; + if (path.length > 1) { + path.node2_ID = path1[start + 2]; + path.node2_WT = path1[start + 2]; + } + } + + savePath(begin, end, path); + + start = path2[i]; + } + + NodeAddress begin = path1[start]; + NodeAddress end = myAddress; + ReachPath path; + path.length = (path1.size() - start - 1); + if (path.length > 0) { + path.node1_ID = path1[start + 1]; + path.node1_WT = path1[start + 1]; + if (path.length > 1) { + path.node2_ID = path1[start + 2]; + path.node2_WT = path1[start + 2]; + } + } + + savePath(begin, end, path); + +} + +// +// Salva il percorso fra quelli conosciuti +// +void +SHIVA_Agent::savePath(NodeAddress begin, NodeAddress end, ReachPath path) +{ + if (utility) { + + NodeList members; + if (path.length > 0) + members.insert(path.node1_ID); + if (path.length > 1) + members.insert(path.node2_ID); + + ((ShivaUtility*)utility)->addVirtualArc(begin, end, members); + } + + if (reachComplete[begin][end].length == -1) { + reachComplete[begin][end] = path; + if ((path.length == 0) || (path.length == 1)) + reachComplete[end][begin] = path; + else { + int tmp_ID = path.node1_ID; + int tmp_WT = path.node1_ID; + path.node1_ID = path.node2_ID; + path.node1_WT = path.node2_WT; + path.node2_ID = tmp_ID; + path.node2_WT = tmp_WT; + reachComplete[end][begin] = path; + } + } + else { + path = higherPath(path, reachComplete[begin][end]); + reachComplete[begin][end] = path; + if ((path.length == 0) || (path.length == 1)) + reachComplete[end][begin] = path; + else { + int tmp_ID = path.node1_ID; + int tmp_WT = path.node1_ID; + path.node1_ID = path.node2_ID; + path.node1_WT = path.node2_WT; + path.node2_ID = tmp_ID; + path.node2_WT = tmp_WT; + reachComplete[end][begin] = path; + } + } +} + +// +// Sceglie, fra due il percorso pi conveniente. +// +ReachPath +SHIVA_Agent::higherPath(ReachPath path1, ReachPath path2) +{ + // + // Restituisce il percorso pi corto. + // + if (path1.length < path2.length) + return path1; + if (path2.length < path1.length) + return path2; + + // + // Se il path  diretto lo sceglie. + // + if (path1.length == 0) + return path1; + + // + // A paritˆ di lunghezza sceglie il percorso che contiene + // il nodo di ID superiore. + // + NodeAddress max1 = path1.node1_ID; + NodeAddress other1 = -1; + if (path1.length > 1) { + other1 = (max1 > path1.node2_ID ? path1.node2_ID : max1); + max1 = (max1 > path1.node2_ID ? max1 : path1.node2_ID); + } + + NodeAddress max2 = path2.node1_ID; + NodeAddress other2 = -1; + if (path2.length > 1) { + other2 = (max2 > path2.node2_ID ? path2.node2_ID : max1); + max2 = (max2 > path2.node2_ID ? max2 : path2.node2_ID); + } + + // + // Restituisce il path con il nodo pi grande. + // + if (max1 > max2) + return path1; + + if (max2 > max1) + return path2; + + // + // Restituisce il path con il secondo nodo + // pi grande + // + if (other1 > other2) + return path1; + + // + // O il path 2  piu'grande o sono uguali. + // + return path2; +} + +void +SHIVA_Agent::lastTimeout(ShivaMessageType type, NodeAddress from, int seq) +{ + /* + if (_DEBUG_) + printf("(%f.2) %d LAST TIMEOUT %d from %d (seq=%d)\n", NOW, myAddress, (int)type, from, seq); + */ + + // if (type == SHIVA_DISCOVER) { + // neighbors.erase(from); + // } +} + +void +SHIVA_Agent::startModule() +{ + ClusteringModule::startModule(); + + // initialTime = NOW; + + if (!lowerModule && target()) { + ClusteringModule * bottom = (ClusteringModule*)target(); + setClusterHead(myAddress, bottom->getClusterHead(myAddress)); + finalClusterHead = getClusterHead(myAddress); + for (NodeList::iterator i = neighbors.begin(); i != neighbors.end(); i++) { + setClusterHead(*i, bottom->getClusterHead(*i)); + /* + if (_DEBUG_) + printf("[%d] My neighbor %d has clusterhead %d\n", myAddress, *i, getClusterHead(*i)); + */ + } + + if (bottom->supportProtocol("reachbility")) { + with_bottom_router = true; + if (getClusterHead(myAddress) == myAddress) { + reach = *((Reachbility*)bottom->getData("reachPath")); + for (Reachbility::iterator i = reach.begin(); i != reach.end(); i++) { + if (utility) { + + NodeList members; + if (i->second.length > 0) + members.insert(i->second.node1_ID); + if (i->second.length > 1) + members.insert(i->second.node2_ID); + + ((ShivaUtility*)utility)->addVirtualArc(myAddress, i->first, members); + } + if ((i->second).length > 0) + neighbors_on_route.insert((i->second).node1_ID); + } + if (_DEBUG_) { + printf("%d BLACK rotte:\n", myAddress); + for (Reachbility::iterator r = reach.begin(); r != reach.end(); r++) { + if ((r->second).length == 1) { + printf("{ %d } ---> %d\n", (r->second).node1_ID, r->first); + } + if ((r->second).length == 2) { + printf("{ %d , %d } ---> %d\n", (r->second).node1_ID, (r->second).node2_ID, r->first); + } + } + printf("\n"); + } + } + else { + forward_path = *((map*)bottom->getData("forwardPath")); + + // + // Un nodo gateway attende che tutti i nodi da cui dipendono + // le rotte del forward inviino un messaggio di TURN ON/OFF. + // + turnOnMessages.clear(); + for (map::iterator n = forward_path.begin(); n != forward_path.end(); n++) { + if ((n->second).size() > 0) + turnOnMessages.insert(n->first); + } + + if (_DEBUG_) { + printf("%d WHITE (%d) forward:\n", myAddress, getClusterHead(myAddress)); + for (map::iterator f = forward_path.begin(); f != forward_path.end(); f++) + for (NodeList::iterator n = (f->second).begin(); n != (f->second).end(); n++) + printf("from %d ---()---> %d\n", (f->first), *n); + printf("\n"); + } + } + } + } + + // + // Inizia la fase di discover: il nodo cerca di memorizzare i percorsi + // verso i nodi neri a distanza massimo 3 e li annota come se fossere degli + // ipotetici vicini. + // + status = SHIVA_STATUS_DISCOVER; + + // + // Il nodo e' nella fase di discover, ma opera solo se e' un nodo di tipo + // BLACK, gli altri nodi si limiatno a veicolare le informazioni. + // + if (with_bottom_router) { + if (getClusterHead(myAddress) == myAddress) { + // Un nodo clusterHead invia il messaggio di DISCOVER a tutti + // i vicini che sono su almeno una rotta. + + // + // Lancia un messaggio di discover per trovare i vicini BLACK a distanza + // minore uguale a 3 e per trovare i percorsi minimi fra questi nodi. + // + Path path1(1); + Path path2(1); + path1[0] = myAddress; + path2[0] = 0; + + struct DiscoveryMessage msg = createDiscover(-1, path1, path2, -1); + + for (NodeList::iterator node = neighbors_on_route.begin(); node != neighbors_on_route.end(); node++) { + // + // Invia il messaggio. + // + send_DISCOVER(*node, msg); + + // + // Lancia i timeout + // + timer->launchDiscover(*node, seq); + } + } + else { + // + // Il nodo gateway che non e'presente in nessun percorso, termina + // l'algoritmo direttamente + // + if (turnOnMessages.size() == 0) { + endModule(); + return; + } + } + } + + timer->beginDestruction(); +} + +void +SHIVA_Agent::endModule() +{ + // L'algoritmo termina: il nodo puo'memorizzare il proprio clusterHead. + status = SHIVA_STATUS_END; + + // + // Memorizza il proprio clusterHead: + // se il nodo e'nero e'se stesso, altrimenti e'il vicino NERO maggiore. + // + if (utility) { + NodeList backboneNeighbors; + if (myAddress == getClusterHead(myAddress)) { + // + // Se il nodo era un clusterhead allora aggiunge al suo come vicini + // tutti i nodi che sono sul reachComplete. + // + for (Reachbility::iterator r = reach.begin(); r != reach.end(); r++) { + if ((r->second).length == 0) { + if (node_to_turn_off.find(r->first) == node_to_turn_off.end()) + backboneNeighbors.insert(r->first); + } + else if ((r->second).length > 0) { + if (node_to_turn_off.find(r->second.node1_ID) == node_to_turn_off.end()) + backboneNeighbors.insert((r->second).node1_ID); + } + } + } + else { + for (map::iterator f = forward_path.begin(); f != forward_path.end(); f++) { + if (turnOnValues[f->first]) { + backboneNeighbors.insert(f->first); + for (NodeList::iterator n = (f->second).begin(); n != (f->second).end(); n++) { + backboneNeighbors.insert(*n); + } + } + } + if (backboneNeighbors.size() == 0) { + // Il nodo  un nodo bianco (lo si verifica anche con + // myAddress != finalClusterHead + // e va ad attaccarsi al clusterhead maggiore. + } + if (myAddress != finalClusterHead) + backboneNeighbors.insert(finalClusterHead); + } + ((BackboneUtility*)utility)->setBackbone(myAddress, backboneNeighbors); + ((BackboneUtility*)utility)->setColor(myAddress, myAddress == finalClusterHead ? "black" : "white"); + } + + setClusterHead(myAddress, finalClusterHead); + + if (getClusterHead(myAddress) == myAddress) { + if (_DEBUG_) { + printf("%d SHIVA END: BLACK; rotte:\n", myAddress); + for (map::iterator begin = reachComplete.begin(); begin != reachComplete.end(); begin++) { + for (Reachbility::iterator end = (begin->second).begin(); end != (begin->second).end(); end++) { + ReachPath path = (end->second); + printf("(%d)-", begin->first); + if (path.length > 0) { + printf("-[%d]-", path.node1_ID); + } + if (path.length > 1) { + printf("-[%d]-", path.node2_ID); + } + printf("-(%d)\n", end->first); + } + } + } + } + else { + if (_DEBUG_) + printf("%d SHIVA END: WHITE\n", myAddress); + } + + if (_DEBUG_) + printf("%d Consumed %f\n", myAddress, initialEnergy - myMobileNode->energy_model()->energy()); + + ClusteringModule::endModule(); +} + +// +// Funzione per la gestione dei messaggi di discover. +// +void +SHIVA_Agent::receive_DISCOVER(NodeAddress from, struct DiscoveryMessage message) +{ + // + // Le regole di propagazione del messaggio di DISCOVER sono: + // + // 1) Un nodo clusterHead invia il DISCOVERY solo ai vicini gateway che sono + // interessati in una rotta. + // + // 2) Un nodo gateway che riceve da un nodo di cui conosce il percorso di + // propagazione lo propaga secondo le rotte prestabilite. + // Se il messaggio proviene da un nodo che non e'sulla lista dei messaggi + // da forwardare allora lo scarta. + // + // 3) Un nodo gateway che riceve un messaggio da un altro nodo gateway lo propaga + // al suo clusterHead. + // + + // + // Calcola la lunghezza massima dei percorsi che bisgna forwardare. + // + int MAXIMUM = (max_length % 2 == 0) ? max_length / 2 : (max_length + 1) / 2; + + int length_white_path = (message.path1.size() - message.path2[message.path2.size() - 1] - 1); + NodeAddress last_black_node = message.path1[message.path2[message.path2.size() - 1]]; + + /* + if (_DEBUG_) { + if (message.dummy) { + printf("(%f.2) %d receive DISCOVER DUMMY from %d\n", NOW, myAddress, from); + } + else { + printf("(%f.2) ", NOW); + if (getClusterHead(myAddress) == myAddress) + printf("(%d)", myAddress); + else + printf("[%d]", myAddress); + printf(" receive DISCOVER: "); + for (int i = 0; i < message.path1.size(); i++) { + if (i != 0) + printf("-"); + printf("[%d]", message.path1[i]); + } + printf("---"); + for (int i = 0; i < message.path2.size(); i++) { + if (i != 0) + printf("-"); + printf("[%d]", message.path2[i]); + } + printf("\n"); + } + } + */ + + // + // Se SHIVA e'utilizzato con DCA allora adotta le regole prestabilite per + // scartare i messaggi. + // + + if (with_bottom_router) { + + if (getClusterHead(myAddress) != myAddress) { + // + // Il nodo e'un gateway. + // + + // + // Imposta la variabile a true se il messaggio proviene + // da un nodo gateway. + // + bool from_gateway = ((message.path2[message.path2.size() - 1]) != (message.path1.size() - 1)); + + // + // Accoda l'identita' del nodo corrente al percorso. + // + Path new_path1; + copy(message.path1, new_path1); + new_path1.push_back(myAddress); + + Path new_path2; + copy(message.path2, new_path2); + + // + // Prepara il messaggio + // + struct DiscoveryMessage msg = createDiscover(message.my_seq, new_path1, new_path2, from); + + // + // Se il messaggio proviene da un nodo gateway allora lo invia al suo CH + // e attende la conferma, lo invia anche al mittente per conferma. + // + if (from_gateway) { + // + // Se il messaggio proviene da un nodo gateway allora lo invia in broadcast e attende la conferma + // solo dai vicini clusterHead. + // + + // + // Propaga al proprio CH + // + send_DISCOVER(getClusterHead(myAddress), msg); + + // + // Invia il timeout. + // + timer->launchDiscover(getClusterHead(myAddress), seq); + + // + // Invia la conferma di ricezione. + // + struct DiscoveryMessage msg = createDummyDiscover(message.my_seq, from); + send_DISCOVER(from, msg); + + return; + } + else { + // + // Propaga verso tutti i forward path. + // + /* + if (_DEBUG_) { + printf("%d deve propagare a: (", myAddress); + for (NodeList::iterator n = forward_path[from].begin(); n != forward_path[from].end(); n++) + printf("%d ", *n); + printf(")\n"); + } + */ + + for (map::iterator f = forward_path.begin(); f != forward_path.end(); f++) { + if ((f->first) == from) { + for (NodeList::iterator n = (f->second).begin(); n != (f->second).end(); n++) { + // + // Invia il messaggio + // + send_DISCOVER(*n, msg); + + // + // Invia il timeout. + // + timer->launchDiscover(*n, seq); + } + } + } + + // + // Invia la conferma di ricezione. + // + struct DiscoveryMessage msg = createDummyDiscover(message.my_seq, from); + send_DISCOVER(from, msg); + + return; + } + } + else { + // + // Il nodo e'BLACK + // + + // + // Se il nodo  nero registra il percorso. + // + if (getClusterHead(myAddress) == myAddress) { + savePaths(message.path1, message.path2); + } + + // + // Se il nodo ha gia'propagato il messaggio, allora si + // invia la conferma e si scarta. + // + if (alreadyPresentBlack(message.path1, message.path2, myAddress)) { + // + // Invia il messaggio di conferma. + // + struct DiscoveryMessage msg = createDummyDiscover(message.my_seq, from); + send_DISCOVER(from, msg); + + return; + } + + // + // Se si e'raggiunta la meta'della lunghezza del ciclo: + // memorizza il path. + // + if (message.path2.size() == MAXIMUM) { + + Path black_path; + for (int i = 0; i < message.path2.size(); i++) + black_path.push_back(message.path1[message.path2[i]]); + paths.push_back(black_path); + + if (_DEBUG_) { + printf("%d pezzo di ciclo: (-", myAddress); + for (Path::iterator i = black_path.begin(); i != black_path.end(); i++) + printf("%d-", *i); + printf(")\n"); + } + + // + // Invia la conferma di ricezione. + // + struct DiscoveryMessage msg = createDummyDiscover(message.my_seq, from); + send_DISCOVER(from, msg); + + return; + } + + // + // Prepara il messaggio per la propagazione. + // + Path new_path1; + copy(message.path1, new_path1); + new_path1.push_back(myAddress); + + Path new_path2; + copy(message.path2, new_path2); + new_path2.push_back(new_path1.size() - 1); + + struct DiscoveryMessage msg = createDiscover(message.my_seq, new_path1, new_path2, from); + + for (NodeList::iterator node = neighbors_on_route.begin(); node != neighbors_on_route.end(); node++) { + // + // Invia il messaggio. + // + send_DISCOVER(*node, msg); + + // + // Lancia i timeout + // + timer->launchDiscover(*node, seq); + } + } + } +} + +void +SHIVA_Agent::receive_TURN_ON(NodeAddress from, bool on) +{ + // + // Se si riceve un messaggio di TURN ON, si deve cambiare colore + // + /* + if (_DEBUG_) + printf("(%f.2) %d receive TURN %s from %d\n", NOW, myAddress, (on ? "ON" : "OFF"), from); + */ + + turnOnMessages.erase(from); + turnOnValues[from] = on; + + /* + if (with_bottom_router) { + // + // I gateway che devono accendersi diventano clusterHead + // + if ((getClusterHead(myAddress) != myAddress) && on) { + // + // Divento un clusterhead + // + finalClusterHead = myAddress; + + if (utility) + ((ShivaUtility*)utility)->colorNode(myAddress); + } + } + */ +} + +void +ShivaTimer::handle(Event* e) +{ + if (e == NULL) + return; + + if (e == begin_cycle_destruction) { + begin_cycle_destruction = NULL; + agent->endCycleDiscover(); + return; + } + + // + // Gestisce i timeout per le conferme ai messaggi DISCOVER inviati + // + for (map::iterator s = seqFromTimeouts.begin(); s != seqFromTimeouts.end(); s++) { + for (map::iterator i = (s->second).begin(); i != (s->second).end(); i++) { + if ((i->second).timeout == e) { + (i->second).num--; + if ((i->second).num <= 0) + agent->lastTimeout(SHIVA_DISCOVER, i->first, s->first); + else { + Scheduler::instance().schedule(this, e, + SHIVA_Agent::timeout_discover + Random::uniform(SHIVA_Agent::jitter_timeout_discover)); + agent->timeout(SHIVA_DISCOVER, i->first, s->first); + } + return; + } + } + } + + // + // Gestisce i timeout per le conferme ai messaggi TURN ON inviati + // + for (TimeoutMap::iterator i = turn_on_messages.begin(); i != turn_on_messages.end(); i++) { + if ((i->second).timeout == e) { + (i->second).num--; + if ((i->second).num <= 0) + agent->lastTimeout(SHIVA_TURN_ON, i->first, 0); + else { + Scheduler::instance().schedule(this, e, + SHIVA_Agent::timeout_turn_on + Random::uniform(SHIVA_Agent::jitter_timeout_turn_on)); + agent->timeout(SHIVA_TURN_ON, i->first, 0); + } + return; + } + } +} + +// +// Viene lanciato un timeout verso il vicino "to" per il DISCOVER massege originato +// dal nodo "source" e originariamente proveniente dal nodo "from" +// +void +ShivaTimer::launchDiscover(NodeAddress to, int seq) +{ + struct Timeout t; + t.timeout = new Event(); + t.num = SHIVA_Agent::max_timeout_discover; + seqFromTimeouts[seq][to] = t; + Scheduler::instance().schedule(this, t.timeout, + SHIVA_Agent::timeout_discover + Random::uniform(SHIVA_Agent::jitter_timeout_discover)); +} + +void +ShivaTimer::cancelAllDiscover() +{ + seqFromTimeouts.clear(); +} + +// +// La funzione elimina il timeout verso un vicino per un messaggio con un +// determinato sequence number. +// +void +ShivaTimer::cancelDiscover(NodeAddress from, int seq) +{ + TimeoutMap::iterator i; + for (i = seqFromTimeouts[seq].begin(); i != seqFromTimeouts[seq].end(); i++) { + if (i->first == from) { + Scheduler::instance().cancel(i->second.timeout); + break; + } + } + if (i != seqFromTimeouts[seq].end()) + seqFromTimeouts[seq].erase(i); +} + +void +ShivaTimer::launchTurnOn(NodeAddress to) +{ + struct Timeout t; + t.timeout = new Event(); + t.num = SHIVA_Agent::max_timeout_turn_on; + turn_on_messages[to] = t; + Scheduler::instance().schedule(this, t.timeout, + SHIVA_Agent::timeout_turn_on + Random::uniform(SHIVA_Agent::jitter_timeout_turn_on)); + +} + +void +ShivaTimer::beginDestruction() +{ + begin_cycle_destruction = new Event(); + Scheduler::instance().schedule(this, begin_cycle_destruction, SHIVA_Agent::timeout_destruction + Random::uniform(SHIVA_Agent::jitter_timeout_destruction)); +} + + +// +// Ritorna true se sono stati ricevuti tutti i messaggi di +// TURN ON inviati. +// +bool +ShivaTimer::cancelTurnOn(NodeAddress from) +{ + TimeoutMap::iterator i; + for (i = turn_on_messages.begin(); i != turn_on_messages.end(); i++) { + if (i->first == from) { + Scheduler::instance().cancel(i->second.timeout); + break; + } + } + if (i != turn_on_messages.end()) + turn_on_messages.erase(i); + + return turn_on_messages.empty(); +} + +// Verifica che un pacchetto sia di tipo DATA. +bool +SHIVA_Agent::isDataPacket(Packet * p) +{ + struct hdr_shiva *shivah = HDR_SHIVA(p); + return (shivah->msg_type == SHIVA_DATA); +} + +// Preparazione all'invio di un messaggio al layer inferiore +void +SHIVA_Agent::prepareSendDataDown(Packet * p) +{ + struct hdr_shiva *shivah = HDR_SHIVA(p); + hdr_ip* iph = hdr_ip::access(p); + + // Marca il nodo come dato. + shivah->msg_type = SHIVA_DATA; +} + +bool +SHIVA_Agent::alreadyPresentBlack(Path & path1, Path & path2, NodeAddress node) +{ + for (Path::iterator i = path2.begin(); i != path2.end(); i++) + if (path1[*i] == node) + return true; + return false; +} + +NodeAddress +SHIVA_Agent::greaterCluster() +{ + NodeAddress tmp = -1; + for (NodeList::iterator i = neighbors.begin(); i != neighbors.end(); i++) + if ((getClusterHead(*i) == (*i)) && ((*i) > tmp)) + tmp = (*i); + return tmp; +} + +void +SHIVA_Agent::copy(Path & path1, Path & path2) +{ + path2.clear(); + for (Path::iterator i = path1.begin(); i != path1.end(); i++) + path2.push_back(*i); +} diff -Naur ns-allinone-2.29-old/ns-2.29/clustering/shiva/shiva.h ns-allinone-2.29/ns-2.29/clustering/shiva/shiva.h --- ns-allinone-2.29-old/ns-2.29/clustering/shiva/shiva.h 1970-01-01 01:00:00.000000000 +0100 +++ ns-allinone-2.29/ns-2.29/clustering/shiva/shiva.h 2007-08-03 22:23:30.000000000 +0200 @@ -0,0 +1,304 @@ + +/** + * Copyright (c) 2006 Michele Mastrogiovanni. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#ifndef _SHIVA_H_ +#define _SHIVA_H_ + +#include "ClusteringModule.h" +#include "CyclesFinder.h" +#include "ShivaUtility.h" +// #include "BackboneUtility.h" + +// #include "dca_mastro.h" +// #include "connector_mastro.h" + +#include +#include +#include +#include + +#include + +//////////////// +// Definition // +//////////////// +#define CLUSTER_HEAD 0 +#define NORMAL 1 +#define GATEWAY 2 + +///////////////////// +/// Stato del nodo // +///////////////////// +typedef enum { + + SHIVA_STATUS_DISCOVER = 0x0, // Discover dei vicini BLACK a distanza minore uguale a MAX_LENGTH + // e creazione del grafo virtual di grado massimo MAX_LENGTH. + SHIVA_STATUS_CONNECTING = 0x1, // Colorazione dei nodi di connessione del backbone dopo + // l'eliminazione dei cicli. + SHIVA_STATUS_END = 0x2 // Fine algoritmo. + +} ShivaStatus; + +////////////////////// +// Tipi di messaggi // +////////////////////// +typedef enum +{ + SHIVA_DISCOVER = 0x0, // Scopre i nodi BLACK vicini, i percorsi e i cicli. + SHIVA_TURN_ON = 0x1, // Rende BLACK un nodo WHITE sul backbone. + SHIVA_TURN_OFF = 0x2, // Rende BLACK un nodo WHITE sul backbone. + SHIVA_CONFIRM = 0x3, // Messaggio DISCOVER finale. + SHIVA_DATA = 0x4 // DATA message. +} ShivaMessageType; + +// +// Struttura del messaggio di discovery. +// +struct DiscoveryMessage { + + int my_seq; // Numero di sequenza del messaggio + // + int ack_seq; // Numero di sequenza del pacchetto che ha scatenato la + // trasmissione (serve per conferma). + NodeAddress parent; // Nodo che ha scatenato la trasmissione. + // + Path path1; // Percorso di nodi BLACK: contiene i nodi BLACK presenti + // dal primo (in testa) all'ultimo + Path path2; // Percorso di nodi WHITE dal vicino dell'ultimo nodo + // BLACK al nodo WHITE precedente. + bool dummy; // True se il messaggio e'di tipo DUMMY (e quindi i + // path sono vuoti). +}; + +////////////////////////// +// Header del pacchetto // +////////////////////////// +struct hdr_shiva +{ + ShivaMessageType msg_type; // Tipo di messaggio. + + struct DiscoveryMessage discovery_message; + ShivaMessageType confirm; + + ///////////////// + /// Addressing // + ///////////////// + static int offset_; + inline static int& offset() { return offset_; } + inline static hdr_shiva* access(const Packet* p) { + return (hdr_shiva*) p->access(offset_); + } +}; + +struct ShivaArc { + int length; + NodeAddress begin; + NodeAddress end; +}; + +bool isBetterThan(ShivaArc arc1, ShivaArc arc2) { + if (arc1.length > arc2.length) + return true; + if (arc1.length < arc2.length) + return false; + int max1 = (arc1.begin > arc1.end ? arc1.begin : arc1.end); + int max2 = (arc2.begin > arc2.end ? arc2.begin : arc2.end); + int other_max1 = (arc1.begin > arc1.end ? arc1.end : arc1.begin); + int other_max2 = (arc2.begin > arc2.end ? arc2.end : arc2.begin); + + if (max1 < max2) + return true; + + if (max1 > max2) + return false; + + return other_max1 < other_max2; +} + +/////////// +// Timer // +/////////// +class ShivaTimer; + +/////////// +// Agent // +/////////// +class SHIVA_Agent : public ClusteringModule +{ +public: + SHIVA_Agent(); + + // Parsing dei comandi TCL. + // virtual int command(int argc, const char * const * argv); + + // Funzione di ricezione dell'algoritmo di clustering. + virtual void receive(Packet * p, Handler * h); + + // Fa partire il modulo. + virtual void startModule(); + + // Termine del lavoro del modulo. + virtual void endModule(); + + void beginBackboneFormation(); + + void endCycleDiscover(); + + // Callback from timer to signal a timeout + void timeout(ShivaMessageType type, NodeAddress from, int seq); + + // Reach max number of retransmissions + void lastTimeout(ShivaMessageType type, NodeAddress from, int seq); + + // Verifica che un pacchetto sia di tipo DATA. + virtual bool isDataPacket(Packet * p); + + // Preparazione all'invio di un messaggio al layer inferiore + virtual void prepareSendDataDown(Packet * p); + + virtual Color getColor(NodeAddress node) { return NO_COLOR; } + + void copy(Path & path1, Path & path2); + + void savePath(NodeAddress begin, NodeAddress end, ReachPath path); + void savePaths(Path path1, Path path2); + + ReachPath higherPath(ReachPath path1, ReachPath path2); + +protected: + + Paths paths; // Percorsi per calcolare i cicli (tabella). + ShivaStatus status; // Stato del nodo. + + Reachbility reach; // Percorso per raggiungere un altro nodo BLACK (solo clusterHead). + // Source, Destination, Reach Path. + map > reachComplete; + + NodeList neighbors_on_route; // Vicini di un nero che sono su almeno una rotta. + NodeList node_to_turn_off; + + map forward_path; // Path di forward (solo nodi gateway). + + int seq; // Sequence number dei messaggi di Discovery. + ShivaTimer * timer; // Gestore dei timeout. + + // + // Buffer dei messaggi di DISCOVERY (per le ritrasmissioni). + // + map myDiscoveryMessages; + map myTurnedOn; + map > receivedMessagesFrom; + NodeList turnOnMessages; // Vicini che non mi hanno inviato ancora il turn ON. + map turnOnValues; + + NodeAddress finalClusterHead; // ClusterHead finale. + + int with_bottom_router; + +protected: + + ////////////// + // Messages // + ////////////// + + // Invio di un discover. + void send_DISCOVER(NodeAddress to, struct DiscoveryMessage message); + + // Invio di un TURN ON. + void send_TURN_ON(NodeAddress to); + + // Invia di una conferma a un messaggio di TURN ON. + void send_CONFIRM_TURN_ON(NodeAddress to); + + // Ricezione di un pacchetto di DISCOVER: vengono specificati: la provenienza + void receive_DISCOVER(NodeAddress from, struct DiscoveryMessage message); + + // Ricezione di un pacchetto di TURN ON: viene specificata la provenienza. + void receive_TURN_ON(NodeAddress from, bool on); + + struct DiscoveryMessage createDiscover(int ack_seq, Path path1, Path path2, NodeAddress parent); + struct DiscoveryMessage createDummyDiscover(int ack_seq, NodeAddress parent); + + // Verifica che in un percorso non sia gia'presente un certo nodo nero. + bool alreadyPresentBlack(Path & path1, Path & path2, NodeAddress node); + + NodeAddress greaterCluster(); + + void processPhase(); + +private: + + // double initialTime; + + map neighborTurnOn; + +public: + + static int _DEBUG_; + + static int max_length; // 3; // Lunghezza massima dei cicli + // (di nodi BLACK) da tagliare + + static double max_delay; // 0.2; // Delay di una broadcast + + static double jitter_timeout_destruction; + static double timeout_destruction; + + static int max_timeout_discover; // 4; // Numero massimo di timeout al messaggio DISCOVER + static double jitter_timeout_discover; // 0.2; // Jitter per il messaggio DISCOVER. + static double timeout_discover; // 1.0; // Durata timeout messaggio DISCOVER. + + static int max_timeout_turn_on; // 4; // Numero massimo di timeout al messaggio DISCOVER + static double jitter_timeout_turn_on; // 0.2; // Jitter per il messaggio DISCOVER. + static double timeout_turn_on; // 1.0; // Durata timeout messaggio DISCOVER. + +}; + +typedef map FromTimeout; +typedef map SeqFromTimeout; + +///////////////////////////////// +// Timer per le ritrasmissioni // +///////////////////////////////// +class ShivaTimer: public Handler { +public: + + ShivaTimer(SHIVA_Agent * a) : Handler(), agent(a) {} + + void launchDiscover(NodeAddress to, int seq); + void cancelDiscover(NodeAddress from, int seq); + void cancelAllDiscover(); + + void launchTurnOn(NodeAddress to); + bool cancelTurnOn(NodeAddress from); + + void beginDestruction(); + + void handle(Event* e); + +protected: + + SHIVA_Agent * agent; + + SeqFromTimeout seqFromTimeouts; + TimeoutMap turn_on_messages; + Event * begin_cycle_destruction; + +}; + +#endif diff -Naur ns-allinone-2.29-old/ns-2.29/clustering/utility/.DS_Store ns-allinone-2.29/ns-2.29/clustering/utility/.DS_Store --- ns-allinone-2.29-old/ns-2.29/clustering/utility/.DS_Store 1970-01-01 01:00:00.000000000 +0100 +++ ns-allinone-2.29/ns-2.29/clustering/utility/.DS_Store 2007-08-03 22:23:30.000000000 +0200 @@ -0,0 +1,2 @@ +Bud1 boneUt  @€ @€ @€ @BackboneUtility.ccIlocblobZ!˙˙˙˙˙˙BackboneUtility.hIlocblob!˙˙˙˙˙˙ClusteringUtility.ccIlocblobÂ!˙˙˙˙˙˙ClusteringUtility.hIlocblobZ}˙˙˙˙˙˙CommonUtility.ccIlocblob}˙˙˙˙˙˙CommonUtility.hIlocblobÂ}˙˙˙˙˙˙ConnectorUtility.ccIlocblobZŮ˙˙˙˙˙˙ConnectorUtility.hIlocblobŮ˙˙˙˙˙˙LeaderUtility.ccIlocblobÂŮ˙˙˙˙˙˙LeaderUtility.hIlocblobZ5˙˙˙˙˙˙RajaramanUtility.ccIlocblob5˙˙˙˙˙˙RajaramanUtility.hIlocblobÂ5˙˙˙˙˙˙ShivaUtility.ccIlocblobZ‘˙˙˙˙˙˙ShivaUtility.hIlocblob‘˙˙˙˙˙˙StackUtility.ccIlocblob‘˙˙˙˙˙˙StackUtility.hIlocblobZí˙˙˙˙˙˙tmpIlocblobí˙˙˙˙˙˙tmpfwi0blobŚü'clmvtmpfwswlongvtmpfwvhshortmpicspblob +Utility.ccIlocblobÂí˙˙˙˙˙˙ Utility.hIlocblobZI˙˙˙˙˙˙ E DSDB `€ @€ @€ @ty.hIlocblobZI˙˙˙˙˙˙ \ No newline at end of file diff -Naur ns-allinone-2.29-old/ns-2.29/clustering/utility/BackboneUtility.cc ns-allinone-2.29/ns-2.29/clustering/utility/BackboneUtility.cc --- ns-allinone-2.29-old/ns-2.29/clustering/utility/BackboneUtility.cc 1970-01-01 01:00:00.000000000 +0100 +++ ns-allinone-2.29/ns-2.29/clustering/utility/BackboneUtility.cc 2007-08-03 22:23:30.000000000 +0200 @@ -0,0 +1,53 @@ + +/** + * Copyright (c) 2006 Michele Mastrogiovanni. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#include "BackboneUtility.h" + +static class BackboneUtilityClass : public TclClass { +public: + BackboneUtilityClass() : TclClass("Utility/BACKBONE") {} + TclObject* create(int , const char*const* ) { + return(new BackboneUtility()); + } +} class_backbone_utility; + +void +BackboneUtility::setBackbone(NodeAddress node, NodeList & neighbors) +{ + for (NodeList::iterator n = neighbors.begin(); n != neighbors.end(); n++) { + backbone[node].insert(*n); + backbone[*n].insert(node); + } +} + +void +BackboneUtility::dump() +{ + ClusteringUtility::dump(); + + // + // Stampa i vicini di ogni nodo sul backbone. + // + cout << backbone.size() << endl; + for (map::iterator n = backbone.begin(); n != backbone.end(); n++) { + cout << (n->first) << " "; + for (NodeList::iterator i = (n->second).begin(); i != (n->second).end(); i++) + cout << *i << " "; + cout << endl; + } +} diff -Naur ns-allinone-2.29-old/ns-2.29/clustering/utility/BackboneUtility.h ns-allinone-2.29/ns-2.29/clustering/utility/BackboneUtility.h --- ns-allinone-2.29-old/ns-2.29/clustering/utility/BackboneUtility.h 1970-01-01 01:00:00.000000000 +0100 +++ ns-allinone-2.29/ns-2.29/clustering/utility/BackboneUtility.h 2007-08-03 22:23:30.000000000 +0200 @@ -0,0 +1,45 @@ + +/** + * Copyright (c) 2006 Michele Mastrogiovanni. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#ifndef _BACKBONE_UTILITY_H_ +#define _BACKBONE_UTILITY_H_ + +#include "ClusteringUtility.h" + +#include +#include +#include + +class BackboneUtility : public ClusteringUtility +{ +public: + BackboneUtility() : ClusteringUtility() { + utility_name = "BACKBONE"; + } + + virtual void dump(); + + void setBackbone(NodeAddress node, NodeList & neighbors); + +protected: + + map backbone; + +}; + +#endif diff -Naur ns-allinone-2.29-old/ns-2.29/clustering/utility/ClusteringUtility.cc ns-allinone-2.29/ns-2.29/clustering/utility/ClusteringUtility.cc --- ns-allinone-2.29-old/ns-2.29/clustering/utility/ClusteringUtility.cc 1970-01-01 01:00:00.000000000 +0100 +++ ns-allinone-2.29/ns-2.29/clustering/utility/ClusteringUtility.cc 2007-08-03 22:23:30.000000000 +0200 @@ -0,0 +1,53 @@ + +/** + * Copyright (c) 2006 Michele Mastrogiovanni. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#include "ClusteringUtility.h" + +static class ClusteringUtilityClass : public TclClass { +public: + ClusteringUtilityClass() : TclClass("Utility/CLUSTERING") {} + TclObject* create(int , const char*const* ) { + return(new ClusteringUtility()); + } +} class_clustering_utility; + +void +ClusteringUtility::setColor(NodeAddress node, string color) +{ + colors[color].insert(node); +} + +void +ClusteringUtility::dump() +{ + CommonUtility::dump(); + + // + // Stampa i nodi associati a ciascun colore. + // + cout << colors.size() << endl; + for (map::iterator c = colors.begin(); c != colors.end(); c++) { + cout << c->first << " "; + for (NodeList::iterator n = (c->second).begin(); n != (c->second).end(); n++) + cout << *n << " "; + cout << endl; + } +} + + + diff -Naur ns-allinone-2.29-old/ns-2.29/clustering/utility/ClusteringUtility.h ns-allinone-2.29/ns-2.29/clustering/utility/ClusteringUtility.h --- ns-allinone-2.29-old/ns-2.29/clustering/utility/ClusteringUtility.h 1970-01-01 01:00:00.000000000 +0100 +++ ns-allinone-2.29/ns-2.29/clustering/utility/ClusteringUtility.h 2007-08-03 22:23:30.000000000 +0200 @@ -0,0 +1,47 @@ + +/** + * Copyright (c) 2006 Michele Mastrogiovanni. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#ifndef _CLUSTERING_UTILITY_ +#define _CLUSTERING_UTILITY_ + +#include "CommonUtility.h" +#include "clustering-header.h" + +#include +#include +#include + +class ClusteringUtility : public CommonUtility +{ +public: + ClusteringUtility() : CommonUtility() { + utility_name = "CLUSTERING"; + } + + virtual void dump(); + + void setColor(NodeAddress node, string color); + +protected: + + map colors; +}; + +#endif + + \ No newline at end of file diff -Naur ns-allinone-2.29-old/ns-2.29/clustering/utility/CommonUtility.cc ns-allinone-2.29/ns-2.29/clustering/utility/CommonUtility.cc --- ns-allinone-2.29-old/ns-2.29/clustering/utility/CommonUtility.cc 1970-01-01 01:00:00.000000000 +0100 +++ ns-allinone-2.29/ns-2.29/clustering/utility/CommonUtility.cc 2007-08-03 22:23:30.000000000 +0200 @@ -0,0 +1,69 @@ + +/** + * Copyright (c) 2006 Michele Mastrogiovanni. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#include +#include "CommonUtility.h" + +static class CommonUtilityClass : public TclClass { +public: + CommonUtilityClass() : TclClass("Utility/COMMON") {} + TclObject* create(int , const char*const* ) { + return(new CommonUtility()); + } +} class_common_utility; + +void +CommonUtility::dump() +{ + Utility::dump(); + + // + // Stampa i dati associati a ciascun nodo + // + cout << datas.size() << endl; + for (map::iterator n = datas.begin(); n != datas.end(); n++) { + cout << n->first << " "; + for (int i = 0; i < 10; i++) + cout << (n->second).values[i] << " "; + cout << endl; + } + + // + // Stampa Pacchetti e Bytes trasmessi in totale a livello fisico. + // + cout << packetsTransmit << " " << bytesTransmit << endl; +} + +void +CommonUtility::add(NodeAddress node, double value, DumpType type) +{ + datas[node].values[type] += value; +} + +void +CommonUtility::set(NodeAddress node, double value, DumpType type) +{ + datas[node].values[type] = value; +} + +double +CommonUtility::get(NodeAddress node, DumpType type) +{ + return datas[node].values[type]; +} + diff -Naur ns-allinone-2.29-old/ns-2.29/clustering/utility/CommonUtility.h ns-allinone-2.29/ns-2.29/clustering/utility/CommonUtility.h --- ns-allinone-2.29-old/ns-2.29/clustering/utility/CommonUtility.h 1970-01-01 01:00:00.000000000 +0100 +++ ns-allinone-2.29/ns-2.29/clustering/utility/CommonUtility.h 2007-08-03 22:23:30.000000000 +0200 @@ -0,0 +1,78 @@ + +/** + * Copyright (c) 2006 Michele Mastrogiovanni. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#ifndef _COMMON_UTILITY_H_ +#define _COMMON_UTILITY_H_ + +#include "Utility.h" +#include "clustering-header.h" +#include "packet.h" + +#include +#include + +typedef enum DumpType +{ + TX_BYTE_UNICAST = 0, + TX_MSG_UNICAST = 1, + TX_BYTE_BROADCAST = 2, + TX_MSG_BROADCAST = 3, + + RX_BYTE_UNICAST = 4, + RX_MSG_UNICAST = 5, + RX_BYTE_BROADCAST = 6, + RX_MSG_BROADCAST = 7, + + TIME = 8, + ENERGY = 9 +}; + +typedef struct { + double values[10]; +} DumpData; + +class CommonUtility : public Utility { + +public: + + CommonUtility() : Utility(), packetsTransmit(0), bytesTransmit(0) { + utility_name = "COMMON"; + } + + // Dump Nodes. + virtual void dump(); + + // Aggiunge valori ai dati. + void add(NodeAddress node, double value, DumpType type); + void set(NodeAddress node, double value, DumpType type); + double get(NodeAddress node, DumpType type); + + virtual void addTransmitPacket(double packets, double bytes) { + packetsTransmit += packets; + bytesTransmit += bytes; + } + +public: + + map datas; + double packetsTransmit; + double bytesTransmit; + +}; + +#endif \ No newline at end of file diff -Naur ns-allinone-2.29-old/ns-2.29/clustering/utility/ConnectorUtility.cc ns-allinone-2.29/ns-2.29/clustering/utility/ConnectorUtility.cc --- ns-allinone-2.29-old/ns-2.29/clustering/utility/ConnectorUtility.cc 1970-01-01 01:00:00.000000000 +0100 +++ ns-allinone-2.29/ns-2.29/clustering/utility/ConnectorUtility.cc 2007-08-03 22:23:30.000000000 +0200 @@ -0,0 +1,47 @@ + +/** + * Copyright (c) 2006 Michele Mastrogiovanni. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#include "ConnectorUtility.h" + +static class ConnectorUtilityClass : public TclClass { +public: + ConnectorUtilityClass() : TclClass("Utility/CONNECTOR") {} + TclObject* create(int , const char*const* ) { + return(new ConnectorUtility()); + } +} class_connector_utility; + +void ConnectorUtility::dump() +{ + BackboneUtility::dump(); + + long connected_ch = 0; + for (map::iterator n = connectedClusterHeads.begin(); + n != connectedClusterHeads.end(); + n++) + connected_ch += n->second; + + cout << connectedClusterHeads.size() << " " << connected_ch << endl; + + cerr << "Average Connected ClusterHeads: " << ((double)connected_ch / (double)connectedClusterHeads.size()) << endl; +} + +void ConnectorUtility::setConnectedClusterHeads(NodeAddress node, int size) +{ + connectedClusterHeads[node] = size; +} diff -Naur ns-allinone-2.29-old/ns-2.29/clustering/utility/ConnectorUtility.h ns-allinone-2.29/ns-2.29/clustering/utility/ConnectorUtility.h --- ns-allinone-2.29-old/ns-2.29/clustering/utility/ConnectorUtility.h 1970-01-01 01:00:00.000000000 +0100 +++ ns-allinone-2.29/ns-2.29/clustering/utility/ConnectorUtility.h 2007-08-03 22:23:30.000000000 +0200 @@ -0,0 +1,43 @@ + +/** + * Copyright (c) 2006 Michele Mastrogiovanni. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#ifndef _CONNECTOR_UTILITY_H_ +#define _CONNECTOR_UTILITY_H_ + +#include "BackboneUtility.h" + +#include + +class ConnectorUtility : public BackboneUtility +{ +public: + ConnectorUtility() : BackboneUtility() { + utility_name = "CONNECTOR"; + } + + virtual void dump(); + + void setConnectedClusterHeads(NodeAddress node, int size); + +protected: + + map connectedClusterHeads; + +}; + +#endif diff -Naur ns-allinone-2.29-old/ns-2.29/clustering/utility/LeaderUtility.cc ns-allinone-2.29/ns-2.29/clustering/utility/LeaderUtility.cc --- ns-allinone-2.29-old/ns-2.29/clustering/utility/LeaderUtility.cc 1970-01-01 01:00:00.000000000 +0100 +++ ns-allinone-2.29/ns-2.29/clustering/utility/LeaderUtility.cc 2007-08-03 22:23:30.000000000 +0200 @@ -0,0 +1,63 @@ + +/** + * Copyright (c) 2006 Michele Mastrogiovanni. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#include "LeaderUtility.h" + +static class LeaderUtilityClass : public TclClass { +public: + LeaderUtilityClass() : TclClass("Utility/LEADER") {} + TclObject* create(int , const char*const* ) { + return(new LeaderUtility()); + } +} class_leader_utility; + +void +LeaderUtility::dump() +{ + CommonUtility::dump(); + + // + // Stampa la sequenza di join + // + cout << joins.size() << " "; + for (list::iterator i = joins.begin(); i != joins.end(); i++) + cout << (*i) << " "; + cout << endl; + + // + // Stampa il leader + // + cout << leader << endl; + + cerr << "\t- Joins: " << (joins.size() / 2) << endl; + cerr << "\t- Leader: " << leader << endl; +} + +void +LeaderUtility::addJoin(NodeAddress node, NodeAddress to) +{ + joins.push_back(node); + joins.push_back(to); +} + +void +LeaderUtility::setLeader(NodeAddress l) +{ + leader = l; +} + diff -Naur ns-allinone-2.29-old/ns-2.29/clustering/utility/LeaderUtility.h ns-allinone-2.29/ns-2.29/clustering/utility/LeaderUtility.h --- ns-allinone-2.29-old/ns-2.29/clustering/utility/LeaderUtility.h 1970-01-01 01:00:00.000000000 +0100 +++ ns-allinone-2.29/ns-2.29/clustering/utility/LeaderUtility.h 2007-08-03 22:23:30.000000000 +0200 @@ -0,0 +1,50 @@ + +/** + * Copyright (c) 2006 Michele Mastrogiovanni. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#ifndef _LEADER_UTILITY_ +#define _LEADER_UTILITY_ + +#include +#include +#include + +#include "packet.h" +#include "scheduler.h" +#include "CommonUtility.h" + +class LeaderUtility : public CommonUtility +{ +public: + + LeaderUtility() : CommonUtility(), leader(-1) { + utility_name = "LEADER"; + } + + virtual void dump(); + + void addJoin(NodeAddress node, NodeAddress to); + void setLeader(NodeAddress l); + +protected: + + list joins; + NodeAddress leader; + +}; + +#endif \ No newline at end of file diff -Naur ns-allinone-2.29-old/ns-2.29/clustering/utility/RajaramanUtility.cc ns-allinone-2.29/ns-2.29/clustering/utility/RajaramanUtility.cc --- ns-allinone-2.29-old/ns-2.29/clustering/utility/RajaramanUtility.cc 1970-01-01 01:00:00.000000000 +0100 +++ ns-allinone-2.29/ns-2.29/clustering/utility/RajaramanUtility.cc 2007-08-03 22:23:30.000000000 +0200 @@ -0,0 +1,52 @@ + +/** + * Copyright (c) 2006 Michele Mastrogiovanni. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#include "RajaramanUtility.h" + +static class RajaramanUtilityClass : public TclClass { +public: + RajaramanUtilityClass() : TclClass("Utility/RAJARAMAN") {} + TclObject* create(int , const char*const* ) { + return(new RajaramanUtility()); + } +} class_rajaraman_utility; + +void +RajaramanUtility::setCycles(NodeAddress node, int n) +{ + cycles[node] = n; +} + +void +RajaramanUtility::dump() +{ + ClusteringUtility::dump(); + + double avg = 0.0; + for (map::iterator n = cycles.begin(); n != cycles.end(); n++) { + cout << n->second << " "; + avg += n->second; + } + + avg /= cycles.size(); + + cout << endl; + + cerr << "Avg. Rounds: " << avg << endl; +} + diff -Naur ns-allinone-2.29-old/ns-2.29/clustering/utility/RajaramanUtility.h ns-allinone-2.29/ns-2.29/clustering/utility/RajaramanUtility.h --- ns-allinone-2.29-old/ns-2.29/clustering/utility/RajaramanUtility.h 1970-01-01 01:00:00.000000000 +0100 +++ ns-allinone-2.29/ns-2.29/clustering/utility/RajaramanUtility.h 2007-08-03 22:23:30.000000000 +0200 @@ -0,0 +1,42 @@ + +/** + * Copyright (c) 2006 Michele Mastrogiovanni. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#ifndef _RAJARAMAN_UTILITY_H_ +#define _RAJARAMAN_UTILITY_H_ + +#include "ClusteringUtility.h" + +#include + +class RajaramanUtility : public ClusteringUtility +{ +public: + RajaramanUtility() : ClusteringUtility() { + utility_name = "RAJARAMAN"; + } + + virtual void dump(); + + void setCycles(NodeAddress node, int cycles); + +protected: + map cycles; + +}; + +#endif diff -Naur ns-allinone-2.29-old/ns-2.29/clustering/utility/ShivaUtility.cc ns-allinone-2.29/ns-2.29/clustering/utility/ShivaUtility.cc --- ns-allinone-2.29-old/ns-2.29/clustering/utility/ShivaUtility.cc 1970-01-01 01:00:00.000000000 +0100 +++ ns-allinone-2.29/ns-2.29/clustering/utility/ShivaUtility.cc 2007-08-03 22:23:30.000000000 +0200 @@ -0,0 +1,166 @@ + +/** + * Copyright (c) 2006 Michele Mastrogiovanni. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#include "ShivaUtility.h" + +static class ShivaUtilityClass : public TclClass { +public: + ShivaUtilityClass() : TclClass("Utility/SHIVA") {} + TclObject* create(int , const char*const* ) { + return(new ShivaUtility()); + } +} class_shiva_utility; + +void ShivaUtility::dump() +{ + BackboneUtility::dump(); + + // DEBUG + cerr << "----------------------" << endl; + cerr << "Mapping Arcs" << endl; + for (map::iterator n = mappingArcs.begin(); n != mappingArcs.end(); n++) { + cerr << n->first.first << "\t" << n->first.second; + for (NodeList::iterator i = n->second.begin(); i != n->second.end(); i++) + cerr << "\t" << *i; + cerr << endl; + } + + cerr << "Virtual Arcs" << endl; + for (int i = 0; i < 3; i++) { + for (Arcs::iterator arc = virtualArcs[i].begin(); arc != virtualArcs[i].end(); arc++) + cerr << arc->first << "\t" << arc->second << endl; + } + + cerr << "Virtual Arcs Erased" << endl; + for (int i = 0; i < 3; i++) { + for (Arcs::iterator arc = virtualArcsErased[i].begin(); arc != virtualArcsErased[i].end(); arc++) + cerr << arc->first << "\t" << arc->second << endl; + } + cerr << "----------------------" << endl; + + // + // Stampa il numero totale di archi virtuali che contengono + // 0, 1 o 2 nodi gateway. + // + cout << virtualArcs[0].size() << " "; + cout << virtualArcs[1].size() << " "; + cout << virtualArcs[2].size() << " "; + + cout << virtualArcsErased[0].size() << " "; + cout << virtualArcsErased[1].size() << " "; + cout << virtualArcsErased[2].size() << " "; + + cerr << "Archi Rilevati: " << (virtualArcs[0].size() + virtualArcs[1].size() + virtualArcs[2].size()) << endl; + cerr << "Archi Da Eliminare: " << (virtualArcsErased[0].size() + virtualArcsErased[1].size() + virtualArcsErased[2].size()) << endl; + + int reallyErased[4]; + + reallyErased[3] = 0; + + for (int i = 0; i < 3; i++) { + reallyErased[i] = 0; + // Scorre la lista degli archi di una certa lunghezza da eliminare. + for (Arcs::iterator arc = virtualArcsErased[i].begin(); + arc != virtualArcsErased[i].end(); + arc++) { + + // Per ognuno di questi archi nel mapping ritrova la lista dei + // nodi che c'è fra i due estremi: se almeno un nodo fra i due + // estremi non è colorato, l'arco è eliminato veramente. Altrimenti + // resta. + + + int decolored = 0; + + for (NodeList::iterator node = mappingArcs[*arc].begin(); + node != mappingArcs[*arc].end(); + node++) + if (find(coloredGateways.begin(), coloredGateways.end(), *node) == coloredGateways.end()) + decolored++; + + if (decolored == i) + reallyErased[i]++; + + if ((i == 2) && (decolored == 1)) + reallyErased[3]++; + } + } + + cout << reallyErased[0] << " "; + cout << reallyErased[1] << " "; + cout << reallyErased[2] << " "; + cout << reallyErased[3] << " "; + + cerr << "Archi Eliminati Effettivi: " << (reallyErased[0] + reallyErased[1] + reallyErased[2]) << endl; + cerr << "Archi Lunghi 2 con un solo gateway off: " << reallyErased[3] << endl; + + cout << endl; +} + +void ShivaUtility::addVirtualArc(NodeAddress a, NodeAddress b, NodeList members) +{ + if (a > b) { + NodeAddress tmp = b; + b = a; + a = tmp; + } + + // DEBUG + /* + cout << a << "\t" << b; + for (NodeList::iterator n = members.begin(); n != members.end(); n++) + cout << "\t" << *n; + cout << endl; + */ + + Arc arc(a, b); + virtualArcs[members.size()].insert(arc); + + // DEBUG + /* + bool exists = false; + if (mappingArcs.find(arc) != mappingArcs.end()) + exists = true; + int size_before = mappingArcs[arc].size(); + for (NodeList::iterator n = members.begin(); n != members.end(); n++) + mappingArcs[arc].insert(*n); + if (exists && (size_before != mappingArcs[arc].size())) { + cout << "ERRORE: ho memorizzato un arco diverso da quello di partenza: " << endl; + cout << arc.first << " - " << arc.second << endl; + } + */ + + mappingArcs[arc] = members; +} + +void ShivaUtility::eraseVirtualArc(NodeAddress a, NodeAddress b, int size) +{ + if (a > b) { + NodeAddress tmp = b; + b = a; + a = tmp; + } + + virtualArcsErased[size].insert(Arc(a, b)); +} + +void ShivaUtility::colorNode(NodeAddress node) +{ + coloredGateways.insert(node); +} + diff -Naur ns-allinone-2.29-old/ns-2.29/clustering/utility/ShivaUtility.h ns-allinone-2.29/ns-2.29/clustering/utility/ShivaUtility.h --- ns-allinone-2.29-old/ns-2.29/clustering/utility/ShivaUtility.h 1970-01-01 01:00:00.000000000 +0100 +++ ns-allinone-2.29/ns-2.29/clustering/utility/ShivaUtility.h 2007-08-03 22:23:30.000000000 +0200 @@ -0,0 +1,52 @@ + +/** + * Copyright (c) 2006 Michele Mastrogiovanni. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#ifndef _SHIVA_UTILITY_H_ +#define _SHIVA_UTILITY_H_ + +#include "BackboneUtility.h" + +#include + + +class ShivaUtility : public BackboneUtility +{ +public: + ShivaUtility() : BackboneUtility() { + utility_name = "SHIVA"; + } + + virtual void dump(); + + void addVirtualArc(NodeAddress a, NodeAddress b, NodeList members); + void eraseVirtualArc(NodeAddress a, NodeAddress b, int size); + + // Mantiene tutti gli archi che passano di li'. + void colorNode(NodeAddress node); + +protected: + + map virtualArcs; + map virtualArcsErased; + map mappingArcs; + + NodeList coloredGateways; + +}; + +#endif diff -Naur ns-allinone-2.29-old/ns-2.29/clustering/utility/StackUtility.cc ns-allinone-2.29/ns-2.29/clustering/utility/StackUtility.cc --- ns-allinone-2.29-old/ns-2.29/clustering/utility/StackUtility.cc 1970-01-01 01:00:00.000000000 +0100 +++ ns-allinone-2.29/ns-2.29/clustering/utility/StackUtility.cc 2007-08-03 22:23:30.000000000 +0200 @@ -0,0 +1,92 @@ + +/** + * Copyright (c) 2006 Michele Mastrogiovanni. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#include "StackUtility.h" + +static class StackUtilityClass : public TclClass { +public: + StackUtilityClass() : TclClass("Utility/STACK") {} + TclObject* create(int , const char*const* ) { + return(new StackUtility()); + } +} class_stack_utility; + +int +StackUtility::command(int argc, const char * const * argv) +{ + if (argc == 4) { + // + // $stack-utility set-module 0 $utility0 + // $stack-utility set-module 1 $utility1 + // + if (strcmp (argv[1], "set-module") == 0) { + int num = atoi(argv[2]); + dumpData[num] = (CommonUtility *) TclObject::lookup(argv[3]); + if (num > top_module) + top_module = num; + if (base_module == -1) + base_module = num; + else if (num < base_module) + base_module = num; + return (TCL_OK); + } + } + else if (argc == 3) { + if (strcmp (argv[1], "set-separator") == 0) { + separator = (Separator *) TclObject::lookup(argv[2]); + return (TCL_OK); + } + else if (strcmp (argv[1], "set-topology-name") == 0) { + topology = string(argv[2]); + return TCL_OK; + } + } + + return CommonUtility::command(argc, argv); +} + +void +StackUtility::dump() +{ + cerr << topology << " - "; + for (map::iterator i = dumpData.begin(); i != dumpData.end();) { + cout << (i->second)->algorithm; + cerr << (i->second)->algorithm; + i++; + if (i != dumpData.end()) { + cout << "-"; + cerr << "-"; + } + else + cout << " "; + } + cerr << endl; + cout << endl; + + for (map::iterator i = dumpData.begin(); i != dumpData.end(); i++) + (i->second)->dump(); +} + +void +StackUtility::addTransmitPacket(double packets, double bytes) { + packetsTransmit += packets; + bytesTransmit += bytes; + + dumpData[separator->getIndexCurrentModule()]->packetsTransmit += packets; + dumpData[separator->getIndexCurrentModule()]->bytesTransmit += bytes; +} diff -Naur ns-allinone-2.29-old/ns-2.29/clustering/utility/StackUtility.h ns-allinone-2.29/ns-2.29/clustering/utility/StackUtility.h --- ns-allinone-2.29-old/ns-2.29/clustering/utility/StackUtility.h 1970-01-01 01:00:00.000000000 +0100 +++ ns-allinone-2.29/ns-2.29/clustering/utility/StackUtility.h 2007-08-03 22:23:30.000000000 +0200 @@ -0,0 +1,66 @@ + +/** + * Copyright (c) 2006 Michele Mastrogiovanni. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#ifndef _STACK_UTILITY_ +#define _STACK_UTILITY_ + +#include + +#include "CommonUtility.h" +#include "ClusteringModule.h" +#include "Separator.h" + +/* + Questa classe offre le funzioni di utilita'per il funzionamento + di un protocollo di clustering modulare. + + set stack_utility [new StackUtility] + stack_utility $module0 [new Utility/DCA] + stack_utility $module1 [new Utility/SHIVA] + stack_utility $mac + + La classe registra il dump di ogni layer separatamente e poi propone + un responso riassuntivo. + +*/ + +class StackUtility : public CommonUtility { + +public: + StackUtility() : CommonUtility() { + base_module = -1; + top_module = -1; + } + + virtual int command(int argc, const char * const * argv); + virtual void dump(); + +protected: + int base_module; + int top_module; + map dumpData; + + Separator * separator; + + string topology; + + virtual void addTransmitPacket(double packets, double bytes); + +}; + +#endif \ No newline at end of file diff -Naur ns-allinone-2.29-old/ns-2.29/clustering/utility/Utility.cc ns-allinone-2.29/ns-2.29/clustering/utility/Utility.cc --- ns-allinone-2.29-old/ns-2.29/clustering/utility/Utility.cc 1970-01-01 01:00:00.000000000 +0100 +++ ns-allinone-2.29/ns-2.29/clustering/utility/Utility.cc 2007-08-03 22:23:30.000000000 +0200 @@ -0,0 +1,45 @@ + +/** + * Copyright (c) 2006 Michele Mastrogiovanni. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#include +#include "Utility.h" + +int +Utility::command(int argc, const char * const * argv) +{ + if (argc == 2) { + if (strcmp (argv[1], "dump") == 0) { + dump(); + return (TCL_OK); + } + } + else if (argc == 3) { + if (strcmp (argv[1], "set-algorithm-name") == 0) { + algorithm = string(argv[2]); + return (TCL_OK); + } + } + + return TclObject::command(argc, argv); +} + +void +Utility::dump() +{ + cout << utility_name << endl; +} \ No newline at end of file diff -Naur ns-allinone-2.29-old/ns-2.29/clustering/utility/Utility.h ns-allinone-2.29/ns-2.29/clustering/utility/Utility.h --- ns-allinone-2.29-old/ns-2.29/clustering/utility/Utility.h 1970-01-01 01:00:00.000000000 +0100 +++ ns-allinone-2.29/ns-2.29/clustering/utility/Utility.h 2007-08-03 22:23:30.000000000 +0200 @@ -0,0 +1,48 @@ + +/** + * Copyright (c) 2006 Michele Mastrogiovanni. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#ifndef _UTILITY_H_ +#define _UTILITY_H_ + +#include "clustering-header.h" +#include "packet.h" +#include +#include + +class Utility : public TclObject { + +public: + + Utility() : TclObject(), utility_name("") {} + + virtual int command(int argc, const char * const * argv); + virtual void recv(Packet *p, Handler *h) {}; + virtual void recv(Packet *p, const char * h) {}; + + // Dump Nodes. + virtual void dump(); + +public: + + string utility_name; + string algorithm; + +}; + + +#endif diff -Naur ns-allinone-2.29-old/ns-2.29/clustering/utility/tmp/CSparsifierUtility.cc ns-allinone-2.29/ns-2.29/clustering/utility/tmp/CSparsifierUtility.cc --- ns-allinone-2.29-old/ns-2.29/clustering/utility/tmp/CSparsifierUtility.cc 1970-01-01 01:00:00.000000000 +0100 +++ ns-allinone-2.29/ns-2.29/clustering/utility/tmp/CSparsifierUtility.cc 2007-08-03 22:23:30.000000000 +0200 @@ -0,0 +1,87 @@ + +/** + * Copyright (c) 2006 Michele Mastrogiovanni. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#include "CSparsifierUtility.h" +#include + +static class CSparsifierUtilityClass : public TclClass { +public: + CSparsifierUtilityClass() : TclClass("Utility/CSPARSIFIER") {} + TclObject* create(int , const char*const* ) { + return(new CSparsifierUtility()); + } +} class_c_sparsifier_utility; + +void +CSparsifierUtility::dump() +{ + // Utility::dump(); + + cerr << "Mancano: "; + for (int i = 0; i < 50; i++) { + if (neighbors[i].size() == 0) + cerr << i << " "; + } + cerr << endl; + cerr << "Tempo Medio di convergenza sparsificatore: " << time << endl; + cerr << "Topologia sparsificata di " << neighbors.size() << " nodi" << endl; + + // Marca tutti i nodi come non visitati: + // 0: non visitato + // 1: visitato + vector color(neighbors.size(), 0); + + // Marca il primo nodo come visitato + unsigned int visited = 0; + + // Effettua una visita in profondita' + DFS(0, color, visited); + + // Verifica che il numero dei nodi visitati sia pari al numero + // di nodi del grafo. + if (visited == neighbors.size()) + cerr << "Topologia Connessa" << endl; + else + cerr << "Topologia NON Connessa" << endl; +} + +void +CSparsifierUtility::DFS(int node, vector & colors, unsigned int & visited) +{ + // Colora il nodo di grigio + colors[node] = 1; + + for(set::iterator neighbor = neighbors[node].begin(); + neighbor != neighbors[node].end(); + neighbor++ ) + // Se il nodo non e' stato ancora colorato + if (colors[*neighbor] == 0) + // Effettua la ricerca il profondita' a partire da quel nodo + DFS(*neighbor, colors, visited); + + // Colora il nodo di nero + colors[node] = 2; + + visited++; +} + +void +CSparsifierUtility::setNeighbors(NodeAddress node, NodeList & neigh) +{ + neighbors[node] = neigh; +} diff -Naur ns-allinone-2.29-old/ns-2.29/clustering/utility/tmp/CSparsifierUtility.h ns-allinone-2.29/ns-2.29/clustering/utility/tmp/CSparsifierUtility.h --- ns-allinone-2.29-old/ns-2.29/clustering/utility/tmp/CSparsifierUtility.h 1970-01-01 01:00:00.000000000 +0100 +++ ns-allinone-2.29/ns-2.29/clustering/utility/tmp/CSparsifierUtility.h 2007-08-03 22:23:30.000000000 +0200 @@ -0,0 +1,42 @@ + +/** + * Copyright (c) 2006 Michele Mastrogiovanni. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#ifndef _CSPARSIFIER_UTILITY_ +#define _CSPARSIFIER_UTILITY_ + +#include "Utility.h" + +#include +#include + +class CSparsifierUtility : public Utility +{ +public: + CSparsifierUtility() : Utility(string("CSPARSIFIER")) {} + + virtual void dump(); + + void DFS(int node, vector & colors, unsigned int & visited); + + void setNeighbors(NodeAddress node, NodeList & neighbors); + +protected: + map neighbors; +}; + +#endif diff -Naur ns-allinone-2.29-old/ns-2.29/clustering/utility/tmp/DcaUtility.cc ns-allinone-2.29/ns-2.29/clustering/utility/tmp/DcaUtility.cc --- ns-allinone-2.29-old/ns-2.29/clustering/utility/tmp/DcaUtility.cc 1970-01-01 01:00:00.000000000 +0100 +++ ns-allinone-2.29/ns-2.29/clustering/utility/tmp/DcaUtility.cc 2007-08-03 22:23:30.000000000 +0200 @@ -0,0 +1,59 @@ + +/** + * Copyright (c) 2006 Michele Mastrogiovanni. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#include "DcaUtility.h" + +static class DcaUtilityClass : public TclClass { +public: + DcaUtilityClass() : TclClass("Utility/DCA") {} + TclObject* create(int argc, const char*const* argv) { + return(new DcaUtility()); + } +} class_dca_utility; + +void +DcaUtility::setStatus(NodeAddress node, int status) +{ + statusNode[node] = status; +} + +void +DcaUtility::dump() +{ + Utility::dump(); + + int clusterHeads = 0; + int gateway = 0; + int normali = 0; + + cout << statusNode.size() << " "; + for (map::iterator i = statusNode.begin(); i != statusNode.end(); i++) { + cout << (i->first) << " "; + cout << (i->second == CLUSTER_HEAD ? "*" : (i->second == NORMAL ? "o" : "x") << endl; + switch (i->second) { + case CLUSTER_HEAD : clusterHeads++; break; + case GATEWAY : gateway++; break; + case NORMAL : normali++; break; + } + } + + cerr << "\t- ClusterHeads: " << clusterHeads << endl; + cerr << "\t- Gateway: " << gateway << endl; + cerr << "\t- Normali: " << normali << endl; +} + diff -Naur ns-allinone-2.29-old/ns-2.29/clustering/utility/tmp/DcaUtility.h ns-allinone-2.29/ns-2.29/clustering/utility/tmp/DcaUtility.h --- ns-allinone-2.29-old/ns-2.29/clustering/utility/tmp/DcaUtility.h 1970-01-01 01:00:00.000000000 +0100 +++ ns-allinone-2.29/ns-2.29/clustering/utility/tmp/DcaUtility.h 2007-08-03 22:23:30.000000000 +0200 @@ -0,0 +1,46 @@ + +/** + * Copyright (c) 2006 Michele Mastrogiovanni. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#ifndef _DCA_UTILITY_H_ +#define _DCA_UTILITY_H_ + +#include "Utility.h" + +#include + +#define CLUSTER_HEAD 0 +#define NORMAL 1 +#define GATEWAY 2 + +class DcaUtility : public Utility +{ +public: + DcaUtility() : Utility() {} + + void setStatus(NodeAddress node, int status); + + virtual void dump(); + +protected: + + map statusNode; + + +}; + +#endif diff -Naur ns-allinone-2.29-old/ns-2.29/clustering/utility/tmp/Utility.cc ns-allinone-2.29/ns-2.29/clustering/utility/tmp/Utility.cc --- ns-allinone-2.29-old/ns-2.29/clustering/utility/tmp/Utility.cc 1970-01-01 01:00:00.000000000 +0100 +++ ns-allinone-2.29/ns-2.29/clustering/utility/tmp/Utility.cc 2007-08-03 22:23:30.000000000 +0200 @@ -0,0 +1,112 @@ + +/** + * Copyright (c) 2006 Michele Mastrogiovanni. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#include +#include "Utility.h" + +using namespace std; + +void +Utility::dump() { + // + // Stampa del debug di una simulazione: + // + // IDNodo + // Bytes / Messaggi trasmessi UNICAST. + // Bytes / Messaggi trasmessi BROADCAST. + // Bytes / Messaggi ricevuti UNICAST. + // Bytes / Messaggi ricevuti BROADCAST. + // Durata Livello. + // EnergiaConsumata. + // + // PacchettiPersiALivelloFisico + // BytesPersiALivelloFisico + // NumeroClusters Cluster1 ... ClusterM + // + cout << algorithm << " "; + + time = 0; + energy = 0; + + for (NodeList::iterator node = getNodes().begin(); node != getNodes().end(); node++) { + // IDNodo + cout << (*node) << " "; + + // Bytes / Messaggi trasmessi UNICAST + cout << getTransmitted(*node, true, true) << " "; + cout << getTransmitted(*node, false, true) << " "; + + // Bytes / Messaggi trasmessi BROADCAST + cout << getTransmitted(*node, true, false) << " "; + cout << getTransmitted(*node, false, false) << " "; + + // Bytes / Messaggi ricevuti UNICAST + cout << getReceived(*node, true, true) << " "; + cout << getReceived(*node, false, true) << " "; + + // Bytes / Messaggi ricevuti BROADCAST + cout << getReceived(*node, true, false) << " "; + cout << getReceived(*node, false, false) << " "; + + // Tempo di creazione del backbone + cout << getTimeConsumption(*node) << " "; + + // Energia consumata + cout << getEnergyConsumption(*node) << " "; + + time += getTimeConsumption(*node); + energy += getEnergyConsumption(*node); + + } + + // double physicPackets = (packetsTransmit / getNodes().size()); + // double physicBytes = (bytesTransmit / getNodes().size()); + + // Pacchetti / Bytes trasmessi a livello fisico (in totale) + cout << packetsTransmit << " " << bytesTransmit << " "; + // cout << physicPackets << " " << physicBytes << " "; + + // Clusters + cout << getNodes().size() << " "; + int clusters = 0; + int notClusters = 0; + for (NodeList::iterator node = getNodes().begin(); node != getNodes().end(); node++) { + cout << (*node) << " " << getClusterHead(*node) << " "; + if (getClusterHead(*node) == (*node)) + clusters++; + else + notClusters++; +// else if (getClusterHead(*node) != -1) +// notClusters++; + } + + time /= getNodes().size(); + energy /= getNodes().size(); + + cerr << algorithm << endl; + cerr << "\t- " << getNodes().size() << " nodes" << endl; + cerr << "\t- "; + if (clusters > 0) + cerr << "Cluster: " << clusters << "/" << (clusters + notClusters) << endl; + else + cerr << "Cluster: No One" << endl; + cerr << "\t- Avg. Time: " << time << endl; + cerr << "\t- Avg. Energy: " << energy << endl; + cerr << "\t- Overhead: " << bytesTransmit << endl; +} + diff -Naur ns-allinone-2.29-old/ns-2.29/clustering/utility/tmp/WuliUtility.cc ns-allinone-2.29/ns-2.29/clustering/utility/tmp/WuliUtility.cc --- ns-allinone-2.29-old/ns-2.29/clustering/utility/tmp/WuliUtility.cc 1970-01-01 01:00:00.000000000 +0100 +++ ns-allinone-2.29/ns-2.29/clustering/utility/tmp/WuliUtility.cc 2007-08-03 22:23:30.000000000 +0200 @@ -0,0 +1,75 @@ + +/** + * Copyright (c) 2006 Michele Mastrogiovanni. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#include "WuliUtility.h" + +static class WuliUtilityClass : public TclClass { +public: + WuliUtilityClass() : TclClass("Utility/WULI") {} + TclObject* create(int , const char*const* ) { + return(new WuliUtility()); + } +} class_wuli_utility; + +void +WuliUtility::setNeighbors(NodeAddress node, NodeList nn, NodeAddress CH) +{ + neighbors[node] = nn; + clusterHead[node] = CH; +} + +/* +void +WuliUtility::dump() +{ + map newNeighbors; + + for (map::iterator n = neighbors.begin(); n != neighbors.end(); n++) { + // ClusterHead + if (clusterHead[n->first] == (n->first)) { + for (NodeList::iterator nn = (n->second).begin(); nn != (n->second).end(); nn++) + if (clusterHead[*nn] == (*nn)) + newNeighbors[n->first].insert(*nn); + } + // Gateway. + else { + newNeighbors[n->first].clear(); + NodeAddress CH = -1; + for (NodeList::iterator nn = (n->second).begin(); nn != (n->second).end(); nn++) + if (clusterHead[*nn] == (*nn)) + if ((*nn) > CH) + CH = (*nn); + if (CH != -1) { + newNeighbors[n->first].insert(CH); + newNeighbors[CH].insert(n->first); + } + else { + newNeighbors[n->first] = (n->second); + } + } + } + + for (map::iterator n = newNeighbors.begin(); n != newNeighbors.end(); n++) { + cout << (n->first) << " "; + cout << (n->second).size() << " "; + for (NodeList::iterator nn = (n->second).begin(); nn != (n->second).end(); nn++) + cout << (*nn) << " "; + } + +} +*/ diff -Naur ns-allinone-2.29-old/ns-2.29/clustering/utility/tmp/WuliUtility.h ns-allinone-2.29/ns-2.29/clustering/utility/tmp/WuliUtility.h --- ns-allinone-2.29-old/ns-2.29/clustering/utility/tmp/WuliUtility.h 1970-01-01 01:00:00.000000000 +0100 +++ ns-allinone-2.29/ns-2.29/clustering/utility/tmp/WuliUtility.h 2007-08-03 22:23:30.000000000 +0200 @@ -0,0 +1,38 @@ + +/** + * Copyright (c) 2006 Michele Mastrogiovanni. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#ifndef _WULI_UTILITY_H_ +#define _WULI_UTILITY_H_ + +#include "Utility.h" + +#include + +class WuliUtility : public Utility +{ +public: + WuliUtility() : Utility(string("WULI")) {} + + //virtual void dump(); + void setNeighbors(NodeAddress node, NodeList nn, NodeAddress CH); + + map clusterHead; + map neighbors; +}; + +#endif diff -Naur ns-allinone-2.29-old/ns-2.29/clustering/wuli/wuli.cc ns-allinone-2.29/ns-2.29/clustering/wuli/wuli.cc --- ns-allinone-2.29-old/ns-2.29/clustering/wuli/wuli.cc 1970-01-01 01:00:00.000000000 +0100 +++ ns-allinone-2.29/ns-2.29/clustering/wuli/wuli.cc 2007-08-03 22:23:31.000000000 +0200 @@ -0,0 +1,1004 @@ + +/** + * Copyright (c) 2006 Michele Mastrogiovanni. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +//////////////// +// NS Headers // +//////////////// +#include "BackboneUtility.h" +#include "Separator.h" + +#include "wuli.h" +#include "random.h" +#include "gridkeeper.h" +#include +#include + +/////////////////////////////////// +// Parte di dichiarazione comune // +/////////////////////////////////// + +int hdr_wuli::offset_; + +int WULI_Agent::degree; +int WULI_Agent::stojmenovic; +int WULI_Agent::_DEBUG_; + +int WULI_Agent::limit; +double WULI_Agent::max_delay; +int WULI_Agent::max_timeout_hello; +double WULI_Agent::jitter_timeout_hello; +double WULI_Agent::timeout_hello; +int WULI_Agent::max_timeout_first_decision; +double WULI_Agent::jitter_timeout_first_decision; +double WULI_Agent::timeout_first_decision; +int WULI_Agent::max_timeout_last_decision; +double WULI_Agent::jitter_timeout_last_decision; +double WULI_Agent::timeout_last_decision; + +static class WuliClass : public TclClass { +public: + WuliClass() : TclClass("Agent/WULI") {} + TclObject* create(int argc, const char*const* argv) { + return(new WULI_Agent()); + } +} class_wuli; + + +static class WuliHeaderClass : public PacketHeaderClass { +public: + WuliHeaderClass() : PacketHeaderClass("PacketHeader/WULI", + sizeof(hdr_wuli)) { + bind_offset(&hdr_wuli::offset_); + } +} class_wulihdr; + +// +// Verifica che il timeout sia di tipo HELLO. +// +bool +WuliTimer::isHelloTimeout(Event * e) +{ + for (TimeoutMap::iterator i = hello_timeouts.begin(); i != hello_timeouts.end(); i++) { + if (i->second.timeout == e) { + i->second.num--; + if (i->second.num <= 0) { + agent->lastTimeout(WULI_STATUS_HELLO, i->first); + } + else { + Scheduler::instance().schedule(this, e, + WULI_Agent::timeout_hello + Random::uniform(WULI_Agent::jitter_timeout_hello)); + agent->timeout(WULI_STATUS_HELLO, i->first); + } + return true; + } + } + return false; +} + +// +// Verifica che il timeout sia di tipo FIRST DECISION. +// +bool +WuliTimer::isFirstDecisionTimeout(Event * e) +{ + for (TimeoutMap::iterator i = first_decision_timeouts.begin(); i != first_decision_timeouts.end(); i++) { + if (i->second.timeout == e) { + i->second.num--; + if (i->second.num <= 0) { + agent->lastTimeout(WULI_STATUS_FIRST_DECISION, i->first); + } + else { + Scheduler::instance().schedule(this, e, + WULI_Agent::timeout_first_decision + Random::uniform(WULI_Agent::jitter_timeout_first_decision)); + agent->timeout(WULI_STATUS_FIRST_DECISION, i->first); + } + return true; + } + } + return false; +} + +// +// Verifica che il timeout sia di tipo LAST DECISION. +// +bool +WuliTimer::isLastDecisionTimeout(Event * e) +{ + for (TimeoutMap::iterator i = last_decision_timeouts.begin(); i != last_decision_timeouts.end(); i++) { + if (i->second.timeout == e) { + i->second.num--; + if (i->second.num <= 0) { + agent->lastTimeout(WULI_STATUS_LAST_DECISION, i->first); + } + else { + Scheduler::instance().schedule(this, e, + WULI_Agent::timeout_last_decision + Random::uniform(WULI_Agent::jitter_timeout_last_decision)); + agent->timeout(WULI_STATUS_LAST_DECISION, i->first); + } + return true; + } + } + return false; +} + +// +// Gestisce l'arrivo di un timeout segnalandolo +// opportunamente all'Agente. +// +void +WuliTimer::handle(Event *e) +{ + if (isHelloTimeout(e)) + return; + + if (isFirstDecisionTimeout(e)) + return; + + if (isLastDecisionTimeout(e)) + return; +} + +// +// Inizializza i timeout che si possono lanciare in base ai vicini del nodo. +// +void +WuliTimer::initTimeouts(NodeList & neighbors) +{ + for (NodeList::iterator i = neighbors.begin(); i != neighbors.end(); i++) { + + // Definisce i Timeout di tipo HELLO + struct Timeout h; + h.timeout = new Event(); + h.num = WULI_Agent::max_timeout_hello; + hello_timeouts[*i] = h; + + // Definisce i Timeout di tipo FIRST DECISION + struct Timeout f; + f.timeout = new Event(); + f.num = WULI_Agent::max_timeout_first_decision; + first_decision_timeouts[*i] = f; + + // Definisce i Timeout di tipo LAST DECISION + struct Timeout s; + s.timeout = new Event(); + s.num = WULI_Agent::max_timeout_last_decision; + last_decision_timeouts[*i] = s; + + } +} + +// +// Fa partire i timeout per i nodi che non hanno ancora risposto al +// messaggio di HELLO inviando la propria lista di vicini. +// +void +WuliTimer::launchHelloTimeouts() +{ + for (TimeoutMap::iterator i = hello_timeouts.begin(); i != hello_timeouts.end(); i++) { + Scheduler::instance().schedule(this, i->second.timeout, + WULI_Agent::timeout_hello + Random::uniform(WULI_Agent::jitter_timeout_hello)); + } +} + +// +// Fa partire i timeout per i nodi che non hanno ancora inviato +// il proprio colore (iniziale). +// +void +WuliTimer::launchFirstDecisionTimeouts() +{ + for (TimeoutMap::iterator i = first_decision_timeouts.begin(); i != first_decision_timeouts.end(); i++) { + Scheduler::instance().schedule(this, i->second.timeout, + WULI_Agent::timeout_first_decision + Random::uniform(WULI_Agent::jitter_timeout_first_decision)); + } +} + +// +// Fa partire i timeout per i nodi che non hanno ancora inviato +// il proprio colore (finale). +// +void +WuliTimer::launchLastDecisionTimeouts() +{ + for (TimeoutMap::iterator i = last_decision_timeouts.begin(); i != last_decision_timeouts.end(); i++) { + Scheduler::instance().schedule(this, i->second.timeout, + WULI_Agent::timeout_last_decision + Random::uniform(WULI_Agent::jitter_timeout_last_decision)); + } +} + +// +// L'agente segnala la ricezione di un messaggio di tipo HELLO: +// il timeout viene eliminato. +// +void +WuliTimer::receivedHello(NodeAddress from) +{ + TimeoutMap::iterator i; + for (i = hello_timeouts.begin(); i != hello_timeouts.end(); i++) { + if (i->first == from) { + Scheduler::instance().cancel(i->second.timeout); + break; + } + } + if (i != hello_timeouts.end()) + hello_timeouts.erase(i); +} + +// +// L'agente segnala la ricezione di un messaggio di tipo FIRST DECISION: +// il timeout viene eliminato. +// +void +WuliTimer::receivedFirstDecision(NodeAddress from) +{ + TimeoutMap::iterator i; + for (i = first_decision_timeouts.begin(); i != first_decision_timeouts.end(); i++) { + if (i->first == from) { + Scheduler::instance().cancel(i->second.timeout); + break; + } + } + if (i != first_decision_timeouts.end()) + first_decision_timeouts.erase(i); +} + +// +// L'agente segnala la ricezione di un messaggio di tipo LAST DECISION: +// il timeout viene eliminato. +// +void +WuliTimer::receivedLastDecision(NodeAddress from) +{ + TimeoutMap::iterator i; + for (i = last_decision_timeouts.begin(); i != last_decision_timeouts.end(); i++) { + if (i->first == from) { + Scheduler::instance().cancel(i->second.timeout); + break; + } + } + if (i != last_decision_timeouts.end()) + last_decision_timeouts.erase(i); +} + +// +// Costruttore +// +WULI_Agent::WULI_Agent() : ClusteringModule(PT_WULI) +{ + timer = new WuliTimer(this); + + bind_bool("debug", &_DEBUG_); + bind_bool("degree", °ree); + bind_bool("stojmenovic", &stojmenovic); + + bind("limit", &limit); + + bind("max-delay", &max_delay); + bind("max-timeout-hello", &max_timeout_hello); + bind("jitter-timeout-hello", &jitter_timeout_hello); + bind("timeout-hello", &timeout_hello); + bind("max-timeout-first-decision", &max_timeout_first_decision); + bind("jitter-timeout-first-decision", &jitter_timeout_first_decision); + bind("timeout-first-decision", &timeout_first_decision); + bind("max-timeout-last-decision", &max_timeout_last_decision); + bind("jitter-timeout-last-decision", &jitter_timeout_last_decision); + bind("timeout-last-decision", &timeout_last_decision); + +} + +void +WULI_Agent::receive(Packet *p, Handler *h) +{ + struct hdr_wuli *wulih = HDR_WULI(p); + struct hdr_ip *iph = HDR_IP(p); + + // Mittente. + NodeAddress sender_address = iph->saddr(); //dcah->my_status.node_ID; + // Destinazione. + NodeAddress destination_address = iph->daddr(); // dcah->destination_address; + + switch (wulih->msg_type) { + case WULI_NEIGHBORS : + receive_NEIGHBORS(sender_address, *(wulih->node_list)); + break; + + case WULI_COLOR : + receive_COLOR(sender_address, wulih->status, wulih->color); + break; + + case WULI_REQUEST : + receive_REQUEST(sender_address, wulih->status); + break; + default: + break; + } + +} + +// +// Richiede un messaggio che forse e'stato perduto. +// +void +WULI_Agent::send_REQUEST(WuliStatus _status_, NodeAddress to) +{ + if (_DEBUG_) + printf("%d send REQUEST\n", myAddress); + + Packet* p = allocpkt(); + + struct hdr_wuli * wulih = HDR_WULI(p); + + wulih->msg_type = WULI_REQUEST; + wulih->status = _status_; + + sendDown(p, sizeof(WuliMessageType) + sizeof(WuliStatus), to, WULI_Agent::max_delay); +} + +// +// Messaggio usato per cumunicare la propria lista dei vicini ad un nodo vicino +// +void +WULI_Agent::send_NEIGHBORS(NodeAddress to) +{ + if (_DEBUG_) + printf("%d send NEIGHBORS\n", myAddress); + + Packet* p = allocpkt(); + + struct hdr_wuli * wulih = HDR_WULI(p); + + wulih->msg_type = WULI_NEIGHBORS; + wulih->node_list = & neighbors; + + sendDown(p, sizeof(WuliMessageType) + sizeof(nsaddr_t) * neighbors.size(), to, WULI_Agent::max_delay); +} + +// +// Messaggio usato per comunicare il colore del nodo in una certa fase dell'algoritmo. +// +void +WULI_Agent::send_COLOR(WuliStatus _status_, NodeAddress to, Color color) +{ + if (_DEBUG_) + printf("%d send COLOR\n", myAddress); + + // Attention: set status of Agent BEFORE send GATEWAY message + Packet* p = allocpkt(); + + struct hdr_wuli * wulih = HDR_WULI(p); + + wulih->msg_type = WULI_COLOR; + wulih->status = _status_; + wulih->color = color; + + sendDown(p, sizeof(WuliMessageType) + sizeof(WuliStatus) + sizeof(Color), to, WULI_Agent::max_delay); +} + +//////////////////// +// Interrogazioni // +//////////////////// + +// +// Procedura per verificare se esistono due vicini del nodo +// non collegati fra loro. +// +bool +WULI_Agent::twoNeighborsAreUnlinked() +{ + NodeList tmp; + + // Il nodo A punta ad un vicino. + for (NodeList::iterator A = neighbors.begin(); A != neighbors.end(); A++) { + NodeList & nlA = nodeNeighbors[*A]; + // Il nodo B punta all'altro vicino. + for (NodeList::iterator B = A; B != neighbors.end(); B++) + // Se i vicini sono diversi + if (A != B) { + tmp.clear(); + tmp.insert(*B); + // Se fra i vicini di A non c'e' B allora i due vicini sono scollegati. + if (!includes(nlA.begin(), nlA.end(), tmp.begin(), tmp.end())) + return true; + } + } + + // Tutti i vicini sono collegati fra loro + return false; +} + +// +// Verifica se l'insieme dei vicini passato come parametro +// costituisce un insieme connesso. +// Viene effettuata una visita in profonditˆ dei nodi scelti. +// +bool +WULI_Agent::neighborsConnected(NodeList & nodes) +{ + map mappa; + + for (NodeList::iterator n = nodes.begin(); n != nodes.end(); n++) + mappa[*n] = 0; + + vector stack; + int size = nodes.size(); + NodeAddress currentNode; + + if (nodes.size() == 0) + return true; + + if (nodes.size() == 1) + return true; + + stack.push_back(*(nodes.begin())); + + while (stack.size() > 0) { + // + // 1) elimina il primo elemento dallo stack, + currentNode = stack.back(); + stack.pop_back(); + + // 2) lo colora, + mappa[currentNode] = 1; + + // 3) introduce tutti i vicini del nodo che + // sono parte dell'insieme e che non sono + // ancora marcati. + for (NodeList::iterator it = shortNeighbors[currentNode].begin(); + it != shortNeighbors[currentNode].end(); + it++) { + + // Se il vicino non  uno dei nodi da considerare. + if (find(nodes.begin(), nodes.end(), *it) == nodes.end()) + continue; + + if (mappa[*it] == 1) + continue; + + stack.push_back(*it); + } + } + + for (NodeList::iterator n = nodes.begin(); n != nodes.end(); n++) + if (mappa[*n] == 0) + return false; + return true; +} + +// +// Controlla se il vicino passato come parametro e'adiacente +// a tutti i vicini del nodo. +// +bool +WULI_Agent::neighborsCoversMyNeighbors(NodeList & nodes) +{ + int size = neighbors.size(); + + // + // Se i nodi scelti sono tanti quanti sono i vicini + // allora i vicini sono automaticamente coperti. + // + if (nodes.size() == size) + return true; + + // + // Se il nodo  uno solo e i suoi vicini, escluso il nodo corrente + // sono quanti sono i vicini del nodo - 1 allora ritorna true. + // + if (nodes.size() == 1) + return (shortNeighbors[*(nodes.begin())].size() == (size - 1)); + + NodeList covered; + + for (NodeList::iterator it = nodes.begin(); it != nodes.end(); it++) + copy(shortNeighbors[*it].begin(), shortNeighbors[*it].end(), inserter(covered, covered.begin())); + + return (covered.size() == size); +} + +// +// Verifica se esiste un sottoinsieme di nodi di grandezza specificata +// che abbia le seguenti caratteristiche: +// 1) L'insieme dei nodi  connesso. +// 2) Tutti i nodi sono marcati. +// 3) Tutti i nodi hanno ID maggiore del nodo. +// +bool +WULI_Agent::checkRule(int max) +{ + // Determina i nodi vicini che possono determinare il coloramento. + NodeList rightNodes; + for (NodeList::iterator n = neighbors.begin(); n != neighbors.end(); n++) { + if (WULI_Agent::degree == 1) { + if ((neighbors.size() < nodeNeighbors[*n].size()) || + ((neighbors.size() == nodeNeighbors[*n].size()) && (myAddress < (*n)))) + if (firstColorNeighbors[*n] == COLOR_BLACK) + rightNodes.insert(*n); + } + else { + if ((myAddress < (*n)) && (firstColorNeighbors[*n] == COLOR_BLACK)) + rightNodes.insert(*n); + } + } + + if (_DEBUG_) { + printf("%d BLACK NEIGHBORS: ", myAddress); + for (NodeList::iterator n = rightNodes.begin(); n != rightNodes.end(); n++) + printf("%d ", *n); + printf("\n"); + } + + max = (max < rightNodes.size() ? max : rightNodes.size()); + + if (_DEBUG_) + printf("%d max = %d\n", myAddress, max); + + // + // Estrae tutti i possibili accoppiamenti di nodi + // + int I = 0; + int A = 0; + int S = 0; + bool print = true; + + NodeList::iterator E = rightNodes.begin(); + + vector V; + NodeList empty; + V.push_back(empty); + + while (E != rightNodes.end()) { + A = 0; + S = V.size(); + while (A < S) { + + NodeList nodi = V[I]; + + if ((print) && (nodi.size() > 0)) { + + if (_DEBUG_) { + printf("%d verifica: (", myAddress); + for (NodeList::iterator n = nodi.begin(); n != nodi.end(); n++) + printf("%d ", *n); + printf(")\n"); + } + + // + // Verifica se la lista dei vicini  connessa + // + if (neighborsConnected(nodi)) { + + // + // e copre ogni vicino del nodo. + // + if (neighborsCoversMyNeighbors(nodi)) { + + return true; + + } + } + } + + NodeList tmp(V[A]); + tmp.insert(*E); + + if (tmp.size() <= max) { + V.push_back(tmp); + I++; + print = true; + } + else { + print = false; + } + + A++; + } + E++; + } + + while (I < V.size()) { + + if (_DEBUG_) { + printf("%d verifica: (", myAddress); + for (NodeList::iterator n = V[I].begin(); n != V[I].end(); n++) + printf("%d ", *n); + printf(")\n"); + } + + // + // Verifica se la lista dei vicini  connessa + // + if (neighborsConnected(V[I])) { + + // + // e copre ogni vicino del nodo. + // + if (neighborsCoversMyNeighbors(V[I])) { + + return true; + + } + } + + I++; + } + + return false; +} + +// +// Funzione richiamata allo scadere di un timeout per un certo tipo di messaggio: +// Il nodo invia la richiesta del dato al vicino interessato. +// +void +WULI_Agent::timeout(WuliStatus type, NodeAddress from) +{ + send_REQUEST(type, from); +} + +// +// Funzione richiamata allo scadere dell'ultimo timeout. +// +void +WULI_Agent::lastTimeout(WuliStatus type, NodeAddress from) +{ + /* + switch(type) { + case WULI_STATUS_HELLO : + if (_DEBUG_) + printf("%d LAST TIMEOUT (HELLO) from %d (%f)\n", myAddress, from, Scheduler::instance().clock()); + break; + + case WULI_STATUS_FIRST_DECISION : + if (_DEBUG_) + printf("%d LAST TIMEOUT (FIRST_DECISION) from %d (%f)\n", myAddress, from, Scheduler::instance().clock()); + break; + + case WULI_STATUS_LAST_DECISION : + if (_DEBUG_) + printf("%d LAST TIMEOUT (LAST DECISION) from %d (%f)\n", myAddress, from, Scheduler::instance().clock()); + break; + } + */ +} + +// +// Procedura di partenza per l'algoritmo di clustering. +// +void +WULI_Agent::startModule() +{ + // Inizializza le informazioni comuni del clustering. + ClusteringModule::startModule(); + + // + // Carica le informazioni di stato dal modulo sottostante. + // + if (!lowerModule && target()) { + ClusteringModule * bottom = (ClusteringModule*)target(); + if (bottom->supportProtocol("sparsification")) + neighbors = *((NodeList*)bottom->getData("neighbors")); + } + + // Inizializza le strutture dei timeout. + timer->initTimeouts(neighbors); + + lastColorNeighbors.clear(); + + // Stato dell'agente + status = WULI_STATUS_HELLO; + + // Se il nodo  isolato allora  un clusterHead. + if (neighbors.size() == 0) { + firstColor = COLOR_WHITE; + lastColor = COLOR_WHITE; + endModule(); + return; + } + + // Invia un HELLO per richiedere la lista dei vicini. + /* + if (myAddress == 0) { + Packet* p = allocpkt(); + struct hdr_wuli * wulih = HDR_WULI(p); + wulih->msg_type = WULI_NEIGHBORS; + sendDown(p, sizeof(WuliMessageType) + sizeof(NodeAddress) * 1000000, -1, 0.1); + } + else if (myAddress == 2) { + Packet* p = allocpkt(); + struct hdr_wuli * wulih = HDR_WULI(p); + wulih->msg_type = WULI_NEIGHBORS; + sendDown(p, sizeof(WuliMessageType) + sizeof(NodeAddress) * 1000000, 1, 0.0); + } + + return; + */ + + send_NEIGHBORS(-1); + + // Inizializza i timeout per i messaggi NEIGHBORS. + timer->launchHelloTimeouts(); +} + +// +// Procedura richiamata alla fine dell'algoritmo di clustering. +// +void +WULI_Agent::endModule() +{ + // L'algoritmo termina: il nodo puo'memorizzare il proprio clusterHead. + status = WULI_STATUS_END; + + // Memorizza il proprio clusterHead: + // se il nodo e'nero e'se stesso, altrimenti e'il vicino NERO maggiore. + NodeAddress CH = ((lastColor == COLOR_BLACK) ? myAddress : greaterCluster()); + + setClusterHead(myAddress, CH); + + if (utility) { + NodeList backboneNeighbors; + if (myAddress == CH) { + for (NodeList::iterator n = neighbors.begin(); n != neighbors.end(); n++) + if (lastColorNeighbors[*n] == COLOR_BLACK) + backboneNeighbors.insert(*n); + } + else { + backboneNeighbors.insert(CH); + } + ((BackboneUtility*)utility)->setBackbone(myAddress, backboneNeighbors); + ((BackboneUtility*)utility)->setColor(myAddress, myAddress == CH ? "black" : "white"); + } + + // Segnala la conclusione del processo di clustering. + ClusteringModule::endModule(); + + // Start upper module + if (upTarget) + Separator::instance().endCurrentModule(myAddress); +} + +// +// Procedura di ricezione del messaggio NEIGHBORS. +// +void +WULI_Agent::receive_NEIGHBORS(NodeAddress from, NodeList & neigh) +{ + if (_DEBUG_) + printf("%d receive NEIGHBORS\n", myAddress); + + // Se il messaggio e'di una fase passata, si scarta. + if (status > WULI_STATUS_HELLO) + return; + + // Cancella il timeout sulla ricezione di questo messaggio + timer->receivedHello(from); + + // Memorizza l'informazione. + nodeNeighbors[from] = neigh; + + // + // Assegna come lista di vicini di un nodo tutti i nodi che sono + // anche vicini del nodo corrrente. + // + for (NodeList::iterator i = neigh.begin(); i != neigh.end(); i++) + if (find(neighbors.begin(), neighbors.end(), *i) != neighbors.end()) + shortNeighbors[from].insert(*i); + + // Verifica se eventualemente si puo'avanzare di stato. + processStatus(); +} + +// +// Procedura di ricezione del messaggio di colore. +// +void +WULI_Agent::receive_COLOR(NodeAddress _from_, WuliStatus _status_, Color color) +{ + if (_DEBUG_) + printf("%d receive COLOR\n", myAddress); + + // Se il messaggio e'di una fase passata, si scarta. + if (status > _status_) + return; + + // Cancella il timeout e memorizza le informazioni sul colore. + switch (_status_) { + case WULI_STATUS_FIRST_DECISION : + timer->receivedFirstDecision(_from_); + firstColorNeighbors[_from_] = color; + break; + case WULI_STATUS_LAST_DECISION : + timer->receivedLastDecision(_from_); + lastColorNeighbors[_from_] = color; + break; + } + + processStatus(); +} + +// +// Ricezione di un messaggio di richiesta. +// +void +WULI_Agent::receive_REQUEST(NodeAddress _from_, WuliStatus _status_) +{ + if (_DEBUG_) + printf("%d receive REQUEST\n", myAddress); + + // Se il dato e'disponibile, si procede a soddisfare la richiesta + switch(_status_) { + + case WULI_STATUS_HELLO : + send_NEIGHBORS(-1); + break; + + case WULI_STATUS_FIRST_DECISION : + if (status > WULI_STATUS_HELLO) + send_COLOR(WULI_STATUS_FIRST_DECISION, _from_, firstColor); + break; + + case WULI_STATUS_LAST_DECISION : + if (status > WULI_STATUS_FIRST_DECISION) + send_COLOR(WULI_STATUS_LAST_DECISION, _from_, lastColor); + break; + + } +} + +// +// Restituisce il piu'grande vicino NERO. +// +NodeAddress +WULI_Agent::greaterCluster() +{ + // Ritorna il vicino clusterHead piu'grande. + NodeAddress max = -1; + for (NodeColor::iterator i = lastColorNeighbors.begin(); i != lastColorNeighbors.end(); i++) { + if (((i->second) == COLOR_BLACK) && ((i->first) > max)) + max = (i->first); + } + return max; +} + +// +// Questa procedura si occupa della valutazione dello stato attuale del nodo +// e della decisione di avanzare di fase. +// La procedura gestisce tutta la logica dell'algoritmo. +// +void +WULI_Agent::processStatus() +{ + switch (status) { + + case WULI_STATUS_HELLO : + + // Se un nodo NON ha collezionato tutte le informazioni sui vicini + // allora non avanza di fase + if (nodeNeighbors.size() != neighbors.size()) + return; + + // Hack: se due un nodo fa parte di un insieme completo di due nodi + // diventa allora tutti i nodi sono gateway. + if (neighbors.size() == 1) { + if (nodeNeighbors[*(neighbors.begin())].size() == 1) { + firstColor = COLOR_WHITE; + lastColor = COLOR_WHITE; + endModule(); + return; + } + } + + // Il nodo avanza di fase + status = WULI_STATUS_FIRST_DECISION; + + // Il nodo decide la sua prima colorazione in base al fatto che due suoi + // vicini siano scollegati oppure no. + firstColor = (twoNeighborsAreUnlinked() ? COLOR_BLACK : COLOR_WHITE); + + // + // Un valore di limit pari a zero oppure con la variazione di stojmenovic + // significa la mancanza di applicazione della regola di decolorazione. + // Pertanto viene saltata la parte di scambio + // di informazioni relative al primo colore e si procede direttamente alla + // comunicazione della colorazione finale. + // + if ((WULI_Agent::limit != 0) && (WULI_Agent::stojmenovic != 1)) { + + // Invia l'informazione sul proprio colore ai vicini. + send_COLOR(WULI_STATUS_FIRST_DECISION, -1, firstColor); + + // Fa partire il timeout sulla ricezione del primo colore da parte dei vicini. + timer->launchFirstDecisionTimeouts(); + } + + case WULI_STATUS_FIRST_DECISION : + + if ((WULI_Agent::limit != 0) && (WULI_Agent::stojmenovic != 1)) { + + // Se un nodo NON ha collezionato tutte le informazioni sulla prima + // colorazione dei vicini allora non avanza di fase + if (firstColorNeighbors.size() != neighbors.size()) + return; + + } + + // + // Simula che tutti i vicini siano neri. + // + if (WULI_Agent::stojmenovic == 1) { + + for (NodeList::iterator n = neighbors.begin(); n != neighbors.end(); n++) + firstColorNeighbors[*n] = COLOR_BLACK; + + } + + // Il nodo avanza di fase + status = WULI_STATUS_LAST_DECISION; + + // Imposta il secondo colore. + lastColor = firstColor; + + if (WULI_Agent::limit != 0) { + + // Applica le regole di decolorazione. + if (lastColor == COLOR_BLACK) { + if (_DEBUG_) + printf("%d e' BLACK: verifica decolorazione\n", myAddress); + + if (checkRule((WULI_Agent::limit < 0) ? neighbors.size() : WULI_Agent::limit) == true) + lastColor = COLOR_WHITE; + } + + if (_DEBUG_) + printf("%d E': %s\n", myAddress, (lastColor == COLOR_BLACK) ? "BLACK" : "WHITE"); + } + + // Invia l'informazione sul proprio colore ai vicini. + send_COLOR(WULI_STATUS_LAST_DECISION, -1, lastColor); + + // Fa partire il timeout sulla ricezione del secondo colore da parte dei vicini. + timer->launchLastDecisionTimeouts(); + + case WULI_STATUS_LAST_DECISION : + + // Se un nodo NON ha collezionato tutte le informazioni sull'ultima + // colorazione dei vicini allora non avanza di fase + if (lastColorNeighbors.size() != neighbors.size()) + return; + + endModule(); + } +} + +// Verifica che un pacchetto sia di tipo DATA. +bool +WULI_Agent::isDataPacket(Packet * p) +{ + struct hdr_wuli *wulih = HDR_WULI(p); + return (wulih->msg_type == WULI_DATA); +} + +// Preparazione all'invio di un messaggio al layer inferiore +void +WULI_Agent::prepareSendDataDown(Packet * p) +{ + struct hdr_wuli *wulih = HDR_WULI(p); + + // Marca il nodo come dato. + wulih->msg_type = WULI_DATA; +} + diff -Naur ns-allinone-2.29-old/ns-2.29/clustering/wuli/wuli.h ns-allinone-2.29/ns-2.29/clustering/wuli/wuli.h --- ns-allinone-2.29-old/ns-2.29/clustering/wuli/wuli.h 1970-01-01 01:00:00.000000000 +0100 +++ ns-allinone-2.29/ns-2.29/clustering/wuli/wuli.h 2007-08-03 22:23:31.000000000 +0200 @@ -0,0 +1,237 @@ + +/** + * Copyright (c) 2006 Michele Mastrogiovanni. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#ifndef _WULI_H_ +#define _WULI_H_ + +#include + +//////////////////// +// Stato del nodo // +//////////////////// +typedef enum { + WULI_STATUS_HELLO = 0x1, // Il nodo sta ricevendo informazioni dai vicini. + WULI_STATUS_FIRST_DECISION = 0x2, // Il nodo si e' colorato la prima volta. + WULI_STATUS_LAST_DECISION = 0x3, // Il nodo si e' colorato l'ultima volta. + WULI_STATUS_END = 0x4 // Il nodo ha terminato l'algoritmo di colorazione. +} WuliStatus; + +////////////////////// +// Tipi di messaggi // +////////////////////// +typedef enum +{ + WULI_NEIGHBORS = 0x0, // Messaggio per comunicare la propria lista dei vicini. + WULI_COLOR = 0x1, // Messaggio per comunicare il colore. + WULI_REQUEST = 0x2, // Messaggio di richiesta di ritrasmissione. + WULI_DATA = 0x3 // Messaggio di dati. +} WuliMessageType; + +////////////////////////// +// Header del pacchetto // +////////////////////////// +struct hdr_wuli +{ + + WuliMessageType msg_type; // Tipo di messaggio. + WuliStatus status; // Stato del nodo all'invio del messaggio (usato per le ritrasmissioni). + NodeList * node_list; // Lista dei vicini del mittente (solo per messaggio di tipo WULI_NEIGHBORS). + Color color; // Informazioni sul colore (messaggio WULI_COLOR). + + //////////////////// + // Accessibilita' // + //////////////////// + static int offset_; + inline static int& offset() { return offset_; } + inline static hdr_wuli* access(const Packet* p) { + return (hdr_wuli*) p->access(offset_); + } +}; + +/////////// +// Timer // +/////////// +class WuliTimer; + +/////////// +// Agent // +/////////// +class WULI_Agent : public ClusteringModule +{ +public: + + WULI_Agent(); + + // Funzione di ricezione dell'algoritmo di clustering. + virtual void receive(Packet * p, Handler * h); + + // Fa partire il modulo. + virtual void startModule(); + + // Termine del lavoro del modulo. + virtual void endModule(); + + // Segnala lo scadere di un timeout per un messaggio. + void timeout(WuliStatus type, NodeAddress from); + + // Segnala il raggiungimento del massimo numero di timeout per un messaggio. + void lastTimeout(WuliStatus type, NodeAddress from); + + // Verifica che un pacchetto sia di tipo DATA. + virtual bool isDataPacket(Packet * p); + + // Preparazione all'invio di un messaggio al layer inferiore + virtual void prepareSendDataDown(Packet * p); + +protected: + + Color firstColor; // Primo colore del nodo (memorizzato per le ritrasmissioni). + Color lastColor; // Ultimo colore del nodo (memorizzato per le ritrasmissioni). + WuliStatus status; // Stato dell'agente. + NodeColor firstColorNeighbors; // Mappa del primo colore dei vicini. + NodeColor lastColorNeighbors; // Mappa dell'ultimo colore dei vicini (e il clusterHead). + NodeNeighbors nodeNeighbors; // Vicini dei vicini. + NodeNeighbors shortNeighbors; // Vicini dei vicini che sono anche vicini del nodo. Il nodo escluso. + WuliTimer * timer; // Gestore dei timeout. + +protected: + + /////////////// + // Procedure // + /////////////// + + // Gestione della fase di transisione da uno stato all'altro + void processStatus(); + + // Invia la propria lista dei vicini ad un nodo o a tutti. + void send_NEIGHBORS(NodeAddress to); + + // Invia la segnalazione di colore (BIANCO o NERO) per una fase dell'algoritmo. + void send_COLOR(WuliStatus status, NodeAddress to, Color color); + + // Invia la richiesta di un certo messaggio ad un vicino. + void send_REQUEST(WuliStatus message, NodeAddress to); + + // Ricezione della lista dei vicini di un vicino. + void receive_NEIGHBORS(NodeAddress from, NodeList & neighbors); + + // Ricezione del colore NERO di un vicino per una fase del protocollo. + void receive_COLOR(NodeAddress from, WuliStatus status, Color color); + + // Ricezione di una richiesta di ritrasmissione per un messaggio da parte di un vicino. + void receive_REQUEST(NodeAddress from, WuliStatus message); + + //////////////////// + // Interrogazioni // + //////////////////// + + // Verifica se due vicini del nodo solo NON connessi. + bool twoNeighborsAreUnlinked(); + + // Verifica se il nodo passato come parametro copre tutti i vicini del nodo (REGOLA 1). + bool neighborsCoversMyNeighbors(NodeList & nodes); + + // Verifica la REGOLA sulla base delle lunghezze specificate. + bool checkRule(int max); + + bool neighborsConnected(NodeList & nodes); + + // Crea un vettore di combinazioni. + void makeCombinations(NodeList & elements, Combinations & combinations, NodeList & lengths); + + void printDecoloredMessage(NodeList & nodi); + + // Restituisce il piu'grande vicino NERO. + NodeAddress greaterCluster(); + +public: + + static int degree; // Variante degree. + static int stojmenovic; // Variation Stojmenovic (no second communication phase). + static int _DEBUG_; + static int limit; + static double max_delay; + static int max_timeout_hello; + static double jitter_timeout_hello; + static double timeout_hello; + static int max_timeout_first_decision; + static double jitter_timeout_first_decision; + static double timeout_first_decision; + static int max_timeout_last_decision; + static double jitter_timeout_last_decision; + static double timeout_last_decision; + +}; + +///////////////////////////////// +// Timer per le ritrasmissioni // +///////////////////////////////// +class WuliTimer: public Handler { +public: + + WuliTimer(WULI_Agent * a) : Handler(), agent(a) {} + + void handle(Event* e); + + // Inizializza i timeout di un nodo + void initTimeouts(NodeList & neighbors); + + // Lancia tutti i timeout per i messaggi HELLO. + void launchHelloTimeouts(); + + // Lancia tutti i timeout per i messaggi FIRST DECISION. + void launchFirstDecisionTimeouts(); + + // Lancia tutti i timeout per i messaggi SECOND DECISION. + void launchLastDecisionTimeouts(); + + // Viene segnalata la ricezione di un messaggio di HELLO: si elimina il timeout. + void receivedHello(NodeAddress from); + + // Viene segnalata la ricezione di un messaggio di FIRST DECISION: si elimina il timeout. + void receivedFirstDecision(NodeAddress from); + + // Viene segnalata la ricezione di un messaggio di SECOND DECISION: si elimina il timeout. + void receivedLastDecision(NodeAddress from); + + // Verifica che il timeout sia per il messaggio di HELLO. + bool isHelloTimeout(Event * e); + + // Verifica che il timeout sia per il messaggio di FIRST DECISION. + bool isFirstDecisionTimeout(Event * e); + + // Verifica che il timeout sia per il messaggio di LAST DECISION. + bool isLastDecisionTimeout(Event * e); + +protected: + + // Timeout attivi per i messaggi HELLO. + TimeoutMap hello_timeouts; + + // Timeout attivi per i messaggi FIRST DECISION. + TimeoutMap first_decision_timeouts; + + // Timeout attivi per i messaggi LAST DECISION. + TimeoutMap last_decision_timeouts; + + // Agente proprietario del Timer. + WULI_Agent * agent; + +}; + +#endif \ No newline at end of file diff -Naur ns-allinone-2.29-old/ns-2.29/common/packet.h ns-allinone-2.29/ns-2.29/common/packet.h --- ns-allinone-2.29-old/ns-2.29/common/packet.h 2005-10-20 06:45:22.000000000 +0200 +++ ns-allinone-2.29/ns-2.29/common/packet.h 2007-08-03 22:23:40.000000000 +0200 @@ -70,6 +70,18 @@ //#define HDR_DIFF(p) (hdr_diff::access(p)) /* SCADD's diffusion ported into ns */ #define HDR_LMS(p) (hdr_lms::access(p)) +#define HDR_DCA(p) (hdr_dca::access(p)) /* DCA Distributed Clustering Algorithm */ +#define HDR_WULI(p) (hdr_wuli::access(p)) /* WULI Distributed Clustering Algorithm */ +#define HDR_MPR(p) (hdr_mpr::access(p)) +#define HDR_WULI_SPARSIFIER(p) (hdr_wuli_sparsifier::access(p)) /* WULI SPARSIFIER Distributed Sparsifier Algorithm */ +#define HDR_ALZOUBI(p) (hdr_alzoubi::access(p)) /* ALZOUBI Distributed Clustering Algorithm */ +#define HDR_LEADER(p) (hdr_leader::access(p)) +#define HDR_SHIVA(p) (hdr_shiva::access(p)) /* SHIVA Distributed Clustering Algorithm */ +#define HDR_CSPARSIFIER(p) (hdr_c_sparsifier::access(p)) /* SPARSIFICATOR Algorithm */ +#define HDR_RAJARAMAN(p) (hdr_rajaraman::access(p)) /* RAJARAMAN Algorithm */ +#define HDR_CONNECTOR(p) (hdr_connector::access(p)) /* CONNECTOR Algorithm */ +#define HDR_ALGORITHM(p) (hdr_algorithm::access(p)) /* ALGORITHM Algortirhm */ + /* --------------------------------------------------------------------*/ enum packet_t { @@ -167,6 +179,18 @@ // HDLC packet PT_HDLC, + PT_DCA, + PT_WULI, + PT_MPR, + PT_WULI_SPARSIFIER, + PT_ALZOUBI, + PT_LEADER, + PT_SHIVA, + PT_CSPARSIFIER, + PT_RAJARAMAN, + PT_ALGORITHM, + PT_CONNECTOR, + // insert new packet types here PT_NTYPE // This MUST be the LAST one }; @@ -262,6 +286,18 @@ // XCP name_[PT_XCP]="xcp"; + + name_[PT_DCA]="DCA"; + name_[PT_WULI]="WULI"; + name_[PT_MPR]="MPR"; + name_[PT_WULI_SPARSIFIER]="WULI_SPARSIFIER"; + name_[PT_ALZOUBI]="ALZOUBI"; + name_[PT_LEADER]="LEADER"; + name_[PT_SHIVA]="SHIVA"; + name_[PT_CSPARSIFIER]="CSPARSIFIER"; + name_[PT_RAJARAMAN]="RAJARAMAN"; + name_[PT_ALGORITHM]="ALGORITHM"; + name_[PT_CONNECTOR]="CONNECTOR"; name_[PT_NTYPE]= "undefined"; } diff -Naur ns-allinone-2.29-old/ns-2.29/mac/channel.cc ns-allinone-2.29/ns-2.29/mac/channel.cc --- ns-allinone-2.29-old/ns-2.29/mac/channel.cc 2005-10-20 06:45:22.000000000 +0200 +++ ns-allinone-2.29/ns-2.29/mac/channel.cc 2007-08-03 22:25:48.000000000 +0200 @@ -325,9 +325,9 @@ /* list-based improvement */ if(highestAntennaZ_ == -1) { - fprintf(stdout, "channel.cc:sendUp - Calc highestAntennaZ_ and distCST_\n"); + // fprintf(stdout, "channel.cc:sendUp - Calc highestAntennaZ_ and distCST_\n"); calcHighestAntennaZ(tifp); - fprintf(stdout, "highestAntennaZ_ = %0.1f, distCST_ = %0.1f\n", highestAntennaZ_, distCST_); + // fprintf(stdout, "highestAntennaZ_ = %0.1f, distCST_ = %0.1f\n", highestAntennaZ_, distCST_); } hdr->direction() = hdr_cmn::UP; diff -Naur ns-allinone-2.29-old/ns-2.29/mac/mac-802_11.cc ns-allinone-2.29/ns-2.29/mac/mac-802_11.cc --- ns-allinone-2.29-old/ns-2.29/mac/mac-802_11.cc 2005-10-20 06:45:22.000000000 +0200 +++ ns-allinone-2.29/ns-2.29/mac/mac-802_11.cc 2007-08-03 22:24:14.000000000 +0200 @@ -187,7 +187,7 @@ Mac802_11::Mac802_11() : Mac(), phymib_(this), macmib_(this), mhIF_(this), mhNav_(this), mhRecv_(this), mhSend_(this), - mhDefer_(this), mhBackoff_(this) + mhDefer_(this), mhBackoff_(this), utility(0) { nav_ = 0.0; @@ -255,7 +255,10 @@ // command added to support event tracing by Sushmita et_ = (EventTrace *)TclObject::lookup(argv[2]); return (TCL_OK); - } + } else if (strcmp(argv[1], "utility") == 0) { + utility = (CommonUtility*)TclObject::lookup(argv[2]); + return TCL_OK; + } } return Mac::command(argc, argv); } @@ -795,6 +798,12 @@ exit(1); } transmit(pktTx_, timeout); + + //MM: + hdr_cmn* ch = HDR_CMN(pktTx_); + if (utility) + utility->addTransmitPacket(1, ch->size()); + return 0; } /* @@ -1590,3 +1599,4 @@ mac_log(p); } + diff -Naur ns-allinone-2.29-old/ns-2.29/mac/mac-802_11.h ns-allinone-2.29/ns-2.29/mac/mac-802_11.h --- ns-allinone-2.29-old/ns-2.29/mac/mac-802_11.h 2005-10-20 06:45:22.000000000 +0200 +++ ns-allinone-2.29/ns-2.29/mac/mac-802_11.h 2007-08-03 22:23:40.000000000 +0200 @@ -46,6 +46,7 @@ #include "mac-timers.h" #include "marshall.h" +#include "CommonUtility.h" #include class EventTrace; @@ -348,6 +349,8 @@ PHY_MIB phymib_; MAC_MIB macmib_; + CommonUtility *utility; + /* the macaddr of my AP in BSS mode; for IBSS mode * this is set to a reserved value IBSS_ID - the * MAC_BROADCAST reserved value can be used for this diff -Naur ns-allinone-2.29-old/ns-2.29/mobile/god.cc ns-allinone-2.29/ns-2.29/mobile/god.cc --- ns-allinone-2.29-old/ns-2.29/mobile/god.cc 2005-10-20 06:45:22.000000000 +0200 +++ ns-allinone-2.29/ns-2.29/mobile/god.cc 2007-08-03 22:23:40.000000000 +0200 @@ -914,7 +914,7 @@ assert(num_nodes > 0); - printf("num_nodes is set %d\n", num_nodes); + // printf("num_nodes is set %d\n", num_nodes); min_hops = new int[num_nodes * num_nodes]; mb_node = new MobileNode*[num_nodes]; diff -Naur ns-allinone-2.29-old/ns-2.29/tcl/lib/ns-packet.tcl ns-allinone-2.29/ns-2.29/tcl/lib/ns-packet.tcl --- ns-allinone-2.29-old/ns-2.29/tcl/lib/ns-packet.tcl 2005-10-20 06:45:23.000000000 +0200 +++ ns-allinone-2.29/ns-2.29/tcl/lib/ns-packet.tcl 2007-08-03 22:23:40.000000000 +0200 @@ -170,6 +170,17 @@ Encap # common/encap.cc IPinIP # IP encapsulation HDLC # High Level Data Link Control + DCA + WULI + WULI_SPARSIFIER + STOJMENOVIC + ALZOUBI + LEADER + SHIVA + CSPARSIFIER + RAJARAMAN + ALGORITHM + CONNECTOR } { add-packet-header $prot } diff -Naur ns-allinone-2.29-old/ns-2.29/trace/cmu-trace.cc ns-allinone-2.29/ns-2.29/trace/cmu-trace.cc --- ns-allinone-2.29-old/ns-2.29/trace/cmu-trace.cc 2005-10-20 06:45:25.000000000 +0200 +++ ns-allinone-2.29/ns-2.29/trace/cmu-trace.cc 2007-08-03 22:23:40.000000000 +0200 @@ -1174,6 +1174,20 @@ case PT_GAF: case PT_PING: break; + + case PT_DCA : + case PT_WULI : + case PT_MPR: + case PT_WULI_SPARSIFIER: + case PT_ALZOUBI: + case PT_LEADER: + case PT_SHIVA: + case PT_CSPARSIFIER: + case PT_RAJARAMAN: + case PT_ALGORITHM: + case PT_CONNECTOR: + break; + default: /* fprintf(stderr, "%s - invalid packet type (%s).\n",