Commit f2bc48be authored by jehan's avatar jehan

Merge branch 'master' of git.linphone.org:belle-sip

Conflicts:
	include/belle-sip/belle-sip.h
	src/belle_sip_internal.h
	src/belle_sip_utils.c
parents d33a7887 5f7197f4
......@@ -53,7 +53,7 @@ fi
# Checks for library functions.
AC_CHECK_LIB(rt, clock_gettime)
AM_CONDITIONAL(BUILD_TESTS,test x$found_cunit = xyes)
......
......@@ -18,9 +18,15 @@
#ifndef BELLE_SIP_H
#define BELLE_SIP_H
#include "belle-sip/uri.h"
#include "belle-sip/headers.h"
#include "belle-sip/list.h"
#include "belle-sip/mainloop.h"
#include "belle-sip/uri.h"
#include "belle-sip/headers.h"
#undef TRUE
#define TRUE 1
#undef FALSE
#define FALSE 0
#endif
......@@ -19,23 +19,72 @@
#ifndef BELLE_SIP_MAINLOOP_H
#define BELLE_SIP_MAINLOOP_H
#define BELLE_SIP_EVENT_READ 1
#define BELLE_SIP_EVENT_ERROR (1<<1)
#define BELLE_SIP_EVENT_WRITE (1<<1)
#define BELLE_SIP_EVENT_ERROR (1<<2)
#define BELLE_SIP_EVENT_TIMEOUT (1<<3)
typedef struct belle_sip_source belle_sip_source_t;
typedef int (*belle_sip_source_func_t)(void *user_data, int events);
belle_sip_source_t * belle_sip_timeout_source_new(belle_sip_source_func_t func, void *data, unsigned int timeout_value_ms);
/**
* Callback function prototype for main loop notifications.
* Return value is important:
* 0 => source is removed from main loop.
* non zero value => source is kept.
**/
typedef int (*belle_sip_source_func_t)(void *user_data, unsigned int events);
typedef struct belle_sip_main_loop belle_sip_main_loop_t;
belle_sip_main_loop_t *belle_sip_main_loop_new(void);
void belle_sip_main_loop_add_source(belle_sip_main_loop_t *ml, belle_sip_source_t *source);
void belle_sip_main_loop_remove_source(belle_sip_main_loop_t *ml, belle_sip_source_t *source);
void 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);
/**
* Creates a mainloop.
**/
belle_sip_main_loop_t *belle_sip_main_loop_new(void);
/**
* Adds a timeout into the main loop
* @param ml
* @param func a callback function to be called to notify timeout expiration
* @param data a pointer to be passed to the callback
* @param timeout_value_ms duration of the timeout.
* @returns timeout id
**/
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);
/**
* Creates a timeout source, similarly to belle_sip_main_loop_add_timeout().
* However in this case the timeout must be entered manually using belle_sip_main_loop_add_source().
* Its pointer can be used to remove it from the source (that is cancelling it).
**/
belle_sip_source_t * belle_sip_timeout_source_new(belle_sip_source_func_t func, void *data, unsigned int timeout_value_ms);
/**
* Executes the main loop forever (or until belle_sip_main_loop_quit() is called)
**/
void belle_sip_main_loop_run(belle_sip_main_loop_t *ml);
/**
* Executes the main loop for the time specified in milliseconds.
**/
void belle_sip_main_loop_sleep(belle_sip_main_loop_t *ml, int milliseconds);
/**
* Break out the main loop.
**/
void belle_sip_main_loop_quit(belle_sip_main_loop_t *ml);
/**
* Cancel (removes) a source. It is not freed.
**/
void belle_sip_main_loop_cancel_source(belle_sip_main_loop_t *ml, unsigned long id);
#endif
......@@ -23,7 +23,8 @@ lib_LTLIBRARIES=libbellesip.la
libbellesip_la_SOURCES=belle_sip_uri_impl.c \
belle_sip_utils.c belle_sip_internal.h \
belle_sip_loop.c
belle_sip_loop.c \
belle_sip_resolver.c belle_sip_resolver.h
libbellesip_la_CFLAGS=$(STRICT_OPTIONS)
......
......@@ -22,8 +22,11 @@
#include <string.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdint.h>
#include <errno.h>
#include <unistd.h>
#include "belle-sip/list.h"
#include "belle-sip/belle-sip.h"
struct _belle_sip_list {
struct _belle_sip_list *next;
......@@ -31,8 +34,22 @@ struct _belle_sip_list {
void *data;
};
typedef void (*belle_sip_source_remove_callback_t)(belle_sip_source_t *);
struct belle_sip_source{
belle_sip_list_t node;
unsigned long id;
int fd;
unsigned int events;
int timeout;
void *data;
uint64_t expire_ms;
int index; /* index in pollfd table */
belle_sip_source_func_t notify;
belle_sip_source_remove_callback_t on_remove;
};
void belle_sip_fd_source_init(belle_sip_source_t *s, belle_sip_source_func_t func, void *data, int fd, unsigned int events, unsigned int timeout_value_ms);
#define belle_list_next(elem) ((elem)->next)
......@@ -45,6 +62,7 @@ void *belle_sip_malloc(size_t size);
void *belle_sip_malloc0(size_t size);
void *belle_sip_realloc(void *ptr, size_t size);
void belle_sip_free(void *ptr);
char * belle_sip_strdup(const char *s);
#define belle_sip_new(type) (type*)belle_sip_malloc(sizeof(type))
#define belle_sip_new0(type) (type*)belle_sip_malloc0(sizeof(type))
......@@ -166,6 +184,8 @@ static inline void belle_sip_fatal(const char *fmt,...)
char * belle_sip_concat (const char *str, ...);
uint64_t belle_sip_time_ms(void);
/*parameters accessors*/
#define GET_SET_STRING(object_type,attribute) \
const char* object_type##_get_##attribute (object_type##_t* obj) {\
......
......@@ -19,37 +19,57 @@
#include "belle-sip/belle-sip.h"
#include "belle_sip_internal.h"
struct belle_sip_source{
belle_sip_list_t node;
int fd;
int revents;
int timeout;
void *data;
belle_sip_source_func_t notify;
void (*on_remove)(belle_sip_source_t *);
};
#include <unistd.h>
#include <poll.h>
void belle_sip_source_destroy(belle_sip_source_t *obj){
if (obj->node.next || obj->node.prev){
belle_sip_fatal("Destroying source currently used in main loop !");
}
belle_sip_free(obj);
}
belle_sip_source_t * belle_sip_timeout_source_new(belle_sip_source_func_t func, void *data, unsigned int timeout_value_ms){
belle_sip_source_t *s=belle_sip_new0(belle_sip_source_t);
s->fd=-1;
void belle_sip_fd_source_init(belle_sip_source_t *s, belle_sip_source_func_t func, void *data, int fd, unsigned int events, unsigned int timeout_value_ms){
static unsigned long global_id=1;
s->id=global_id++;
s->fd=fd;
s->events=events;
s->timeout=timeout_value_ms;
s->data=data;
s->notify=func;
}
static belle_sip_source_t * belle_sip_fd_source_new(belle_sip_source_func_t func, void *data, int fd, unsigned int events, unsigned int timeout_value_ms){
belle_sip_source_t *s=belle_sip_new0(belle_sip_source_t);
belle_sip_fd_source_init(s,func,data,fd,events,timeout_value_ms);
return s;
}
belle_sip_source_t * belle_sip_timeout_source_new(belle_sip_source_func_t func, void *data, unsigned int timeout_value_ms){
return belle_sip_fd_source_new(func,data,-1,0,timeout_value_ms);
}
struct belle_sip_main_loop{
belle_sip_source_t *sources;
belle_sip_source_t *control;
int nsources;
int run;
int control_fds[2];
};
static int main_loop_done(void *data, unsigned int events){
belle_sip_debug("Got data on control fd...");
return TRUE;
}
belle_sip_main_loop_t *belle_sip_main_loop_new(void){
belle_sip_main_loop_t*m=belle_sip_new0(belle_sip_main_loop_t);
if (pipe(m->control_fds)==-1){
belle_sip_fatal("Could not create control pipe.");
}
m->control=belle_sip_fd_source_new (main_loop_done,NULL,m->control_fds[0],BELLE_SIP_EVENT_READ,-1);
belle_sip_main_loop_add_source(m,m->control);
return m;
}
......@@ -58,15 +78,139 @@ void belle_sip_main_loop_add_source(belle_sip_main_loop_t *ml, belle_sip_source_
belle_sip_fatal("Source is already linked somewhere else.");
return;
}
if (source->timeout>0){
source->expire_ms=belle_sip_time_ms()+source->timeout;
}
ml->sources=(belle_sip_source_t*)belle_sip_list_append_link((belle_sip_list_t*)ml->sources,(belle_sip_list_t*)source);
ml->nsources++;
}
void belle_sip_main_loop_remove_source(belle_sip_main_loop_t *ml, belle_sip_source_t *source){
ml->sources=(belle_sip_source_t*)belle_sip_list_remove_link((belle_sip_list_t*)ml->sources,(belle_sip_list_t*)source);
ml->nsources--;
if (source->on_remove)
source->on_remove(source);
}
void 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){
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){
belle_sip_source_t * s=belle_sip_timeout_source_new(func,data,timeout_value_ms);
s->on_remove=belle_sip_source_destroy;
belle_sip_main_loop_add_source(ml,s);
return s->id;
}
/*
Poll() based implementation of event loop.
*/
static int belle_sip_event_to_poll(unsigned int events){
int ret=0;
if (events & BELLE_SIP_EVENT_READ)
ret|=POLLIN;
if (events & BELLE_SIP_EVENT_WRITE)
ret|=POLLOUT;
if (events & BELLE_SIP_EVENT_ERROR)
ret|=POLLERR;
return ret;
}
static unsigned int belle_sip_poll_to_event(short events){
unsigned int ret=0;
if (events & POLLIN)
ret|=BELLE_SIP_EVENT_READ;
if (events & POLLOUT)
ret|=BELLE_SIP_EVENT_WRITE;
if (events & POLLERR)
ret|=BELLE_SIP_EVENT_ERROR;
return ret;
}
void belle_sip_main_loop_iterate(belle_sip_main_loop_t *ml){
struct pollfd *pfd=(struct pollfd*)alloca(ml->nsources*sizeof(struct pollfd));
int i=0;
belle_sip_source_t *s,*next;
uint64_t min_time_ms=(uint64_t)-1;
int duration=-1;
int ret;
uint64_t cur;
/*prepare the pollfd table */
for(s=ml->sources;s!=NULL;s=(belle_sip_source_t*)s->node.next){
if (s->fd!=-1){
pfd[i].fd=s->fd;
pfd[i].events=belle_sip_event_to_poll (s->events);
pfd[i].revents=0;
s->index=i;
++i;
}
if (s->timeout>0){
if (min_time_ms>s->expire_ms){
min_time_ms=s->expire_ms;
}
}
}
if (min_time_ms!=(uint64_t)-1 ){
/* compute the amount of time to wait for shortest timeout*/
cur=belle_sip_time_ms();
int64_t diff=min_time_ms-cur;
if (diff>0)
duration=(int)diff;
else
duration=0;
}
/* do the poll */
ret=poll(pfd,i,duration);
if (ret==-1 && errno!=EINTR){
belle_sip_error("poll() error: %s",strerror(errno));
return;
}
cur=belle_sip_time_ms();
/* examine poll results*/
for(s=ml->sources;s!=NULL;s=next){
unsigned revents=0;
next=(belle_sip_source_t*)s->node.next;
if (s->fd!=-1){
if (pfd[s->index].revents!=0){
revents=belle_sip_poll_to_event(pfd[s->index].revents);
}
}
if (revents!=0 || (s->timeout>0 && cur>=s->expire_ms)){
ret=s->notify(s->data,revents);
if (ret==0){
/*this source needs to be removed*/
belle_sip_main_loop_remove_source(ml,s);
}else if (revents==0){
/*timeout needs to be started again */
s->expire_ms+=s->timeout;
}
}
}
}
void belle_sip_main_loop_run(belle_sip_main_loop_t *ml){
ml->run=1;
while(ml->run){
belle_sip_main_loop_iterate(ml);
}
}
void belle_sip_main_loop_quit(belle_sip_main_loop_t *ml){
ml->run=0;
write(ml->control_fds[1],"a",1);
}
void belle_sip_main_loop_sleep(belle_sip_main_loop_t *ml, int milliseconds){
belle_sip_main_loop_add_timeout(ml,(belle_sip_source_func_t)belle_sip_main_loop_quit,ml,milliseconds);
belle_sip_main_loop_run(ml);
}
void belle_sip_main_loop_destroy(belle_sip_main_loop_t *ml){
belle_sip_main_loop_remove_source (ml,ml->control);
belle_sip_source_destroy(ml->control);
close(ml->control_fds[0]);
close(ml->control_fds[1]);
belle_sip_free(ml);
}
/*
belle-sip - SIP (RFC3261) library.
Copyright (C) 2010 Belledonne Communications SARL
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "belle_sip_resolver.h"
void belle_sip_resolver_context_destroy(belle_sip_resolver_context_t *ctx){
if (ctx->thread!=0){
if (!ctx->exited){
ctx->cancelled=1;
pthread_cancel(ctx->thread);
}
pthread_join(ctx->thread,NULL);
}
if (ctx->name)
belle_sip_free(ctx->name);
if (ctx->ai){
freeaddrinfo(ctx->ai);
}
belle_sip_free(ctx);
}
static int resolver_callback(belle_sip_resolver_context_t *ctx){
ctx->cb(ctx->cb_data, ctx->name, ctx->ai);
return 0;
}
belle_sip_resolver_context_t *belle_sip_resolver_context_new(){
belle_sip_resolver_context_t *ctx=belle_sip_new0(belle_sip_resolver_context_t);
if (pipe(ctx->ctlpipe)==-1){
belle_sip_fatal("pipe() failed: %s",strerror(errno));
}
belle_sip_fd_source_init(&ctx->source,(belle_sip_source_func_t)resolver_callback,ctx,ctx->ctlpipe[0],BELLE_SIP_EVENT_READ,-1);
ctx->source.on_remove=(belle_sip_source_remove_callback_t)belle_sip_resolver_context_destroy;
return ctx;
}
static void *belle_sip_resolver_thread(void *ptr){
belle_sip_resolver_context_t *ctx=(belle_sip_resolver_context_t *)ptr;
if (write(ctx->ctlpipe[1],"q",1)==-1){
belle_sip_error("belle_sip_resolver_thread(): Fail to write on pipe.");
}
return NULL;
}
unsigned long belle_sip_resolve(const char *name, unsigned int hints, belle_sip_resolver_callback_t cb , void *data, belle_sip_main_loop_t *ml){
belle_sip_resolver_context_t *ctx=belle_sip_resolver_context_new();
ctx->cb_data=data;
ctx->cb=cb;
ctx->name=belle_sip_strdup(name);
ctx->hints=hints;
belle_sip_main_loop_add_source(ml,(belle_sip_source_t*)ctx);
pthread_create(&ctx->thread,NULL,belle_sip_resolver_thread,ctx);
return ctx->source.id;
}
/*
belle-sip - SIP (RFC3261) library.
Copyright (C) 2010 Belledonne Communications SARL
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef belle_sip_resolver_h
#define belle_sip_resolver_h
#include "belle_sip_internal.h"
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <pthread.h>
#define BELLE_SIP_RESOLVER_HINT_IPV6 (1)
#define BELLE_SIP_RESOLVER_HINT_SRV (1<<1)
typedef struct belle_sip_resolver_context belle_sip_resolver_context_t;
typedef void (*belle_sip_resolver_callback_t)(void *data, const char *name, const struct addrinfo *result);
struct belle_sip_resolver_context{
belle_sip_source_t source;
belle_sip_resolver_callback_t cb;
void *cb_data;
char *name;
struct addrinfo *ai;
unsigned int hints;
pthread_t thread;
int ctlpipe[2];
uint8_t cancelled;
uint8_t exited;
};
unsigned long belle_sip_resolve(const char *name, unsigned int hints, belle_sip_resolver_callback_t cb , void *data, belle_sip_main_loop_t *ml);
#endif
......@@ -18,6 +18,8 @@
#include "belle_sip_internal.h"
#include <time.h>
static FILE *__log_file=0;
......@@ -417,6 +419,25 @@ void belle_sip_free(void *ptr){
free(ptr);
}
char * belle_sip_strdup(const char *s){
return strdup(s);
}
uint64_t belle_sip_time_ms(void){
struct timespec ts;
static int clock_id=CLOCK_MONOTONIC;
if (clock_gettime(clock_id,&ts)==-1){
belle_sip_error("clock_gettime() error for clock_id=%i: %s",clock_id,strerror(errno));
if (clock_id==CLOCK_MONOTONIC){
clock_id=CLOCK_REALTIME;
return belle_sip_time_ms();
}
return 0;
}
return (ts.tv_sec*1000LL) + (ts.tv_nsec/1000000LL);
}
/**
* parser parameter pair
*/
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment