DESERT 3.6.0
Loading...
Searching...
No Matches
uwApplication_module.cpp
Go to the documentation of this file.
1//
2// Copyright (c) 2017 Regents of the SIGNET lab, University of Padova.
3// All rights reserved.
4//
5// Redistribution and use in source and binary forms, with or without
6// modification, are permitted provided that the following conditions
7// are met:
8// 1. Redistributions of source code must retain the above copyright
9// notice, this list of conditions and the following disclaimer.
10// 2. Redistributions in binary form must reproduce the above copyright
11// notice, this list of conditions and the following disclaimer in the
12// documentation and/or other materials provided with the distribution.
13// 3. Neither the name of the University of Padova (SIGNET lab) nor the
14// names of its contributors may be used to endorse or promote products
15// derived from this software without specific prior written permission.
16//
17// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
19// TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
20// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
21// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
22// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
23// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
24// OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
25// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
26// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
27// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28//
29
40#include <rng.h>
41#include <uwip-module.h>
42#include <uwudp-module.h>
43
44#include <climits>
45#include <iostream>
46#include <string>
47
49
50static class uwApplicationModuleClass : public TclClass
51{
52public:
57 : TclClass("Module/UW/APPLICATION")
58 {
59 }
60
66 TclObject *
67 create(int, const char *const *)
68 {
69 return (new uwApplicationModule());
70 }
72
74 : socket_active(false)
75 , socket_tcp(true)
76 , sn_check()
77 , dst_addr(0)
78 , poisson_traffic(0)
79 , payloadsize(16)
80 , port_num(55550)
81 , drop_out_of_order(0)
82 , uidcnt(0)
83 , hrsn(0)
84 , txsn(1)
85 , rftt(0)
86 , pkts_lost(0)
87 , pkts_recv(0)
88 , pkts_ooseq(0)
89 , pkts_invalid(0)
90 , pkts_last_reset(0)
91 , sea_trial(0)
92 , node_id(0)
93 , servSockDescr(0)
94 , clnSockDescr(0)
95 , servPort(0)
96 , esn(0)
97 , rttsamples(0)
98 , fttsamples(0)
99 , period(10)
100 , lrtime(0)
101 , sumrtt(0)
102 , sumrtt2(0)
103 , sumftt(0)
104 , sumftt2(0)
105 , sumbytes(0)
106 , sumdt(0)
107 , servAddr()
108 , clnAddr()
109 , socket_thread()
110 , receiving(false)
111 , queuePckReadTCP()
112 , queuePckReadUDP()
113{
114 bind("period_", (double *) &period);
115 bind("Socket_Port_", (int *) &servPort);
116 bind("Payload_size_", (int *) &payloadsize);
117 bind("PoissonTraffic_", (int *) &poisson_traffic);
118 bind("drop_out_of_order_", (int *) &drop_out_of_order);
119 bind("node_ID_", (int *) &node_id);
120 bind("max_read_length", (uint *) &uwApplicationModule::MAX_READ_LEN);
121 bind("sea_trial_", (int *) &sea_trial);
122 bind("destAddr_", (int *) &dst_addr);
123 bind("destPort_", (int *) &port_num);
124
125 if (period < 0) {
126 std::cout << "UWAPPLICATION::uwApplicationModule()::Period < 0, "
127 "default to 10."
128 << endl;
129
130 period = 10;
131 }
132
133 sn_check = new bool[USHRT_MAX];
134 for (int i = 0; i < USHRT_MAX; i++) {
135 sn_check[i] = false;
136 }
137}
138
143
144int
145uwApplicationModule::command(int argc, const char *const *argv)
146{
147 Tcl &tcl = Tcl::instance();
148
149 if (argc == 2) {
150 if (strcasecmp(argv[1], "start") == 0) {
151 if (!withoutSocket()) {
152 receiving.store(true);
153
154 if (useTCP()) {
155 if (!listenTCP())
156 return TCL_ERROR;
157
158 socket_thread = std::thread(&uwApplicationModule::acceptTCP, this);
159
160 } else {
161 if (!openConnectionUDP())
162 return TCL_ERROR;
163
165 }
166 }
167
170
171 return TCL_OK;
172 } else if (strcasecmp(argv[1], "stop") == 0) {
173 stop();
174
175 return TCL_OK;
176 } else if (strcasecmp(argv[1], "getsentpkts") == 0) {
177 tcl.resultf("%d", getPktSent());
178
179 return TCL_OK;
180 } else if (strcasecmp(argv[1], "lostpkts") == 0) {
181 tcl.resultf("%f", getPktLost());
182
183 return TCL_OK;
184 } else if (strcasecmp(argv[1], "getrecvpkts") == 0) {
185 tcl.resultf("%d", getPktRecv());
186
187 return TCL_OK;
188 } else if (strcasecmp(argv[1], "outofsequencepkts") == 0) {
189 tcl.resultf("%f", getPktsOOSequence());
190
191 return TCL_OK;
192 } else if (strcasecmp(argv[1], "notknownpktrx") == 0) {
193 tcl.resultf("%f", getPktsInvalidRx());
194
195 return TCL_OK;
196 } else if (strcasecmp(argv[1], "getrecvpktsqueue") == 0) {
197 tcl.resultf("%d", getPktsPushQueue());
198
199 return TCL_OK;
200 } else if (strcasecmp(argv[1], "getrtt") == 0) {
201 tcl.resultf("%f", GetRTT());
202 return TCL_OK;
203 } else if (strcasecmp(argv[1], "getrttstd") == 0) {
204 tcl.resultf("%f", GetRTTstd());
205
206 return TCL_OK;
207 } else if (strcasecmp(argv[1], "getftt") == 0) {
208 tcl.resultf("%f", GetFTT());
209
210 return TCL_OK;
211 } else if (strcasecmp(argv[1], "getfttstd") == 0) {
212 tcl.resultf("%f", GetFTTstd());
213
214 return TCL_OK;
215 } else if (strcasecmp(argv[1], "getper") == 0) {
216 tcl.resultf("%f", GetPER());
217
218 return TCL_OK;
219 } else if (strcasecmp(argv[1], "getthr") == 0) {
220 tcl.resultf("%f", GetTHR());
221
222 return TCL_OK;
223 }
224 } else if (argc == 3) {
225 if (strcasecmp(argv[1], "SetSocketProtocol") == 0) {
226 std::string protocol = argv[2];
227
228 if (protocol == "TCP") {
229 socket_tcp = true;
230 } else if (protocol == "UDP") {
231 socket_tcp = false;
232 } else {
233 tcl.result("Invalid socket protocol.");
234 return TCL_ERROR;
235 }
236 socket_active = true;
237
238 return TCL_OK;
239 }
240 }
241
242 return Module::command(argc, argv);
243}
244
245void
247{
248 hdr_cmn *ch = hdr_cmn::access(p);
250
251 if (ch->ptype_ != PT_DATA_APPLICATION) {
252 printOnLog(Logger::LogLevel::ERROR,
253 "UWAPPLICATION",
254 "recv(Packet *)::Drop packet, wrong type");
255
258
259 return;
260 }
261
262 esn = hrsn + 1;
263
264 if (useDropOutOfOrder()) {
265 // Packet already processed: drop it
266 if (sn_check[uwApph->sn_ & 0x00ffffff]) {
267 printOnLog(Logger::LogLevel::ERROR,
268 "UWAPPLICATION",
269 "recv(Packet *)::Drop packet with sn " +
270 to_string((int) uwApph->sn_) +
271 ", already processed");
272
275
276 return;
277 }
278 }
279
280 // The data packet with this particular SN is not already processed
281 // Set true sn_check. In this way we assume that these sn are already
282 // processed by the node
283 sn_check[uwApph->sn_ & 0x00ffffff] = true;
284
285 if (useDropOutOfOrder()) {
286 // packet is out of sequence and is to be discarded
287 if (uwApph->sn_ < esn) {
288 incrPktOoseq();
289
290 printOnLog(Logger::LogLevel::ERROR,
291 "UWAPPLICATION",
292 "recv(Packet *)::Drop packet with sn " +
293 to_string((int) uwApph->sn_) + ", out of sequence");
294
296
297 return;
298 }
299 }
300
301 rftt = NOW - ch->timestamp();
302 if ((uwApph->rftt_valid_) / 10000) {
303 double rtt = rftt + uwApph->rftt();
304 updateRTT(rtt);
305 }
307
308 hrsn = uwApph->sn_;
309
310 if (useDropOutOfOrder()) {
311 // Verify if a packet is lost
312 if (uwApph->sn_ > esn) {
313 printOnLog(Logger::LogLevel::DEBUG,
314 "UWAPPLICATION",
315 "recv(Packet *)::Packet lost. Received has sn " +
316 to_string((int) uwApph->sn_) +
317 ", expected has sn " + to_string(esn));
318
319 incrPktLost(uwApph->sn_ - (esn));
320 }
321 }
322
323 double dt = NOW - lrtime;
324 updateThroughput(uwApph->payload_size(), dt);
325 incrPktRecv();
326 lrtime = NOW;
327
328 if (!withoutSocket())
329 printOnLog(Logger::LogLevel::DEBUG,
330 "UWAPPLICATION",
331 "recv(Packet *)::Payload received : " +
332 std::string(uwApph->payload_msg, uwApph->payload_size()));
333
334 printOnLog(Logger::LogLevel::DEBUG,
335 "UWAPPLICATION",
336 "recv(Packet *)::Payload size : " +
337 to_string((int) uwApph->payload_size()));
338 printOnLog(Logger::LogLevel::DEBUG,
339 "UWAPPLICATION",
340 "recv(Packet *)::Sequence number : " +
341 to_string((int) uwApph->sn()));
342
343 if (!withoutSocket() && clnSockDescr)
344 write(clnSockDescr,
345 uwApph->payload_msg,
346 (size_t) uwApph->payload_size());
347
348 Packet::free(p);
349};
350
351void
353{
354 Packet *p;
355
356 if (withoutSocket()) {
357 p = Packet::alloc();
358 } else {
359 if (useTCP()) {
360 if (queuePckReadTCP.empty()) {
362 return;
363 }
364
365 p = queuePckReadTCP.front();
366 queuePckReadTCP.pop();
367 } else {
368 if (queuePckReadUDP.empty()) {
370 return;
371 }
372
373 p = queuePckReadUDP.front();
374 queuePckReadUDP.pop();
375 }
376 }
377
378 hdr_cmn *ch = HDR_CMN(p);
379 hdr_uwudp *uwudp = HDR_UWUDP(p);
380 hdr_uwip *uwiph = HDR_UWIP(p);
382
383 ch->uid() = uidcnt++;
384 ch->ptype() = PT_DATA_APPLICATION;
385 ch->direction() = hdr_cmn::DOWN;
386 ch->timestamp() = NOW;
387
388 uwudp->dport() = port_num;
389 uwiph->daddr() = dst_addr;
390
391 if (withoutSocket()) {
392 ch->size() = payloadsize;
393 uwApph->payload_size() = payloadsize;
394
396 for (int i = 0; i < payloadsize; i++) {
397 (*uwApph).payload_msg[i] = RNG::defaultrng()->uniform(26) + 'a';
398 }
399 for (int i = payloadsize; i < MAX_LENGTH_PAYLOAD; i++) {
400 (*uwApph).payload_msg[i] = '0';
401 }
402 } else {
403 for (int i = 0; i < MAX_LENGTH_PAYLOAD; i++) {
404 (*uwApph).payload_msg[i] = RNG::defaultrng()->uniform(26) + 'a';
405 }
406 }
407 }
408 incrPktSent();
409 uwApph->sn() = txsn;
410 if (rftt >= 0) {
411 uwApph->rftt() = (int) (rftt * 10000);
412 uwApph->rftt_valid() = true;
413 } else {
414 uwApph->rftt_valid() = false;
415 }
416 uwApph->priority() = 0;
417
418 printOnLog(Logger::LogLevel::DEBUG,
419 "UWAPPLICATION",
420 "transmit()::Unique id : " + to_string(ch->uid()));
421 printOnLog(Logger::LogLevel::DEBUG,
422 "UWAPPLICATION",
423 "transmit()::Dest addr : " + to_string((int) uwiph->daddr()));
424 printOnLog(Logger::LogLevel::DEBUG,
425 "UWAPPLICATION",
426 "transmit()::Payload size : " +
427 to_string((int) uwApph->payload_size()));
428 printOnLog(Logger::LogLevel::DEBUG,
429 "UWAPPLICATION",
430 "transmit()::Sequence number : " + to_string((int) uwApph->sn()));
431 printOnLog(Logger::LogLevel::DEBUG,
432 "UWAPPLICATION",
433 "transmit()::Send down packet");
434
435 sendDown(p);
437}
438
439void
441{
442 if (!withoutSocket()) {
443 receiving.store(false);
444
445 if (clnSockDescr >= 0) {
446 shutdown(clnSockDescr, SHUT_RDWR);
447 close(servSockDescr);
448 clnSockDescr = -1;
449 }
450
451 if (servSockDescr >= 0) {
452 shutdown(servSockDescr, SHUT_RDWR);
453 close(servSockDescr);
454 servSockDescr = -1;
455 }
456
457 if (socket_thread.joinable()) {
458 socket_thread.join();
459 }
460 }
461
462 chkTimerPeriod->force_cancel();
463}
464
465double
467{
468 if (withoutSocket() && usePoissonTraffic()) {
469 double u = RNG::defaultrng()->uniform_double();
470 double lambda = 1.0 / period;
471
472 return (-log(u) / lambda);
473 }
474
475 return period;
476}
477
478double
480{
481 return (rttsamples > 0) ? sumrtt / rttsamples : 0;
482}
483
484double
486{
487 if (rttsamples > 1) {
488 double var =
489 (sumrtt2 - (sumrtt * sumrtt / rttsamples)) / (rttsamples - 1);
490 return (sqrt(var));
491 }
492
493 return 0;
494}
495
496void
498{
499 sumrtt += rtt;
500 sumrtt2 += rtt * rtt;
501 rttsamples++;
502}
503
504double
506{
507 return (fttsamples > 0) ? sumftt / fttsamples : 0;
508}
509
510double
512{
513 if (fttsamples > 1) {
514 double var =
515 (sumftt2 - (sumftt * sumftt / fttsamples)) / (fttsamples - 1);
516
517 return (var > 0) ? sqrt(var) : 0;
518 }
519
520 return 0;
521}
522
523double
525{
526 if (drop_out_of_order) {
527 if ((pkts_recv + pkts_lost) > 0)
528 return ((double) pkts_lost / (double) (pkts_recv + pkts_lost));
529 } else {
530 if (esn > 0)
531 return (1 - (double) pkts_recv / (double) esn);
532 }
533 return 0;
534}
535
536double
538{
539 return ((sumdt != 0) ? sumbytes * 8 / sumdt : 0);
540}
541
542void
544{
545 sumftt += ftt;
546 sumftt2 += ftt * ftt;
547 fttsamples++;
548}
549
550void
552{
553 sumbytes += bytes;
554 sumdt += dt;
555}
556
557void
559{
560 module->transmit();
561}
packet_t PT_DATA_APPLICATION
DATA packet type.
TclObject * create(int, const char *const *)
Creates the TCL object needed for the TCL language interpretation.
uwApplicationModuleClass()
Constructor of uwApplicationModuleClass class.
virtual void updateThroughput(int bytes, double dt)
Update the Throughput after the reception of a new packet.
virtual int getPktsInvalidRx() const
return the number of DATA packets received with error by the server
virtual bool withoutSocket()
Check if the communication take place without socket.
virtual void stop()
Close the socket connection in the case the communication take place with socket, otherwise stop the ...
int rttsamples
Number of RTT samples.
std::atomic< bool > receiving
virtual int getPktsPushQueue() const
Return the number of DATA packets sorted in the server queue.
double sumftt2
Sum of (FTT^2).
int hrsn
Highest received sequence number.
std::thread socket_thread
Object with the socket rx thread.
virtual void incrPktOoseq()
Increase the number of DATA packets received out of order by the server.
virtual double getTimeBeforeNextPkt()
Compute the DATA generation rate, that can be constant and equal to the period established by the use...
int node_id
Node id to be print in log output.
virtual int getPktLost() const
return the number of DATA packets lost by the server
double sumftt
Sum of FTT samples.
virtual int getPktRecv() const
return the number of DATA packet correctly received by the server
uint32_t esn
Expected serial number.
int pkts_recv
Counter of the packets correctly received by the server.
virtual void readFromUDP()
Method that waits for UDP packets from external application and converts it to a Packet.
int drop_out_of_order
Ordering of data packet received 1 enabled 0 not enabled.
virtual bool openConnectionUDP()
When socket communication is used, this method establish a connection between client and server.
int servSockDescr
Socket descriptor for server.
double sumrtt
Sum of RTT samples.
int rftt
Forward round trip time.
virtual void incrPktLost(int npkts)
Increase the number of DATA packets lost by the server.
bool socket_tcp
Flag set to true if packets are received from external application.
std::queue< Packet * > queuePckReadUDP
Queue that store the DATA packets recevied from the client by the server using a UDP protocol.
virtual void incrPktSent()
Increase the sequence number and so the number of packets sent by the server.
virtual ~uwApplicationModule()
Destructor of uwApplicationModule class.
virtual double GetRTT() const
Returns the average Round Trip Time.
double sumdt
Sum of the delays.
virtual int getPktSent() const
return the number of packets sent by the server
virtual double GetPER() const
Rerturn the Packet Error Rate calculated.
int fttsamples
Number of FTT samples.
virtual bool useDropOutOfOrder()
If the communication take place without sockets verify if the data packets received by the server is ...
virtual void recv(Packet *) override
Performs the reception of packets from upper and lower layers.
virtual double GetFTT() const
int servPort
Socket server port.
virtual double GetTHR() const
Return the Throughput calculated [bps].
virtual void updateFTT(double ftt)
Returns the average Forward Trip Time.
virtual void transmit()
Set all the field of the DATA packet that must be send down after the creation to the below level.
virtual int command(int argc, const char *const *argv) override
TCL command interpreter.
int uidcnt
Identifier counter that identify uniquely the DATA packet generated.
double sumbytes
Sum of bytes received.
int sea_trial
Set to 1 to enable epoch time in log output.
double sumrtt2
Sum of (RTT^2).
virtual bool usePoissonTraffic()
If the communication take place without sockets verify if the data generation period is constant or a...
virtual bool listenTCP()
Method that binds the listening TCP socket.
int pkts_lost
Counter of the packet lost during the transmission.
virtual void acceptTCP()
Method that puts in place a listening TCP socket.
int clnSockDescr
Socket descriptor for client.
uwSendTimerAppl * chkTimerPeriod
Timer that schedule the period between successive generation of DATA packets.
bool * sn_check
Flag set to true if the external application is connected via a TCP socket, false if UDP.
int payloadsize
Size of each data packet payaload generated.
virtual void incrPktInvalid()
Increse the number of DATA packets received with error by the server.
virtual double GetRTTstd() const
Return the standard deviation of the Round Trip Time calculated.
uwApplicationModule()
Constructor of uwApplicationModule class.
static uint MAX_READ_LEN
Maximum size (bytes) of a single read of the socket.
int poisson_traffic
Poisson process for generation of data packets 1 enabled 0 not enabled.
virtual int getPktsOOSequence() const
return the number of DATA packets received out of order by the server
int port_num
Destination port number.
uint8_t dst_addr
Destination IP address.
double period
Time between successive generation data packets.
virtual void printOnLog(Logger::LogLevel log_level, const std::string &module, const std::string &message) const override
Method to send the log message to the logger.
virtual bool useTCP()
Check if the socket protocol is TCP or UDP.
std::queue< Packet * > queuePckReadTCP
Atomic boolean variable that controls the socket rx looping thread.
int txsn
Transmission sequence number of DATA packet.
virtual void incrPktRecv()
Increase the number of DATA packet correctly received by the server.
virtual double GetFTTstd() const
Return the standard deviation of the Forward Trip Time calculated.
double lrtime
Time of last packet reception.
virtual void updateRTT(double rtt)
Update the RTT after the reception of a new packet.
virtual void expire(Event *e)
Content header of DATA packet.
uint8_t & priority()
Reference to the priority variable.
char payload_msg[MAX_LENGTH_PAYLOAD]
Message payload.
int & rftt()
Reference to the rftt_ variable.
uint16_t sn_
Serial number of the packet.
bool rftt_valid_
Flag used to set the validity of the fft field.
bool & rftt_valid()
Reference to the rftt_valid_ variable.
uint16_t & sn()
Reference to the sn_ variable.
hdr_uwip describes UWIP packets.
Definition uwip-module.h:67
uint8_t & daddr()
Reference to the daddr_ variable.
hdr_uwudp describes UWUDP packets.
uint8_t & dport()
Reference to the dport_ variable.
#define MAX_LENGTH_PAYLOAD
#define HDR_DATA_APPLICATION(p)
Alias defined to access the DATA HEADER.
uwApplicationModuleClass class_module_uwapplicationmodule
#define UWAPPLICATION_DROP_REASON_OUT_OF_SEQUENCE
Drop the packet.
#define UWAPPLICATION_DROP_REASON_UNKNOWN_TYPE
Drop the packet.
#define UWAPPLICATION_DROP_REASON_DUPLICATED_PACKET
Drop the packet.
Provides the UWIP packets header description. Definition of the class that define the network layer.
#define HDR_UWIP(P)
Definition uwip-module.h:57
Provides the UWUDP packets header description and the definition of the class UWUDP.
#define HDR_UWUDP(P)