2 * Copyright (C) 2012 Tobias Brunner
3 * Copyright (C) 2005-2006 Martin Willi
4 * Copyright (C) 2005 Jan Hutter
5 * Hochschule fuer Technik Rapperswil
7 * This program is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License as published by the
9 * Free Software Foundation; either version 2 of the License, or (at your
10 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
12 * This program is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
14 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
24 #include <network/socket.h>
25 #include <processing/jobs/callback_job.h>
26 #include <threading/thread.h>
27 #include <threading/condvar.h>
28 #include <threading/mutex.h>
31 typedef struct private_sender_t private_sender_t
;
34 * Private data of a sender_t object.
36 struct private_sender_t
{
38 * Public part of a sender_t object.
43 * The packets are stored in a linked list
48 * mutex to synchronize access to list
53 * condvar to signal for packets added to list
58 * condvar to signal for packets sent
63 * Delay for sending outgoing packets, to simulate larger RTT
68 * Specific message type to delay, 0 for any
73 * Delay request messages?
75 bool send_delay_request
;
78 * Delay response messages?
80 bool send_delay_response
;
83 METHOD(sender_t
, send_no_marker
, void,
84 private_sender_t
*this, packet_t
*packet
)
86 this->mutex
->lock(this->mutex
);
87 this->list
->insert_last(this->list
, packet
);
88 this->got
->signal(this->got
);
89 this->mutex
->unlock(this->mutex
);
92 METHOD(sender_t
, send_
, void,
93 private_sender_t
*this, packet_t
*packet
)
97 /* if neither source nor destination port is 500 we add a Non-ESP marker */
98 src
= packet
->get_source(packet
);
99 dst
= packet
->get_destination(packet
);
100 DBG1(DBG_NET
, "sending packet: from %#H to %#H", src
, dst
);
102 if (this->send_delay
)
106 message
= message_create_from_packet(packet
->clone(packet
));
107 if (message
->parse_header(message
) == SUCCESS
)
109 if (this->send_delay_type
== 0 ||
110 this->send_delay_type
== message
->get_exchange_type(message
))
112 if ((message
->get_request(message
) && this->send_delay_request
) ||
113 (!message
->get_request(message
) && this->send_delay_response
))
115 DBG1(DBG_NET
, "using send delay: %dms", this->send_delay
);
116 usleep(this->send_delay
* 1000);
120 message
->destroy(message
);
123 if (dst
->get_port(dst
) != IKEV2_UDP_PORT
&&
124 src
->get_port(src
) != IKEV2_UDP_PORT
)
126 chunk_t data
, marker
= chunk_from_chars(0x00, 0x00, 0x00, 0x00);
128 data
= chunk_cat("cc", marker
, packet
->get_data(packet
));
129 packet
->set_data(packet
, data
);
132 send_no_marker(this, packet
);
136 * Job callback function to send packets
138 static job_requeue_t
send_packets(private_sender_t
*this)
143 this->mutex
->lock(this->mutex
);
144 while (this->list
->get_count(this->list
) == 0)
146 /* add cleanup handler, wait for packet, remove cleanup handler */
147 thread_cleanup_push((thread_cleanup_t
)this->mutex
->unlock
, this->mutex
);
148 oldstate
= thread_cancelability(TRUE
);
150 this->got
->wait(this->got
, this->mutex
);
152 thread_cancelability(oldstate
);
153 thread_cleanup_pop(FALSE
);
155 this->list
->remove_first(this->list
, (void**)&packet
);
156 this->sent
->signal(this->sent
);
157 this->mutex
->unlock(this->mutex
);
159 charon
->socket
->send(charon
->socket
, packet
);
160 packet
->destroy(packet
);
161 return JOB_REQUEUE_DIRECT
;
164 METHOD(sender_t
, flush
, void,
165 private_sender_t
*this)
167 /* send all packets in the queue */
168 this->mutex
->lock(this->mutex
);
169 while (this->list
->get_count(this->list
))
171 this->sent
->wait(this->sent
, this->mutex
);
173 this->mutex
->unlock(this->mutex
);
176 METHOD(sender_t
, destroy
, void,
177 private_sender_t
*this)
179 this->list
->destroy_offset(this->list
, offsetof(packet_t
, destroy
));
180 this->got
->destroy(this->got
);
181 this->sent
->destroy(this->sent
);
182 this->mutex
->destroy(this->mutex
);
187 * Described in header.
189 sender_t
* sender_create()
191 private_sender_t
*this;
196 .send_no_marker
= _send_no_marker
,
200 .list
= linked_list_create(),
201 .mutex
= mutex_create(MUTEX_TYPE_DEFAULT
),
202 .got
= condvar_create(CONDVAR_TYPE_DEFAULT
),
203 .sent
= condvar_create(CONDVAR_TYPE_DEFAULT
),
204 .send_delay
= lib
->settings
->get_int(lib
->settings
,
205 "%s.send_delay", 0, charon
->name
),
206 .send_delay_type
= lib
->settings
->get_int(lib
->settings
,
207 "%s.send_delay_type", 0, charon
->name
),
208 .send_delay_request
= lib
->settings
->get_bool(lib
->settings
,
209 "%s.send_delay_request", TRUE
, charon
->name
),
210 .send_delay_response
= lib
->settings
->get_bool(lib
->settings
,
211 "%s.send_delay_response", TRUE
, charon
->name
),
214 lib
->processor
->queue_job(lib
->processor
,
215 (job_t
*)callback_job_create_with_prio((callback_job_cb_t
)send_packets
,
216 this, NULL
, (callback_job_cancel_t
)return_false
, JOB_PRIO_CRITICAL
));
218 return &this->public;