f3b31fefbc9e80e9f80f817f93c3e7d4a821df36
[kamailio] / src / core / receive.c
1 /*
2  * Copyright (C) 2001-2003 FhG Fokus
3  *
4  * This file is part of Kamailio, a free SIP server.
5  *
6  * Kamailio is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version
10  *
11  * Kamailio is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
19  *
20  */
21
22 /*!
23  * \file
24  * \brief Kamailio core ::
25  * \ingroup core
26  * Module: \ref core
27  */
28
29
30 #include <string.h>
31 #include <stdlib.h>
32 #include <sys/time.h>
33
34 #include "receive.h"
35 #include "globals.h"
36 #include "dprint.h"
37 #include "route.h"
38 #include "parser/msg_parser.h"
39 #include "forward.h"
40 #include "action.h"
41 #include "mem/mem.h"
42 #include "ip_addr.h"
43 #include "script_cb.h"
44 #include "nonsip_hooks.h"
45 #include "dset.h"
46 #include "fmsg.h"
47 #include "usr_avp.h"
48 #include "xavp.h"
49 #include "select_buf.h"
50 #include "locking.h"
51
52 #include "tcp_server.h"  /* for tcpconn_add_alias */
53 #include "tcp_options.h" /* for access to tcp_accept_aliases*/
54 #include "cfg/cfg.h"
55 #include "core_stats.h"
56 #include "kemi.h"
57
58 #ifdef DEBUG_DMALLOC
59 #include <mem/dmalloc.h>
60 #endif
61
62 int _sr_ip_free_bind = 0;
63
64 unsigned int msg_no = 0;
65 /* address preset vars */
66 str default_global_address = {0, 0};
67 str default_global_port = {0, 0};
68 str default_via_address = {0, 0};
69 str default_via_port = {0, 0};
70
71 int ksr_route_locks_size = 0;
72 static rec_lock_set_t* ksr_route_locks_set = NULL;
73
74 int ksr_route_locks_set_init(void)
75 {
76         if(ksr_route_locks_set!=NULL || ksr_route_locks_size<=0)
77                 return 0;
78
79         ksr_route_locks_set = rec_lock_set_alloc(ksr_route_locks_size);
80         if(ksr_route_locks_set==NULL) {
81                 LM_ERR("failed to allocate route locks set\n");
82                 return -1;
83         }
84         if(rec_lock_set_init(ksr_route_locks_set)==NULL) {
85                 LM_ERR("failed to init route locks set\n");
86                 return -1;
87         }
88         return 0;
89 }
90
91 void ksr_route_locks_set_destroy(void)
92 {
93         if(ksr_route_locks_set==NULL)
94                 return;
95
96         rec_lock_set_destroy(ksr_route_locks_set);
97         rec_lock_set_dealloc(ksr_route_locks_set);
98         ksr_route_locks_set = NULL;
99 }
100
101 /**
102  * increment msg_no and return the new value
103  */
104 unsigned int inc_msg_no(void)
105 {
106         return ++msg_no;
107 }
108
109 /**
110  *
111  */
112 int sip_check_fline(char *buf, unsigned int len)
113 {
114         char *p;
115         int m;
116
117         m = 0;
118         for(p = buf; p < buf + len; p++) {
119                 /* first check if is a reply - starts with SIP/2.0 */
120                 if(m == 0) {
121                         if(*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n')
122                                 continue;
123                         if(buf + len - p < 10)
124                                 return -1;
125                         if(strncmp(p, "SIP/2.0 ", 8) == 0) {
126                                 LM_DBG("first line indicates a SIP reply\n");
127                                 return 0;
128                         }
129                         m = 1;
130                 } else {
131                         /* check if a request - before end of first line is SIP/2.0 */
132                         if(*p != '\r' && *p != '\n')
133                                 continue;
134                         if(p - 10 >= buf) {
135                                 if(strncmp(p - 8, " SIP/2.0", 8) == 0) {
136                                         LM_DBG("first line indicates a SIP request\n");
137                                         return 0;
138                                 }
139                         }
140                         return -1;
141                 }
142         }
143         return -1;
144 }
145
146 /**
147  *
148  */
149 static sr_net_info_t *ksr_evrt_rcvnetinfo = NULL;
150 int ksr_evrt_received_mode = 0;
151 str kemi_received_route_callback = STR_NULL;
152
153 /**
154  *
155  */
156 sr_net_info_t *ksr_evrt_rcvnetinfo_get(void)
157 {
158         return ksr_evrt_rcvnetinfo;
159 }
160
161 /**
162  *
163  */
164 int ksr_evrt_received(char *buf, unsigned int len, receive_info_t *rcv_info)
165 {
166         sr_kemi_eng_t *keng = NULL;
167         sr_net_info_t netinfo;
168         int ret = 0;
169         int rt = -1;
170         run_act_ctx_t ra_ctx;
171         run_act_ctx_t *bctx = NULL;
172         sip_msg_t *fmsg = NULL;
173         str evname = str_init("core:msg-received");
174
175         if(len==0 || rcv_info==NULL || buf==NULL) {
176                 LM_ERR("required parameters are not available\n");
177                 return -1;
178         }
179
180         if(kemi_received_route_callback.len>0) {
181                 keng = sr_kemi_eng_get();
182                 if(keng == NULL) {
183                         LM_DBG("kemi enabled with no core:msg-receive event route callback\n");
184                         return 0;
185                 }
186         } else {
187                 rt = route_lookup(&event_rt, evname.s);
188                 if (rt < 0 || event_rt.rlist[rt] == NULL) {
189                         LM_DBG("event route core:msg-received not defined\n");
190                         return 0;
191                 }
192         }
193         memset(&netinfo, 0, sizeof(sr_net_info_t));
194         netinfo.data.s = buf;
195         netinfo.data.len = len;
196         netinfo.rcv = rcv_info;
197
198         ksr_evrt_rcvnetinfo = &netinfo;
199         set_route_type(REQUEST_ROUTE);
200         fmsg = faked_msg_get_next();
201         init_run_actions_ctx(&ra_ctx);
202         if(keng) {
203                 bctx = sr_kemi_act_ctx_get();
204                 sr_kemi_act_ctx_set(&ra_ctx);
205                 ret=sr_kemi_route(keng, fmsg, REQUEST_ROUTE,
206                                 &kemi_received_route_callback, NULL);
207                 sr_kemi_act_ctx_set(bctx);
208         } else {
209                 ret=run_actions(&ra_ctx, event_rt.rlist[rt], fmsg);
210         }
211         if(ra_ctx.run_flags&DROP_R_F) {
212                 LM_DBG("dropping received message\n");
213                 ret = -1;
214         }
215         ksr_evrt_rcvnetinfo = NULL;
216
217         return ret;
218 }
219
220
221 static int ksr_evrt_pre_routing_idx = -1;
222 str kemi_pre_routing_callback = STR_NULL;
223
224
225 /**
226  *
227  */
228 int ksr_evrt_pre_routing(sip_msg_t *msg)
229 {
230         int ret = 0;
231         int rt = -1;
232         run_act_ctx_t ra_ctx;
233         run_act_ctx_t *bctx = NULL;
234         sr_kemi_eng_t *keng = NULL;
235         str evname = str_init("core:pre-routing");
236         recv_flags_t brflags;
237
238         if(msg->rcv.rflags & RECV_F_INTERNAL) {
239                 DBG("skip internal routed message\n");
240                 return 0;
241         }
242
243         if(kemi_pre_routing_callback.len>0) {
244                 keng = sr_kemi_eng_get();
245                 if(keng == NULL) {
246                         LM_DBG("kemi enabled with no core:pre-routing event route callback\n");
247                         return 0;
248                 }
249         } else {
250                 if(ksr_evrt_pre_routing_idx == -1) {
251                         rt = route_lookup(&event_rt, evname.s);
252                         if (rt < 0 || event_rt.rlist[rt] == NULL) {
253                                 ksr_evrt_pre_routing_idx = -2;
254                         }
255                 } else {
256                         rt = ksr_evrt_pre_routing_idx;
257                 }
258                 if (rt < 0 || event_rt.rlist[rt] == NULL) {
259                         LM_DBG("event route core:pre-routing not defined\n");
260                         return 0;
261                 }
262         }
263
264         set_route_type(REQUEST_ROUTE);
265         init_run_actions_ctx(&ra_ctx);
266         brflags = msg->rcv.rflags;
267         msg->rcv.rflags |= RECV_F_PREROUTING;
268         if(keng) {
269                 bctx = sr_kemi_act_ctx_get();
270                 sr_kemi_act_ctx_set(&ra_ctx);
271                 ret=sr_kemi_route(keng, msg, REQUEST_ROUTE,
272                                 &kemi_pre_routing_callback, &evname);
273                 sr_kemi_act_ctx_set(bctx);
274         } else {
275                 ret=run_actions(&ra_ctx, event_rt.rlist[rt], msg);
276         }
277         msg->rcv.rflags = brflags;
278         if(ra_ctx.run_flags&DROP_R_F) {
279                 LM_DBG("drop was used\n");
280                 return 1;
281         }
282         LM_DBG("execution returned %d\n", ret);
283
284         return 0;
285 }
286
287 /** Receive message
288  *  WARNING: buf must be 0 terminated (buf[len]=0) or some things might
289  * break (e.g.: modules/textops)
290  */
291 int receive_msg(char *buf, unsigned int len, receive_info_t *rcv_info)
292 {
293         struct sip_msg *msg = NULL;
294         struct run_act_ctx ctx;
295         struct run_act_ctx *bctx = NULL;
296         int ret = -1;
297         struct timeval tvb = {0}, tve = {0};
298         unsigned int diff = 0;
299         str inb = STR_NULL;
300         sr_net_info_t netinfo = {0};
301         sr_kemi_eng_t *keng = NULL;
302         sr_event_param_t evp = {0};
303         unsigned int cidlockidx = 0;
304         unsigned int cidlockset = 0;
305         int errsipmsg = 0;
306         int exectime = 0;
307
308         if(rcv_info->bind_address==NULL) {
309                 LM_ERR("critical - incoming message without local socket [%.*s ...]\n",
310                                 (len>128)?128:len, buf);
311                 return -1;
312         }
313
314         if(ksr_evrt_received_mode!=0) {
315                 if(ksr_evrt_received(buf, len, rcv_info)<0) {
316                         LM_DBG("dropping the received message\n");
317                         goto error00;
318                 }
319         }
320         if(sr_event_enabled(SREV_NET_DATA_RECV)) {
321                 if(sip_check_fline(buf, len) == 0) {
322                         memset(&netinfo, 0, sizeof(sr_net_info_t));
323                         netinfo.data.s = buf;
324                         netinfo.data.len = len;
325                         netinfo.rcv = rcv_info;
326                         evp.data = (void *)&netinfo;
327                         sr_event_exec(SREV_NET_DATA_RECV, &evp);
328                 }
329         }
330
331         inb.s = buf;
332         inb.len = len;
333         evp.data = (void *)&inb;
334         evp.rcv = rcv_info;
335         sr_event_exec(SREV_NET_DATA_IN, &evp);
336         len = inb.len;
337
338         msg = pkg_malloc(sizeof(struct sip_msg));
339         if(unlikely(msg == 0)) {
340                 PKG_MEM_ERROR;
341                 goto error00;
342         }
343         msg_no++;
344         /* number of vias parsed -- good for diagnostic info in replies */
345         via_cnt = 0;
346
347         memset(msg, 0, sizeof(struct sip_msg)); /* init everything to 0 */
348         /* fill in msg */
349         msg->buf = buf;
350         msg->len = len;
351         /* zero termination (termination of orig message below not that
352          * useful as most of the work is done with scratch-pad; -jiri  */
353         /* buf[len]=0; */ /* WARNING: zero term removed! */
354         msg->rcv = *rcv_info;
355         msg->id = msg_no;
356         msg->pid = my_pid();
357         msg->set_global_address = default_global_address;
358         msg->set_global_port = default_global_port;
359
360         if(likely(sr_msg_time == 1))
361                 msg_set_time(msg);
362
363         if(parse_msg(buf, len, msg) != 0) {
364                 errsipmsg = 1;
365                 evp.data = (void *)msg;
366                 if((ret = sr_event_exec(SREV_RCV_NOSIP, &evp)) < NONSIP_MSG_DROP) {
367                         LM_DBG("attempt of nonsip message processing failed\n");
368                 } else if(ret == NONSIP_MSG_DROP) {
369                         LM_DBG("nonsip message processing completed\n");
370                         goto end;
371                 }
372         }
373         if(errsipmsg==1) {
374                 LOG(cfg_get(core, core_cfg, sip_parser_log),
375                                 "core parsing of SIP message failed (%s:%d/%d)\n",
376                                 ip_addr2a(&msg->rcv.src_ip), (int)msg->rcv.src_port,
377                                 (int)msg->rcv.proto);
378                 sr_core_ert_run(msg, SR_CORE_ERT_RECEIVE_PARSE_ERROR);
379                 goto error02;
380         }
381
382         if(unlikely(parse_headers(msg, HDR_FROM_F | HDR_TO_F | HDR_CALLID_F | HDR_CSEQ_F, 0)
383                         < 0)) {
384                 LOG(cfg_get(core, core_cfg, sip_parser_log),
385                                 "parsing relevant headers failed\n");
386         }
387         LM_DBG("--- received sip message - %s - call-id: [%.*s] - cseq: [%.*s]\n",
388                         (msg->first_line.type == SIP_REQUEST) ? "request" : "reply",
389                         (msg->callid && msg->callid->body.s) ? msg->callid->body.len : 0,
390                         (msg->callid && msg->callid->body.s) ? msg->callid->body.s : "",
391                         (msg->cseq && msg->cseq->body.s) ? msg->cseq->body.len : 0,
392                         (msg->cseq && msg->cseq->body.s) ? msg->cseq->body.s : "");
393
394         /* set log prefix */
395         log_prefix_set(msg);
396
397         /* ... clear branches from previous message */
398         clear_branches();
399
400         ret = ksr_evrt_pre_routing(msg);
401         if(ret<0) {
402                 goto error02;
403         }
404         if(ret == 1) {
405                 /* finished */
406                 goto end;
407         }
408
409         if(unlikely(ksr_route_locks_set!=NULL && msg->callid && msg->callid->body.s
410                         && msg->callid->body.len >0)) {
411                 cidlockidx = get_hash1_raw(msg->callid->body.s, msg->callid->body.len);
412                 cidlockidx = cidlockidx % ksr_route_locks_set->size;
413                 cidlockset = 1;
414         }
415
416
417         if(is_printable(cfg_get(core, core_cfg, latency_cfg_log))) {
418                 exectime = 1;
419         }
420
421         if(msg->first_line.type == SIP_REQUEST) {
422                 ruri_mark_new(); /* ruri is usable for forking (not consumed yet) */
423                 if(!IS_SIP(msg)) {
424                         if((ret = nonsip_msg_run_hooks(msg)) != NONSIP_MSG_ACCEPT) {
425                                 if(unlikely(ret == NONSIP_MSG_ERROR))
426                                         goto error03;
427                                 goto end; /* drop the message */
428                         }
429                 }
430                 /* sanity checks */
431                 if(unlikely((msg->via1 == 0) || (msg->via1->error != PARSE_OK))) {
432                         /* no via, send back error ? */
433                         LOG(cfg_get(core, core_cfg, sip_parser_log),
434                                         "no via found in request\n");
435                         STATS_BAD_MSG();
436                         goto error02;
437                 }
438 /* check if necessary to add receive?->moved to forward_req */
439 /* check for the alias stuff */
440 #ifdef USE_TCP
441                 if(msg->via1->alias && cfg_get(tcp, tcp_cfg, accept_aliases)
442                                 && (((rcv_info->proto == PROTO_TCP) && !tcp_disable)
443 #ifdef USE_TLS
444                                                    || ((rcv_info->proto == PROTO_TLS) && !tls_disable)
445 #endif
446                                                                    )) {
447                         if(tcpconn_add_alias(rcv_info->proto_reserved1, msg->via1->port,
448                                            rcv_info->proto)
449                                         != 0) {
450                                 LM_ERR("tcp alias failed\n");
451                                 /* continue */
452                         }
453                 }
454 #endif
455
456                 /*      skip: */
457                 LM_DBG("preparing to run routing scripts...\n");
458                 if(exectime) {
459                         gettimeofday(&tvb, NULL);
460                 }
461                 /* execute pre-script callbacks, if any; -jiri */
462                 /* if some of the callbacks said not to continue with
463                  * script processing, don't do so
464                  * if we are here basic sanity checks are already done
465                  * (like presence of at least one via), so you can count
466                  * on via1 being parsed in a pre-script callback --andrei
467                 */
468                 if(exec_pre_script_cb(msg, REQUEST_CB_TYPE) == 0) {
469                         STATS_REQ_FWD_DROP();
470                         goto end; /* drop the request */
471                 }
472
473                 set_route_type(REQUEST_ROUTE);
474                 /* exec the routing script */
475                 if(unlikely(main_rt.rlist[DEFAULT_RT] == NULL)) {
476                         keng = sr_kemi_eng_get();
477                         if(keng == NULL) {
478                                 LM_ERR("no request_route {...} and no other config routing"
479                                                 " engine registered\n");
480                                 goto error_req;
481                         }
482                         if(unlikely(cidlockset)) {
483                                 rec_lock_set_get(ksr_route_locks_set, cidlockidx);
484                                 if(sr_kemi_route(keng, msg, REQUEST_ROUTE, NULL, NULL) < 0)
485                                         LM_NOTICE("negative return code from engine function\n");
486                                 rec_lock_set_release(ksr_route_locks_set, cidlockidx);
487                         } else {
488                                 if(sr_kemi_route(keng, msg, REQUEST_ROUTE, NULL, NULL) < 0)
489                                         LM_NOTICE("negative return code from engine function\n");
490                         }
491                 } else {
492                         if(unlikely(cidlockset)) {
493                                 rec_lock_set_get(ksr_route_locks_set, cidlockidx);
494                                 if(run_top_route(main_rt.rlist[DEFAULT_RT], msg, 0) < 0) {
495                                         rec_lock_set_release(ksr_route_locks_set, cidlockidx);
496                                         LM_WARN("error while trying script\n");
497                                         goto error_req;
498                                 }
499                                 rec_lock_set_release(ksr_route_locks_set, cidlockidx);
500                         } else {
501                                 if(run_top_route(main_rt.rlist[DEFAULT_RT], msg, 0) < 0) {
502                                         LM_WARN("error while trying script\n");
503                                         goto error_req;
504                                 }
505                         }
506                 }
507
508                 if(exectime) {
509                         gettimeofday(&tve, NULL);
510                         diff = (tve.tv_sec - tvb.tv_sec) * 1000000
511                                    + (tve.tv_usec - tvb.tv_usec);
512                         if (cfg_get(core, core_cfg, latency_limit_cfg) == 0
513                                         || cfg_get(core, core_cfg, latency_limit_cfg) <= diff) {
514                                 LOG(cfg_get(core, core_cfg, latency_cfg_log),
515                                                 "request-route executed in: %d usec\n", diff);
516                         }
517                 }
518
519                 /* execute post request-script callbacks */
520                 exec_post_script_cb(msg, REQUEST_CB_TYPE);
521         } else if(msg->first_line.type == SIP_REPLY) {
522                 /* sanity checks */
523                 if((msg->via1 == 0) || (msg->via1->error != PARSE_OK)) {
524                         /* no via, send back error ? */
525                         LM_ERR("no via found in reply\n");
526                         STATS_BAD_RPL();
527                         goto error02;
528                 }
529
530                 if(exectime) {
531                         gettimeofday(&tvb, NULL);
532                 }
533
534                 /* execute pre-script callbacks, if any; -jiri */
535                 /* if some of the callbacks said not to continue with
536                  * script processing, don't do so
537                  * if we are here basic sanity checks are already done
538                  * (like presence of at least one via), so you can count
539                  * on via1 being parsed in a pre-script callback --andrei
540                 */
541                 if(exec_pre_script_cb(msg, ONREPLY_CB_TYPE) == 0) {
542                         STATS_RPL_FWD_DROP();
543                         goto end; /* drop the reply */
544                 }
545
546                 /* exec the onreply routing script */
547                 if(kemi_reply_route_callback.len>0) {
548                         keng = sr_kemi_eng_get();
549                 }
550                 if(onreply_rt.rlist[DEFAULT_RT] != NULL || keng != NULL) {
551                         set_route_type(CORE_ONREPLY_ROUTE);
552                         ret = 1;
553                         if(unlikely(keng != NULL)) {
554                                 bctx = sr_kemi_act_ctx_get();
555                                 init_run_actions_ctx(&ctx);
556                                 sr_kemi_act_ctx_set(&ctx);
557                                 if(unlikely(cidlockset)) {
558                                         rec_lock_set_get(ksr_route_locks_set, cidlockidx);
559                                         ret = sr_kemi_route(keng, msg, CORE_ONREPLY_ROUTE, NULL, NULL);
560                                         rec_lock_set_release(ksr_route_locks_set, cidlockidx);
561                                 } else {
562                                         ret = sr_kemi_route(keng, msg, CORE_ONREPLY_ROUTE, NULL, NULL);
563                                 }
564                                 sr_kemi_act_ctx_set(bctx);
565                         } else {
566                                 if(unlikely(cidlockset)) {
567                                         rec_lock_set_get(ksr_route_locks_set, cidlockidx);
568                                         ret = run_top_route(onreply_rt.rlist[DEFAULT_RT], msg, &ctx);
569                                         rec_lock_set_release(ksr_route_locks_set, cidlockidx);
570                                 } else  {
571                                         ret = run_top_route(onreply_rt.rlist[DEFAULT_RT], msg, &ctx);
572                                 }
573                         }
574 #ifndef NO_ONREPLY_ROUTE_ERROR
575                         if(unlikely(ret < 0)) {
576                                 LM_WARN("error while trying onreply script\n");
577                                 goto error_rpl;
578                         } else
579 #endif /* NO_ONREPLY_ROUTE_ERROR */
580                                 if(unlikely(ret == 0 || (ctx.run_flags & DROP_R_F))) {
581                                         STATS_RPL_FWD_DROP();
582                                         LM_DBG("drop flag set - skip forwarding the reply\n");
583                                         goto skip_send_reply; /* drop the message, no error */
584                                 }
585                 }
586                 /* send the msg */
587                 forward_reply(msg);
588         skip_send_reply:
589                 if(exectime) {
590                         gettimeofday(&tve, NULL);
591                         diff = (tve.tv_sec - tvb.tv_sec) * 1000000
592                                    + (tve.tv_usec - tvb.tv_usec);
593                         if (cfg_get(core, core_cfg, latency_limit_cfg) == 0
594                                         || cfg_get(core, core_cfg, latency_limit_cfg) <= diff) {
595                                 LOG(cfg_get(core, core_cfg, latency_cfg_log),
596                                                 "reply-route executed in: %d usec\n", diff);
597                         }
598                 }
599
600                 /* execute post reply-script callbacks */
601                 exec_post_script_cb(msg, ONREPLY_CB_TYPE);
602         }
603
604 end:
605         ksr_msg_env_reset();
606         LM_DBG("cleaning up\n");
607         free_sip_msg(msg);
608         pkg_free(msg);
609         /* reset log prefix */
610         log_prefix_set(NULL);
611         return 0;
612
613 #ifndef NO_ONREPLY_ROUTE_ERROR
614 error_rpl:
615         /* execute post reply-script callbacks */
616         exec_post_script_cb(msg, ONREPLY_CB_TYPE);
617         goto error02;
618 #endif /* NO_ONREPLY_ROUTE_ERROR */
619 error_req:
620         LM_DBG("error:...\n");
621         /* execute post request-script callbacks */
622         exec_post_script_cb(msg, REQUEST_CB_TYPE);
623 error03:
624 error02:
625         free_sip_msg(msg);
626         pkg_free(msg);
627 error00:
628         ksr_msg_env_reset();
629         /* reset log prefix */
630         log_prefix_set(NULL);
631         return -1;
632 }
633
634 /**
635  * clean up msg environment, such as avp, xavp and xavu lists
636  */
637 void ksr_msg_env_reset(void)
638 {
639         reset_avps();
640         xavp_reset_list();
641         xavu_reset_list();
642         xavi_reset_list();
643 }