Browse code

uac(k): added remote registration capability

- uac module can register contacts to a remote server
- can auth REGISTER challenges
- uses db table uacreg to load credentials at startup
- no reload for now (have to restart to get the db updates)
- rpc function uac.reg_dump to dump in-memory table

Daniel-Constantin Mierla authored on 24/01/2010 20:48:20
Showing 7 changed files
... ...
@@ -14,4 +14,5 @@ DEFS+=-DOPENSER_MOD_INTERFACE
14 14
 
15 15
 SERLIBPATH=../../lib
16 16
 SER_LIBS+=$(SERLIBPATH)/kcore/kcore
17
+SER_LIBS+=$(SERLIBPATH)/srdb1/srdb1
17 18
 include ../../Makefile.modules
... ...
@@ -14,40 +14,43 @@ Ramona-Elena Modroiu
14 14
 
15 15
    <ramona@rosdev.ro>
16 16
 
17
-   Copyright � 2005 Voice Sistem
17
+   Copyright � 2009-2010 asipto.com
18 18
 
19
-   Copyright � 2009 Asipto.com
20
-     __________________________________________________________
19
+   Copyright � 2005 Voice Sistem
20
+     __________________________________________________________________
21 21
 
22 22
    Table of Contents
23 23
 
24 24
    1. Admin Guide
25 25
 
26
-        1.1. Overview
27
-        1.2. Dependencies
26
+        1. Overview
27
+        2. Dependencies
28 28
 
29
-              1.2.1. Kamailio Modules
30
-              1.2.2. External Libraries or Applications
29
+              2.1. Kamailio Modules
30
+              2.2. External Libraries or Applications
31 31
 
32
-        1.3. Exported Parameters
32
+        3. Exported Parameters
33 33
 
34
-              1.3.1. rr_store_param (string)
35
-              1.3.2. from_restore_mode (string)
36
-              1.3.3. from_passwd (string)
37
-              1.3.4. credential (string)
38
-              1.3.5. auth_realm_avp (string)
39
-              1.3.6. auth_username_avp (string)
40
-              1.3.7. auth_password_avp (string)
34
+              3.1. rr_store_param (string)
35
+              3.2. from_restore_mode (string)
36
+              3.3. from_passwd (string)
37
+              3.4. credential (string)
38
+              3.5. auth_realm_avp (string)
39
+              3.6. auth_username_avp (string)
40
+              3.7. auth_password_avp (string)
41
+              3.8. reg_db_url (string)
42
+              3.9. reg_contact_addr (string)
41 43
 
42
-        1.4. Exported Functions
44
+        4. Exported Functions
43 45
 
44
-              1.4.1. uac_replace_from(display,uri)
45
-              1.4.2. uac_replace_from(uri)
46
-              1.4.3. uac_restore_from()
47
-              1.4.4. uac_auth()
48
-              1.4.5. uac_req_send()
46
+              4.1. uac_replace_from(display,uri)
47
+              4.2. uac_replace_from(uri)
48
+              4.3. uac_restore_from()
49
+              4.4. uac_auth()
50
+              4.5. uac_req_send()
51
+              4.6. uac_reg_lookup(uuid, dst)
49 52
 
50
-        1.5. Exported pseudo-variables
53
+        5. Exported pseudo-variables
51 54
 
52 55
    List of Examples
53 56
 
... ...
@@ -58,48 +61,94 @@ Ramona-Elena Modroiu
58 58
    1.5. Set auth_realm_avp parameter
59 59
    1.6. Set auth_username_avp parameter
60 60
    1.7. Set auth_password_avp parameter
61
-   1.8. uac_replace_from usage
62
-   1.9. uac_replace_from usage
63
-   1.10. uac_restore_from usage
64
-   1.11. uac_auth usage
65
-   1.12. uac_req_send usage
61
+   1.8. Set reg_db_url parameter
62
+   1.9. Set reg_contact_addr parameter
63
+   1.10. uac_replace_from usage
64
+   1.11. uac_replace_from usage
65
+   1.12. uac_restore_from usage
66
+   1.13. uac_auth usage
67
+   1.14. uac_req_send usage
68
+   1.15. uac_reg_lookup usage
66 69
 
67 70
 Chapter 1. Admin Guide
68 71
 
69
-1.1. Overview
72
+   Table of Contents
73
+
74
+   1. Overview
75
+   2. Dependencies
76
+
77
+        2.1. Kamailio Modules
78
+        2.2. External Libraries or Applications
79
+
80
+   3. Exported Parameters
81
+
82
+        3.1. rr_store_param (string)
83
+        3.2. from_restore_mode (string)
84
+        3.3. from_passwd (string)
85
+        3.4. credential (string)
86
+        3.5. auth_realm_avp (string)
87
+        3.6. auth_username_avp (string)
88
+        3.7. auth_password_avp (string)
89
+        3.8. reg_db_url (string)
90
+        3.9. reg_contact_addr (string)
91
+
92
+   4. Exported Functions
70 93
 
71
-   UAC (User Agent Client) module provides some basic UAC
72
-   functionalities like FROM header manipulation (anonymization)
73
-   or client authentication. From version 1.5.0 it has function to
74
-   send SIP message from configuration file.
94
+        4.1. uac_replace_from(display,uri)
95
+        4.2. uac_replace_from(uri)
96
+        4.3. uac_restore_from()
97
+        4.4. uac_auth()
98
+        4.5. uac_req_send()
99
+        4.6. uac_reg_lookup(uuid, dst)
100
+
101
+   5. Exported pseudo-variables
102
+
103
+1. Overview
104
+
105
+   UAC (User Agent Client) module provides some basic UAC functionalities
106
+   like FROM header manipulation (anonymization) or client authentication.
107
+   From version 1.5.0 it has function to send SIP message from
108
+   configuration file. Version 3.1.0 adds user registration functionality.
75 109
 
76 110
    Known limitations in this version:
77
-     * authentication does not support qop auth-int, just qop
78
-       auth;
79
-     * CSeq not increased during authentication - the response may
80
-       be rejected.
111
+     * authentication does not support qop auth-int, just qop auth;
112
+     * CSeq not increased during authentication - the response may be
113
+       rejected.
114
+
115
+2. Dependencies
81 116
 
82
-1.2. Dependencies
117
+   2.1. Kamailio Modules
118
+   2.2. External Libraries or Applications
83 119
 
84
-1.2.1. Kamailio Modules
120
+2.1. Kamailio Modules
85 121
 
86 122
    The following modules must be loaded before this module:
87 123
      * TM - Transaction Module
88
-     * RR - Record-Route Module, but only if restore mode for FROM
89
-       URI is set to "auto".
124
+     * RR - Record-Route Module, but only if restore mode for FROM URI is
125
+       set to "auto".
90 126
 
91
-1.2.2. External Libraries or Applications
127
+2.2. External Libraries or Applications
92 128
 
93
-   The following libraries or applications must be installed
94
-   before running Kamailio with this module loaded:
129
+   The following libraries or applications must be installed before
130
+   running Kamailio with this module loaded:
95 131
      * None
