OpenSolaris defines MUTEX_DEFAULT therefore we rename the members of the enums mutex...
[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
16 #include "fetcher_manager.h"
17
18 #include <debug.h>
19 #include <utils/mutex.h>
20 #include <utils/linked_list.h>
21
22 typedef struct private_fetcher_manager_t private_fetcher_manager_t;
23
24 /**
25 * private data of fetcher_manager
26 */
27 struct private_fetcher_manager_t {
28
29 /**
30 * public functions
31 */
32 fetcher_manager_t public;
33
34 /**
35 * list of registered fetchers, as entry_t
36 */
37 linked_list_t *fetchers;
38
39 /**
40 * read write lock to list
41 */
42 rwlock_t *lock;
43 };
44
45 typedef struct {
46 /** assocaited fetcher construction function */
47 fetcher_constructor_t create;
48 /** URL this fetcher support */
49 char *url;
50 } entry_t;
51
52 /**
53 * destroy an entry_t
54 */
55 static void entry_destroy(entry_t *entry)
56 {
57 free(entry->url);
58 free(entry);
59 }
60
61 /**
62 * Implementation of fetcher_manager_t.fetch.
63 */
64 static status_t fetch(private_fetcher_manager_t *this,
65 char *url, chunk_t *response, ...)
66 {
67 enumerator_t *enumerator;
68 status_t status = NOT_SUPPORTED;
69 entry_t *entry;
70 bool capable = FALSE;
71
72 this->lock->read_lock(this->lock);
73 enumerator = this->fetchers->create_enumerator(this->fetchers);
74 while (enumerator->enumerate(enumerator, &entry))
75 {
76 fetcher_option_t opt;
77 fetcher_t *fetcher;
78 bool good = TRUE;
79 va_list args;
80
81 /* check URL support of fetcher */
82 if (strncasecmp(entry->url, url, strlen(entry->url)))
83 {
84 continue;
85 }
86 /* create fetcher instance and set options */
87 fetcher = entry->create();
88 if (!fetcher)
89 {
90 continue;
91 }
92 va_start(args, response);
93 while (good)
94 {
95 opt = va_arg(args, fetcher_option_t);
96 switch (opt)
97 {
98 case FETCH_REQUEST_DATA:
99 good = fetcher->set_option(fetcher, opt, va_arg(args, chunk_t));
100 continue;
101 case FETCH_REQUEST_TYPE:
102 case FETCH_REQUEST_HEADER:
103 good = fetcher->set_option(fetcher, opt, va_arg(args, char*));
104 continue;
105 case FETCH_HTTP_VERSION_1_0:
106 good = fetcher->set_option(fetcher, opt);
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 this->lock->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 this->lock->write_lock(this->lock);
154 this->fetchers->insert_last(this->fetchers, entry);
155 this->lock->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 this->lock->write_lock(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 this->lock->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 this->lock->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 this->lock = rwlock_create(RWLOCK_TYPE_DEFAULT);
205
206 return &this->public;
207 }
208