2 * Copyright (C) 2005-2006 Martin Willi
3 * Copyright (C) 2005 Jan Hutter
4 * Hochschule fuer Technik Rapperswil
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by the
8 * Free Software Foundation; either version 2 of the License, or (at your
9 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
11 * This program is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
13 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
23 #include <network/socket.h>
24 #include <processing/jobs/callback_job.h>
25 #include <threading/thread.h>
26 #include <threading/condvar.h>
27 #include <threading/mutex.h>
30 typedef struct private_sender_t private_sender_t
;
33 * Private data of a sender_t object.
35 struct private_sender_t
{
37 * Public part of a sender_t object.
47 * The packets are stored in a linked list
52 * mutex to synchronize access to list
57 * condvar to signal for packets added to list
62 * condvar to signal for packets sent
67 * Delay for sending outgoing packets, to simulate larger RTT
72 * Specific message type to delay, 0 for any
77 * Delay request messages?
79 bool send_delay_request
;
82 * Delay response messages?
84 bool send_delay_response
;
87 METHOD(sender_t
, send_
, void,
88 private_sender_t
*this, packet_t
*packet
)
92 src
= packet
->get_source(packet
);
93 dst
= packet
->get_destination(packet
);
94 DBG1(DBG_NET
, "sending packet: from %#H to %#H", src
, dst
);
100 message
= message_create_from_packet(packet
->clone(packet
));
101 if (message
->parse_header(message
) == SUCCESS
)
103 if (this->send_delay_type
== 0 ||
104 this->send_delay_type
== message
->get_exchange_type(message
))
106 if ((message
->get_request(message
) && this->send_delay_request
) ||
107 (!message
->get_request(message
) && this->send_delay_response
))
109 DBG1(DBG_NET
, "using send delay: %dms", this->send_delay
);
110 usleep(this->send_delay
* 1000);
114 message
->destroy(message
);
117 this->mutex
->lock(this->mutex
);
118 this->list
->insert_last(this->list
, packet
);
119 this->got
->signal(this->got
);
120 this->mutex
->unlock(this->mutex
);
124 * Job callback function to send packets
126 static job_requeue_t
send_packets(private_sender_t
* this)
131 this->mutex
->lock(this->mutex
);
132 while (this->list
->get_count(this->list
) == 0)
134 /* add cleanup handler, wait for packet, remove cleanup handler */
135 thread_cleanup_push((thread_cleanup_t
)this->mutex
->unlock
, this->mutex
);
136 oldstate
= thread_cancelability(TRUE
);
138 this->got
->wait(this->got
, this->mutex
);
140 thread_cancelability(oldstate
);
141 thread_cleanup_pop(FALSE
);
143 this->list
->remove_first(this->list
, (void**)&packet
);
144 this->sent
->signal(this->sent
);
145 this->mutex
->unlock(this->mutex
);
147 charon
->socket
->send(charon
->socket
, packet
);
148 packet
->destroy(packet
);
149 return JOB_REQUEUE_DIRECT
;
152 METHOD(sender_t
, destroy
, void,
153 private_sender_t
*this)
155 /* send all packets in the queue */
156 this->mutex
->lock(this->mutex
);
157 while (this->list
->get_count(this->list
))
159 this->sent
->wait(this->sent
, this->mutex
);
161 this->mutex
->unlock(this->mutex
);
162 this->job
->cancel(this->job
);
163 this->list
->destroy(this->list
);
164 this->got
->destroy(this->got
);
165 this->sent
->destroy(this->sent
);
166 this->mutex
->destroy(this->mutex
);
171 * Described in header.
173 sender_t
* sender_create()
175 private_sender_t
*this;
182 .list
= linked_list_create(),
183 .mutex
= mutex_create(MUTEX_TYPE_DEFAULT
),
184 .got
= condvar_create(CONDVAR_TYPE_DEFAULT
),
185 .sent
= condvar_create(CONDVAR_TYPE_DEFAULT
),
186 .job
= callback_job_create_with_prio((callback_job_cb_t
)send_packets
,
187 this, NULL
, NULL
, JOB_PRIO_CRITICAL
),
188 .send_delay
= lib
->settings
->get_int(lib
->settings
,
189 "charon.send_delay", 0),
190 .send_delay_type
= lib
->settings
->get_int(lib
->settings
,
191 "charon.send_delay_type", 0),
192 .send_delay_request
= lib
->settings
->get_bool(lib
->settings
,
193 "charon.send_delay_request", TRUE
),
194 .send_delay_response
= lib
->settings
->get_int(lib
->settings
,
195 "charon.send_delay_response", TRUE
),
198 lib
->processor
->queue_job(lib
->processor
, (job_t
*)this->job
);
200 return &this->public;