96 132
 
97
-1.3. Exported Parameters
133
+3. Exported Parameters
98 134
 
99
-1.3.1. rr_store_param (string)
135
+   3.1. rr_store_param (string)
136
+   3.2. from_restore_mode (string)
137
+   3.3. from_passwd (string)
138
+   3.4. credential (string)
139
+   3.5. auth_realm_avp (string)
140
+   3.6. auth_username_avp (string)
141
+   3.7. auth_password_avp (string)
142
+   3.8. reg_db_url (string)
143
+   3.9. reg_contact_addr (string)
100 144
 
101
-   Name of Record-Route header parameter that will be used to
102
-   store (encoded) the original FROM URI.
145
+3.1. rr_store_param (string)
146
+
147
+   Name of Record-Route header parameter that will be used to store
148
+   (encoded) the original FROM URI.
103 149
 
104 150
    This parameter is optional, it's default value being "vsf".
105 151
 
... ...
@@ -108,16 +157,16 @@ Chapter 1. Admin Guide
108 108
 modparam("uac","rr_store_param","my_param")
109 109
 ...
110 110
 
111
-1.3.2. from_restore_mode (string)
111
+3.2. from_restore_mode (string)
112 112
 
113 113
    There are 3 mode of restoring the original FROM URI:
114
-     * "none" - no information about original URI is stored;
115
-       restoration is not possible.
116
-     * "manual" - all following replies will be restored, but not
117
-       also the sequential requests - this must be manually
118
-       updated based on original URI.
119
-     * "auto" - all sequential requests and replies will be
120
-       automatically updated based on stored original URI.
114
+     * "none" - no information about original URI is stored; restoration
115
+       is not possible.
116
+     * "manual" - all following replies will be restored, but not also the
117
+       sequential requests - this must be manually updated based on
118
+       original URI.
119
+     * "auto" - all sequential requests and replies will be automatically
120
+       updated based on stored original URI.
121 121
 
122 122
    This parameter is optional, it's default value being "auto".
123 123
 
... ...
@@ -126,10 +175,10 @@ modparam("uac","rr_store_param","my_param")
126 126
 modparam("uac","from_restore_mode","auto")
127 127
 ...
128 128
 
129
-1.3.3. from_passwd (string)
129
+3.3. from_passwd (string)
130 130
 
131
-   String password to be used to encrypt the RR storing parameter.
132
-   If empty, no encryption will be used.
131
+   String password to be used to encrypt the RR storing parameter. If
132
+   empty, no encryption will be used.
133 133
 
134 134
    Default value of this parameter is empty.
135 135
 
... ...
@@ -138,7 +187,7 @@ modparam("uac","from_restore_mode","auto")
138 138
 modparam("uac","from_passwd","my_secret_passwd")
139 139
 ...
140 140
 
141
-1.3.4. credential (string)
141
+3.4. credential (string)
142 142
 
143 143
    Contains a multiple definition of credentials used to perform
144 144
    authentication.
... ...
@@ -150,63 +199,86 @@ modparam("uac","from_passwd","my_secret_passwd")
150 150
 modparam("uac","credential","username:domain:password")
151 151
 ...
152 152
 
153
-1.3.5. auth_realm_avp (string)
153
+3.5. auth_realm_avp (string)
154 154
 
155
-   The definition of an AVP that might contain the realm to be
156
-   used to perform authentication.
155
+   The definition of an AVP that might contain the realm to be used to
156
+   perform authentication.
157 157
 
158 158
    If you define it, you also need to define "auth_username_avp"
