Commit 16e30ac6 authored by jehan's avatar jehan
Browse files

rework uri parser

parent 5af50a06
/*
* belle_sip_list.h
*
* Created on: 1 oct. 2010
* Author: jehanmonnier
*/
#ifndef BELLE_SIP_LIST_H_
#define BELLE_SIP_LIST_H_
typedef struct _belle_sip_list belle_sip_list;
belle_sip_list * belle_sip_list_append(belle_sip_list *elem, void * data);
belle_sip_list * belle_sip_list_prepend(belle_sip_list *elem, void * data);
belle_sip_list * belle_sip_list_free(belle_sip_list *elem);
belle_sip_list * belle_sip_list_concat(belle_sip_list *first, belle_sip_list *second);
belle_sip_list * belle_sip_list_remove(belle_sip_list *first, void *data);
int belle_sip_list_size(const belle_sip_list *first);
void belle_sip_list_for_each(const belle_sip_list *list, void (*func)(void *));
void belle_sip_list_for_each2(const belle_sip_list *list, void (*func)(void *, void *), void *user_data);
belle_sip_list *belle_sip_list_remove_link(belle_sip_list *list, belle_sip_list *elem);
belle_sip_list *belle_sip_list_find(belle_sip_list *list, void *data);
belle_sip_list *belle_sip_list_find_custom(belle_sip_list *list, int (*compare_func)(const void *, const void*), void *user_data);
void * belle_sip_list_nth_data(const belle_sip_list *list, int index);
int belle_sip_list_position(const belle_sip_list *list, belle_sip_list *elem);
int belle_sip_list_index(const belle_sip_list *list, void *data);
belle_sip_list *belle_sip_list_insert_sorted(belle_sip_list *list, void *data, int (*compare_func)(const void *, const void*));
belle_sip_list *belle_sip_list_insert(belle_sip_list *list, belle_sip_list *before, void *data);
belle_sip_list *belle_sip_list_copy(const belle_sip_list *list);
#endif /* BELLE_SIP_LIST_H_ */
grammar belle_sip_uri;
options { language = C;}
options {
language = C;
}
@header { #include "belle_sip_uri.h"}
an_sip_uri returns [belle_sip_uri* ret]
scope { belle_sip_uri* current; }
@init { $an_sip_uri::current = belle_sip_uri_new(); }
: sip_schema userinfo? hostport uri_parameters headers? {$ret = $an_sip_uri::current;};
: sip_schema ((userinfo hostport) | hostport ) uri_parameters? headers? {$ret = $an_sip_uri::current;};
sip_schema : ('sip' | is_sips='sips') ':' {if ($is_sips) belle_sip_uri_set_secure($an_sip_uri::current,1);};
userinfo : user ( ':' password )? '@' ;
user : ( unreserved | escaped | user_unreserved )+ {belle_sip_uri_set_user($an_sip_uri::current,(const char *)$text->chars);};
......@@ -14,43 +17,44 @@ user_unreserved : '&' | '=' | '+' | '$' | ',' | ';' | '?' | '/';
password : ( unreserved |'&' | '=' | '+' | '$' | ',' )*;
hostport : host ( ':' port )? {belle_sip_uri_set_host($an_sip_uri::current,(const char *)$host.text->chars);};
host : (hostname | ipv4address | ipv6reference) ;
fragment hostname : ( domainlabel '.' )* toplabel '.'? ;
hostname : ( domainlabel '.' )* toplabel '.'? ;
fragment domainlabel : alphanum | alphanum ( alphanum | '-' )* alphanum ;
fragment toplabel : ALPHA | ALPHA ( alphanum | '-' )* alphanum;
domainlabel : alphanum | (alphanum ( alphanum | '-' )* alphanum) ;
toplabel : alpha | (alpha ( alphanum | '-' )* alphanum) ;
ipv4address : three_digit '.' three_digit '.' three_digit '.' three_digit;
ipv6reference : '[' ipv6address ']';
ipv6address : hexpart ( ':' ipv4address )?;
fragment hexpart : hexseq | hexseq '::' ( hexseq )? | '::' ( hexseq )?;
fragment hexseq : hex4 ( ':' hex4)*;
fragment hex4 : HEXDIG HEXDIG HEXDIG HEXDIG ;
hexpart : hexseq | hexseq '::' ( hexseq )? | '::' ( hexseq )?;
hexseq : hex4 ( ':' hex4)*;
hex4 : hexdigit hexdigit hexdigit hexdigit ;
port : DIGIT+ {belle_sip_uri_set_port($an_sip_uri::current,atoi((const char *)$text->chars));};
uri_parameters
: ( ';' uri_parameter)*;
: ( ';' uri_parameter)+;
uri_parameter
: transport_param | user_param
| ttl_param | maddr_param | lr_param | other_param ;
: {strcmp("transport=",(const char*)(INPUT->toStringTT(INPUT,LT(1),LT(10)))->chars) == 0}? transport_param
| {strcmp("user=",(const char*)(INPUT->toStringTT(INPUT,LT(1),LT(5)))->chars) == 0}? user_param
| {strcmp("ttl=",(const char*)(INPUT->toStringTT(INPUT,LT(1),LT(4)))->chars) == 0}? ttl_param
| {strcmp("maddr=",(const char*)(INPUT->toStringTT(INPUT,LT(1),LT(6)))->chars) == 0}? maddr_param
| {strcmp("lr",(const char*)(INPUT->toStringTT(INPUT,LT(1),LT(2)))->chars) == 0}? lr_param
| other_param ;
transport_param
: 'transport=' transport_value;
transport_value: ('udp' | 'tcp' | 'sctp' | 'tls'| other_transport)
: pname '=' transport_value;
transport_value: token
{belle_sip_uri_set_transport_param($an_sip_uri::current,(const char *)$text->chars);};
other_transport
: token ;
user_param
: 'user=' ( 'phone' | 'ip' | other_user);
other_user
: token;
: other_param;
ttl_param
: 'ttl=' ttl;
: pname '=' ttl;
maddr_param
: 'maddr=' host {belle_sip_uri_set_maddr_param($an_sip_uri::current,(const char *)$host.text->chars);};
: pname '=' host {belle_sip_uri_set_maddr_param($an_sip_uri::current,(const char *)$host.text->chars);};
lr_param
: 'lr' {belle_sip_uri_set_lr_param($an_sip_uri::current,1);};
: alpha alpha {belle_sip_uri_set_lr_param($an_sip_uri::current,1);};
other_param : pname ( '=' pvalue )?;
pname
: paramchar+;
......@@ -62,23 +66,30 @@ param_unreserved
: '[' | ']' | '/' | ':' | '&' | '+' | '$';
headers : '?' header ( '&' header )* ;
header : hname '=' hvalue;
header : hname '=' hvalue? {belle_sip_uri_set_header($an_sip_uri::current,$hname.text->chars,$hvalue.text->chars);};
hname : ( hnv_unreserved | unreserved | escaped )+;
hvalue : ( hnv_unreserved | unreserved | escaped )*;
hvalue : ( hnv_unreserved | unreserved | escaped )+;
fragment hnv_unreserved : '[' | ']' | '|' | '?' | ':' | '+' | '$' ;
fragment escaped : '%' HEXDIG HEXDIG;
fragment ttl : three_digit;
fragment three_digit: DIGIT DIGIT? DIGIT? ;
fragment token
hnv_unreserved : '[' | ']' | '|' | '?' | ':' | '+' | '$' ;
escaped : '%' hexdigit hexdigit;
ttl : three_digit;
three_digit: DIGIT | (DIGIT DIGIT) | (DIGIT DIGIT DIGIT) ;
token
: (alphanum | MARK_LEX | '%' | '+' | '`' )+;
fragment unreserved : alphanum |MARK_LEX;
fragment alphanum : ALPHA | DIGIT ;
fragment MARK_LEX : '-' | '_' | '.' | '!' | '~' | '*' | '\'' ;
fragment HEXDIG
: 'a'..'f' |'A'..'F'|DIGIT;
ALPHA : ('a'..'z'|'A'..'Z');
unreserved : alphanum |MARK_LEX;
alphanum : alpha | DIGIT ;
hexdigit
: HEX_CHAR|DIGIT;
alpha : HEX_CHAR | COMMON_CHAR;
COMMON_CHAR
: 'g'..'z' | 'G'..'Z' ;
MARK_LEX : '-' | '_' | '.' | '!' | '~' | '*' | '\'' ;
HEX_CHAR: 'a'..'f' |'A'..'F';
DIGIT : '0'..'9' ;
#include <stdlib.h>
#include <string.h>
#include <stdarg.h>
#include <stdio.h>
#include "belle_sip_utils.h"
static FILE *__log_file=0;
/**
*@param file a FILE pointer where to output the belle logs.
*
**/
void belle_sip_set_log_file(FILE *file)
{
__log_file=file;
}
static void __belle_sip_logv_out(belle_sip_log_level lev, const char *fmt, va_list args);
belle_sip_log_function belle_sip_logv_out=__belle_sip_logv_out;
/**
*@param func: your logging function, compatible with the OrtpLogFunc prototype.
*
**/
void belle_sip_set_log_handler(belle_sip_log_function func){
belle_sip_logv_out=func;
}
unsigned int __belle_sip_log_mask=BELLE_SIP_WARNING|BELLE_SIP_ERROR|BELLE_SIP_FATAL;
/**
* @ param levelmask a mask of BELLE_SIP_DEBUG, BELLE_SIP_MESSAGE, BELLE_SIP_WARNING, BELLE_SIP_ERROR
* BELLE_SIP_FATAL .
**/
void belle_sip_set_log_level_mask(int levelmask){
__belle_sip_log_mask=levelmask;
}
char * belle_sip_strdup_vprintf(const char *fmt, va_list ap)
{
/* Guess we need no more than 100 bytes. */
int n, size = 200;
char *p,*np;
#ifndef WIN32
va_list cap;/*copy of our argument list: a va_list cannot be re-used (SIGSEGV on linux 64 bits)*/
#endif
if ((p = (char *) malloc (size)) == NULL)
return NULL;
while (1)
{
/* Try to print in the allocated space. */
#ifndef WIN32
va_copy(cap,ap);
n = vsnprintf (p, size, fmt, cap);
va_end(cap);
#else
/*this works on 32 bits, luckily*/
n = vsnprintf (p, size, fmt, ap);
#endif
/* If that worked, return the string. */
if (n > -1 && n < size)
return p;
//printf("Reallocing space.\n");
/* Else try again with more space. */
if (n > -1) /* glibc 2.1 */
size = n + 1; /* precisely what is needed */
else /* glibc 2.0 */
size *= 2; /* twice the old size */
if ((np = (char *) realloc (p, size)) == NULL)
{
free(p);
return NULL;
}
else
{
p = np;
}
}
}
char *belle_sip_strdup_printf(const char *fmt,...){
char *ret;
va_list args;
va_start (args, fmt);
ret=belle_sip_strdup_vprintf(fmt, args);
va_end (args);
return ret;
}
#if defined(WIN32) || defined(_WIN32_WCE)
#define ENDLINE "\r\n"
#else
#define ENDLINE "\n"
#endif
#if defined(WIN32) || defined(_WIN32_WCE)
void belle_sip_logv(int level, const char *fmt, va_list args)
{
if (belle_sip_logv_out!=NULL && belle_sip_log_level_enabled(level))
belle_sip_logv_out(level,fmt,args);
#if !defined(_WIN32_WCE)
if ((level)==BELLE_SIP_FATAL) abort();
#endif
}
#endif
static void __belle_sip_logv_out(belle_sip_log_level lev, const char *fmt, va_list args){
const char *lname="undef";
char *msg;
if (__log_file==NULL) __log_file=stderr;
switch(lev){
case BELLE_SIP_DEBUG:
lname="debug";
break;
case BELLE_SIP_MESSAGE:
lname="message";
break;
case BELLE_SIP_WARNING:
lname="warning";
break;
case BELLE_SIP_ERROR:
lname="error";
break;
case BELLE_SIP_FATAL:
lname="fatal";
break;
default:
belle_sip_fatal("Bad level !");
}
msg=belle_sip_strdup_vprintf(fmt,args);
#if defined(_MSC_VER) && !defined(_WIN32_WCE)
OutputDebugString(msg);
OutputDebugString("\r\n");
#endif
fprintf(__log_file,"belle-sip-%s-%s" ENDLINE,lname,msg);
fflush(__log_file);
free(msg);
}
belle_sip_list *belle_sip_list_new(void *data){
belle_sip_list *new_elem=(belle_sip_list *)malloc(sizeof(belle_sip_list));
memset(new_elem,0,sizeof(belle_sip_list));
new_elem->prev=new_elem->next=NULL;
new_elem->data=data;
return new_elem;
}
belle_sip_list * belle_sip_list_append(belle_sip_list *elem, void * data){
belle_sip_list *new_elem=belle_sip_list_new(data);
belle_sip_list *it=elem;
if (elem==NULL) return new_elem;
while (it->next!=NULL) it=belle_sip_list_next(it);
it->next=new_elem;
new_elem->prev=it;
return elem;
}
belle_sip_list * belle_sip_list_prepend(belle_sip_list *elem, void *data){
belle_sip_list *new_elem=belle_sip_list_new(data);
if (elem!=NULL) {
new_elem->next=elem;
elem->prev=new_elem;
}
return new_elem;
}
belle_sip_list * belle_sip_list_concat(belle_sip_list *first, belle_sip_list *second){
belle_sip_list *it=first;
if (it==NULL) return second;
while(it->next!=NULL) it=belle_sip_list_next(it);
it->next=second;
second->prev=it;
return first;
}
belle_sip_list * belle_sip_list_free(belle_sip_list *list){
belle_sip_list *elem = list;
belle_sip_list *tmp;
if (list==NULL) return NULL;
while(elem->next!=NULL) {
tmp = elem;
elem = elem->next;
free(tmp);
}
free(elem);
return NULL;
}
belle_sip_list * belle_sip_list_remove(belle_sip_list *first, void *data){
belle_sip_list *it;
it=belle_sip_list_find(first,data);
if (it) return belle_sip_list_remove_link(first,it);
else {
belle_sip_warning("belle_sip_list_remove: no element with %p data was in the list", data);
return first;
}
}
int belle_sip_list_size(const belle_sip_list *first){
int n=0;
while(first!=NULL){
++n;
first=first->next;
}
return n;
}
void belle_sip_list_for_each(const belle_sip_list *list, void (*func)(void *)){
for(;list!=NULL;list=list->next){
func(list->data);
}
}
void belle_sip_list_for_each2(const belle_sip_list *list, void (*func)(void *, void *), void *user_data){
for(;list!=NULL;list=list->next){
func(list->data,user_data);
}
}
belle_sip_list *belle_sip_list_remove_link(belle_sip_list *list, belle_sip_list *elem){
belle_sip_list *ret;
if (elem==list){
ret=elem->next;
elem->prev=NULL;
elem->next=NULL;
if (ret!=NULL) ret->prev=NULL;
free(elem);
return ret;
}
elem->prev->next=elem->next;
if (elem->next!=NULL) elem->next->prev=elem->prev;
elem->next=NULL;
elem->prev=NULL;
free(elem);
return list;
}
belle_sip_list *belle_sip_list_find(belle_sip_list *list, void *data){
for(;list!=NULL;list=list->next){
if (list->data==data) return list;
}
return NULL;
}
belle_sip_list *belle_sip_list_find_custom(belle_sip_list *list, int (*compare_func)(const void *, const void*), void *user_data){
for(;list!=NULL;list=list->next){
if (compare_func(list->data,user_data)==0) return list;
}
return NULL;
}
void * belle_sip_list_nth_data(const belle_sip_list *list, int index){
int i;
for(i=0;list!=NULL;list=list->next,++i){
if (i==index) return list->data;
}
belle_sip_error("belle_sip_list_nth_data: no such index in list.");
return NULL;
}
int belle_sip_list_position(const belle_sip_list *list, belle_sip_list *elem){
int i;
for(i=0;list!=NULL;list=list->next,++i){
if (elem==list) return i;
}
belle_sip_error("belle_sip_list_position: no such element in list.");
return -1;
}
int belle_sip_list_index(const belle_sip_list *list, void *data){
int i;
for(i=0;list!=NULL;list=list->next,++i){
if (data==list->data) return i;
}
belle_sip_error("belle_sip_list_index: no such element in list.");
return -1;
}
belle_sip_list *belle_sip_list_insert_sorted(belle_sip_list *list, void *data, int (*compare_func)(const void *, const void*)){
belle_sip_list *it,*previt=NULL;
belle_sip_list *nelem;
belle_sip_list *ret=list;
if (list==NULL) return belle_sip_list_append(list,data);
else{
nelem=belle_sip_list_new(data);
for(it=list;it!=NULL;it=it->next){
previt=it;
if (compare_func(data,it->data)<=0){
nelem->prev=it->prev;
nelem->next=it;
if (it->prev!=NULL)
it->prev->next=nelem;
else{
ret=nelem;
}
it->prev=nelem;
return ret;
}
}
previt->next=nelem;
nelem->prev=previt;
}
return ret;
}
belle_sip_list *belle_sip_list_insert(belle_sip_list *list, belle_sip_list *before, void *data){
belle_sip_list *elem;
if (list==NULL || before==NULL) return belle_sip_list_append(list,data);
for(elem=list;elem!=NULL;elem=belle_sip_list_next(elem)){
if (elem==before){
if (elem->prev==NULL)
return belle_sip_list_prepend(list,data);
else{
belle_sip_list *nelem=belle_sip_list_new(data);
nelem->prev=elem->prev;
nelem->next=elem;
elem->prev->next=nelem;
elem->prev=nelem;
}
}
}
return list;
}
belle_sip_list *belle_sip_list_copy(const belle_sip_list *list){
belle_sip_list *copy=NULL;
const belle_sip_list *iter;
for(iter=list;iter!=NULL;iter=belle_sip_list_next(iter)){
copy=belle_sip_list_append(copy,iter->data);
}
return copy;
}
char * belle_sip_concat (const char *str, ...) {
va_list ap;
size_t allocated = 100;
char *result = (char *) malloc (allocated);
if (result != NULL)
{
char *newp;
char *wp;
const char* s;
va_start (ap, str);
wp = result;
for (s = str; s != NULL; s = va_arg (ap, const char *)) {
size_t len = strlen (s);
/* Resize the allocated memory if necessary. */
if (wp + len + 1 > result + allocated)
{
allocated = (allocated + len) * 2;
newp = (char *) realloc (result, allocated);
if (newp == NULL)
{
free (result);
return NULL;
}
wp = newp + (wp - result);
result = newp;
}
memcpy (wp, s, len);
wp +=len;
}
/* Terminate the result string. */
*wp++ = '\0';
/* Resize memory to the optimal size. */
newp = realloc (result, wp - result);
if (newp != NULL)
result = newp;
va_end (ap);
}
return result;
}
#ifndef belle_utils_h
#define belle_utils_h
#include "belle_sip_list.h"
struct _belle_sip_list {
struct _belle_sip_list *next;
struct _belle_sip_list *prev;
void *data;
};
#define belle_list_next(elem) ((elem)->next)
#ifdef __cplusplus
extern "C"{
#endif
belle_sip_list *belle_sip_list_new(void *data);
belle_sip_list * belle_sip_list_free(belle_sip_list *list);
#define belle_sip_list_next(elem) ((elem)->next)
/***************/
/* logging api */
/***************/
typedef enum {
BELLE_SIP_DEBUG=1,
BELLE_SIP_MESSAGE=1<<1,
BELLE_SIP_WARNING=1<<2,
BELLE_SIP_ERROR=1<<3,
BELLE_SIP_FATAL=1<<4,
BELLE_SIP_LOGLEV_END=1<<5
} belle_sip_log_level;
typedef void (*belle_sip_log_function)(belle_sip_log_level lev, const char *fmt, va_list args);
void belle_sip_set_log_file(FILE *file);
void belle_sip_set_log_handler(belle_sip_log_function func);
extern belle_sip_log_function belle_sip_logv_out;
extern unsigned int __belle_sip_log_mask;
#define belle_sip_log_level_enabled(level) (__belle_sip_log_mask & (level))
#if !defined(WIN32) && !defined(_WIN32_WCE)
#define belle_sip_logv(level,fmt,args) \
{\
if (belle_sip_logv_out!=NULL && belle_sip_log_level_enabled(level)) \
belle_sip_logv_out(level,fmt,args);\
if ((level)==BELLE_SIP_FATAL) abort();\
}while(0)
#else
void belle_sip_logv(int level, const char *fmt, va_list args);
#endif
void belle_sip_set_log_level_mask(int levelmask);
#ifdef BELLE_SIP_DEBUG_MODE
static inline void belle_sip_debug(const char *fmt,...)
{
va_list args;
va_start (args, fmt);
belle_sip_logv(BELLE_SIP_DEBUG, fmt, args);
va_end (args);
}
#else
#define belle_sip_debug(...)
#endif
#ifdef BELLE_SIP_NOMESSAGE_MODE
#define belle_sip_log(...)
#define belle_sip_message(...)
#define belle_sip_warning(...)
#else