1 /**
2 * @file sip/location.c Mock SIP server -- location handling
3 *
4 * Copyright (C) 2010 - 2016 Creytiv.com
5 */
6 #include <time.h>
7 #include <re.h>
8 #include "sipsrv.h"
9
10
11 struct loctmp {
12 struct sa src;
13 struct uri duri;
14 char *uri;
15 char *callid;
16 uint32_t expires;
17 uint32_t cseq;
18 double q;
19 };
20
21
destructor_loctmp(void * arg)22 static void destructor_loctmp(void *arg)
23 {
24 struct loctmp *tmp = arg;
25
26 mem_deref(tmp->uri);
27 mem_deref(tmp->callid);
28 }
29
30
destructor_location(void * arg)31 static void destructor_location(void *arg)
32 {
33 struct location *loc = arg;
34
35 list_unlink(&loc->le);
36 mem_deref(loc->uri);
37 mem_deref(loc->callid);
38 mem_deref(loc->tmp);
39 }
40
41
cmp_handler(struct le * le,void * arg)42 static bool cmp_handler(struct le *le, void *arg)
43 {
44 struct location *loc = le->data;
45
46 return uri_cmp(&loc->duri, arg);
47 }
48
49
location_update(struct list * locl,const struct sip_msg * msg,const struct sip_addr * contact,uint32_t expires)50 int location_update(struct list *locl, const struct sip_msg *msg,
51 const struct sip_addr *contact, uint32_t expires)
52 {
53 struct location *loc, *loc_new = NULL;
54 struct loctmp *tmp;
55 struct pl pl;
56 int err;
57
58 if (!locl || !msg || !contact)
59 return EINVAL;
60
61 loc = list_ledata(list_apply(locl, true, cmp_handler,
62 (void *)&contact->uri));
63 if (!loc) {
64 if (expires == 0)
65 return 0;
66
67 loc = loc_new = mem_zalloc(sizeof(*loc), destructor_location);
68 if (!loc)
69 return ENOMEM;
70
71 list_append(locl, &loc->le, loc);
72 }
73 else {
74 if (!pl_strcmp(&msg->callid, loc->callid) &&
75 msg->cseq.num <= loc->cseq)
76 return EPROTO;
77
78 if (expires == 0) {
79 loc->rm = true;
80 return 0;
81 }
82 }
83
84 tmp = mem_zalloc(sizeof(*tmp), destructor_loctmp);
85 if (!tmp) {
86 err = ENOMEM;
87 goto out;
88 }
89
90 err = pl_strdup(&tmp->uri, &contact->auri);
91 if (err)
92 goto out;
93
94 pl_set_str(&pl, tmp->uri);
95
96 if (uri_decode(&tmp->duri, &pl)) {
97 err = EBADMSG;
98 goto out;
99 }
100
101 err = pl_strdup(&tmp->callid, &msg->callid);
102 if (err)
103 goto out;
104
105
106 if (!msg_param_decode(&contact->params, "q", &pl))
107 tmp->q = pl_float(&pl);
108 else
109 tmp->q = 1;
110
111 tmp->cseq = msg->cseq.num;
112 tmp->expires = expires;
113 tmp->src = msg->src;
114
115 out:
116 if (err) {
117 mem_deref(loc_new);
118 mem_deref(tmp);
119 }
120 else {
121 mem_deref(loc->tmp);
122 loc->tmp = tmp;
123 }
124
125 return err;
126 }
127
128
location_commit(struct list * locl)129 void location_commit(struct list *locl)
130 {
131 time_t now = time(NULL);
132 struct le *le;
133
134 if (!locl)
135 return;
136
137 for (le=locl->head; le; ) {
138
139 struct location *loc = le->data;
140
141 le = le->next;
142
143 if (loc->rm) {
144 list_unlink(&loc->le);
145 mem_deref(loc);
146 }
147 else if (loc->tmp) {
148
149 mem_deref(loc->uri);
150 mem_deref(loc->callid);
151
152 loc->uri = mem_ref(loc->tmp->uri);
153 loc->callid = mem_ref(loc->tmp->callid);
154 loc->duri = loc->tmp->duri;
155 loc->cseq = loc->tmp->cseq;
156 loc->expires = loc->tmp->expires + now;
157 loc->src = loc->tmp->src;
158 loc->q = loc->tmp->q;
159
160 loc->tmp = mem_deref(loc->tmp);
161 }
162 }
163 }
164
165
location_rollback(struct list * locl)166 void location_rollback(struct list *locl)
167 {
168 struct le *le;
169
170 if (!locl)
171 return;
172
173 for (le=locl->head; le; ) {
174
175 struct location *loc = le->data;
176
177 le = le->next;
178
179 if (!loc->uri) {
180 list_unlink(&loc->le);
181 mem_deref(loc);
182 }
183 else {
184 loc->tmp = mem_deref(loc->tmp);
185 loc->rm = false;
186 }
187 }
188 }
189