Creating a timer within a module
Hello, I'm trying to extend the functionality of the trust router client which is implemented in the trustrouter.c file (within the rlm_realm module) by providing basic re-keying capabilities. The intention is to create some sort of timer that calls the TIDC library periodically (e.g. every 10 minutes) and refresh the REALM structure (with the TLS keys). So far, this only happens when there is traffic associated to that REALM once they keys have expired. Now, for that periodical call, I need to create some sort of timer that calls me back when the time has expired and let me invoke the TIDC library to update the realm. Since I don't want re-inventing the wheel here, is there any recommended way of doing so? I could create a thread, but since you're using some sort of thread pool, I don't want to do anything out of control here which can lead to race conditions while writing to the realm list. Thanks, Alejandro
On May 8, 2017, at 2:06 PM, Alejandro Pérez Méndez <alex@um.es> wrote:
I'm trying to extend the functionality of the trust router client which is implemented in the trustrouter.c file (within the rlm_realm module) by providing basic re-keying capabilities.
The intention is to create some sort of timer that calls the TIDC library periodically (e.g. every 10 minutes) and refresh the REALM structure (with the TLS keys). So far, this only happens when there is traffic associated to that REALM once they keys have expired. Now, for that periodical call, I need to create some sort of timer that calls me back when the time has expired and let me invoke the TIDC library to update the realm.
Since I don't want re-inventing the wheel here, is there any recommended way of doing so? I could create a thread, but since you're using some sort of thread pool, I don't want to do anything out of control here which can lead to race conditions while writing to the realm list.
You should create a thread in the modules initialization routine. Then, call radius_event_list_corral() to get the main server event list. That thread can do updates. You will need to be sure that memory accesses are thread-safe. How to do that... is not simple. I've made some changes in realms.c, but I don't think they're finished. In the end, v3 isn't designed to have dynamic realm updates. And fixing it will be almost impossible at this stage. Alan DeKok.
You should create a thread in the modules initialization routine. Then, call radius_event_list_corral() to get the main server event list.
That thread can do updates.
Thanks. I'll look into it. I didn't want to make changes to rlm_realm, just to trustrouter.c. But if I need to create the thread there, so be it.
You will need to be sure that memory accesses are thread-safe. How to do that... is not simple. I've made some changes in realms.c, but I don't think they're finished.
In the end, v3 isn't designed to have dynamic realm updates. And fixing it will be almost impossible at this stage.
I see. My code won't do anything different to what it is currently being done in trustrouter.c... would there be any difference? I assume current code can potentially be executed from different threads. What I see is that trustrouter.c either: 1) Adds a new realm, which seems to be mutex protected by the tree itself. 2) Replaces one server pool with another one. This change does not seem to be mutex protected (https://github.com/FreeRADIUS/freeradius-server/blob/v3.0.x/src/modules/rlm_...) I will only do 2), in exactly the same way as it is being done right now, but within the event handler. Alejandro
Alan DeKok.
- List info/subscribe/unsubscribe? See http://www.freeradius.org/list/devel.html
El 08/05/17 a las 21:18, Alejandro Pérez Méndez escribió:
You should create a thread in the modules initialization routine. Then, call radius_event_list_corral() to get the main server event list.
That thread can do updates.
Thanks. I'll look into it. I didn't want to make changes to rlm_realm, just to trustrouter.c. But if I need to create the thread there, so be it.
Hi Alan, I've been trying to make this work, but I'm sure I'm doing something wrong. When you say "You should create a thread in the modules initialization routine." do you mean by using pthread_create() directly or by using any of the thread primitives FR has (although those seem to be intended only for handling REQUEST* objects). I've also tried without creating a thread, but then the event's callback seems to be called from the main server thread, precluding other tasks to be executed until the callback is finished. Even with a thread, how do I make events to be handled by that thread? Or should the event trigger the execution of a thread? Thanks, Alejandro
You should create a thread in the modules initialization routine. Then, call radius_event_list_corral() to get the main server event list.
That thread can do updates.
Thanks. I'll look into it. I didn't want to make changes to rlm_realm, just to trustrouter.c. But if I need to create the thread there, so be it.
Hi Alan,
I've been trying to make this work, but I'm sure I'm doing something wrong. When you say "You should create a thread in the modules initialization routine." do you mean by using pthread_create() directly or by using any of the thread primitives FR has (although those seem to be intended only for handling REQUEST* objects).
I've also tried without creating a thread, but then the event's callback seems to be called from the main server thread, precluding other tasks to be executed until the callback is finished. Even with a thread, how do I make events to be handled by that thread? Or should the event trigger the execution of a thread?
Ok I think I got it. Was your suggestion to use the event list for having the timer functionality, but then on the event handler start/use a custom thread for performing the lengthy operation? Thanks
Thanks, Alejandro
On May 9, 2017, at 7:10 AM, Alejandro Pérez Méndez <alex@um.es> wrote:
Ok I think I got it. Was your suggestion to use the event list for having the timer functionality, but then on the event handler start/use a custom thread for performing the lengthy operation?
If the work to be done is small, it can just use the main thread, and the main event loop. If the work to be done is large, the module should start it's own thread, and use it's own event loop. Alan DeKok.
El 09/05/17 a las 14:57, Alan DeKok escribió:
On May 9, 2017, at 7:10 AM, Alejandro Pérez Méndez <alex@um.es> wrote:
Ok I think I got it. Was your suggestion to use the event list for having the timer functionality, but then on the event handler start/use a custom thread for performing the lengthy operation? If the work to be done is small, it can just use the main thread, and the main event loop.
If the work to be done is large, the module should start it's own thread, and use it's own event loop. Thanks. My case would be the second one, so would not need to call radius_event_list_corral() as a new event loop must be created.
Alejandro
Alan DeKok.
- List info/subscribe/unsubscribe? See http://www.freeradius.org/list/devel.html
On May 9, 2017, at 7:10 AM, Alejandro Pérez Méndez <alex@um.es> wrote:
Ok I think I got it. Was your suggestion to use the event list for having the timer functionality, but then on the event handler start/use a custom thread for performing the lengthy operation? If the work to be done is small, it can just use the main thread, and the main event loop.
If the work to be done is large, the module should start it's own thread, and use it's own event loop. Thanks. My case would be the second one, so would not need to call radius_event_list_corral() as a new event loop must be created.
It seems that an event loop do not serve my purposes, as it is not thread-safe and I will be inserting from the REQUEST thread pool, whereas consuming from the rekeyer thread (the one I create for my module). I can obviously add a mutex but then REQUESTS handling might be blocked for as long as a rekey can last (which is what I wanted to avoid in the first place). Would it be ok for FR standards to use a HEAP directly and have my rekeyer thread consuming data from the HEAP and performing the specific task of rekeying? In that way I can separate extracting from the HEAP (mutex protected) than executing the rekey (does not need to be protected). I'm asking since I will eventually want this code to be merged, so I'd better know beforehand :). Alejandro
Alejandro
Alan DeKok.
- List info/subscribe/unsubscribe? See http://www.freeradius.org/list/devel.html
- List info/subscribe/unsubscribe? See http://www.freeradius.org/list/devel.html
On 10 May 2017, at 16:39, Alejandro Pérez Méndez <alex@um.es> wrote:
It seems that an event loop do not serve my purposes, as it is not thread-safe and I will be inserting from the REQUEST thread pool, whereas consuming from the rekeyer thread (the one I create for my module). I can obviously add a mutex but then REQUESTS handling might be blocked for as long as a rekey can last (which is what I wanted to avoid in the first place).
Instead of handling it on a built in timer, does it change things if you trigger it via the control socket? You could add some hooks so that radmin can trigger a rekey for a domain, then have an external process handle the timing. Regards, Adam Bishop gpg: E75B 1F92 6407 DFDF 9F1C BF10 C993 2504 6609 D460 jisc.ac.uk Jisc is a registered charity (number 1149740) and a company limited by guarantee which is registered in England under Company No. 5747339, VAT No. GB 197 0632 86. Jisc’s registered office is: One Castlepark, Tower Hill, Bristol, BS2 0JA. T 0203 697 5800. Jisc Services Limited is a wholly owned Jisc subsidiary and a company limited by guarantee which is registered in England under company number 2881024, VAT number GB 197 0632 86. The registered office is: One Castle Park, Tower Hill, Bristol BS2 0JA. T 0203 697 5800.
On 10 May 2017, at 16:39, Alejandro Pérez Méndez <alex@um.es> wrote:
It seems that an event loop do not serve my purposes, as it is not thread-safe and I will be inserting from the REQUEST thread pool, whereas consuming from the rekeyer thread (the one I create for my module). I can obviously add a mutex but then REQUESTS handling might be blocked for as long as a rekey can last (which is what I wanted to avoid in the first place). Instead of handling it on a built in timer, does it change things if you trigger it via the control socket?
You could add some hooks so that radmin can trigger a rekey for a domain, then have an external process handle the timing.
I thought that at first, and indeed was my first approach. It was based on special REQUESTS messages (using radtest) rather than control socket, but after all pretty similar approach. But it has the problem of requiring an external daemon to be up & running, instead of being built-in. I had a conversation with Stefan and he didn't like the idea of having an additional daemon (more hackish)... and I agree. Furthermore, you loose some control over the whole process (you need to somehow export which realms are dynamically created, when they expire, etc.). Of course you can execvp() radmin from trustrouter.c but that is quite ugly. Regards, Alejandro
Regards,
Adam Bishop
gpg: E75B 1F92 6407 DFDF 9F1C BF10 C993 2504 6609 D460
jisc.ac.uk
Jisc is a registered charity (number 1149740) and a company limited by guarantee which is registered in England under Company No. 5747339, VAT No. GB 197 0632 86. Jisc’s registered office is: One Castlepark, Tower Hill, Bristol, BS2 0JA. T 0203 697 5800.
Jisc Services Limited is a wholly owned Jisc subsidiary and a company limited by guarantee which is registered in England under company number 2881024, VAT number GB 197 0632 86. The registered office is: One Castle Park, Tower Hill, Bristol BS2 0JA. T 0203 697 5800.
- List info/subscribe/unsubscribe? See http://www.freeradius.org/list/devel.html
participants (3)
-
Adam Bishop -
Alan DeKok -
Alejandro Pérez Méndez