-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathEEBTProtocol_Mutex.cc
1087 lines (941 loc) · 42.3 KB
/
EEBTProtocol_Mutex.cc
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
/*
* SimpleBroadcastProtocol.cc
*
* Created on: 02.06.2020
* Author: krassus
*/
#include <math.h>
#include "ns3/EEBTPTag.h"
#include "SendEvent.h"
#include "SeqNoCache.h"
#include "Mutex_SendEvent.h"
#include "EEBTProtocol_Mutex.h"
#include "EEBTPQueueDiscItem.h"
#include "float.h"
#include "ns3/nstime.h"
#include "ns3/mac-low.h"
#include "ns3/log.h"
#include "ns3/integer.h"
#include "ns3/callback.h"
#include "ns3/core-module.h"
#include "ns3/wifi-mac.h"
#include "ns3/wifi-phy.h"
#include "ns3/mobility-module.h"
#include "ns3/traffic-control-helper.h"
#include "ns3/threshold-preamble-detection-model.h"
namespace ns3
{
NS_LOG_COMPONENT_DEFINE("EEBTProtocolMutex");
NS_OBJECT_ENSURE_REGISTERED(EEBTProtocolMutex);
EEBTProtocolMutex::EEBTProtocolMutex() : EEBTProtocol()
{
}
EEBTProtocolMutex::~EEBTProtocolMutex()
{
}
TypeId EEBTProtocolMutex::GetTypeId()
{
static TypeId tid = TypeId("ns3::EEBTProtocolMutex").SetParent<EEBTProtocol>().AddConstructor<EEBTProtocolMutex>();
return tid;
}
TypeId EEBTProtocolMutex::GetInstanceTypeId() const
{
return GetTypeId();
}
/*
* Install method to install this protocol on the stack of a node
*/
void EEBTProtocolMutex::Install(Ptr<WifiNetDevice> netDevice, Ptr<CycleWatchDog> cwd)
{
this->device = netDevice;
this->cycleWatchDog = cwd;
this->random = CreateObject<UniformRandomVariable>();
this->wifiPhy = this->device->GetMac()->GetWifiPhy();
this->myAddress = Mac48Address::ConvertFrom(this->device->GetAddress());
//Set the number of power levels to one to ensure the node sends with a constant power
this->wifiPhy->SetNTxPower(1);
//Set the max allowed transmission power according to the selected standard
switch (this->wifiPhy->GetStandard())
{
case WIFI_PHY_STANDARD_80211a:
case WIFI_PHY_STANDARD_80211n_5GHZ:
this->maxAllowedTxPower = 23.0;
break;
case WIFI_PHY_STANDARD_80211b:
case WIFI_PHY_STANDARD_80211g:
case WIFI_PHY_STANDARD_80211n_2_4GHZ:
default:
this->maxAllowedTxPower = 20.0;
break;
}
this->wifiPhy->SetTxPowerStart(this->maxAllowedTxPower);
this->wifiPhy->SetTxPowerEnd(this->maxAllowedTxPower);
//Register a callback for incoming packets to read the rxPower, SNR and noise levels
this->packetManager = Create<EEBTPPacketManager>();
this->packetManager->setDevice(this->device);
this->wifiPhy->TraceConnectWithoutContext("PhyRxBegin", MakeCallback(&EEBTPPacketManager::onRxStart, this->packetManager));
this->wifiPhy->TraceConnectWithoutContext("PhyRxEnd", MakeCallback(&EEBTPPacketManager::onRxEnd, this->packetManager));
this->wifiPhy->TraceConnectWithoutContext("PhyTxBegin", MakeCallback(&EEBTPPacketManager::onTxStart, this->packetManager));
this->wifiPhy->TraceConnectWithoutContext("PhyTxDrop", MakeCallback(&EEBTPPacketManager::onTxDrop, this->packetManager));
this->wifiPhy->TraceConnectWithoutContext("PhyTxEnd", MakeCallback(&EEBTPPacketManager::onTxEnd, this->packetManager));
this->wifiPhy->TraceConnectWithoutContext("MonitorSnifferRx", MakeCallback(&EEBTPPacketManager::onPacketRx, this->packetManager));
this->wifiPhy->TraceConnectWithoutContext("MonitorSnifferTx", MakeCallback(&EEBTPPacketManager::onPacketTx, this->packetManager));
this->device->GetMac()->TraceConnectWithoutContext("TxOkHeader", MakeCallback(&EEBTPPacketManager::onTxSuccessful, this->packetManager));
this->device->GetMac()->TraceConnectWithoutContext("MacTxDrop", MakeCallback(&EEBTPPacketManager::onTxDropped, this->packetManager));
this->device->GetMac()->TraceConnectWithoutContext("MacTx", MakeCallback(&EEBTPPacketManager::onTx, this->packetManager));
this->device->GetMac()->TraceConnectWithoutContext("TxErrHeader", MakeCallback(&EEBTPPacketManager::onTxFailed, this->packetManager));
this->device->GetMac()->GetWifiRemoteStationManager()->TraceConnectWithoutContext("MacTxFinalRtsFailed", MakeCallback(&EEBTPPacketManager::onTxFinalRtsFailed, this->packetManager));
this->device->GetMac()->GetWifiRemoteStationManager()->TraceConnectWithoutContext("MacTxFinalDataFailed", MakeCallback(&EEBTPPacketManager::onTxFinalDataFailed, this->packetManager));
this->ndInterval = this->device->GetMac()->GetSlot().GetMicroSeconds() * 2000;
TrafficControlHelper tch = TrafficControlHelper();
tch.Install(this->device);
this->tcl = this->device->GetNode()->GetObject<TrafficControlLayer>();
this->device->GetNode()->RegisterProtocolHandler(MakeCallback(&TrafficControlLayer::Receive, this->tcl), EEBTProtocol::PROT_NUMBER, this->device);
this->tcl->RegisterProtocolHandler(MakeCallback(&EEBTProtocolMutex::Receive, this), EEBTProtocol::PROT_NUMBER, this->device);
//this->device->GetNode()->RegisterProtocolHandler(MakeCallback(&EEBTProtocolMutex::Receive, this), EEBTProtocol::PROT_NUMBER, this->device);
}
void EEBTProtocolMutex::Receive(Ptr<NetDevice> device, Ptr<const Packet> packet, uint16_t pID, const Address &sender, const Address &receiver, NetDevice::PacketType pType)
{
EEBTPTag tag;
EEBTPHeader header;
Ptr<WifiNetDevice> dev = DynamicCast<WifiNetDevice>(device);
Mac48Address sender_addr = Mac48Address::ConvertFrom(sender);
//Mac48Address receiver_addr = Mac48Address::ConvertFrom(receiver);
//Get packet header
packet->PeekHeader(header);
//Get packet tag
tag = this->packetManager->getPacketTag(header.GetSequenceNumber());
NS_LOG_DEBUG("[Node " << dev->GetNode()->GetId() << " / " << Now() << "]: [" << this->myAddress << "] received packet from " << sender_addr << " / SeqNo: " << header.GetSequenceNumber() << " / FRAME_TYPE: " << (int)header.GetFrameType() << " / txPower: " << header.GetTxPower() << "dBm / noise: " << tag.getNoise() << "dBm");
NS_LOG_DEBUG("\thTx: " << header.GetHighestMaxTxPower() << ", shTx: " << header.GetSecondHighestMaxTxPower());
//Check for duplicated sequence number
if (this->cache.checkForDuplicate(sender_addr, header.GetSequenceNumber()))
{
NS_LOG_DEBUG("Received duplicated frame from '" << sender_addr << "' with GID " << header.GetGameId() << " and SeqNo " << header.GetSequenceNumber());
return;
}
//Get the GameState
Ptr<GameState> gs = this->getGameState(header.GetGameId());
//Update frame type seq no
if (gs->checkLastFrameType(sender_addr, header.GetFrameType(), header.GetSequenceNumber()))
gs->updateLastFrameType(sender_addr, header.GetFrameType(), header.GetSequenceNumber());
else
{
NS_LOG_DEBUG("\tReceived a frame with the same type and a higher sequence number earlier. Ignoring this packet");
return;
}
//Only for MUTEX
if (header.getNeededLockUpdate())
{
gs->setNewParentWaitingForLock(true);
gs->setNewParentWaitingLockOriginator(Create<EEBTPNode>(header.GetOriginator(), this->maxAllowedTxPower));
}
else
{
gs->setNewParentWaitingForLock(false);
gs->setNewParentWaitingLockOriginator(0);
}
//Check if node is in our neighbor list
if (!gs->isNeighbor(sender_addr))
gs->addNeighbor(sender_addr);
//Get the EEBTPNode
Ptr<EEBTPNode> node = gs->getNeighbor(sender_addr);
if (header.GetFrameType() != APPLICATION_DATA)
{
node->setParentAddress(header.GetParent());
node->setReachPower(this->calculateTxPower(tag.getSignal(), header.GetTxPower(), tag.getNoise(), tag.getMinSNR()));
node->updateRxInfo(tag.getSignal(), tag.getNoise());
node->setHighestMaxTxPower(header.GetHighestMaxTxPower());
node->setSecondHighestMaxTxPower(header.GetSecondHighestMaxTxPower());
node->setFinished(header.getGameFinishedFlag());
gs->findHighestTxPowers();
//If the node has a reachpower that is higher than our maximum allowed txPower
if (node->getReachPower() > this->maxAllowedTxPower)
{
NS_LOG_DEBUG("[Node " << this->device->GetNode()->GetId() << " / " << Now() << "]: ReachPower for node [" << node->getAddress() << "] is too high: " << node->getReachPower() << "dBm > " << this->maxAllowedTxPower << "dBm; FRAME_TYPE: " << (uint)header.GetFrameType());
//Mark node with the reach problem flag
node->hasReachPowerProblem(true);
//If this node is a child of us
if (gs->isChild(node) && header.GetFrameType() != PARENT_REVOCATION)
{
gs->updateLastFrameType(sender_addr, PARENT_REVOCATION, header.GetSequenceNumber());
//Handle as parent revocation
this->handleParentRevocation(gs, node);
//And reject the connection
EEBTProtocol::Send(gs, CHILD_REJECTION, node->getAddress(), node->getReachPower());
return;
}
}
else
{
node->hasReachPowerProblem(false);
//NS_LOG_DEBUG("ReachPower for node [" << node->getAddress() << "]: " << node->getReachPower() << "dBm | hTx: " << node->getHighestMaxTxPower() << "dBm, shTx: " << node->getSecondHighestMaxTxPower() << "dBm");
}
//If node had receiving problems
if (header.hadReceivingProblems())
{
node->hasReachPowerProblem(true);
NS_LOG_DEBUG("[Node " << this->device->GetNode()->GetId() << " / " << Now() << "]: Recipient had receive problems. New frame type is " << (uint)(header.GetFrameType() & 0b01111111));
//and node is a child of us
if (gs->isChild(node) && header.GetFrameType() != PARENT_REVOCATION)
{
//and its reachpower is too high
if (node->getReachPower() > this->maxAllowedTxPower)
{
gs->updateLastFrameType(sender_addr, PARENT_REVOCATION, header.GetSequenceNumber());
//Handle as parent revocation
this->handleParentRevocation(gs, node);
//And reject the connection
EEBTProtocol::Send(gs, CHILD_REJECTION, node->getAddress(), node->getReachPower());
return;
}
else
{
//send out updated information
gs->resetUnchangedCounter();
EEBTProtocol::Send(gs, NEIGHBOR_DISCOVERY, this->maxAllowedTxPower);
}
}
}
}
switch (header.GetFrameType())
{
case CYCLE_CHECK:
{
Ptr<EEBTPNode> originator = gs->getNeighbor(header.GetOriginator());
Ptr<EEBTPNode> newOriginator = gs->getNeighbor(header.GetNewParent());
Ptr<EEBTPNode> childLockFinishedOrg = gs->getNeighbor(header.GetOldParent());
if (originator == 0)
originator = Create<EEBTPNode>(header.GetOriginator(), this->maxAllowedTxPower);
if (newOriginator == 0)
newOriginator = Create<EEBTPNode>(header.GetNewParent(), this->maxAllowedTxPower);
if (childLockFinishedOrg == 0)
childLockFinishedOrg = Create<EEBTPNode>(header.GetOldParent(), this->maxAllowedTxPower);
this->handleCycleCheck(gs, node, originator, newOriginator, childLockFinishedOrg);
break;
}
case NEIGHBOR_DISCOVERY:
this->handleNeighborDiscovery(gs, node);
break;
case CHILD_REQUEST:
this->handleChildRequest(gs, node);
break;
case CHILD_CONFIRMATION:
this->handleChildConfirmation(gs, node);
break;
case CHILD_REJECTION:
this->handleChildRejection(gs, node);
break;
case PARENT_REVOCATION:
this->handleParentRevocation(gs, node);
break;
case END_OF_GAME:
this->handleEndOfGame(gs, node);
break;
case APPLICATION_DATA:
this->handleApplicationData(gs, node, packet->Copy());
break;
default:
NS_LOG_DEBUG("[Node " << this->device->GetNode()->GetId() << "]: Invalid frame type: " << (int)header.GetFrameType());
}
node->resetReachPowerChanged();
//Print new line to separate events
NS_LOG_DEBUG("\n");
}
//Send method for locking child nodes in subtree
void EEBTProtocolMutex::Send(Ptr<GameState> gs, Ptr<EEBTPNode> receiver, Mac48Address originator, Mac48Address newOriginator, Mac48Address childLockFinishedOrg)
{
EEBTPHeader header = EEBTPHeader();
header.SetFrameType(CYCLE_CHECK);
header.SetOriginator(originator);
header.SetNewParent(newOriginator);
header.SetOldParent(childLockFinishedOrg);
this->Send(gs, header, receiver->getAddress(), receiver->getReachPower(), false);
}
//Send method for CCSendevent to check if a packet needs retransmission or not
void EEBTProtocolMutex::Send(Ptr<GameState> gs, Ptr<EEBTPNode> receiver, Mac48Address originator, Mac48Address newOriginator, Mac48Address childLockFinishedOrg, uint16_t seqNo, double txPower, Ptr<MutexSendEvent> event)
{
if (this->packetManager->isPacketAcked(seqNo))
{
NS_LOG_DEBUG("[Node " << this->device->GetNode()->GetId() << "]: Packet with seqNo " << seqNo << " has been acked. No retransmission, time = " << Now());
this->packetManager->deleteSeqNoEntry(seqNo);
return;
}
else if (this->packetManager->isPacketLost(seqNo) || event->getNTimes() > 20)
{
if (gs->isChild(receiver) || (gs->getParent() != 0 && receiver->getAddress() == gs->getParent()->getAddress()))
{
if (event->getNTimes() > 20)
NS_LOG_DEBUG("[Node " << this->device->GetNode()->GetId() << "]: Packet with seqNo " << seqNo << " has not been acked yet. Retransmitting..., time = " << Now());
else
NS_LOG_DEBUG("[Node " << this->device->GetNode()->GetId() << "]: Packet with seqNo " << seqNo << " has been lost. Retransmitting..., time = " << Now());
EEBTPHeader header = EEBTPHeader();
header.SetFrameType(CYCLE_CHECK);
header.SetOriginator(originator);
header.SetNewParent(newOriginator);
header.SetOldParent(childLockFinishedOrg);
header.SetSequenceNumber(seqNo);
this->Send(gs, header, receiver->getAddress(), receiver->getReachPower() + 1, true);
}
else
NS_LOG_DEBUG("[Node " << this->device->GetNode()->GetId() << "]: Packet with seqNo " << seqNo << " has been lost but [" << receiver->getAddress() << "] is not a child of us anymore nor our parent, time = " << Now());
this->packetManager->deleteSeqNoEntry(seqNo);
}
else
{
Time ttw = this->device->GetMac()->GetAckTimeout() * 200;
Simulator::Schedule(ttw, event);
NS_LOG_DEBUG("[Node " << this->device->GetNode()->GetId() << "]: Rescheduled MutexSendEvent(" << seqNo << ") for " << (Now() + ttw) << ", now = " << Now());
}
}
void EEBTProtocolMutex::Send(Ptr<GameState> gs, EEBTPHeader header, Mac48Address recipient, double txPower, bool isRetransmission)
{
//If we send out a child confirmation...
if (header.GetFrameType() == CHILD_CONFIRMATION && gs->isLocked())
{
//...set the 'needed lock update' flag is we are locked
header.setNeededLockUpdate(gs->isLocked());
header.SetOriginator(gs->getLockedBy());
}
//Adjust the transmission power
header.setReceivingProblems(false);
if (txPower > this->maxAllowedTxPower)
{
txPower = this->maxAllowedTxPower;
header.setReceivingProblems(true);
}
gs->findHighestTxPowers();
//Set sequence number
if (!isRetransmission)
this->cache.injectSeqNo(&header);
if (header.GetFrameType() == NEIGHBOR_DISCOVERY) //Check the neighbor discovery event handler (SendEvent)
{
if (!this->checkNeigborDiscoverySendEvent(gs) || gs->isLocked())
return;
}
if (header.GetFrameType() == CYCLE_CHECK)
{
Time ttw = this->device->GetMac()->GetAckTimeout() * 100;
Simulator::Schedule(ttw, Create<MutexSendEvent>(gs, this, gs->getNeighbor(recipient), header.GetOriginator(), header.GetNewParent(), header.GetOldParent(), txPower, header.GetSequenceNumber()));
NS_LOG_DEBUG("[Node " << this->device->GetNode()->GetId() << "]: Scheduled MutexSendEvent(" << header.GetSequenceNumber() << ") for " << (Now() + ttw));
}
else if (header.GetFrameType() == CHILD_REQUEST || header.GetFrameType() == CHILD_CONFIRMATION || header.GetFrameType() == CHILD_REJECTION ||
header.GetFrameType() == PARENT_REVOCATION || header.GetFrameType() == END_OF_GAME)
{
Time ttw = this->device->GetMac()->GetAckTimeout() * 100;
EventId id = Simulator::Schedule(ttw, Create<SendEvent>(gs, this, (FRAME_TYPE)header.GetFrameType(), recipient, txPower, header.GetSequenceNumber()));
NS_LOG_DEBUG("[Node " << this->device->GetNode()->GetId() << "]: Scheduled SendEvent(" << (uint)header.GetFrameType() << ") for " << (Now() + ttw) << ". EventID = " << id.GetUid());
}
//Packet size must be greater than 0 to prevent this error in visualized mode:
// assert failed. cond="m_current >= m_dataStart && m_current < m_dataEnd"
Ptr<Packet> packet = Create<Packet>(1);
header.SetGameId(gs->getGameID());
header.SetTxPower(txPower);
if (gs->getParent() == 0)
header.SetParent(Mac48Address::GetBroadcast());
else
header.SetParent(gs->getParent()->getAddress());
header.SetHighestMaxTxPower(gs->getHighestTxPower());
header.SetSecondHighestMaxTxPower(gs->getSecondHighestTxPower());
header.setGameFinishedFlag((gs->hasChilds() && gs->allChildsFinished()) || gs->gameFinished());
packet->AddHeader(header);
/*Ptr<EEBTPQueueDiscItem> qdi = Create<EEBTPQueueDiscItem>(packet, recipient, EEBTProtocol::PROT_NUMBER);
this->tcl->Send(this->device, qdi);*/
EEBTPTag tag;
tag.setGameID(gs->getGameID());
tag.setFrameType(header.GetFrameType());
tag.setSequenceNumber(header.GetSequenceNumber());
tag.setTxPower(header.GetTxPower());
packet->AddPacketTag(tag);
//this->device->Send(packet, recipient, EEBTProtocol::PROT_NUMBER);
this->packetManager->sendPacket(packet, recipient);
NS_LOG_DEBUG("[Node " << this->device->GetNode()->GetId() << "]: EEBTProtocolMutex::Send(): " << this->myAddress << " => " << recipient << " / SeqNo: " << header.GetSequenceNumber() << " / FRAME_TYPE: " << (uint)header.GetFrameType() << " / txPower: " << header.GetTxPower() << "/" << this->wifiPhy->GetTxPowerStart() << "|" << this->wifiPhy->GetTxPowerEnd() << "dBm");
NS_LOG_DEBUG("\thTx: " << header.GetHighestMaxTxPower() << ", shTx: " << header.GetSecondHighestMaxTxPower() << ", rounds: " << gs->getUnchangedCounter() << "/" << ((gs->getNNeighbors() * 0.5) + 2) << ", time = " << Now());
}
/*
* Handle the cycle check (FrameType 0)
*/
void EEBTProtocolMutex::handleCycleCheck(Ptr<GameState> gs, Ptr<EEBTPNode> node, Ptr<EEBTPNode> originator, Ptr<EEBTPNode> newOriginator, Ptr<EEBTPNode> childLockFinishedOrg)
{
NS_ASSERT_MSG(originator != 0, "[Node " << this->device->GetNode()->GetId() << "]: originator is null");
//!Assertion
if (gs->isInitiator())
{
//NS_LOG_DEBUG("Ignoring mutex from " << node->getAddress() << " because I am the initiator");
NS_LOG_ERROR("[Node " << this->device->GetNode()->GetId() << "]: Received mutex from [" << node->getAddress() << "] but I am the initiator and therefore cannot be a child of someone :O");
}
else if (gs->getParent() == node)
{
//If the mutex comes from our parent, we can get locked, an updated lock or unlocked.
//If we are currently locked by ourself, we probably want to switch our parent
if (gs->isLocked() && gs->getLockedBy() == this->myAddress)
{
//If the game already finished, we note the lock request and look after it when we got rejected
if (gs->gameFinished())
{
//Node that our parent requested a mutex and carry on
gs->setParentWaitingForLock(true);
gs->setParentWaitingLockOriginator(originator);
NS_LOG_DEBUG("[Node " << this->device->GetNode()->GetId() << "]: Note lock from parent [" << gs->getParent()->getAddress() << "] but I want to change my parent");
}
else
{
if (gs->getParent() == 0)
NS_LOG_DEBUG("[Node " << this->device->GetNode()->GetId() << "]: Ignoring lock from parent [" << node->getAddress() << "] because I want to switch parents");
else
NS_LOG_ERROR("[Node " << this->device->GetNode()->GetId() << "]: The game is not finished and we have a parent [" << gs->getParent()->getAddress() << "] and are locked by ourself?!");
}
return;
}
//If the originator contains not the broadcast address, we received a new lock
if (originator->getAddress() != Mac48Address::GetBroadcast())
{
if (originator->getAddress() == this->myAddress)
{
NS_LOG_DEBUG("[Node " << this->device->GetNode()->GetId() << "]: Received mutex from our parent [" << gs->getParent()->getAddress() << "] with me as originator [" << originator->getAddress() << "]?! Ignoring lock...");
}
else
{
NS_LOG_DEBUG("[Node " << this->device->GetNode()->GetId() << "]: Received mutex from our parent [" << gs->getParent()->getAddress() << "] with new originator [" << originator->getAddress() << "]. Locking subtree...");
//Set lock holder
gs->setLockedBy(originator->getAddress());
//...lock the subtree and respond if we have no child nodes
this->lockChildNodes(gs);
this->checkNodeLocks(gs);
}
}
else if (newOriginator->getAddress() != Mac48Address::GetBroadcast())
{
if (newOriginator->getAddress() == this->myAddress)
{
NS_LOG_DEBUG("[Node " << this->device->GetNode()->GetId() << "]: Received mutex from our parent [" << gs->getParent()->getAddress() << "] with me as new originator [" << originator->getAddress() << "]?! Ignoring lock...");
}
else
{
//Update our lock
gs->setLockedBy(newOriginator->getAddress());
//Update subtree
this->lockChildNodes(gs);
this->checkNodeLocks(gs);
}
}
else
{
NS_LOG_DEBUG("[Node " << this->device->GetNode()->GetId() << "]: Received mutex from our parent [" << gs->getParent()->getAddress() << "] with no new originator. Unlocking subtree...");
//Unlock the subtree
this->unlockChildNodes(gs);
//Broadcast neighbor discovery frames again
EEBTProtocol::Send(gs, NEIGHBOR_DISCOVERY, this->maxAllowedTxPower);
}
}
else if (gs->getContactedParent() == node)
{
//If we received a mutex from the parent we want to connect to means that the child confirmation frame is late
NS_LOG_DEBUG("[Node " << this->device->GetNode()->GetId() << "]: Received mutex from parent we want to connect to [" << node->getAddress() << "]");
gs->setNewParentWaitingForLock(true);
gs->setNewParentWaitingLockOriginator(originator);
}
else if (gs->isChild(node))
{
NS_LOG_DEBUG("[Node " << this->device->GetNode()->GetId() << "]: Received mutex from one of our child nodes [" << node->getAddress() << "] with lock holder [" << childLockFinishedOrg->getAddress() << "]");
//If we get a mutex from a child of ours, check if the childLockFinishedOrg is correct
if (childLockFinishedOrg->getAddress() == gs->getLockedBy())
{
//Add node to locked child node list
gs->lock(node, true);
NS_LOG_DEBUG("[Node " << this->device->GetNode()->GetId() << "]: Waiting for:");
for (int i = 0; i < gs->getNChilds(); i++)
{
if (!gs->isLocked(gs->getChild(i)))
NS_LOG_DEBUG("\t" << gs->getChild(i)->getAddress());
}
//Check status of locks
this->checkNodeLocks(gs);
}
else
NS_LOG_DEBUG("[Node " << this->device->GetNode()->GetId() << "]: Ignoring lock with old originator because I am locked by [" << gs->getLockedBy() << "]");
}
else
{
NS_LOG_DEBUG("[Node " << this->device->GetNode()->GetId() << "]: Received mutex from unknown [" << node->getAddress() << "]");
}
}
/*
* Handle neighbor discovery (FrameType 1)
*/
void EEBTProtocolMutex::handleNeighborDiscovery(Ptr<GameState> gs, Ptr<EEBTPNode> node)
{
NS_LOG_DEBUG("[Node " << this->device->GetNode()->GetId() << "]: EEBTProtocolMutex::handleNeighborDiscovery()");
if (!gs->isLocked())
{
if (gs->isInitiator())
gs->resetUnchangedCounter();
if (node->getReachPower() <= this->maxAllowedTxPower && !gs->isChild(node))
gs->resetRejectionCounter();
EEBTProtocol::handleNeighborDiscovery(gs, node);
}
else
{
NS_LOG_DEBUG("[Node " << this->device->GetNode()->GetId() << "]: Ignoring neighbor discovery because I am locked by [" << gs->getLockedBy() << "]");
}
}
/*
* Handle child request (FrameType 2)
* Sent by child, received by parent
* if a child wants to connect to the parent node
*/
void EEBTProtocolMutex::handleChildRequest(Ptr<GameState> gs, Ptr<EEBTPNode> node)
{
if (gs->checkLastFrameType(node->getAddress(), CHILD_REQUEST, gs->getLastSeqNo(node->getAddress(), PARENT_REVOCATION)))
{
NS_LOG_DEBUG("[Node " << this->device->GetNode()->GetId() << "]: Child request from [" << node->getAddress() << "] dismissed because we received a PARENT_REVOCATION with a higher sequence number earlier.");
return;
}
//If we are not the initiator...
if (!gs->isInitiator() && !gs->isChild(node))
{
//...and currently locked...
if (gs->isLocked())
{
//...and the request comes from the lock holder, reject this request (=> Cycle detected)
if (gs->getLockedBy() == node->getAddress())
{
NS_LOG_DEBUG("[Node " << this->device->GetNode()->GetId() << "]: Reject child request from [" << node->getAddress() << "] because I am somehow connected to it");
return EEBTProtocol::Send(gs, CHILD_REJECTION, node->getAddress(), node->getReachPower());
}
else if (node == gs->getContactedParent()) //...and the node we want to connect to contacts us, reject it since this could end up in a deadlock
{
NS_LOG_DEBUG("[Node " << this->device->GetNode()->GetId() << "]: Reject child request from [" << node->getAddress() << "] because this situation is a deadlock");
return EEBTProtocol::Send(gs, CHILD_REJECTION, node->getAddress(), node->getReachPower());
}
else if (gs->getNChildsLocked() >= gs->getNChilds() && !gs->isInitiator()) //...and we already sent a child request (all nodes are locked), reject it since this could also end up in a deadlock
{
if (gs->getLockedBy() == this->myAddress)
NS_LOG_DEBUG("[Node " << this->device->GetNode()->GetId() << "]: Reject child request from [" << node->getAddress() << "] because I already sent a child request to [" << gs->getContactedParent()->getAddress() << "]");
else
NS_LOG_DEBUG("[Node " << this->device->GetNode()->GetId() << "]: Reject child request from [" << node->getAddress() << "] because I am locked by [" << gs->getLockedBy() << "]");
return EEBTProtocol::Send(gs, CHILD_REJECTION, node->getAddress(), node->getReachPower());
}
//Else we are locked but still waiting for all responses
NS_LOG_DEBUG("[Node " << this->device->GetNode()->GetId() << "]: Processing child request from [" << node->getAddress() << "]");
}
else if (gs->getParent() == 0 && gs->getContactedParent() == 0) //...and we are not connected to the source node (should not happen)
{
NS_LOG_DEBUG("[Node " << this->device->GetNode()->GetId() << "]: Reject child request from '" << node->getAddress() << "' because I am not connected to the source node");
EEBTProtocol::Send(gs, CHILD_REJECTION, node->getAddress(), node->getReachPower());
if (gs->getRejectionCounter() > (gs->getNNeighbors() * 2) && gs->getParent() == 0)
{
NS_LOG_DEBUG("[Node " << this->device->GetNode()->GetId() << "]: I am still waiting for neighbor discovery frames since I failed " << gs->getRejectionCounter() << " times in a row to connect to a parent.");
return;
}
return this->contactCheapestNeighbor(gs);
}
}
EEBTProtocol::handleChildRequest(gs, node);
}
/*
* Handle child confirmation (FrameType 3)
* Sent by parent, received by child
* if parent accepts the child request
*/
void EEBTProtocolMutex::handleChildConfirmation(Ptr<GameState> gs, Ptr<EEBTPNode> node)
{
if (gs->checkLastFrameType(node->getAddress(), CHILD_CONFIRMATION, gs->getLastSeqNo(node->getAddress(), CHILD_REJECTION)))
{
NS_LOG_DEBUG("[Node " << this->device->GetNode()->GetId() << "]: Child confirmation from [" << node->getAddress() << "] dismissed because we received a CHILD_REJECTION with a higher sequence number earlier.");
return;
}
//If we have a parent... (!Assertion)
if (gs->getParent() != 0)
{
//...and we did not contact a new one, send parent revocation to sender
if (gs->getContactedParent() != node)
{
if (gs->getParent() == node)
{
NS_LOG_DEBUG("[Node " << this->device->GetNode()->GetId() << "]: Child confirmation from [" << node->getAddress() << "] ignored because we already connected to that node");
return;
}
else
return EEBTProtocol::Send(gs, PARENT_REVOCATION, node->getAddress(), node->getReachPower());
}
else if (gs->gameFinished()) //...and the game is already finished, disconnect from old parent
{
this->disconnectOldParent(gs);
}
}
else if (node != gs->getContactedParent())
{
NS_LOG_DEBUG("[Node " << this->device->GetNode()->GetId() << "]: Child confirmation from [" << node->getAddress() << "] dismissed because we did not ask him to be our parent");
return EEBTProtocol::Send(gs, PARENT_REVOCATION, node->getAddress(), node->getReachPower());
}
//Set new parent
gs->setParent(node);
node->incrementConnCounter();
NS_LOG_DEBUG("[Node " << this->device->GetNode()->GetId() << "]: Connected to [" << node->getAddress() << "]");
NS_LOG_DEBUG("[Node " << this->device->GetNode()->GetId() << "]: rP(" << node->getAddress() << ") = " << node->getReachPower() << ", hTx(" << node->getAddress() << ") = " << node->getHighestMaxTxPower() << ", shTx(" << node->getAddress() << ") = " << node->getSecondHighestMaxTxPower());
for (uint i = 0; i < gs->getNNeighbors(); i++)
{
Ptr<EEBTPNode> neighbor = gs->getNeighbor(i);
NS_LOG_DEBUG("[Node " << this->device->GetNode()->GetId() << "]:\trP(" << neighbor->getAddress() << ") = " << neighbor->getReachPower() << ", hTx(" << neighbor->getAddress() << ") = " << neighbor->getHighestMaxTxPower() << ", shTx(" << neighbor->getAddress() << ") = " << neighbor->getSecondHighestMaxTxPower());
}
this->cycleWatchDog->checkForCycles(gs->getGameID(), this->device);
//Reset contacted parent
gs->setContactedParent(0);
if (gs->doIncrAfterConfirm())
{
NS_LOG_DEBUG("[Node " << this->device->GetNode()->GetId() << "]: Incrementing unchanged counter");
gs->incrementUnchangedCounter();
}
if (gs->getUnchangedCounter() < EEBTProtocol::MAX_UNCHANGED_ROUNDS)
{
//Check if we note a possible better parent in the past
if (!gs->isNewParentWaitingForLock())
this->contactCheapestNeighbor(gs);
}
//If we did not contact another node...
if (gs->getContactedParent() == 0)
{
node->resetConnCounter();
gs->resetRejectionCounter();
if (node->hasFinished())
this->handleEndOfGame(gs, node);
//If we finished our game earlier, send END_OF_GAME to our parent
if (gs->gameFinished())
EEBTProtocol::Send(gs, END_OF_GAME, gs->getParent()->getAddress(), gs->getParent()->getReachPower());
if (gs->isNewParentWaitingForLock())
{
NS_LOG_DEBUG("[Node " << this->device->GetNode()->GetId() << "]: New parent is waiting for his lock. Locked by [" << gs->getNewParentWaitingLockOriginator()->getAddress() << "]");
gs->setLockedBy(Mac48Address::GetBroadcast());
this->handleCycleCheck(gs, gs->getParent(), gs->getNewParentWaitingLockOriginator(), Create<EEBTPNode>(Mac48Address::GetBroadcast(), 23.0), Create<EEBTPNode>(Mac48Address::GetBroadcast(), 23.0));
gs->setNewParentWaitingForLock(false);
gs->setNewParentWaitingLockOriginator(0);
}
else
{
//...unlock child nodes and check waiting list
this->unlockChildNodes(gs);
//Reset the unchanged counter, since our topology changed
if (!gs->doIncrAfterConfirm() && gs->getUnchangedCounter() < EEBTProtocol::MAX_UNCHANGED_ROUNDS)
{
NS_LOG_DEBUG("[Node " << this->device->GetNode()->GetId() << "]: Resetting unchanged counter");
gs->resetUnchangedCounter();
}
gs->setDoIncrAfterConfirm(false);
//Inform our neighbors
EEBTProtocol::Send(gs, NEIGHBOR_DISCOVERY, this->maxAllowedTxPower);
}
}
else
{
if (!(gs->gameFinished() && gs->getParent() != 0))
{
gs->setNewParentWaitingForLock(false);
gs->setNewParentWaitingLockOriginator(0);
}
else
NS_LOG_DEBUG("[Node " << this->device->GetNode()->GetId() << "]: Not resetting waiting status for parent lock");
}
}
/*
* Handle child rejection (FrameType 4)
* Sent by parent, received by child
* if a parent rejects a child request
*/
void EEBTProtocolMutex::handleChildRejection(Ptr<GameState> gs, Ptr<EEBTPNode> node)
{
if (gs->checkLastFrameType(node->getAddress(), CHILD_REJECTION, gs->getLastSeqNo(node->getAddress(), CHILD_CONFIRMATION)))
{
NS_LOG_DEBUG("[Node " << this->device->GetNode()->GetId() << "]: Child rejection from [" << node->getAddress() << "] dismissed because we received a CHILD_CONFIRMATION with a higher sequence number earlier.");
return;
}
//Check if node is our parent
if (node != gs->getParent() && node != gs->getContactedParent())
{
NS_LOG_DEBUG("Ignoring child rejection from [" << node->getAddress() << "] since it is not our parent!");
return;
}
//If our parent sends us a CHILD_REVOCATION...
if (node == gs->getParent())
{
NS_LOG_DEBUG("[Node " << this->device->GetNode()->GetId() << "]: My parent [" << node->getAddress() << "] disconnected me");
//Check our last cycle and set the finish time
std::vector<Ptr<CycleInfo>> cycles = this->cycleWatchDog->getCycles(gs->getGameID(), this->device->GetNode()->GetId());
if (cycles.size() > 0)
{
Ptr<CycleInfo> ci = *(cycles.end() - 1);
if (ci->getEndTime().GetNanoSeconds() == 0)
ci->setEndTime(Now());
}
gs->setParent(0);
//If we are locked (not by ourself), we need to update the lock since we must connect to a new parent
if (gs->isLocked() && gs->getLockedBy() != this->myAddress)
{
//Set our lock temporarily to false
gs->lock(false);
//Reset lock list
gs->resetChildLocks();
gs->setContactedParent(0);
}
}
else
{
NS_LOG_DEBUG("[Node " << this->device->GetNode()->GetId() << "]: Failed to connect to [" << node->getAddress() << "]; noise = " << node->getNoise());
node->incrementConnCounter();
}
gs->resetNeighborDiscoveryEvent();
//Add contacted parent to blacklist (only if is was not a reach power problem)
if (!node->hasReachPowerProblem())
gs->updateBlacklist(node);
//Reset the contacted parent
gs->setContactedParent(0);
if (gs->getRejectionCounter() > (gs->getNNeighbors() * 2) && gs->getParent() == 0)
{
gs->lock(false);
gs->resetBlacklist();
gs->resetChildLocks();
this->disconnectAllChildNodes(gs);
gs->setLockedBy(Mac48Address::GetBroadcast());
NS_LOG_DEBUG("[Node " << this->device->GetNode()->GetId() << "]: Failed " << (gs->getNNeighbors() * 2) << " times to connect to any node. Waiting for new neighbor discovery frames");
return;
}
//Contact cheapest neighbor
this->contactCheapestNeighbor(gs);
if (gs->getContactedParent() == 0)
{
node->resetConnCounter();
//If we are still connected to our parent while the game is finished...
if (gs->gameFinished() && gs->getParent() != 0)
{
//And our parent is waiting for his lock, update subtree
if (gs->isParentWaitingForLock())
{
NS_LOG_DEBUG("[Node " << this->device->GetNode()->GetId() << "]: Parent is waiting for his lock");
gs->setLockedBy(Mac48Address::GetBroadcast());
this->handleCycleCheck(gs, gs->getParent(), Create<EEBTPNode>(Mac48Address::GetBroadcast(), 23.0), gs->getParentWaitingLockOriginator(), Create<EEBTPNode>(Mac48Address::GetBroadcast(), 23.0));
}
else
{
NS_LOG_DEBUG("[Node " << this->device->GetNode()->GetId() << "]: Parent is not waiting for a lock.");
this->unlockChildNodes(gs);
}
}
else
{
//If the game is already finished and we did not disconnect our old parent
if (gs->gameFinished() && gs->getParent() != 0)
{
NS_LOG_DEBUG("[Node " << this->device->GetNode()->GetId() << "]: We already finished our game and did not disconnect from our old parent.");
return;
}
else
{
//If this also fails, disconnect child nodes and try again
NS_LOG_DEBUG("[Node " << this->device->GetNode()->GetId() << "]: Unable to connect to any other node. Disconnecting children...");
this->disconnectAllChildNodes(gs);
NS_LOG_DEBUG("[Node " << this->device->GetNode()->GetId() << "]: Searching for cheapest neighbor...");
this->contactCheapestNeighbor(gs);
if (gs->getContactedParent() == 0)
{
NS_LOG_DEBUG("[Node " << this->device->GetNode()->GetId() << "]: Could not find any possible parent.");
gs->lock(false);
gs->resetChildLocks();
gs->setLockedBy(Mac48Address::GetBroadcast());
}
}
}
}
//Reset doIncrementAfterConfirm
gs->setDoIncrAfterConfirm(false);
//Reset unchanged counter
gs->resetUnchangedCounter();
gs->incrementRejectionCounter();
}
/*
* Handle parent revocation (FrameType 5)
* Sent by child, received by parent
* if child wants to disconnect from a parent
*/
void EEBTProtocolMutex::handleParentRevocation(Ptr<GameState> gs, Ptr<EEBTPNode> node)
{
//NS_LOG_DEBUG(this->device->GetNode()->GetId() << " => EEBTProtocolMutex::handleParentRevocation()");
if (gs->checkLastFrameType(node->getAddress(), PARENT_REVOCATION, gs->getLastSeqNo(node->getAddress(), CHILD_REQUEST)))
{
NS_LOG_DEBUG("[Node " << this->device->GetNode()->GetId() << "]: Parent revocation from [" << node->getAddress() << "] dismissed because we received a CHILD_REQUEST with a higher sequence number earlier.");
return;
}
//Assertion
if (gs->isChild(node->getAddress()))
{
//Remove node from lock list
gs->lock(node, false);
//Remove child from child list
gs->removeChild(node);
NS_LOG_DEBUG("[Node " << this->device->GetNode()->GetId() << "]: Child [" << node->getAddress() << "] disconnected");
NS_LOG_DEBUG("[Node " << this->device->GetNode()->GetId() << "]: My current child nodes:");
for (int i = 0; i < gs->getNChilds(); i++)
NS_LOG_DEBUG("\t\t[" << gs->getChild(i)->getAddress() << "]: rP = " << gs->getChild(i)->getReachPower());
NS_LOG_DEBUG("[Node " << this->device->GetNode()->GetId() << "]: hTx = " << gs->getHighestTxPower() << ", shTx = " << gs->getSecondHighestTxPower());
if (!gs->gameFinished())
{
gs->resetUnchangedCounter();
gs->resetNeighborDiscoveryEvent();
if ((!gs->isLocked() && gs->getParent() != 0) || gs->isInitiator())
EEBTProtocol::Send(gs, NEIGHBOR_DISCOVERY, this->maxAllowedTxPower);
}
this->checkNodeLocks(gs);
}
else
NS_LOG_DEBUG("[Node " << this->device->GetNode()->GetId() << "]: Node [" << node->getAddress() << "] is not a child of mine");
}
/*
* Helper methods
*/
/*
* This method handles the CHILD_REQUEST to new parents
*/
void EEBTProtocolMutex::contactNode(Ptr<GameState> gs, Ptr<EEBTPNode> node)
{
//If we are locked...
if (gs->isLocked())
{
//...and are locked by ourself, contact node
if (gs->getLockedBy() == this->myAddress)
{
if (node == gs->getParent())
{
if (gs->isParentWaitingForLock())
{
gs->setLockedBy(gs->getParentWaitingLockOriginator()->getAddress());
this->lockChildNodes(gs);
this->checkNodeLocks(gs);
}
else
this->unlockChildNodes(gs);
}
else
{
if (gs->gameFinished() && gs->getNChildsLocked() < gs->getNChilds())
NS_LOG_DEBUG("[Node " << this->device->GetNode()->GetId() << "]: Tried connecting to [" << node->getAddress() << "] but still waiting for locks! Game finished: " << (gs->gameFinished() ? "true" : "false"));
else
{
gs->setContactedParent(0);
EEBTProtocol::contactNode(gs, node);
}
}
}
else
{
NS_LOG_DEBUG("[Node " << this->device->GetNode()->GetId() << "]: I am locked by someone else: " << gs->getLockedBy());
return;
}
}
else
{
gs->setContactedParent(node);
gs->resetNeighborDiscoveryEvent();
if (!gs->gameFinished())
this->disconnectOldParent(gs);
NS_LOG_DEBUG("[Node " << this->device->GetNode()->GetId() << "]: Locking subtree before connecting to [" << node->getAddress() << "]");
//Lock our subtree
gs->setLockedBy(this->myAddress);
this->lockChildNodes(gs);
this->checkNodeLocks(gs);
}
}
/*
* Mutex helper
*/
bool EEBTProtocolMutex::lockChildNodes(Ptr<GameState> gs)
{
NS_LOG_DEBUG("[Node " << this->device->GetNode()->GetId() << "]: Locking child nodes:");
bool wasLockedBefore = gs->isLocked();
gs->lock(true);
gs->resetChildLocks();
gs->resetUnchangedCounter();
gs->resetNeighborDiscoveryEvent();
if (gs->hasChilds())
{
for (int i = 0; i < gs->getNChilds(); i++)
{
NS_LOG_DEBUG("\t\tSend mutex to [" << gs->getChild(i)->getAddress() << "]");
if (wasLockedBefore)
this->Send(gs, gs->getChild(i), Mac48Address::GetBroadcast(), gs->getLockedBy(), Mac48Address::GetBroadcast());
else