some C libraries need _GNU_SOURCE for rwlocks
[strongswan.git] / src / libstrongswan / fetcher / fetcher_manager.c
1 /*
2 * Copyright (C) 2008 Martin Willi
3 * Hochschule fuer Technik Rapperswil
4 *
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License as published by the
7 * Free Software Foundation; either version 2 of the License, or (at your
8 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
9 *
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
12 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
13 * for more details.
14 *
15 * $Id$
16 */
17
18 #define _GNU_SOURCE
19
20 #include "fetcher_manager.h"
21
22 #include <debug.h>
23 #include <utils/linked_list.h>
24 #include <utils/mutex.h>
25
26 typedef struct private_fetcher_manager_t private_fetcher_manager_t;
27
28 /**
29 * private data of fetcher_manager
30 */
31 struct private_fetcher_manager_t {
32
33 /**
34 * public functions
35 */
36 fetcher_manager_t public;
37
38 /**
39 * list of registered fetchers, as entry_t
40 */
41 linked_list_t *fetchers;
42
43 /**
44 * read write lock to list
45 */
46 pthread_rwlock_t lock;
47 };
48
49 typedef struct {
50 /** assocaited fetcher construction function */
51 fetcher_constructor_t create;
52 /** URL this fetcher support */
53 char *url;
54 } entry_t;
55
56 /**
57 * destroy an entry_t
58 */
59 static void entry_destroy(entry_t *entry)
60 {
61 free(entry->url);
62 free(entry);
63 }
64
65 /**
66 * Implementation of fetcher_manager_t.fetch.
67 */
68 static status_t fetch(private_fetcher_manager_t *this,
69 char *url, chunk_t *response, ...)
70 {
71 enumerator_t *enumerator;
72 status_t status = NOT_SUPPORTED;
73 entry_t *entry;
74 bool capable = FALSE;
75
76 pthread_rwlock_rdlock(&this->lock);
77 enumerator = this->fetchers->create_enumerator(this->fetchers);
78 while (enumerator->enumerate(enumerator, &entry))
79 {
80 fetcher_option_t opt;
81 fetcher_t *fetcher;
82 bool good = TRUE;
83 va_list args;
84
85 /* check URL support of fetcher */
86 if (strncasecmp(entry->url, url, strlen(entry->url)))
87 {
88 continue;
89 }
90 /* create fetcher instance and set options */
91 fetcher = entry->create();
92 if (!fetcher)
93 {
94 continue;
95 }
96 va_start(args, response);
97 while (good)
98 {
99 opt = va_arg(args, fetcher_option_t);
100 switch (opt)
101 {
102 case FETCH_REQUEST_DATA:
103 good = fetcher->set_option(fetcher, opt, va_arg(args, chunk_t));
104 continue;
105 case FETCH_REQUEST_TYPE:
106 good = fetcher->set_option(fetcher, opt, va_arg(args, char*));
107 continue;
108 case FETCH_TIMEOUT:
109 good = fetcher->set_option(fetcher, opt, va_arg(args, u_int));
110 continue;
111 case FETCH_END:
112 break;;
113 }
114 break;
115 }
116 va_end(args);
117 if (!good)
118 { /* fetcher does not support supplied options, try another */
119 fetcher->destroy(fetcher);
120 continue;
121 }
122
123 status = fetcher->fetch(fetcher, url, response);
124 fetcher->destroy(fetcher);
125 /* try another fetcher only if this one does not support that URL */
126 if (status == NOT_SUPPORTED)
127 {
128 continue;
129 }
130 capable = TRUE;
131 break;
132 }
133 enumerator->destroy(enumerator);
134 pthread_rwlock_unlock(&this->lock);
135 if (!capable)
136 {
137 DBG1("unable to fetch from %s, no capable fetcher found", url);
138 }
139 return status;
140 }
141
142 /**
143 * Implementation of fetcher_manager_t.add_fetcher.
144 */
145 static void add_fetcher(private_fetcher_manager_t *this,
146 fetcher_constructor_t create, char *url)
147 {
148 entry_t *entry = malloc_thing(entry_t);
149
150 entry->url = strdup(url);
151 entry->create = create;
152
153 pthread_rwlock_wrlock(&this->lock);
154 this->fetchers->insert_last(this->fetchers, entry);
155 pthread_rwlock_unlock(&this->lock);
156 }
157
158 /**
159 * Implementation of fetcher_manager_t.remove_fetcher.
160 */
161 static void remove_fetcher(private_fetcher_manager_t *this,
162 fetcher_constructor_t create)
163 {
164 enumerator_t *enumerator;
165 entry_t *entry;
166
167 pthread_rwlock_wrlock(&this->lock);
168 enumerator = this->fetchers->create_enumerator(this->fetchers);
169 while (enumerator->enumerate(enumerator, &entry))
170 {
171 if (entry->create == create)
172 {
173 this->fetchers->remove_at(this->fetchers, enumerator);
174 entry_destroy(entry);
175 }
176 }
177 enumerator->destroy(enumerator);
178 pthread_rwlock_unlock(&this->lock);
179 }
180
181 /**
182 * Implementation of fetcher_manager_t.destroy
183 */
184 static void destroy(private_fetcher_manager_t *this)
185 {
186 this->fetchers->destroy_function(this->fetchers, (void*)entry_destroy);
187 pthread_rwlock_destroy(&this->lock);
188 free(this);
189 }
190
191 /*
192 * see header file
193 */
194 fetcher_manager_t *fetcher_manager_create()
195 {
196 private_fetcher_manager_t *this = malloc_thing(private_fetcher_manager_t);
197
198 this->public.fetch = (status_t(*)(fetcher_manager_t*, char *url, chunk_t *response, ...))fetch;
199 this->public.add_fetcher = (void(*)(fetcher_manager_t*, fetcher_constructor_t,char*))add_fetcher;
200 this->public.remove_fetcher = (void(*)(fetcher_manager_t*, fetcher_constructor_t))remove_fetcher;
201 this->public.destroy = (void(*)(fetcher_manager_t*))destroy;
202
203 this->fetchers = linked_list_create();
204 pthread_rwlock_init(&this->lock, NULL);
205
206 return &this->public;
207 }
208