159
-   (Section 1.3.6, "auth_username_avp (string)") and
160
-   "auth_username_avp" (Section 1.3.7, "auth_password_avp
161
-   (string)").
159
+   (Section 3.6, "auth_username_avp (string)") and "auth_username_avp"
160
+   (Section 3.7, "auth_password_avp (string)").
162 161
 
163 162
    Example 1.5. Set auth_realm_avp parameter
164 163
 ...
165 164
 modparam("uac","auth_realm_avp","$avp(i:10)")
166 165
 ...
167 166
 
168
-1.3.6. auth_username_avp (string)
167
+3.6. auth_username_avp (string)
169 168
 
170
-   The definition of an AVP that might contain the username to be
171
-   used to perform authentication.
169
+   The definition of an AVP that might contain the username to be used to
170
+   perform authentication.
172 171
 
173 172
    If you define it, you also need to define "auth_realm_avp"
174
-   (Section 1.3.5, "auth_realm_avp (string)") and
175
-   "auth_username_avp" (Section 1.3.7, "auth_password_avp
176
-   (string)").
173
+   (Section 3.5, "auth_realm_avp (string)") and "auth_username_avp"
174
+   (Section 3.7, "auth_password_avp (string)").
177 175
 
178 176
    Example 1.6. Set auth_username_avp parameter
179 177
 ...
180 178
 modparam("uac","auth_username_avp","$avp(i:11)")
181 179
 ...
182 180
 
183
-1.3.7. auth_password_avp (string)
181
+3.7. auth_password_avp (string)
184 182
 
185
-   The definition of an AVP that might contain the password to be
186
-   used to perform authentication.
183
+   The definition of an AVP that might contain the password to be used to
184
+   perform authentication.
187 185
 
188 186
    If you define it, you also need to define "auth_password_avp"
189
-   (Section 1.3.7, "auth_password_avp (string)") and
190
-   "auth_username_avp" (Section 1.3.7, "auth_password_avp
191
-   (string)").
187
+   (Section 3.7, "auth_password_avp (string)") and "auth_username_avp"
188
+   (Section 3.7, "auth_password_avp (string)").
192 189
 
193 190
    Example 1.7. Set auth_password_avp parameter
194 191
 ...
195 192
 modparam("uac","auth_password_avp","$avp(i:12)")
196 193
 ...
197 194
 
198
-1.4. Exported Functions
195
+3.8. reg_db_url (string)
196
+
197
+   DB URL to fetch user profiles for registration.
199 198
 
200
-1.4.1.  uac_replace_from(display,uri)
199
+   Example 1.8. Set reg_db_url parameter
200
+...
201
+modparam("uac", "reg_db_url",
202
+    "mysql://openser:openserrw@localhost/openser")
203
+...
204
+
205
+3.9. reg_contact_addr (string)
206
+
207
+   Address to be used to build contact address. Must be at least host
208
+   part, can have port and parameters. Must not include 'sip:'.
209
+
210
+   Example 1.9. Set reg_contact_addr parameter
211
+...
212
+modparam("uac", "reg_contact_addr", "192.168.1.2:5080")
213
+...
214
+
215
+4. Exported Functions
216
+
217
+   4.1. uac_replace_from(display,uri)
218
+   4.2. uac_replace_from(uri)
219
+   4.3. uac_restore_from()
220
+   4.4. uac_auth()
221
+   4.5. uac_req_send()
222
+   4.6. uac_reg_lookup(uuid, dst)
223
+
224
+4.1.  uac_replace_from(display,uri)
201 225
 
202 226
    Replace in FROM header the display name and the URI part.
203 227
 
204 228
    display and URI parameters can include pseudo-variables.
205 229
 
206
-   This function can be used from REQUEST_ROUTE and from
207
-   BRANCH_ROUTE.
230
+   This function can be used from REQUEST_ROUTE and from BRANCH_ROUTE.
208 231
 
209
-   Example 1.8. uac_replace_from usage
232
+   Example 1.10. uac_replace_from usage
210 233
 ...
211 234
 # replace both display and uri
212 235
 uac_replace_from("$avp(s:display)","$avp(s:uri)");
... ...
@@ -218,56 +290,54 @@ uac_replace_from("","sip:robin@gotham.org");
218 218
 uac_replace_from("","");
219 219
 ...
220 220
 
221
-1.4.2.  uac_replace_from(uri)
221
+4.2.  uac_replace_from(uri)
222 222
 
223
-   Replace in FROM header the URI part without altering the
224
-   display name.
223
+   Replace in FROM header the URI part without altering the display name.
225 224
 
226 225
    URI parameter can include pseudo-variables.
227 226
 
228
-   This function can be used from REQUEST_ROUTE and from
229
-   BRANCH_ROUTE.
227
+   This function can be used from REQUEST_ROUTE and from BRANCH_ROUTE.
230 228
 
231
-   Example 1.9. uac_replace_from usage
229
+   Example 1.11. uac_replace_from usage
232 230
 ...
233 231
 uac_replace_from("sip:batman@gotham.org");
234 232
 ...
235 233
 
236
-1.4.3.  uac_restore_from()
234
+4.3.  uac_restore_from()
237 235
 
238
-   This function will check if the FROM URI was modified and will
239
-   use the information stored in header parameter to restore the
240
-   original FROM URI value.
236
+   This function will check if the FROM URI was modified and will use the
237
+   information stored in header parameter to restore the original FROM URI
238
+   value.
241 239
 
242 240
    This function can be used from REQUEST_ROUTE.
243 241
 
244
-   Example 1.10. uac_restore_from usage
242
+   Example 1.12. uac_restore_from usage
245 243
 ...
246 244
 uac_restore_from();
247 245
 ...
248 246
 
249
-1.4.4.  uac_auth()
247
+4.4.  uac_auth()
250 248
 
251
-   This function can be called only from failure route and will
252
-   build the authentication response header and insert it into the
253
-   request without sending anything.
249
+   This function can be called only from failure route and will build the
250
+   authentication response header and insert it into the request without
251
+   sending anything.
254 252
 
255 253
    This function can be used from FAILURE_ROUTE.
256 254
 
257
-   Example 1.11. uac_auth usage
255
+   Example 1.13. uac_auth usage
258 256
 ...
259 257
 uac_auth();
260 258
 ...
261 259
 
262
-1.4.5.  uac_req_send()
260
+4.5.  uac_req_send()
263 261
 
264
-   This function sends a SIP message from the configuration file.
265
-   The message is built out of $uac_req(...) pseudo-variable.
262
+   This function sends a SIP message from the configuration file. The
263
+   message is built out of $uac_req(...) pseudo-variable.
266 264
 
267 265
    This function can be used from REQUEST_ROUTE, FAILURE_ROUTE,
268 266
    BRANCH_ROUTE, ONREPLY_ROUTE, LOCAL_ROUTE.
269 267
 
270
-   Example 1.12. uac_req_send usage
268
+   Example 1.14. uac_req_send usage
271 269
 ...
272 270
 $uac_req(method)="OPTIONS";
273 271
 $uac_req(ruri)="sip:kamailio.org";
... ...
@@ -276,7 +346,23 @@ $uac_req(turi)="sip:kamailio.org";
276 276
 uac_req_send();
277 277
 ...
278 278
 
279
-1.5. Exported pseudo-variables
279
+4.6.  uac_reg_lookup(uuid, dst)
280
+
281
+   This function sets the PV dst to SIP URI that correspond to uuid in uac
282
+   registations table. uuid and dst must be pseudo-variables.
283
+
284
+   This function can be used from ANY_ROUTE.
285
+
286
+   Example 1.15. uac_reg_lookup usage
287
+...
288
+
289
+if(uac_reg_lookup("$rU", "$ru"))
290
+{
291
+    lookup("location");
292
+}
293
+...
294
+
295
+5. Exported pseudo-variables
280 296
 
281 297
      * $uac_req(key)
282 298
 
... ...
@@ -30,12 +30,12 @@
30 30
 		</editor>
31 31
 	</authorgroup>
32 32
 	<copyright>
33
-		<year>2005</year>
34
-		<holder>Voice Sistem</holder>
33
+		<year>2009-2010</year>
34
+		<holder>asipto.com</holder>
35 35
 	</copyright>
36 36
 	<copyright>
37
-		<year>2009</year>
38
-		<holder>Asipto.com</holder>
37
+		<year>2005</year>
38
+		<holder>Voice Sistem</holder>
39 39
 	</copyright>
40 40
 	</bookinfo>
41 41
 	<toc></toc>
... ...
@@ -20,7 +20,8 @@
20 20
 		UAC (User Agent Client) module provides some basic UAC
21 21
 		functionalities like FROM header manipulation (anonymization)
22 22
 		or client authentication. From version 1.5.0 it has function to
23
-		send SIP message from configuration file.
23
+		send SIP message from configuration file. Version 3.1.0 adds user
24
+		registration functionality.
24 25
 		</para>
25 26
 		<para>
26 27
 		Known limitations in this version:
... ...
@@ -248,6 +249,36 @@ modparam("uac","auth_password_avp","$avp(i:12)")
248 248
 				</programlisting>
249 249
 			</example>
250 250
 		</section>
251
+		<section id="reg-db-url-id">
252
+			<title><varname>reg_db_url</varname> (string)</title>
253
+			<para>
254
+			DB URL to fetch user profiles for registration.
255
+			</para>
256
+			<example>
257
+				<title>Set <varname>reg_db_url</varname> parameter</title>
258
+				<programlisting format="linespecific">
259
+...
260
+modparam("uac", "reg_db_url",
261
+    "mysql://openser:openserrw@localhost/openser")
262
+...
263
+				</programlisting>
264
+			</example>
265
+		</section>
266
+		<section id="reg-contact-addr-id">
267
+			<title><varname>reg_contact_addr</varname> (string)</title>
268
+			<para>
269
+			Address to be used to build contact address. Must be at least
270
+			host part, can have port and parameters. Must not include 'sip:'.
271
+			</para>
272
+			<example>
273
+				<title>Set <varname>reg_contact_addr</varname> parameter</title>
274
+				<programlisting format="linespecific">
275
+...
276
+modparam("uac", "reg_contact_addr", "192.168.1.2:5080")
277
+...
278
+				</programlisting>
279
+			</example>
280
+		</section>
251 281
 	</section>
252 282
 
253 283
 
... ...
@@ -374,6 +405,30 @@ uac_req_send();
374 374
 				</programlisting>
375 375
 			</example>
376 376
 		</section>
377
+		<section>
378
+			<title>
379
+				<function moreinfo="none">uac_reg_lookup(uuid, dst)</function>
380
+			</title>
381
+			<para>
382
+			This function sets the PV dst to SIP URI that correspond to uuid
383
+			in uac registations table. uuid and dst must be pseudo-variables.
384
+			</para>
385
+			<para>
386
+			This function can be used from ANY_ROUTE.
387
+			</para>
388
+			<example>
389
+				<title><function>uac_reg_lookup</function> usage</title>
390
+				<programlisting format="linespecific">
391
+...
392
+
393
+if(uac_reg_lookup("$rU", "$ru"))
394
+{
395
+    lookup("location");
396
+}
397
+...
398
+				</programlisting>
399
+			</example>
400
+		</section>
377 401
 	</section>
378 402
 	<section>
379 403
 		<title>Exported pseudo-variables</title>
... ...
@@ -35,19 +35,27 @@
35 35
 #include <stdio.h>
36 36
 #include <string.h>
37 37
 #include <stdlib.h>
38
+#include <unistd.h>
38 39
 
39 40
 #include "../../sr_module.h"
40 41
 #include "../../dprint.h"
41 42
 #include "../../error.h"
42 43
 #include "../../pvar.h"
44
+#include "../../pt.h"
45
+#include "../../timer.h"
43 46
 #include "../../mem/mem.h"
44 47
 #include "../../modules/tm/tm_load.h"
45 48
 #include "../../modules/tm/t_hooks.h"
49
+#include "../../mod_fix.h"
50
+#include "../../rpc.h"
51
+#include "../../rpc_lookup.h"
52
+
46 53
 #include "../rr/api.h"
47 54
 
48 55
 #include "from.h"
49 56
 #include "auth.h"
50 57
 #include "uac_send.h"
58
+#include "uac_reg.h"
51 59
 
52 60
 
53 61
 MODULE_VERSION
... ...
@@ -73,10 +81,12 @@ static int w_replace_from1(struct sip_msg* msg, char* str, char* str2);
73 73
 static int w_replace_from2(struct sip_msg* msg, char* str, char* str2);
74 74
 static int w_restore_from(struct sip_msg* msg,  char* foo, char* bar);
75 75
 static int w_uac_auth(struct sip_msg* msg, char* str, char* str2);
76
+static int w_uac_reg_lookup(struct sip_msg* msg,  char* src, char* dst);
76 77
 static int fixup_replace_from1(void** param, int param_no);
77 78
 static int fixup_replace_from2(void** param, int param_no);
78 79
 static int mod_init(void);
79 80
 static void mod_destroy(void);
81
+static int child_init(int rank);
80 82
 
81 83
 
82 84
 static pv_export_t mod_pvs[] = {
... ...
@@ -99,6 +109,8 @@ static cmd_export_t cmds[]={
99 99
 	{"uac_req_send",  (cmd_function)uac_req_send,         0,                  0, 0, 
100 100
 		REQUEST_ROUTE | FAILURE_ROUTE |
101 101
 		ONREPLY_ROUTE | BRANCH_ROUTE | ERROR_ROUTE | LOCAL_ROUTE},
102
+	{"uac_reg_lookup",  (cmd_function)w_uac_reg_lookup,  2, fixup_pvar_pvar,
103
+		fixup_free_pvar_pvar, ANY_ROUTE },
102 104
 
103 105
 	{0,0,0,0,0,0}
104 106
 };
... ...
@@ -114,6 +126,8 @@ static param_export_t params[] = {
114 114
 	{"auth_username_avp", STR_PARAM,                &auth_username_avp     },
115 115
 	{"auth_realm_avp",    STR_PARAM,                &auth_realm_avp        },
116 116
 	{"auth_password_avp", STR_PARAM,                &auth_password_avp     },
117
+	{"reg_db_url",        STR_PARAM,                &reg_db_url.s          },
118
+	{"reg_contact_addr",  STR_PARAM,                &reg_contact_addr.s    },
117 119
 	{0, 0, 0}
118 120
 };
119 121
 
... ...
@@ -131,7 +145,7 @@ struct module_exports exports= {
131 131
 	mod_init,   /* module initialization function */
132 132
 	0,
133 133
 	mod_destroy,
134
-	0  /* per-child init function */
134
+	child_init  /* per-child init function */
135 135
 };
136 136
 
137 137
 
... ...
@@ -218,6 +232,32 @@ static int mod_init(void)
218 218
 		}
219 219
 	}
220 220
 
221
+	if(reg_db_url.s!=NULL)
222
+	{
223
+		if(reg_contact_addr.s==NULL)
224
+		{
225
+			LM_ERR("contact address parameter not set\n");
226
+			goto error;
227
+		}
228
+		if(reg_htable_size>14)
229
+			reg_htable_size = 14;
230
+		if(reg_htable_size<2)
231
+			reg_htable_size = 2;
232
+
233
+		reg_htable_size = 1<<reg_htable_size;
234
+		if(uac_reg_init_rpc()!=0)
235
+		{
236
+			LM_ERR("failed to register RPC commands\n");
237
+			goto error;
238
+		}
239
+		if(uac_reg_init_ht(reg_htable_size)<0)
240
+		{
241
+			LM_ERR("failed to init reg htable\n");
242
+			goto error;
243
+		}
244
+		uac_reg_init_db();
245
+		register_procs(1);
246
+	}
221 247
 	init_from_replacer();
222 248
 
223 249
 	uac_req_init();
... ...
@@ -227,6 +267,33 @@ error:
227 227
 	return -1;
228 228
 }
229 229
 
230
+static int child_init(int rank)
231
+{
232
+	int pid;
233
+	if (rank!=PROC_MAIN)
234
+		return 0;
235
+
236
+	if(reg_db_url.s==NULL)
237
+		return 0;
238
+
239
+	pid=fork_process(PROC_TIMER, "TIMER UAC REG", 1);
240
+	if (pid<0)
241
+	{
242
+		LM_ERR("failed to register timer routine as process\n");
243
+		return -1;
244
+	}
245
+	if (pid==0){
246
+		/* child */
247
+		uac_reg_load_db();
248
+		uac_reg_timer(0);
249
+		for(;;){
250
+			sleep(reg_timer_interval);
251
+			uac_reg_timer(get_ticks());
252
+		}
253
+	}
254
+	/* parent */
255
+	return 0;
256
+}
230 257
 
231 258
 static void mod_destroy(void)
232 259
 {
... ...
@@ -362,3 +429,25 @@ static int w_uac_auth(struct sip_msg* msg, char* str, char* str2)
362 362
 }
363 363
 
364 364
 
365
+static int w_uac_reg_lookup(struct sip_msg* msg,  char* src, char* dst)
366
+{
367
+	pv_spec_t *spv;
368
+	pv_spec_t *dpv;
369
+	pv_value_t val;
370
+
371
+	spv = (pv_spec_t*)src;
372
+	dpv = (pv_spec_t*)dst;
373
+	if(pv_get_spec_value(msg, spv, &val) != 0)
374
+	{
375
+		LM_ERR("cannot get src uri value\n");
376
+		return -1;
377
+	}
378
+
379
+	if (!(val.flags & PV_VAL_STR))
380
+	{
381
+	    LM_ERR("src pv value is not string\n");
382
+	    return -1;
383
+	}
384
+	return uac_reg_lookup(msg, &val.rs, dpv, 0);
385
+}
386
+
365 387
new file mode 100644
... ...
@@ -0,0 +1,926 @@
0
+/**
1
+ * $Id$
2
+ *
3
+ * Copyright (C) 2010 Daniel-Constantin Mierla (asipto.com)
4
+ *
5
+ * This file is part of kamailio, a free SIP server.
6
+ *
7
+ * openser is free software; you can redistribute it and/or modify
8
+ * it under the terms of the GNU General Public License as published by
9
+ * the Free Software Foundation; either version 2 of the License, or
10
+ * (at your option) any later version
11
+ *
12
+ * openser is distributed in the hope that it will be useful,
13
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
14
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15
+ * GNU General Public License for more details.
16
+ *
17
+ * You should have received a copy of the GNU General Public License
18
+ * along with this program; if not, write to the Free Software
19
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
20
+ */
21
+
22
+#include <time.h>
23
+
24
+#include "../../dprint.h"
25
+#include "../../timer.h"
26
+
27
+#include "../../mem/shm_mem.h"
28
+#include "../../lib/srdb1/db.h"
29
+#include "../../ut.h"
30
+#include "../../hashes.h"
31
+#include "../../parser/parse_uri.h"
32
+#include "../../parser/contact/parse_contact.h"
33
+#include "../../rpc.h"
34
+#include "../../rpc_lookup.h"
35
+
36
+#include "../../modules/tm/tm_load.h"
37
+
38
+#include "auth.h"
39
+#include "auth_hdr.h"
40
+#include "uac_reg.h"
41
+
42
+#define UAC_REG_DISABLED	(1<<0)
43
+#define UAC_REG_ONGOING		(1<<1)
44
+#define UAC_REG_ONLINE		(1<<2)
45
+
46
+#define MAX_UACH_SIZE 2048
47
+
48
+typedef struct _reg_uac
49
+{
50
+	unsigned int h_uuid;
51
+	unsigned int h_user;
52
+	str   l_uuid;
53
+	str   l_username;
54
+	str   l_domain;
55
+	str   r_username;
56
+	str   r_domain;
57
+	str   realm;
58
+	str   auth_username;
59
+	str   auth_password;
60
+	str   auth_proxy;
61
+	unsigned int flags;
62
+	unsigned int expires;
63
+	time_t timer_expires;
64
+} reg_uac_t;
65
+
66
+typedef struct _reg_item
67
+{
68
+	reg_uac_t *r;
69
+	struct _reg_item *next;
70
+} reg_item_t;
71
+
72
+
73
+typedef struct _reg_entry
74
+{
75
+	unsigned int isize;
76
+	unsigned int usize;
77
+	reg_item_t *byuser;
78
+	reg_item_t *byuuid;
79
+} reg_entry_t;
80
+
81
+typedef struct _reg_ht
82
+{
83
+	unsigned int htsize;
84
+	reg_entry_t *entries;
85
+} reg_ht_t;
86
+
87
+static reg_ht_t *_reg_htable = NULL;
88
+
89
+int reg_use_domain = 0;
90
+int reg_timer_interval = 90;
91
+int reg_htable_size = 4;
92
+int reg_fetch_rows = 1000;
93
+str reg_contact_addr = {0, 0};
94
+str reg_db_url = {0, 0};
95
+str reg_db_table = {"uacreg", 0};
96
+
97
+str l_uuid_column = {"l_uuid", 0};
98
+str l_username_column = {"l_username", 0};
99
+str l_domain_column = {"l_domain", 0};
100
+str r_username_column = {"r_username", 0};
101
+str r_domain_column = {"r_domain", 0};
102
+str realm_column = {"realm", 0};
103
+str auth_username_column = {"auth_username", 0};
104
+str auth_password_column = {"auth_password", 0};
105
+str auth_proxy_column = {"auth_proxy", 0};
106
+str expires_column = {"expires", 0};
107
+
108
+#if 0
109
+INSERT INTO version (table_name, table_version) values ('uacreg','1');
110
+CREATE TABLE uacreg (
111
+    id INT(10) UNSIGNED AUTO_INCREMENT PRIMARY KEY NOT NULL,
112
+    l_uuid VARCHAR(64) NOT NULL,
113
+    l_username VARCHAR(64) NOT NULL,
114
+    l_domain VARCHAR(128) DEFAULT '' NOT NULL,
115
+    r_username VARCHAR(64) NOT NULL,
116
+    r_domain VARCHAR(128) NOT NULL,
117
+    realm VARCHAR(64) NOT NULL,
118
+    auth_username VARCHAR(64) NOT NULL,
119
+    auth_password VARCHAR(64) NOT NULL,
120
+    auth_proxy VARCHAR(128) DEFAULT '' NOT NULL,
121
+    expires INT(10) UNSIGNED DEFAULT 0 NOT NULL,
122
+    CONSTRAINT l_uuid_idx UNIQUE (l_uuid)
123
+) ENGINE=MyISAM;
124
+#endif
125
+
126
+
127
+extern struct tm_binds uac_tmb;
128
+
129
+/**
130
+ *
131
+ */
132
+int uac_reg_init_db(void)
133
+{
134
+	reg_contact_addr.len = strlen(reg_contact_addr.s);
135
+	
136
+	reg_db_url.len = strlen(reg_db_url.s);
137
+	reg_db_table.len = strlen(reg_db_table.s);
138
+
139
+	l_uuid_column.len = strlen(l_uuid_column.s);
140
+	l_username_column.len = strlen(l_username_column.s);
141
+	l_domain_column.len = strlen(l_domain_column.s);
142
+	r_username_column.len = strlen(r_username_column.s);
143
+	r_domain_column.len = strlen(r_domain_column.s);
144
+	realm_column.len = strlen(realm_column.s);
145
+	auth_username_column.len = strlen(auth_username_column.s);
146
+	auth_password_column.len = strlen(auth_password_column.s);
147
+	auth_proxy_column.len = strlen(auth_proxy_column.s);
148
+	expires_column.len = strlen(expires_column.s);
149
+
150
+	return 0;
151
+}
152
+
153
+/**
154
+ *
155
+ */
156
+int uac_reg_init_ht(unsigned int sz)
157
+{
158
+	_reg_htable = (reg_ht_t*)shm_malloc(sizeof(reg_ht_t));
159
+	if(_reg_htable==NULL)
160
+	{
161
+		LM_ERR("no more shm\n");
162
+		return -1;
163
+	}
164
+	memset(_reg_htable, 0, sizeof(reg_ht_t));
165
+	_reg_htable->htsize = sz;
166
+
167
+	_reg_htable->entries =
168
+			(reg_entry_t*)shm_malloc(_reg_htable->htsize*sizeof(reg_entry_t));
169
+	if(_reg_htable->entries==NULL)
170
+	{
171
+		LM_ERR("no more shm.\n");
172
+		shm_free(_reg_htable);
173
+		return -1;
174
+	}
175
+	memset(_reg_htable->entries, 0, _reg_htable->htsize*sizeof(reg_entry_t));
176
+
177
+	return 0;
178
+}
179
+
180
+/**
181
+ *
182
+ */
183
+int uac_reg_free_ht(void)
184
+{
185
+	int i;
186
+	reg_item_t *it = NULL;
187
+	reg_item_t *it0 = NULL;
188
+
189
+	if(_reg_htable==NULL)
190
+	{
191
+		LM_DBG("no hash table\n");
192
+		return -1;
193
+	}
194
+	for(i=0; i<_reg_htable->htsize; i++)
195
+	{
196
+		/* free entries */
197
+		it = _reg_htable->entries[i].byuuid;
198
+		while(it)
199
+		{
200
+			it0 = it;
201
+			it = it->next;
202
+			shm_free(it0);
203
+		}
204
+		it = _reg_htable->entries[i].byuser;
205
+		while(it)
206
+		{
207
+			it0 = it;
208
+			it = it->next;
209
+			shm_free(it0->r);
210
+			shm_free(it0);
211
+		}
212
+	}
213
+	shm_free(_reg_htable->entries);
214
+	shm_free(_reg_htable);
215
+	_reg_htable = NULL;
216
+	return 0;
217
+}
218
+
219
+#define reg_compute_hash(_s)		get_hash1_raw((_s)->s,(_s)->len)
220
+#define reg_get_entry(_h,_size)		((_h)&((_size)-1))
221
+
222
+/**
223
+ *
224
+ */
225
+int reg_ht_add_byuuid(reg_uac_t *reg)
226
+{
227
+	unsigned int slot;
228
+	reg_item_t *ri = NULL;
229
+
230
+	ri = (reg_item_t*)shm_malloc(sizeof(reg_item_t));
231
+	if(ri==NULL)
232
+	{
233
+		LM_ERR("no more shm\n");
234
+		return -1;
235
+	}
236
+	memset(ri, 0, sizeof(reg_item_t));
237
+	slot = reg_get_entry(reg->h_uuid, _reg_htable->htsize);
238
+	ri->r = reg;
239
+	ri->next = _reg_htable->entries[slot].byuuid;
240
+	_reg_htable->entries[slot].byuuid = ri;
241
+	_reg_htable->entries[slot].isize++;
242
+	return 0;
243
+}
244
+
245
+/**
246
+ *
247
+ */
248
+int reg_ht_add_byuser(reg_uac_t *reg)
249
+{
250
+	unsigned int slot;
251
+	reg_item_t *ri = NULL;
252
+
253
+	ri = (reg_item_t*)shm_malloc(sizeof(reg_item_t));
254
+	if(ri==NULL)
255
+	{
256
+		LM_ERR("no more shm\n");
257
+		return -1;
258
+	}
259
+	memset(ri, 0, sizeof(reg_item_t));
260
+	slot = reg_get_entry(reg->h_user, _reg_htable->htsize);
261
+	ri->r = reg;
262
+	ri->next = _reg_htable->entries[slot].byuser;
263
+	_reg_htable->entries[slot].byuser = ri;
264
+	_reg_htable->entries[slot].usize++;
265
+	return 0;
266
+}
267
+
268
+#define reg_copy_shm(dst, src) do { \
269
+		if((src)->s!=NULL) { \
270
+			(dst)->s = p; \
271
+			strncpy((dst)->s, (src)->s, (src)->len); \
272
+			(dst)->len = (src)->len; \
273
+			(dst)->s[(dst)->len] = '\0'; \
274
+			p = p + (dst)->len + 1; \
275
+		} \
276
+	} while(0);
277
+
278
+/**
279
+ *
280
+ */
281
+int reg_ht_add(reg_uac_t *reg)
282
+{
283
+	int len;
284
+	reg_uac_t *nr = NULL;
285
+	char *p;
286
+
287
+	if(reg==NULL || _reg_htable==NULL)
288
+	{
289
+		LM_ERR("bad paramaers: %p/%p\n", reg, _reg_htable);
290
+		return -1;
291
+	}
292
+	len = reg->l_uuid.len + 1
293
+			+ reg->l_username.len + 1
294
+			+ reg->l_domain.len + 1
295
+			+ reg->r_username.len + 1
296
+			+ reg->r_domain.len + 1
297
+			+ reg->realm.len + 1
298
+			+ reg->auth_username.len + 1
299
+			+ reg->auth_password.len + 1
300
+			+ reg->auth_proxy.len + 1;
301
+	nr = (reg_uac_t*)shm_malloc(sizeof(reg_uac_t) + len);
302
+	if(nr==NULL)
303
+	{
304
+		LM_ERR("no more shm\n");
305
+		return -1;
306
+	}
307
+	memset(nr, 0, sizeof(reg_uac_t) + len);
308
+	nr->expires = reg->expires;
309
+	nr->h_uuid = reg_compute_hash(&reg->l_uuid);
310
+	nr->h_user = reg_compute_hash(&reg->l_username);
311
+	
312
+	p = (char*)nr + sizeof(reg_uac_t);
313
+
314
+	reg_copy_shm(&nr->l_uuid, &reg->l_uuid);
315
+	reg_copy_shm(&nr->l_username, &reg->l_username);
316
+	reg_copy_shm(&nr->l_domain, &reg->l_domain);
317
+	reg_copy_shm(&nr->r_username, &reg->r_username);
318
+	reg_copy_shm(&nr->r_domain, &reg->r_domain);
319
+	reg_copy_shm(&nr->realm, &reg->realm);
320
+	reg_copy_shm(&nr->auth_username, &reg->auth_username);
321
+	reg_copy_shm(&nr->auth_password, &reg->auth_password);
322
+	reg_copy_shm(&nr->auth_proxy, &reg->auth_proxy);
323
+
324
+	reg_ht_add_byuser(nr);
325
+	reg_ht_add_byuuid(nr);
326
+
327
+	return 0;
328
+}
329
+
330
+
331
+/**
332
+ *
333
+ */
334
+reg_uac_t *reg_ht_get_byuuid(str *uuid)
335
+{
336
+	unsigned int hash;
337
+	unsigned int slot;
338
+	reg_item_t *it = NULL;
339
+
340
+	hash = reg_compute_hash(uuid);
341
+	slot = reg_get_entry(hash, _reg_htable->htsize);
342
+	it = _reg_htable->entries[slot].byuuid;
343
+	while(it)
344
+	{
345
+		if((it->r->h_uuid==hash) && (it->r->l_uuid.len==uuid->len)
346
+				&& (strncmp(it->r->l_uuid.s, uuid->s, uuid->len)==0))
347
+		{
348
+			return it->r;
349
+		}
350
+		it = it->next;
351
+	}
352
+	return NULL;
353
+}
354
+
355
+/**
356
+ *
357
+ */
358
+reg_uac_t *reg_ht_get_byuser(str *user, str *domain)
359
+{
360
+	unsigned int hash;
361
+	unsigned int slot;
362
+	reg_item_t *it = NULL;
363
+
364
+	hash = reg_compute_hash(user);
365
+	slot = reg_get_entry(hash, _reg_htable->htsize);
366
+	it = _reg_htable->entries[slot].byuser;
367
+	while(it)
368
+	{
369
+		if((it->r->h_uuid==hash) && (it->r->l_username.len==user->len)
370
+				&& (strncmp(it->r->l_username.s, user->s, user->len)==0))
371
+		{
372
+			if(domain!=NULL && domain->s!=NULL)
373
+			{
374
+				if((it->r->l_domain.len==domain->len)
375
+				&& (strncmp(it->r->l_domain.s, domain->s, domain->len)==0))
376
+				{
377
+					return it->r;
378
+				}
379
+			}
380
+		}
381
+		it = it->next;
382
+	}
383
+	return NULL;
384
+}
385
+
386
+void uac_reg_tm_callback( struct cell *t, int type, struct tmcb_params *ps)
387
+{
388
+	char *uuid;
389
+	str suuid;
390
+	reg_uac_t *ri = NULL;
391
+	contact_t* c;
392
+	int expires;
393
+	struct sip_uri puri;
394
+	struct hdr_field *hdr;
395
+	HASHHEX response;
396
+	str *new_auth_hdr = NULL;
397
+	static struct authenticate_body auth;
398
+	struct uac_credential cred;
399
+	char  b_ruri[MAX_URI_SIZE];
400
+	str   s_ruri;
401
+	char  b_turi[MAX_URI_SIZE];
402
+	str   s_turi;
403
+	char  b_hdrs[MAX_UACH_SIZE];
404
+	str   s_hdrs;
405
+	uac_req_t uac_r;
406
+	str method = {"REGISTER", 8};
407
+	int ret;
408
+
409
+	if(ps->param==NULL || *ps->param==0)
410
+	{
411
+		LM_DBG("uuid not received\n");
412
+		return;
413
+	}
414
+	uuid = *((char**)ps->param);
415
+	LM_DBG("completed with status %d [uuid: %s]\n",
416
+		ps->code, uuid);
417
+	suuid.s = uuid;
418
+	suuid.len = strlen(suuid.s);
419
+	ri = reg_ht_get_byuuid(&suuid);
420
+
421
+	if(ri==NULL)
422
+	{
423
+		LM_DBG("no user with uuid %s\n", uuid);
424
+		goto done;
425
+	}
426
+
427
+	if(ps->code == 200)
428
+	{
429
+		if (parse_headers(ps->rpl, HDR_EOH_F, 0) == -1)
430
+		{
431
+			LM_ERR("failed to parse headers\n");
432
+			goto done;
433
+		}
434
+		if (ps->rpl->contact==NULL)
435
+		{
436
+			LM_ERR("no Contact found\n");
437
+			goto done;
438
+		}
439
+		if (parse_contact(ps->rpl->contact) < 0)
440
+		{
441
+			LM_ERR("failed to parse Contact HF\n");
442
+			goto done;
443
+		}
444
+		if (((contact_body_t*)ps->rpl->contact->parsed)->star)
445
+		{
446
+			LM_DBG("* Contact found\n");
447
+			goto done;
448
+		}
449
+
450
+		if (contact_iterator(&c, ps->rpl, 0) < 0)
451
+			goto done;
452
+		while(c)
453
+		{
454
+			if(parse_uri(c->uri.s, c->uri.len, &puri)!=0)
455
+			{
456
+				LM_ERR("failed to parse c-uri\n");
457
+				goto done;
458
+			}
459
+			if(suuid.len==puri.user.len
460
+					&& (strncmp(puri.user.s, suuid.s, suuid.len)==0))
461
+			{
462
+				/* calculate expires */
463
+				expires=0;
464
+				if(c->expires==NULL || c->expires->body.len<=0)
465
+				{
466
+					if(ps->rpl->expires!=NULL && ps->rpl->expires->body.len>0)
467
+						expires = atoi(ps->rpl->expires->body.s);
468
+				} else {
469
+					str2int(&c->expires->body, (unsigned int*)(&expires));
470
+				}
471
+				ri->timer_expires = ri->timer_expires + expires;
472
+				ri->flags &= ~UAC_REG_ONGOING;
473
+				ri->flags |= UAC_REG_ONLINE;
474
+				goto done;
475
+			}
476
+			if (contact_iterator(&c, ps->rpl, c) < 0)
477
+			{
478
+				LM_DBG("local contact not found\n");
479
+				goto done;
480
+			}
481
+		}
482
+	}
483
+
484
+	if(ps->code == 401)
485
+	{
486
+		hdr = get_autenticate_hdr(ps->rpl, 401);
487
+		if (hdr==0)
488
+		{
489
+			LM_ERR("failed to extract authenticate hdr\n");
490
+			goto done;
491
+		}
492
+
493
+		LM_DBG("auth header body [%.*s]\n",
494
+			hdr->body.len, hdr->body.s);
495
+
496
+		if (parse_authenticate_body(&hdr->body, &auth)<0)
497
+		{
498
+			LM_ERR("failed to parse auth hdr body\n");
499
+			goto done;
500
+		}
501
+		if(auth.realm.len!=ri->realm.len
502
+				|| strncmp(auth.realm.s, ri->realm.s, ri->realm.len)!=0)
503
+		{
504
+			LM_ERR("realms are different - ignire?!?!\n");
505
+		}
506
+		cred.realm = auth.realm;
507
+		cred.user = ri->auth_username; 
508
+		cred.passwd = ri->auth_password;
509
+ 		cred.next = NULL;
510
+
511
+		snprintf(b_ruri, MAX_URI_SIZE, "sip:%.*s",
512
+				ri->r_domain.len, ri->r_domain.s);
513
+		s_ruri.s = b_ruri; s_ruri.len = strlen(s_ruri.s);
514
+
515
+		do_uac_auth(&method, &s_ruri, &cred, &auth, response);
516
+		new_auth_hdr=build_authorization_hdr(401, &s_ruri, &cred,
517
+						&auth, response);
518
+		if (new_auth_hdr==0)
519
+		{
520
+			LM_ERR("failed to build authorization hdr\n");
521
+			goto done;
522
+		}
523
+		
524
+		snprintf(b_turi, MAX_URI_SIZE, "sip:%.*s@%.*s",
525
+				ri->r_username.len, ri->r_username.s,
526
+				ri->r_domain.len, ri->r_domain.s);
527
+		s_turi.s = b_turi; s_turi.len = strlen(s_turi.s);
528
+
529
+		snprintf(b_hdrs, MAX_UACH_SIZE,
530
+				"Contact: <sip:%.*s@%.*s>\r\n"
531
+				"Expires: %d\r\n"
532
+				"%.*s",
533
+				ri->l_uuid.len, ri->l_uuid.s,
534
+				reg_contact_addr.len, reg_contact_addr.s,
535
+				ri->expires,
536
+				new_auth_hdr->len, new_auth_hdr->s);
537
+		s_hdrs.s = b_hdrs; s_hdrs.len = strlen(s_hdrs.s);
538
+		pkg_free(new_auth_hdr->s);
539
+
540
+		memset(&uac_r, '\0', sizeof(uac_r));
541
+		uac_r.method = &method;
542
+		uac_r.headers = &s_hdrs;
543
+		uac_r.cb_flags = TMCB_LOCAL_COMPLETED;
544
+		/* Callback function */
545
+		uac_r.cb  = uac_reg_tm_callback;
546
+		/* Callback parameter */
547
+		uac_r.cbp = (void*)uuid;
548
+		ret = uac_tmb.t_request(&uac_r,  /* UAC Req */
549
+				&s_ruri, /* Request-URI */
550
+				&s_turi, /* To */
551
+				&s_turi, /* From */
552
+				(ri->auth_proxy.len)?&ri->auth_proxy:NULL /* outbound uri */
553
+			);
554
+
555
+		if(ret<0)
556
+			goto done;
557
+		return;
558
+	}
559
+
560
+done:
561
+	ri->flags &= ~UAC_REG_ONGOING;
562
+	shm_free(uuid);
563
+}
564
+
565
+int uac_reg_update(reg_uac_t *reg, time_t tn)
566
+{
567
+	char *uuid;
568
+	uac_req_t uac_r;
569
+	str method = {"REGISTER", 8};
570
+	int ret;
571
+	char  b_ruri[MAX_URI_SIZE];
572
+	str   s_ruri;
573
+	char  b_turi[MAX_URI_SIZE];
574
+	str   s_turi;
575
+	char  b_hdrs[MAX_UACH_SIZE];
576
+	str   s_hdrs;
577
+
578
+	if(uac_tmb.t_request==NULL)
579
+		return -1;
580
+	if(reg->expires==0)
581
+		return 1;
582
+	if(reg->flags&UAC_REG_ONGOING)
583
+		return 2;
584
+	if(reg->timer_expires > tn + reg_timer_interval + 3)
585
+		return 3;
586
+	reg->timer_expires = tn;
587
+	reg->flags |= UAC_REG_ONGOING;
588
+	reg->flags &= ~UAC_REG_ONLINE;
589
+	uuid = (char*)shm_malloc(reg->l_uuid.len+1);
590
+	if(uuid==NULL)
591
+	{
592
+		LM_ERR("no more shm\n");
593
+		return -1;
594
+	}
595
+	memcpy(uuid, reg->l_uuid.s, reg->l_uuid.len);
596
+	uuid[reg->l_uuid.len] = '\0';
597
+
598
+	snprintf(b_ruri, MAX_URI_SIZE, "sip:%.*s",
599
+			reg->r_domain.len, reg->r_domain.s);
600
+	s_ruri.s = b_ruri; s_ruri.len = strlen(s_ruri.s);
601
+
602
+	snprintf(b_turi, MAX_URI_SIZE, "sip:%.*s@%.*s",
603
+			reg->r_username.len, reg->r_username.s,
604
+			reg->r_domain.len, reg->r_domain.s);
605
+	s_turi.s = b_turi; s_turi.len = strlen(s_turi.s);
606
+
607
+	snprintf(b_hdrs, MAX_UACH_SIZE,
608
+			"Contact: <sip:%.*s@%.*s>\r\n"
609
+			"Expires: %d\r\n",
610
+			reg->l_uuid.len, reg->l_uuid.s,
611
+			reg_contact_addr.len, reg_contact_addr.s,
612
+			reg->expires);
613
+	s_hdrs.s = b_hdrs; s_hdrs.len = strlen(s_hdrs.s);
614
+
615
+	memset(&uac_r, '\0', sizeof(uac_r));
616
+	uac_r.method = &method;
617
+	uac_r.headers = &s_hdrs;
618
+	uac_r.cb_flags = TMCB_LOCAL_COMPLETED;
619
+	/* Callback function */
620
+	uac_r.cb  = uac_reg_tm_callback;
621
+	/* Callback parameter */
622
+	uac_r.cbp = (void*)uuid;
623
+	ret = uac_tmb.t_request(&uac_r,  /* UAC Req */
624
+			&s_ruri, /* Request-URI */
625
+			&s_turi, /* To */
626
+			&s_turi, /* From */
627
+			(reg->auth_proxy.len)?&reg->auth_proxy:NULL /* outbound uri */
628
+		);
629
+
630
+	if(ret<0)
631
+	{
632
+		shm_free(uuid);
633
+		return -1;
634
+	}
635
+	return 0;
636
+}
637
+
638
+/**
639
+ *
640
+ */
641
+void uac_reg_timer(unsigned int ticks)
642
+{
643
+	int i;
644
+	reg_item_t *it = NULL;
645
+	time_t tn;
646
+
647
+	tn = time(NULL);
648
+	for(i=0; i<_reg_htable->htsize; i++)
649
+	{
650
+		/* free entries */
651
+		it = _reg_htable->entries[i].byuuid;
652
+		while(it)
653
+		{
654
+			uac_reg_update(it->r, tn);
655
+			it = it->next;
656
+		}
657
+	}
658
+}
659
+
660
+#define reg_db_set_attr(attr, pos) do { \
661
+		if(!VAL_NULL(&RES_ROWS(db_res)[i].values[pos])) { \
662
+			reg.attr.s = \
663
+				(char*)(RES_ROWS(db_res)[i].values[pos].val.string_val); \
664
+			reg.attr.len = strlen(reg.attr.s); \
665
+		} \
666
+	} while(0);
667
+
668
+/**
669
+ *
670
+ */
671
+int uac_reg_load_db(void)
672
+{
673
+	db1_con_t *reg_db_con = NULL;
674
+	db_func_t reg_dbf;
675
+	reg_uac_t reg;
676
+	db_key_t db_cols[10] = {
677
+		&l_uuid_column,
678
+		&l_username_column,
679
+		&l_domain_column,
680
+		&r_username_column,
681
+		&r_domain_column,
682
+		&realm_column,
683
+		&auth_username_column,
684
+		&auth_password_column,
685
+		&auth_proxy_column,
686
+		&expires_column
687
+	};
688
+	db1_res_t* db_res = NULL;
689
+	int i, ret;
690
+
691
+	/* binding to db module */
692
+	if(reg_db_url.s==NULL)
693
+	{
694
+		LM_ERR("no db url\n");
695
+		return -1;
696
+	}
697
+
698
+	if(db_bind_mod(&reg_db_url, &reg_dbf))
699
+	{
700
+		LM_ERR("database module not found\n");
701
+		return -1;
702
+	}
703
+
704
+	if (!DB_CAPABILITY(reg_dbf, DB_CAP_ALL))
705
+	{
706
+		LM_ERR("database module does not "
707
+		    "implement all functions needed by the module\n");
708
+		return -1;
709
+	}
710
+
711
+	/* open a connection with the database */
712
+	reg_db_con = reg_dbf.init(&reg_db_url);
713
+	if(reg_db_con==NULL)
714
+	{
715
+		LM_ERR("failed to connect to the database\n");        
716
+		return -1;