]>
Commit | Line | Data |
---|---|---|
5a61e580 VK |
1 | /* |
2 | * libZRTP SDK library, implements the ZRTP secure VoIP protocol. | |
3 | * Copyright (c) 2006-2009 Philip R. Zimmermann. All rights reserved. | |
4 | * Contact: http://philzimmermann.com | |
5 | * For licensing and other legal details, see the file zrtp_legal.c. | |
6 | * | |
7 | * Viktor Krykun <v.krikun at zfoneproject.com> | |
8 | */ | |
9 | ||
21c145b1 | 10 | #define _POSIX_C_SOURCE 199309L /* for struct timespec */ |
5a61e580 VK |
11 | #include "zrtp.h" |
12 | ||
13 | #if (defined(ZRTP_USE_BUILTIN_SCEHDULER) && (ZRTP_USE_BUILTIN_SCEHDULER ==1)) | |
14 | #if (ZRTP_PLATFORM!=ZP_SYMBIAN) | |
15 | ||
16 | #if defined (ZRTP_DEBUG_WITH_PJSIP) && (ZRTP_DEBUG_WITH_PJSIP == 1) | |
17 | # include <pjlib.h> | |
18 | #endif | |
19 | ||
20 | /* Windows kernel have it's own realization based on kernel timers */ | |
21 | #if (ZRTP_PLATFORM != ZP_WIN32_KERNEL) | |
22 | ||
23 | #define ZRTP_SCHED_QUEUE_SIZE ZRTP_MAX_STREAMS_PER_SESSION * 1000 | |
24 | #define ZRTP_SCHED_LOOP_QVANT 20 | |
25 | ||
26 | #define ZRTP_SCHED_SLEEP(count) zrtp_sleep(ZRTP_SCHED_LOOP_QVANT*count); | |
27 | ||
28 | ||
29 | /** Schedulling tasks structure */ | |
30 | typedef struct | |
31 | { | |
32 | zrtp_stream_t *ctx; /** ZRTP stream context associated with the task */ | |
33 | zrtp_retry_task_t *ztask; /** ZRTP stream associated with the task */ | |
34 | uint64_t wake_at; /* Wake time in milliseconds */ | |
35 | mlist_t _mlist; | |
36 | } zrtp_sched_task_t; | |
37 | ||
38 | /** Initiation flag. Protection from reinitialization. (1 if initiated) */ | |
39 | static uint8_t inited = 0; | |
40 | ||
41 | /** Sorted by wake time tasks list. First task to do at the begining */ | |
42 | static mlist_t tasks_head; | |
43 | ||
44 | /** Tasks queue protector againts race conditions on add/remove tasks */ | |
45 | static zrtp_mutex_t* protector = NULL; | |
46 | ||
47 | /** Main queue symaphore */ | |
48 | static zrtp_sem_t* count = NULL; | |
49 | ||
50 | static uint8_t is_running = 0; | |
51 | #if (ZRTP_PLATFORM == ZP_WIN32 || ZRTP_PLATFORM == ZP_WINCE) | |
52 | HANDLE scheduler_thread = NULL; | |
53 | #else | |
54 | static uint8_t is_working = 0; | |
55 | #endif | |
56 | ||
57 | ||
58 | /*==========================================================================*/ | |
59 | /* Platform Dependent Routine */ | |
60 | /*==========================================================================*/ | |
61 | ||
62 | #if (ZRTP_PLATFORM == ZP_WIN32) || (ZRTP_PLATFORM == ZP_WINCE) | |
63 | #include <Windows.h> | |
64 | ||
65 | int zrtp_sleep(unsigned int msec) | |
66 | { | |
67 | Sleep(msec); | |
68 | return 0; | |
69 | } | |
70 | ||
71 | int zrtp_thread_create(zrtp_thread_routine_t start_routine, void *arg) | |
72 | { | |
73 | DWORD dwThreadId; | |
74 | ||
75 | scheduler_thread = CreateThread(NULL, 0, start_routine, 0, 0, &dwThreadId); | |
76 | if (NULL == scheduler_thread) { | |
77 | return -1; | |
78 | } | |
79 | ||
80 | return 0; | |
81 | } | |
82 | ||
fc97a919 | 83 | #elif (ZRTP_PLATFORM == ZP_LINUX) || (ZRTP_PLATFORM == ZP_DARWIN) || (ZRTP_PLATFORM == ZP_BSD) || (ZRTP_PLATFORM == ZP_ANDROID) |
21c145b1 PW |
84 | /* POSIX.1-2008 removes usleep, so use nanosleep instead when available */ |
85 | #if ZRTP_HAVE_NANOSLEEP | |
86 | #include <time.h> /* for nanosleep */ | |
87 | #elif ZRTP_HAVE_UNISTD_H == 1 | |
5a61e580 VK |
88 | #include <unistd.h> |
89 | #else | |
90 | #error "Used environment dosn't have <unistd.h> - zrtp_scheduler can't be build." | |
91 | #endif | |
21c145b1 | 92 | |
5a61e580 VK |
93 | #if ZRTP_HAVE_PTHREAD_H == 1 |
94 | #include <pthread.h> | |
95 | #else | |
96 | # error "Used environment dosn't have <pthread.h> - zrtp_scheduler can't be build." | |
97 | #endif | |
98 | ||
99 | int zrtp_sleep(unsigned int msec) | |
100 | { | |
21c145b1 PW |
101 | #if ZRTP_HAVE_NANOSLEEP |
102 | struct timespec delay; | |
103 | delay.tv_sec = msec / 1000; | |
104 | delay.tv_nsec = (msec % 1000) * 1000000; | |
8d84aa25 | 105 | while (nanosleep(&delay, &delay)); |
21c145b1 | 106 | #else |
fc97a919 | 107 | usleep(msec*1000); |
21c145b1 | 108 | #endif |
fc97a919 | 109 | return 0; |
5a61e580 VK |
110 | } |
111 | ||
112 | int zrtp_thread_create(zrtp_thread_routine_t start_routine, void *arg) | |
113 | { | |
114 | pthread_t thread; | |
326370ba | 115 | return pthread_create(&thread, NULL, start_routine, arg); |
5a61e580 VK |
116 | } |
117 | #endif | |
118 | ||
119 | ||
120 | /*==========================================================================*/ | |
121 | /* Scheduler Implementation */ | |
122 | /*==========================================================================*/ | |
123 | #if (ZRTP_PLATFORM == ZP_WIN32) || (ZRTP_PLATFORM == ZP_WIN64) || (ZRTP_PLATFORM == ZP_WINCE) | |
124 | static DWORD WINAPI sched_loop(void* param) | |
125 | #elif (ZRTP_PLATFORM == ZP_SYMBIAN) | |
126 | static int sched_loop(void* param) | |
127 | #else | |
128 | static void* sched_loop(void* param) | |
129 | #endif | |
130 | { | |
131 | #if defined (ZRTP_DEBUG_WITH_PJSIP) && (ZRTP_DEBUG_WITH_PJSIP == 1) | |
132 | /* | |
133 | Register current thread if it was created by | |
134 | external system call(not pj_sip call) | |
135 | */ | |
136 | pj_thread_desc desc; | |
137 | pj_thread_t *sched_loop_thread; | |
138 | ||
139 | if (pj_thread_is_registered()==PJ_FALSE){ | |
140 | pj_thread_register("zrtp_sched_loop_thread", desc, &sched_loop_thread); | |
141 | } | |
142 | #endif | |
143 | ||
144 | #if (ZRTP_PLATFORM != ZP_WIN32 && ZRTP_PLATFORM != ZP_WINCE) | |
145 | is_working = 1; | |
146 | #endif | |
147 | while (is_running) | |
148 | { | |
149 | zrtp_sched_task_t* task = NULL; | |
150 | zrtp_sched_task_t task2run; | |
151 | int ready_2_run = 0; | |
152 | mlist_t* node = 0; | |
153 | ||
154 | /* Wait for tasks in queue */ | |
155 | zrtp_sem_wait(count); | |
156 | ||
157 | zrtp_mutex_lock(protector); | |
158 | ||
159 | node = mlist_get(&tasks_head); | |
160 | if (!node) { | |
161 | zrtp_mutex_unlock(protector); | |
162 | continue; | |
163 | } | |
164 | ||
165 | task = mlist_get_struct(zrtp_sched_task_t, _mlist, node); | |
166 | if (task->wake_at <= zrtp_time_now()) | |
167 | { | |
168 | task2run.ctx = task->ctx; | |
169 | task2run.ztask = task->ztask; | |
170 | mlist_del(node); | |
171 | zrtp_sys_free(task); | |
172 | ready_2_run = 1; | |
173 | } | |
174 | ||
175 | zrtp_mutex_unlock(protector); | |
176 | ||
177 | if (ready_2_run) { | |
178 | task2run.ztask->_is_busy = 1; | |
179 | task2run.ztask->callback(task2run.ctx, task2run.ztask); | |
180 | task2run.ztask->_is_busy = 0; | |
181 | } else { | |
182 | zrtp_sem_post(count); | |
183 | } | |
184 | ||
185 | ZRTP_SCHED_SLEEP(1); | |
186 | } | |
187 | ||
188 | #if (ZRTP_PLATFORM != ZP_WIN32)&& (ZRTP_PLATFORM != ZP_WINCE) | |
189 | is_working = 0; | |
190 | #endif | |
191 | ||
192 | #if (ZRTP_PLATFORM != ZP_WIN32) && (ZRTP_PLATFORM != ZP_WIN64) && (ZRTP_PLATFORM != ZP_WINCE) | |
193 | return NULL; | |
194 | #else | |
195 | return 0; | |
196 | #endif | |
197 | } | |
198 | ||
199 | /*---------------------------------------------------------------------------*/ | |
200 | zrtp_status_t zrtp_def_scheduler_init(zrtp_global_t* zrtp) | |
201 | { | |
202 | zrtp_status_t status = zrtp_status_ok; | |
203 | ||
204 | if (inited) { | |
205 | return zrtp_status_ok; | |
206 | } | |
207 | ||
208 | do { | |
209 | init_mlist(&tasks_head); | |
210 | ||
211 | if (zrtp_status_ok != (status = zrtp_mutex_init(&protector))) { | |
212 | break; | |
213 | } | |
214 | if (zrtp_status_ok != (status = zrtp_sem_init(&count, 0, ZRTP_SCHED_QUEUE_SIZE))) { | |
215 | break; | |
216 | } | |
217 | ||
218 | /* Starting processing loop */ | |
219 | is_running = 1; | |
220 | ||
221 | if (0 != zrtp_thread_create(sched_loop, NULL)) { | |
222 | zrtp_sem_destroy(count); | |
223 | zrtp_mutex_destroy(protector); | |
224 | ||
225 | status = zrtp_status_fail; | |
226 | break; | |
227 | } | |
228 | ||
229 | inited = 1; | |
230 | } while (0); | |
231 | ||
232 | return status; | |
233 | } | |
234 | ||
235 | /*---------------------------------------------------------------------------*/ | |
236 | void zrtp_def_scheduler_down() | |
237 | { | |
238 | mlist_t *node = 0, *tmp = 0; | |
239 | ||
240 | if (!inited) { | |
241 | return; | |
242 | } | |
243 | ||
244 | /* Stop main thread */ | |
245 | is_running = 0; | |
246 | zrtp_sem_post(count); | |
247 | #if (ZRTP_PLATFORM == ZP_WIN32) || (ZRTP_PLATFORM == ZP_WINCE) | |
248 | if (NULL != scheduler_thread) | |
249 | { | |
250 | WaitForSingleObject(scheduler_thread, INFINITE); | |
251 | CloseHandle(scheduler_thread); | |
252 | scheduler_thread = NULL; | |
253 | } | |
254 | #else | |
255 | while (is_working) { | |
256 | ZRTP_SCHED_SLEEP(1); | |
257 | } | |
258 | #endif | |
259 | ||
260 | /* Then destroy tasks queue and realease all other resources */ | |
261 | zrtp_mutex_lock(protector); | |
262 | ||
263 | mlist_for_each_safe(node, tmp, &tasks_head) { | |
264 | zrtp_sched_task_t* task = mlist_get_struct(zrtp_sched_task_t, _mlist, node); | |
265 | zrtp_sys_free(task); | |
266 | } | |
267 | init_mlist(&tasks_head); | |
268 | ||
269 | zrtp_mutex_unlock(protector); | |
270 | ||
271 | zrtp_mutex_destroy(protector); | |
272 | zrtp_sem_destroy(count); | |
273 | ||
274 | inited = 0; | |
275 | } | |
276 | ||
277 | /*---------------------------------------------------------------------------*/ | |
278 | void zrtp_def_scheduler_call_later(zrtp_stream_t *ctx, zrtp_retry_task_t* ztask) | |
279 | { | |
280 | mlist_t *node=0, *tmp=0; | |
281 | mlist_t* last = &tasks_head; | |
282 | ||
283 | zrtp_mutex_lock(protector); | |
284 | ||
285 | if (!ztask->_is_enabled) { | |
286 | zrtp_mutex_unlock(protector); | |
287 | return; | |
288 | } | |
289 | ||
290 | do { | |
291 | zrtp_sched_task_t* new_task = zrtp_sys_alloc(sizeof(zrtp_sched_task_t)); | |
292 | if (!new_task) { | |
293 | break; | |
294 | } | |
295 | ||
296 | new_task->ctx = ctx; | |
297 | new_task->ztask = ztask; | |
298 | new_task->wake_at = zrtp_time_now() + ztask->timeout; | |
299 | ||
300 | /* Try to find element with later wacked time than we have */ | |
301 | mlist_for_each_safe(node, tmp, &tasks_head) { | |
302 | zrtp_sched_task_t* tmp_task = mlist_get_struct(zrtp_sched_task_t, _mlist, node); | |
303 | if (tmp_task->wake_at >= new_task->wake_at) { | |
304 | last = node; | |
305 | break; | |
306 | } | |
307 | } | |
308 | ||
309 | /* | |
310 | * If packet wasn't inserted (empty queue or all elements are smaller) | |
311 | * Put them to the end of the queue. | |
312 | */ | |
313 | mlist_insert(last, &new_task->_mlist); | |
314 | ||
315 | zrtp_sem_post(count); | |
316 | } while (0); | |
317 | ||
318 | zrtp_mutex_unlock(protector); | |
319 | } | |
320 | ||
321 | /*---------------------------------------------------------------------------*/ | |
322 | void zrtp_def_scheduler_cancel_call_later(zrtp_stream_t* ctx, zrtp_retry_task_t* ztask) | |
323 | { | |
324 | mlist_t *node=0, *tmp=0; | |
325 | ||
326 | zrtp_mutex_lock(protector); | |
327 | ||
328 | mlist_for_each_safe(node, tmp, &tasks_head) { | |
329 | zrtp_sched_task_t* task = mlist_get_struct(zrtp_sched_task_t, _mlist, node); | |
330 | if ((task->ctx == ctx) && ((task->ztask == ztask) || !ztask)) { | |
331 | mlist_del(&task->_mlist); | |
332 | zrtp_sys_free(task); | |
333 | zrtp_sem_trtwait(count); | |
334 | if (ztask) { | |
335 | break; | |
336 | } | |
337 | } | |
338 | } | |
339 | ||
340 | zrtp_mutex_unlock(protector); | |
341 | } | |
342 | ||
343 | void zrtp_def_scheduler_wait_call_later(zrtp_stream_t* ctx) | |
344 | { | |
345 | while (ctx->messages.hello_task._is_busy) { | |
346 | ZRTP_SCHED_SLEEP(1); | |
347 | } | |
348 | while (ctx->messages.commit_task._is_busy) { | |
349 | ZRTP_SCHED_SLEEP(1); | |
350 | } | |
351 | while (ctx->messages.dhpart_task._is_busy) { | |
352 | ZRTP_SCHED_SLEEP(1); | |
353 | } | |
354 | while (ctx->messages.confirm_task._is_busy) { | |
355 | ZRTP_SCHED_SLEEP(1); | |
356 | } | |
357 | while (ctx->messages.error_task._is_busy) { | |
358 | ZRTP_SCHED_SLEEP(1); | |
359 | } | |
360 | while (ctx->messages.errorack_task._is_busy) { | |
361 | ZRTP_SCHED_SLEEP(1); | |
362 | } | |
363 | while (ctx->messages.goclear_task._is_busy) { | |
364 | ZRTP_SCHED_SLEEP(1); | |
365 | } | |
366 | while (ctx->messages.dh_task._is_busy) { | |
367 | ZRTP_SCHED_SLEEP(1); | |
368 | } | |
369 | } | |
370 | ||
371 | #endif /* not for windows kernel */ | |
372 | ||
373 | #endif // ZRTP_PLATFORM==ZP_SYMBIAN | |
374 | ||
375 | #endif /*ZRTP_USE_BUILTIN_SCEHDULER*/ |