1 /*
2 	belle-sip - SIP (RFC3261) library.
3     Copyright (C) 2010  Belledonne Communications SARL
4 
5     This program is free software: you can redistribute it and/or modify
6     it under the terms of the GNU General Public License as published by
7     the Free Software Foundation, either version 2 of the License, or
8     (at your option) any later version.
9 
10     This program is distributed in the hope that it will be useful,
11     but WITHOUT ANY WARRANTY; without even the implied warranty of
12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13     GNU General Public License for more details.
14 
15     You should have received a copy of the GNU General Public License
16     along with this program.  If not, see <http://www.gnu.org/licenses/>.
17 */
18 
19 #include "belle-sip/belle-sip.h"
20 #include "belle_sip_internal.h"
21 #include "bctoolbox/map.h"
22 #include <limits.h>
23 
24 #ifndef _WIN32
25 #include <unistd.h>
26 #include <poll.h>
27 typedef struct pollfd belle_sip_pollfd_t;
28 
belle_sip_poll(belle_sip_pollfd_t * pfd,int count,int duration)29 static int belle_sip_poll(belle_sip_pollfd_t *pfd, int count, int duration){
30 	int err;
31 	err=poll(pfd,count,duration);
32 	if (err==-1 && errno!=EINTR)
33 		belle_sip_error("poll() error: %s",strerror(errno));
34 	return err;
35 }
36 
37 /*
38  Poll() based implementation of event loop.
39  */
40 
belle_sip_event_to_poll(unsigned int events)41 static int belle_sip_event_to_poll(unsigned int events){
42 	int ret=0;
43 	if (events & BELLE_SIP_EVENT_READ)
44 		ret|=POLLIN;
45 	if (events & BELLE_SIP_EVENT_WRITE)
46 		ret|=POLLOUT;
47 	if (events & BELLE_SIP_EVENT_ERROR)
48 		ret|=POLLERR;
49 	return ret;
50 }
51 
belle_sip_poll_to_event(belle_sip_pollfd_t * pfd)52 static unsigned int belle_sip_poll_to_event(belle_sip_pollfd_t * pfd){
53 	unsigned int ret=0;
54 	short events=pfd->revents;
55 	if (events & POLLIN)
56 		ret|=BELLE_SIP_EVENT_READ;
57 	if (events & POLLOUT)
58 		ret|=BELLE_SIP_EVENT_WRITE;
59 	if (events & POLLERR)
60 		ret|=BELLE_SIP_EVENT_ERROR;
61 	return ret;
62 }
63 
belle_sip_source_to_poll(belle_sip_source_t * s,belle_sip_pollfd_t * pfd,int i)64 static void belle_sip_source_to_poll(belle_sip_source_t *s, belle_sip_pollfd_t *pfd, int i){
65 	pfd[i].fd=s->fd;
66 	pfd[i].events=belle_sip_event_to_poll(s->events);
67 	pfd[i].revents=0;
68 	s->index=i;
69 }
70 
belle_sip_source_get_revents(belle_sip_source_t * s,belle_sip_pollfd_t * pfd)71 static unsigned int belle_sip_source_get_revents(belle_sip_source_t *s,belle_sip_pollfd_t *pfd){
72 	return belle_sip_poll_to_event(&pfd[s->index]);
73 }
74 
75 #else
76 
77 
78 #include <malloc.h>
79 
80 
81 typedef HANDLE belle_sip_pollfd_t;
82 
belle_sip_source_to_poll(belle_sip_source_t * s,belle_sip_pollfd_t * pfd,int i)83 static void belle_sip_source_to_poll(belle_sip_source_t *s, belle_sip_pollfd_t *pfd,int i){
84 	s->index=i;
85 	pfd[i]=s->fd;
86 
87 	/*special treatments for windows sockets*/
88 	if (s->sock!=(belle_sip_socket_t)-1){
89 		int err;
90 		long events=0;
91 
92 		if (s->events & BELLE_SIP_EVENT_READ)
93 			events|=FD_READ|FD_ACCEPT;
94 		if (s->events & BELLE_SIP_EVENT_WRITE)
95 			events|=FD_WRITE|FD_CONNECT;
96 		if (events!=s->armed_events){
97 			s->armed_events=events;
98 			err=WSAEventSelect(s->sock,s->fd,events);
99 			if (err!=0) belle_sip_error("WSAEventSelect() failed: %s",belle_sip_get_socket_error_string());
100 		}
101 	}
102 }
103 
belle_sip_source_get_revents(belle_sip_source_t * s,belle_sip_pollfd_t * pfd)104 static unsigned int belle_sip_source_get_revents(belle_sip_source_t *s,belle_sip_pollfd_t *pfd){
105 	WSANETWORKEVENTS revents={0};
106 	int err;
107 	unsigned int ret=0;
108 
109 	if (WaitForSingleObjectEx(s->fd,0,FALSE)==WAIT_OBJECT_0){
110 		if (s->sock!=(belle_sip_socket_t)-1){
111 			/*special treatments for windows sockets*/
112 			err=WSAEnumNetworkEvents(s->sock,s->fd,&revents);
113 			if (err!=0){
114 				belle_sip_error("WSAEnumNetworkEvents() failed: %s socket=%x",belle_sip_get_socket_error_string(),(unsigned int)s->sock);
115 				return 0;
116 			}
117 			if (revents.lNetworkEvents & FD_READ || revents.lNetworkEvents & FD_ACCEPT){
118 				ret|=BELLE_SIP_EVENT_READ;
119 			}
120 			if (revents.lNetworkEvents & FD_WRITE || revents.lNetworkEvents & FD_CONNECT){
121 				ret|=BELLE_SIP_EVENT_WRITE;
122 			}
123 			s->armed_events=0;
124 		}else{
125 			ret=BELLE_SIP_EVENT_READ;
126 			ResetEvent(s->fd);
127 		}
128 	}
129 	return ret;
130 }
131 
belle_sip_poll(belle_sip_pollfd_t * pfd,int count,int duration)132 static int belle_sip_poll(belle_sip_pollfd_t *pfd, int count, int duration){
133 	DWORD ret;
134 
135 	if (count == 0) {
136 		belle_sip_sleep(duration);
137 		return 0;
138 	}
139 
140 	ret=WaitForMultipleObjectsEx(count,pfd,FALSE,duration,FALSE);
141 	if (ret==WAIT_FAILED){
142 		belle_sip_error("WaitForMultipleObjectsEx() failed.");
143 		return -1;
144 	}
145 	if (ret==WAIT_TIMEOUT){
146 		return 0;
147 	}
148 	return ret-WAIT_OBJECT_0;
149 }
150 
151 #endif
152 
belle_sip_source_destroy(belle_sip_source_t * obj)153 static void belle_sip_source_destroy(belle_sip_source_t *obj){
154 	if (obj->node.next || obj->node.prev){
155 		belle_sip_fatal("Destroying source currently used in main loop !");
156 	}
157 	belle_sip_source_uninit(obj);
158 }
159 
belle_sip_source_init(belle_sip_source_t * s,belle_sip_source_func_t func,void * data,belle_sip_fd_t fd,unsigned int events,unsigned int timeout_value_ms)160 static void belle_sip_source_init(belle_sip_source_t *s, belle_sip_source_func_t func, void *data, belle_sip_fd_t fd, unsigned int events, unsigned int timeout_value_ms){
161 	static unsigned long global_id=1;
162 	s->node.data=s;
163 	if (s->id==0) s->id=global_id++;
164 	s->fd=fd;
165 	s->events=events;
166 	s->timeout=timeout_value_ms;
167 	s->data=data;
168 	s->notify=func;
169 	s->sock=(belle_sip_socket_t)-1;
170 }
171 
belle_sip_source_uninit(belle_sip_source_t * obj)172 void belle_sip_source_uninit(belle_sip_source_t *obj){
173 #ifdef _WIN32
174 	if (obj->sock!=(belle_sip_socket_t)-1){
175 		WSACloseEvent(obj->fd);
176 		obj->fd=(WSAEVENT)-1;
177 	}
178 #endif
179 	obj->fd=(belle_sip_fd_t)-1;
180 	obj->sock=(belle_sip_socket_t)-1;
181 /*	if (obj->it) {
182 		bctbx_iterator_delete(obj->it);
183 		obj->it=NULL;
184 	}*/
185 }
186 
belle_sip_source_set_notify(belle_sip_source_t * s,belle_sip_source_func_t func)187 void belle_sip_source_set_notify(belle_sip_source_t *s, belle_sip_source_func_t func) {
188 	s->notify = func;
189 }
190 
belle_sip_socket_source_init(belle_sip_source_t * s,belle_sip_source_func_t func,void * data,belle_sip_socket_t sock,unsigned int events,unsigned int timeout_value_ms)191 void belle_sip_socket_source_init(belle_sip_source_t *s, belle_sip_source_func_t func, void *data, belle_sip_socket_t sock, unsigned int events, unsigned int timeout_value_ms){
192 #ifdef _WIN32
193 	/*on windows, the fd to poll is not the socket */
194 	belle_sip_fd_t fd=(belle_sip_fd_t)-1;
195 	if (sock!=(belle_sip_socket_t)-1)
196 		fd=WSACreateEvent();
197 	else
198 		fd=(WSAEVENT)-1;
199 	belle_sip_source_init(s,func,data,fd,events,timeout_value_ms);
200 
201 #else
202 	belle_sip_source_init(s,func,data,sock,events,timeout_value_ms);
203 #endif
204 	s->sock=sock;
205 	if (sock!=(belle_sip_socket_t)-1)
206 		belle_sip_socket_set_nonblocking(sock);
207 }
208 
belle_sip_fd_source_init(belle_sip_source_t * s,belle_sip_source_func_t func,void * data,belle_sip_fd_t fd,unsigned int events,unsigned int timeout_value_ms)209 void belle_sip_fd_source_init(belle_sip_source_t *s, belle_sip_source_func_t func, void *data, belle_sip_fd_t fd, unsigned int events, unsigned int timeout_value_ms){
210 	belle_sip_source_init(s,func,data,fd,events,timeout_value_ms);
211 }
212 
213 BELLE_SIP_DECLARE_NO_IMPLEMENTED_INTERFACES(belle_sip_source_t);
214 BELLE_SIP_INSTANCIATE_VPTR(belle_sip_source_t,belle_sip_object_t,belle_sip_source_destroy,NULL,NULL,FALSE);
215 
belle_sip_socket_source_new(belle_sip_source_func_t func,void * data,belle_sip_socket_t sock,unsigned int events,unsigned int timeout_value_ms)216 belle_sip_source_t * belle_sip_socket_source_new(belle_sip_source_func_t func, void *data, belle_sip_socket_t sock, unsigned int events, unsigned int timeout_value_ms){
217 	belle_sip_source_t *s=belle_sip_object_new(belle_sip_source_t);
218 	belle_sip_socket_source_init(s,func,data,sock,events,timeout_value_ms);
219 	return s;
220 }
221 
belle_sip_fd_source_new(belle_sip_source_func_t func,void * data,belle_sip_fd_t fd,unsigned int events,unsigned int timeout_value_ms)222 belle_sip_source_t * belle_sip_fd_source_new(belle_sip_source_func_t func, void *data, belle_sip_fd_t fd, unsigned int events, unsigned int timeout_value_ms){
223 	belle_sip_source_t *s=belle_sip_object_new(belle_sip_source_t);
224 	belle_sip_fd_source_init(s,func,data,fd,events,timeout_value_ms);
225 	return s;
226 }
227 
belle_sip_timeout_source_new(belle_sip_source_func_t func,void * data,unsigned int timeout_value_ms)228 belle_sip_source_t * belle_sip_timeout_source_new(belle_sip_source_func_t func, void *data, unsigned int timeout_value_ms){
229 	return belle_sip_socket_source_new(func,data,(belle_sip_socket_t)-1,0,timeout_value_ms);
230 }
231 
belle_sip_source_get_id(const belle_sip_source_t * s)232 unsigned long belle_sip_source_get_id(const belle_sip_source_t *s){
233 	return s->id;
234 }
belle_sip_source_get_user_data(const belle_sip_source_t * s)235 void * belle_sip_source_get_user_data(const belle_sip_source_t *s) {
236 	return s->data;
237 }
belle_sip_source_set_user_data(belle_sip_source_t * s,void * user_data)238 void belle_sip_source_set_user_data(belle_sip_source_t *s, void *user_data) {
239 	s->data = user_data;
240 }
belle_sip_source_set_events(belle_sip_source_t * source,int event_mask)241 int belle_sip_source_set_events(belle_sip_source_t* source, int event_mask) {
242 	source->events = event_mask;
243 	return 0;
244 }
245 
belle_sip_source_get_socket(const belle_sip_source_t * source)246 belle_sip_socket_t belle_sip_source_get_socket(const belle_sip_source_t* source) {
247 	return source->sock;
248 }
249 
250 
251 struct belle_sip_main_loop{
252 	belle_sip_object_t base;
253 	belle_sip_list_t *fd_sources;
254 	bctbx_map_t *timer_sources;
255 	belle_sip_object_pool_t *pool;
256 	int nsources;
257 	int run;
258 	int in_loop;
259 	bctbx_mutex_t timer_sources_mutex;
260 };
261 
belle_sip_main_loop_remove_source(belle_sip_main_loop_t * ml,belle_sip_source_t * source)262 void belle_sip_main_loop_remove_source(belle_sip_main_loop_t *ml, belle_sip_source_t *source){
263 	bool_t elem_removed = FALSE;
264 	if (source->node.next || source->node.prev || &source->node==ml->fd_sources)  {
265 		ml->fd_sources=belle_sip_list_remove_link(ml->fd_sources,&source->node);
266 		belle_sip_object_unref(source);
267 		elem_removed = TRUE;
268 	}
269 	if (source->it) {
270 		bctbx_mutex_lock(&ml->timer_sources_mutex);
271 		bctbx_map_erase(ml->timer_sources, source->it);
272 		bctbx_iterator_delete(source->it);
273 		bctbx_mutex_unlock(&ml->timer_sources_mutex);
274 
275 		source->it=NULL;
276 		belle_sip_object_unref(source);
277 		elem_removed = TRUE;
278 	}
279 	if (elem_removed) {
280 		source->cancelled=TRUE;
281 		ml->nsources--;
282 		if (source->on_remove)
283 			source->on_remove(source);
284 
285 	}
286 }
287 
288 
belle_sip_main_loop_destroy(belle_sip_main_loop_t * ml)289 static void belle_sip_main_loop_destroy(belle_sip_main_loop_t *ml){
290 	while (ml->fd_sources){
291 		belle_sip_main_loop_remove_source(ml,(belle_sip_source_t*)ml->fd_sources->data);
292 	}
293 	if (belle_sip_object_pool_cleanable(ml->pool)){
294 		belle_sip_object_unref(ml->pool);
295 	}
296 	bctbx_mmap_ullong_delete(ml->timer_sources);
297 	bctbx_mutex_destroy(&ml->timer_sources_mutex);
298 }
299 
300 BELLE_SIP_DECLARE_NO_IMPLEMENTED_INTERFACES(belle_sip_main_loop_t);
301 BELLE_SIP_INSTANCIATE_VPTR(belle_sip_main_loop_t,belle_sip_object_t,belle_sip_main_loop_destroy,NULL,NULL,FALSE);
302 
belle_sip_main_loop_new(void)303 belle_sip_main_loop_t *belle_sip_main_loop_new(void){
304 	belle_sip_main_loop_t*m=belle_sip_object_new(belle_sip_main_loop_t);
305 	m->pool=belle_sip_object_pool_push();
306 	m->timer_sources = bctbx_mmap_ullong_new();
307 	bctbx_mutex_init(&m->timer_sources_mutex,NULL);
308 	return m;
309 }
310 
belle_sip_main_loop_add_source(belle_sip_main_loop_t * ml,belle_sip_source_t * source)311 void belle_sip_main_loop_add_source(belle_sip_main_loop_t *ml, belle_sip_source_t *source){
312 	if (source->node.next || source->node.prev){
313 		belle_sip_fatal("Source is already linked somewhere else.");
314 		return;
315 	}
316 	if (source->node.data!=source){
317 		belle_sip_fatal("Insane source passed to belle_sip_main_loop_add_source() !");
318 		return;
319 	}
320 
321 	source->ml=ml;
322 
323 	if (source->timeout>=0){
324 		belle_sip_object_ref(source);
325 		source->expire_ms=belle_sip_time_ms()+source->timeout;
326 		bctbx_mutex_lock(&ml->timer_sources_mutex);
327 		source->it = bctbx_map_insert_and_delete_with_returned_it(ml->timer_sources
328 																	  , (bctbx_pair_t*)bctbx_pair_ullong_new(source->expire_ms, source));
329 		bctbx_mutex_unlock(&ml->timer_sources_mutex);
330 
331 	}
332 	source->cancelled=FALSE;
333 	if (source->fd != (belle_sip_fd_t)-1 ) {
334 		belle_sip_object_ref(source);
335 		ml->fd_sources=belle_sip_list_prepend_link(ml->fd_sources,&source->node);
336 	}
337 
338 	ml->nsources++;
339 }
340 
belle_sip_main_loop_create_timeout_with_remove_cb(belle_sip_main_loop_t * ml,belle_sip_source_func_t func,void * data,unsigned int timeout_value_ms,const char * timer_name,belle_sip_source_remove_callback_t remove_func)341 belle_sip_source_t* belle_sip_main_loop_create_timeout_with_remove_cb(  belle_sip_main_loop_t *ml
342 																	  , belle_sip_source_func_t func
343 																	  , void *data
344 																	  , unsigned int timeout_value_ms
345 																	  , const char* timer_name
346 																	  , belle_sip_source_remove_callback_t remove_func) {
347 	belle_sip_source_t * s=belle_sip_timeout_source_new(func,data,timeout_value_ms);
348 	belle_sip_object_set_name((belle_sip_object_t*)s,timer_name);
349 	if (remove_func) {
350 		belle_sip_source_set_remove_cb(s, remove_func);
351 	}
352 	belle_sip_main_loop_add_source(ml,s);
353 	return s;
354 }
belle_sip_main_loop_create_timeout(belle_sip_main_loop_t * ml,belle_sip_source_func_t func,void * data,unsigned int timeout_value_ms,const char * timer_name)355 belle_sip_source_t* belle_sip_main_loop_create_timeout(belle_sip_main_loop_t *ml
356 																	  , belle_sip_source_func_t func
357 																	  , void *data
358 																	  , unsigned int timeout_value_ms
359 																	  ,const char* timer_name) {
360 	return belle_sip_main_loop_create_timeout_with_remove_cb(ml, func, data, timeout_value_ms,timer_name,NULL);
361 
362 }
363 
belle_sip_main_loop_add_timeout(belle_sip_main_loop_t * ml,belle_sip_source_func_t func,void * data,unsigned int timeout_value_ms)364 unsigned long belle_sip_main_loop_add_timeout(belle_sip_main_loop_t *ml, belle_sip_source_func_t func, void *data, unsigned int timeout_value_ms){
365 	belle_sip_source_t * s=belle_sip_main_loop_create_timeout(ml,func,data,timeout_value_ms,"Timer");
366 	belle_sip_object_unref(s);
367 	return s->id;
368 }
369 
belle_sip_main_loop_do_later(belle_sip_main_loop_t * ml,belle_sip_callback_t func,void * data)370 void belle_sip_main_loop_do_later(belle_sip_main_loop_t *ml, belle_sip_callback_t func, void *data){
371 	belle_sip_source_t * s=belle_sip_main_loop_create_timeout(ml,(belle_sip_source_func_t)func,data,0,"defered task");
372 	s->oneshot=TRUE;
373 	belle_sip_object_unref(s);
374 }
375 
376 
belle_sip_source_set_timeout(belle_sip_source_t * s,unsigned int value_ms)377 void belle_sip_source_set_timeout(belle_sip_source_t *s, unsigned int value_ms){
378 	if (!s->expired){
379 		belle_sip_main_loop_t *ml = s->ml;
380 		s->expire_ms=belle_sip_time_ms()+value_ms;
381 		if (s->it){
382 			/*this timeout is already sorted in the timer_sources map, we need to move it to its new place*/
383 			bctbx_mutex_lock(&ml->timer_sources_mutex);
384 			bctbx_map_erase(ml->timer_sources, s->it);
385 			bctbx_iterator_delete(s->it);
386 			s->it = bctbx_map_insert_and_delete_with_returned_it(ml->timer_sources,
387 				(bctbx_pair_t*)bctbx_pair_ullong_new(s->expire_ms, s));
388 			bctbx_mutex_unlock(&ml->timer_sources_mutex);
389 		}
390 	}
391 	s->timeout=value_ms;
392 }
393 
belle_sip_source_set_remove_cb(belle_sip_source_t * s,belle_sip_source_remove_callback_t func)394 void belle_sip_source_set_remove_cb(belle_sip_source_t *s, belle_sip_source_remove_callback_t func) {
395 	s->on_remove=func;
396 }
397 
belle_sip_source_get_timeout(const belle_sip_source_t * s)398 unsigned int belle_sip_source_get_timeout(const belle_sip_source_t *s){
399 	return s->timeout;
400 }
401 
belle_sip_source_cancel(belle_sip_source_t * s)402 void belle_sip_source_cancel(belle_sip_source_t *s){
403 	s->cancelled=TRUE;
404 	if (s->it) {
405 		bctbx_mutex_lock(&s->ml->timer_sources_mutex);
406 		bctbx_map_erase(s->ml->timer_sources, s->it);
407 		bctbx_iterator_delete(s->it);
408 		/*put on front*/
409 		s->it = bctbx_map_insert_and_delete_with_returned_it(s->ml->timer_sources, (bctbx_pair_t*)bctbx_pair_ullong_new(0, s));
410 
411 		bctbx_mutex_unlock(&s->ml->timer_sources_mutex);
412 	}
413 }
414 
match_source_id(const void * s,const void * pid)415 static int match_source_id(const void *s, const void *pid){
416 	if ( ((belle_sip_source_t*)s)->id==(unsigned long)(intptr_t)pid){
417 		return 0;
418 	}
419 	return -1;
420 }
421 
belle_sip_main_loop_find_source(belle_sip_main_loop_t * ml,unsigned long id)422 belle_sip_source_t *belle_sip_main_loop_find_source(belle_sip_main_loop_t *ml, unsigned long id){
423 	bctbx_iterator_t *it;
424 	belle_sip_source_t *ret=NULL;
425 	belle_sip_list_t *elem=belle_sip_list_find_custom(ml->fd_sources,match_source_id,(const void*)(intptr_t)id);
426 	if (elem!=NULL) {
427 		ret = (belle_sip_source_t*)elem->data;
428 	} else if ((it = bctbx_map_find_custom(ml->timer_sources, match_source_id, (const void*)(intptr_t)id))) {
429 		ret = (belle_sip_source_t*)bctbx_pair_get_second(bctbx_iterator_get_pair(it));
430 		bctbx_iterator_delete(it);
431 	} /*else
432 		ret = NULL;*/
433 
434 	return ret;
435 
436 }
437 
belle_sip_main_loop_cancel_source(belle_sip_main_loop_t * ml,unsigned long id)438 void belle_sip_main_loop_cancel_source(belle_sip_main_loop_t *ml, unsigned long id){
439 	belle_sip_source_t *s=belle_sip_main_loop_find_source(ml,id);
440 	if (s) belle_sip_source_cancel(s);
441 }
442 
belle_sip_main_loop_iterate(belle_sip_main_loop_t * ml)443 static void belle_sip_main_loop_iterate(belle_sip_main_loop_t *ml){
444 	size_t pfd_size = ml->nsources * sizeof(belle_sip_pollfd_t);
445 	belle_sip_pollfd_t *pfd=(belle_sip_pollfd_t*)belle_sip_malloc0(pfd_size);
446 	int i=0;
447 	belle_sip_source_t *s;
448 	belle_sip_list_t *elem,*next;
449 	int duration=-1;
450 	int ret;
451 	uint64_t cur;
452 	belle_sip_list_t *to_be_notified=NULL;
453 	int can_clean=belle_sip_object_pool_cleanable(ml->pool); /*iterate might not be called by the thread that created the main loop*/
454 	belle_sip_object_pool_t *tmp_pool=NULL;
455 	bctbx_iterator_t *it,*end;
456 
457 	if (!can_clean){
458 		/*Push a temporary pool for the time of the iterate loop*/
459 		tmp_pool=belle_sip_object_pool_push();
460 	}
461 
462 	/*Step 1: prepare the pollfd table and get the next timeout value */
463 	for(elem=ml->fd_sources;elem!=NULL;elem=next) {
464 		next=elem->next;
465 		s=(belle_sip_source_t*)elem->data;
466 		if (!s->cancelled){
467 			if (s->fd!=(belle_sip_fd_t)-1){
468 				belle_sip_source_to_poll(s,pfd,i);
469 				++i;
470 			}
471 		}
472 	}
473 	/*all source with timeout are in ml->timer_sources*/
474 	if (bctbx_map_size(ml->timer_sources) >0) {
475 		int64_t diff;
476 		uint64_t next_wakeup_time;
477 		it = bctbx_map_begin(ml->timer_sources);
478 		/*use first because in case of canceled timer, key ==0 , key != s->expire_ms */
479 		next_wakeup_time = bctbx_pair_ullong_get_first((const bctbx_pair_ullong_t *)bctbx_iterator_get_pair(it));
480 		/* compute the amount of time to wait for shortest timeout*/
481 		cur=belle_sip_time_ms();
482 		diff=next_wakeup_time-cur;
483 		if (diff>0)
484 			duration=MIN((unsigned int)diff,INT_MAX);
485 		else
486 			duration=0;
487 		bctbx_iterator_delete(it);
488 		it = NULL;
489 	}
490 
491 	/* do the poll */
492 	ret=belle_sip_poll(pfd,i,duration);
493 	if (ret==-1){
494 		goto end;
495 	}
496 
497 	/* Step 2: examine poll results and determine the list of source to be notified */
498 	cur=belle_sip_time_ms();
499 	for(elem=ml->fd_sources;elem!=NULL;elem=elem->next){
500 		unsigned revents=0;
501 		s=(belle_sip_source_t*)elem->data;
502 		if (!s->cancelled){
503 			if (s->fd!=(belle_sip_fd_t)-1){
504 				if (s->notify_required) { /*for testing purpose to force channel to read*/
505 					revents=BELLE_SIP_EVENT_READ;
506 					s->notify_required=0; /*reset*/
507 				} else {
508 					revents=belle_sip_source_get_revents(s,pfd);
509 				}
510 				s->revents=revents;
511 			} else {
512 				belle_sip_error("Source [%p] does not contains any fd !",s);
513 			}
514 			if (revents!=0){
515 				to_be_notified=belle_sip_list_append(to_be_notified,belle_sip_object_ref(s));
516 			}
517 		}else to_be_notified=belle_sip_list_append(to_be_notified,belle_sip_object_ref(s));
518 	}
519 
520 	/* Step 3: find timeouted sources */
521 
522 	bctbx_mutex_lock(&ml->timer_sources_mutex); /*iterator chain might be alterated by element insertion*/
523 	it = bctbx_map_begin(ml->timer_sources);
524 	end = bctbx_map_end(ml->timer_sources);
525 	while (!bctbx_iterator_equals(it,end)) {
526 		/*use first because in case of canceled timer, key != s->expire_ms*/
527 		uint64_t expire = bctbx_pair_ullong_get_first((const bctbx_pair_ullong_t *)bctbx_iterator_get_pair(it));
528 		s = (belle_sip_source_t*)bctbx_pair_get_second(bctbx_iterator_get_pair(it));
529 		if (expire > cur) {
530 			/* no need to continue looping because map is ordered*/
531 			break;
532 		} else {
533 			if (s->revents==0) {
534 				s->expired=TRUE;
535 				to_be_notified=belle_sip_list_append(to_be_notified,belle_sip_object_ref(s));
536 			} /*else already in to_be_notified by Step 2*/
537 
538 			s->revents|=BELLE_SIP_EVENT_TIMEOUT;
539 			it=bctbx_iterator_get_next(it);
540 		}
541 	}
542 	bctbx_iterator_delete(it);
543 	bctbx_iterator_delete(end);
544 	bctbx_mutex_unlock(&ml->timer_sources_mutex);
545 
546 	/* Step 4: notify those to be notified */
547 	for(elem=to_be_notified;elem!=NULL;){
548 		s=(belle_sip_source_t*)elem->data;
549 		next=elem->next;
550 		if (!s->cancelled){
551 
552 			if (s->timeout > 0 && belle_sip_log_level_enabled(BELLE_SIP_LOG_DEBUG)) {
553 				/*to avoid too many traces*/
554 				char *objdesc=belle_sip_object_to_string((belle_sip_object_t*)s);
555 				belle_sip_debug("source %s notified revents=%u, timeout=%i",objdesc,revents,s->timeout);
556 				belle_sip_free(objdesc);
557 			}
558 
559 			ret=s->notify(s->data,s->revents);
560 			if (ret==BELLE_SIP_STOP || s->oneshot){
561 				/*this source needs to be removed*/
562 				belle_sip_main_loop_remove_source(ml,s);
563 			} else  {
564 				if (s->expired && s->it) {
565 					bctbx_mutex_lock(&ml->timer_sources_mutex);
566 					bctbx_map_erase(ml->timer_sources, s->it);
567 					bctbx_iterator_delete(s->it);
568 					bctbx_mutex_unlock(&ml->timer_sources_mutex);
569 					s->it=NULL;
570 					belle_sip_object_unref(s);
571 				}
572 				if (!s->it && s->timeout >= 0){
573 					/*timeout needs to be started again */
574 					if (ret==BELLE_SIP_CONTINUE_WITHOUT_CATCHUP){
575 						s->expire_ms=cur+s->timeout;
576 					}else{
577 						s->expire_ms+=s->timeout;
578 					}
579 					s->expired=FALSE;
580 					bctbx_mutex_lock(&ml->timer_sources_mutex);
581 					s->it = bctbx_map_insert_and_delete_with_returned_it(ml->timer_sources,
582 							(bctbx_pair_t*)bctbx_pair_ullong_new(s->expire_ms, s));
583 					bctbx_mutex_unlock(&ml->timer_sources_mutex);
584 					belle_sip_object_ref(s);
585 				}
586 			}
587 		} else {
588 			belle_sip_main_loop_remove_source(ml,s);
589 		}
590 		s->revents=0;
591 		belle_sip_object_unref(s);
592 		belle_sip_free(elem); /*free just the element*/
593 		elem=next;
594 	}
595 
596 	if (can_clean) belle_sip_object_pool_clean(ml->pool);
597 	else if (tmp_pool) {
598 		belle_sip_object_unref(tmp_pool);
599 		tmp_pool=NULL;
600 	}
601 end:
602 
603 	belle_sip_free(pfd);
604 }
605 
belle_sip_main_loop_run(belle_sip_main_loop_t * ml)606 void belle_sip_main_loop_run(belle_sip_main_loop_t *ml){
607 	if (ml->in_loop){
608 		belle_sip_warning("belle_sip_main_loop_run(): reentrancy detected, doing nothing");
609 		return;
610 	}
611 	ml->run = TRUE;
612 	ml->in_loop = TRUE;
613 	while(ml->run){
614 		belle_sip_main_loop_iterate(ml);
615 	}
616 	ml->in_loop = FALSE;
617 }
618 
belle_sip_main_loop_quit(belle_sip_main_loop_t * ml)619 int belle_sip_main_loop_quit(belle_sip_main_loop_t *ml){
620 	ml->run=0;
621 	return BELLE_SIP_STOP;
622 }
623 
belle_sip_main_loop_sleep(belle_sip_main_loop_t * ml,int milliseconds)624 void belle_sip_main_loop_sleep(belle_sip_main_loop_t *ml, int milliseconds){
625 	belle_sip_source_t * s=belle_sip_main_loop_create_timeout(ml,(belle_sip_source_func_t)belle_sip_main_loop_quit,ml,milliseconds,"Main loop sleep timer");
626 	belle_sip_main_loop_run(ml);
627 	belle_sip_main_loop_remove_source(ml,s);
628 	belle_sip_object_unref(s);
629 }
630 
631