parse_fline.c 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247
  1. /*
  2. * sip first line parsing automaton
  3. *
  4. * Copyright (C) 2001-2003 FhG Fokus
  5. *
  6. * This file is part of ser, a free SIP server.
  7. *
  8. * ser is free software; you can redistribute it and/or modify
  9. * it under the terms of the GNU General Public License as published by
  10. * the Free Software Foundation; either version 2 of the License, or
  11. * (at your option) any later version
  12. *
  13. * For a license to use the ser software under conditions
  14. * other than those described here, or to purchase support for this
  15. * software, please contact iptel.org by e-mail at the following addresses:
  16. * [email protected]
  17. *
  18. * ser is distributed in the hope that it will be useful,
  19. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  20. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  21. * GNU General Public License for more details.
  22. *
  23. * You should have received a copy of the GNU General Public License
  24. * along with this program; if not, write to the Free Software
  25. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  26. *
  27. * History:
  28. * ---------
  29. * 2003-02-28 scratchpad compatibility abandoned (jiri)
  30. * 2003-01-28: removed 0-terminators from first line (jiri)
  31. * 2003-04-26 ZSW (jiri)
  32. */
  33. /*! \file
  34. * \brief Parser :: SIP first line parsing automaton
  35. *
  36. * \ingroup parser
  37. */
  38. #include "../comp_defs.h"
  39. #include "../dprint.h"
  40. #include "msg_parser.h"
  41. #include "parser_f.h"
  42. #include "../mem/mem.h"
  43. #include "../ut.h"
  44. int http_reply_parse = 0;
  45. /* grammar:
  46. request = method SP uri SP version CRLF
  47. response = version SP status SP reason CRLF
  48. (version = "SIP/2.0")
  49. */
  50. /* parses the first line, returns pointer to next line & fills fl;
  51. also modifies buffer (to avoid extra copy ops) */
  52. char* parse_first_line(char* buffer, unsigned int len, struct msg_start * fl)
  53. {
  54. char *tmp;
  55. char* second;
  56. char* third;
  57. char* nl;
  58. int offset;
  59. /* int l; */
  60. char* end;
  61. char s1,s2,s3;
  62. char *prn;
  63. unsigned int t;
  64. /* grammar:
  65. request = method SP uri SP version CRLF
  66. response = version SP status SP reason CRLF
  67. (version = "SIP/2.0")
  68. */
  69. offset = 0;
  70. end=buffer+len;
  71. /* see if it's a reply (status) */
  72. /* jku -- parse well-known methods */
  73. /* drop messages which are so short they are for sure useless;
  74. utilize knowledge of minimum size in parsing the first
  75. token
  76. */
  77. if (len <=16 ) {
  78. LOG(L_INFO, "ERROR: parse_first_line: message too short: %d\n", len);
  79. goto error1;
  80. }
  81. tmp=buffer;
  82. /* is it perhaps a reply, ie does it start with "SIP...." ? */
  83. if ( (*tmp=='S' || *tmp=='s') &&
  84. strncasecmp( tmp+1, SIP_VERSION+1, SIP_VERSION_LEN-1)==0 &&
  85. (*(tmp+SIP_VERSION_LEN)==' ')) {
  86. fl->type=SIP_REPLY;
  87. fl->u.reply.version.len=SIP_VERSION_LEN;
  88. tmp=buffer+SIP_VERSION_LEN;
  89. } else if (http_reply_parse != 0 &&
  90. (*tmp=='H' || *tmp=='h') &&
  91. /* 'HTTP/1.' */
  92. strncasecmp( tmp+1, HTTP_VERSION+1, HTTP_VERSION_LEN-1)==0 &&
  93. /* [0|1] */
  94. ((*(tmp+HTTP_VERSION_LEN)=='0') || (*(tmp+HTTP_VERSION_LEN)=='1')) &&
  95. (*(tmp+HTTP_VERSION_LEN+1)==' ') ){
  96. /* ugly hack to be able to route http replies
  97. * Note: - the http reply must have a via
  98. * - the message is marked as SIP_REPLY (ugly)
  99. */
  100. fl->type=SIP_REPLY;
  101. fl->u.reply.version.len=HTTP_VERSION_LEN+1 /*include last digit*/;
  102. tmp=buffer+HTTP_VERSION_LEN+1 /* last digit */;
  103. } else IFISMETHOD( INVITE, 'I' )
  104. else IFISMETHOD( CANCEL, 'C')
  105. else IFISMETHOD( ACK, 'A' )
  106. else IFISMETHOD( BYE, 'B' )
  107. else IFISMETHOD( INFO, 'I' )
  108. else IFISMETHOD( REGISTER, 'R')
  109. else IFISMETHOD( SUBSCRIBE, 'S')
  110. else IFISMETHOD( NOTIFY, 'N')
  111. else IFISMETHOD( MESSAGE, 'M')
  112. else IFISMETHOD( OPTIONS, 'O')
  113. else IFISMETHOD( PRACK, 'P')
  114. else IFISMETHOD( UPDATE, 'U')
  115. else IFISMETHOD( REFER, 'R')
  116. else IFISMETHOD( PUBLISH, 'P')
  117. /* if you want to add another method XXX, include METHOD_XXX in
  118. H-file (this is the value which you will take later in
  119. processing and define XXX_LEN as length of method name;
  120. then just call IFISMETHOD( XXX, 'X' ) ... 'X' is the first
  121. latter; everything must be capitals
  122. */
  123. else {
  124. /* neither reply, nor any of known method requests,
  125. let's believe it is an unknown method request
  126. */
  127. tmp=eat_token_end(buffer,buffer+len);
  128. if ((tmp==buffer)||(tmp>=end)){
  129. LOG(L_INFO, "ERROR:parse_first_line: empty or bad first line\n");
  130. goto error1;
  131. }
  132. if (*tmp!=' ') {
  133. LOG(L_INFO, "ERROR:parse_first_line: method not followed by SP\n");
  134. goto error1;
  135. }
  136. fl->type=SIP_REQUEST;
  137. fl->u.request.method_value=METHOD_OTHER;
  138. fl->u.request.method.len=tmp-buffer;
  139. }
  140. /* identifying type of message over now;
  141. tmp points at space after; go ahead */
  142. fl->u.request.method.s=buffer; /* store ptr to first token */
  143. second=tmp+1; /* jump to second token */
  144. offset=second-buffer;
  145. /* EoJku */
  146. /* next element */
  147. tmp=eat_token_end(second, second+len-offset);
  148. if (tmp>=end){
  149. goto error;
  150. }
  151. offset+=tmp-second;
  152. third=eat_space_end(tmp, tmp+len-offset);
  153. offset+=third-tmp;
  154. if ((third==tmp)||(tmp>=end)){
  155. goto error;
  156. }
  157. fl->u.request.uri.s=second;
  158. fl->u.request.uri.len=tmp-second;
  159. /* jku: parse status code */
  160. if (fl->type==SIP_REPLY) {
  161. if (fl->u.request.uri.len!=3) {
  162. LOG(L_INFO, "ERROR:parse_first_line: len(status code)!=3: %.*s\n",
  163. fl->u.request.uri.len, ZSW(second) );
  164. goto error;
  165. }
  166. s1=*second; s2=*(second+1);s3=*(second+2);
  167. if (s1>='0' && s1<='9' &&
  168. s2>='0' && s2<='9' &&
  169. s3>='0' && s3<='9' ) {
  170. fl->u.reply.statuscode=(s1-'0')*100+10*(s2-'0')+(s3-'0');
  171. } else {
  172. LOG(L_INFO, "ERROR:parse_first_line: status_code non-numerical: %.*s\n",
  173. fl->u.request.uri.len, ZSW(second) );
  174. goto error;
  175. }
  176. }
  177. /* EoJku */
  178. /* last part: for a request it must be the version, for a reply
  179. * it can contain almost anything, including spaces, so we don't care
  180. * about it*/
  181. if (fl->type==SIP_REQUEST){
  182. tmp=eat_token_end(third,third+len-offset);
  183. offset+=tmp-third;
  184. if ((tmp==third)||(tmp>=end)){
  185. goto error;
  186. }
  187. if (! is_empty_end(tmp, tmp+len-offset)){
  188. goto error;
  189. }
  190. }else{
  191. tmp=eat_token2_end(third,third+len-offset,'\r'); /* find end of line
  192. ('\n' or '\r') */
  193. if (tmp>=end){ /* no crlf in packet => invalid */
  194. goto error;
  195. }
  196. offset+=tmp-third;
  197. }
  198. nl=eat_line(tmp,len-offset);
  199. if (nl>=end){ /* no crlf in packet or only 1 line > invalid */
  200. goto error;
  201. }
  202. fl->u.request.version.s=third;
  203. fl->u.request.version.len=tmp-third;
  204. fl->len=nl-buffer;
  205. return nl;
  206. error:
  207. LOG(L_DBG, "parse_first_line: bad %s first line\n",
  208. (fl->type==SIP_REPLY)?"reply(status)":"request");
  209. LOG(L_DBG, "at line 0 char %d: \n", offset );
  210. prn=pkg_malloc( offset );
  211. if (prn) {
  212. for (t=0; t<offset; t++)
  213. if (*(buffer+t)) *(prn+t)=*(buffer+t);
  214. else *(prn+t)=176; /* '°' */
  215. LOG(L_DBG, "parsed so far: %.*s\n", offset, ZSW(prn) );
  216. pkg_free( prn );
  217. };
  218. error1:
  219. fl->type=SIP_INVALID;
  220. LOG(L_ERR, "parse_first_line: bad message (offset: %d)\n", offset);
  221. /* skip line */
  222. nl=eat_line(buffer,len);
  223. return nl;
  224. }