48267ba95cb7ae0363f6b342e16a3224520ce00f
[sip-router] / src / modules / db_mysql / my_uri.c
1 /*
2  * MySQL module interface
3  *
4  * Copyright (C) 2001-2003 FhG FOKUS
5  * Copyright (C) 2006-2007 iptelorg GmbH
6  *
7  * This file is part of Kamailio, a free SIP server.
8  *
9  * Kamailio is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * (at your option) any later version
13  *
14  * Kamailio is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software
21  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
22  */
23
24 #include "my_uri.h"
25
26 #include "../../core/dprint.h"
27 #include "../../core/mem/mem.h"
28 #include "../../core/ut.h"
29 #include "../../lib/srdb2/db_gen.h"
30
31 #include <stdlib.h>
32 #include <string.h>
33
34
35 /* compare s1 & s2  with a function f (which should return 0 if ==);
36  * s1 & s2 can be null
37  * return 0 if match, 1 if not */
38 #define cmpstr(s1, s2, f) \
39         ((s1)!=(s2)) && ((s1)==0 || (s2)==0 || (f)((s1), (s2))!=0)
40
41 /*
42  * Compare two connection identifiers
43  */
44 static unsigned char my_uri_cmp(db_uri_t* uri1, db_uri_t* uri2)
45 {
46         struct my_uri* muri1, *muri2;
47
48         if (!uri1 || !uri2) return 0;
49
50         muri1 = DB_GET_PAYLOAD(uri1);
51         muri2 = DB_GET_PAYLOAD(uri2);
52         if (muri1->port != muri2->port) return 0;
53
54         if (cmpstr(muri1->username, muri2->username, strcmp)) return 0;
55         if (cmpstr(muri1->password, muri2->password, strcmp)) return 0;
56         if (cmpstr(muri1->host, muri2->host, strcasecmp)) return 0;
57         if (cmpstr(muri1->database, muri2->database, strcmp)) return 0;
58         return 1;
59 }
60
61
62
63 /*
64  * Duplicate a string
65  */
66 static int dupl_string(char** dst, const char* begin, const char* end)
67 {
68         if (*dst) pkg_free(*dst);
69
70         *dst = pkg_malloc(end - begin + 1);
71         if ((*dst) == NULL) {
72                 PKG_MEM_ERROR;
73                 return -1;
74         }
75
76         memcpy(*dst, begin, end - begin);
77         (*dst)[end - begin] = '\0';
78         return 0;
79 }
80
81
82 /*
83  * Parse mysql URI of form
84  * //[username[:password]@]hostname[:port]/database
85  *
86  * Returns 0 if parsing was successful and -1 otherwise
87  */
88 static int parse_mysql_uri(struct my_uri* res, str* uri)
89 {
90 #define SHORTEST_DB_URL "//a/b"
91 #define SHORTEST_DB_URL_LEN (sizeof(SHORTEST_DB_URL) - 1)
92
93         enum state {
94                 ST_SLASH1,     /* First slash */
95                 ST_SLASH2,     /* Second slash */
96                 ST_USER_HOST,  /* Username or hostname */
97                 ST_PASS_PORT,  /* Password or port part */
98                 ST_HOST,       /* Hostname part */
99                 ST_PORT,       /* Port part */
100                 ST_DB          /* Database part */
101         };
102
103         enum state st;
104         int  i;
105         const char* begin;
106         char* prev_token;
107
108         prev_token = 0;
109
110         if (!res || !uri) {
111                 goto err;
112         }
113
114         if (uri->len < SHORTEST_DB_URL_LEN) {
115                 goto err;
116         }
117
118         st = ST_SLASH1;
119         begin = uri->s;
120
121         for(i = 0; i < uri->len; i++) {
122                 switch(st) {
123                 case ST_SLASH1:
124                         switch(uri->s[i]) {
125                         case '/':
126                                 st = ST_SLASH2;
127                                 break;
128
129                         default:
130                                 goto err;
131                         }
132                         break;
133
134                 case ST_SLASH2:
135                         switch(uri->s[i]) {
136                         case '/':
137                                 st = ST_USER_HOST;
138                                 begin = uri->s + i + 1;
139                                 break;
140
141                         default:
142                                 goto err;
143                         }
144                         break;
145
146                 case ST_USER_HOST:
147                         switch(uri->s[i]) {
148                         case '@':
149                                 st = ST_HOST;
150                                 if (dupl_string(&res->username, begin, uri->s + i) < 0) goto err;
151                                 begin = uri->s + i + 1;
152                                 break;
153
154                         case ':':
155                                 st = ST_PASS_PORT;
156                                 if (dupl_string(&prev_token, begin, uri->s + i) < 0) goto err;
157                                 begin = uri->s + i + 1;
158                                 break;
159
160                         case '/':
161                                 if (dupl_string(&res->host, begin, uri->s + i) < 0) goto err;
162                                 if (dupl_string(&res->database, uri->s + i + 1, uri->s + uri->len) < 0) goto err;
163                                 return 0;
164                         }
165                         break;
166
167                 case ST_PASS_PORT:
168                         switch(uri->s[i]) {
169                         case '@':
170                                 st = ST_HOST;
171                                 res->username = prev_token;
172                                 prev_token = 0;
173                                 if (dupl_string(&res->password, begin, uri->s + i) < 0) goto err;
174                                 begin = uri->s + i + 1;
175                                 break;
176
177                         case '/':
178                                 res->host = prev_token;
179                                 prev_token = 0;
180                                 res->port = str2s(begin, uri->s + i - begin, 0);
181                                 if (dupl_string(&res->database, uri->s + i + 1, uri->s + uri->len) < 0) goto err;
182                                 return 0;
183                         }
184                         break;
185
186                 case ST_HOST:
187                         switch(uri->s[i]) {
188                         case ':':
189                                 st = ST_PORT;
190                                 if (dupl_string(&res->host, begin, uri->s + i) < 0) goto err;
191                                 begin = uri->s + i + 1;
192                                 break;
193
194                         case '/':
195                                 if (dupl_string(&res->host, begin, uri->s + i) < 0) goto err;
196                                 if (dupl_string(&res->database, uri->s + i + 1, uri->s + uri->len) < 0) goto err;
197                                 return 0;
198                         }
199                         break;
200
201                 case ST_PORT:
202                         switch(uri->s[i]) {
203                         case '/':
204                                 res->port = str2s(begin, uri->s + i - begin, 0);
205                                 if (dupl_string(&res->database, uri->s + i + 1, uri->s + uri->len) < 0) goto err;
206                                 return 0;
207                         }
208                         break;
209
210                 case ST_DB:
211                         break;
212                 }
213         }
214
215         if (st != ST_DB) goto err;
216         return 0;
217
218 err:
219         if (prev_token) pkg_free(prev_token);
220         if (res == NULL) return -1;
221         if (res->username) {
222                 pkg_free(res->username);
223                 res->username = NULL;
224         }
225         if (res->password) {
226                 pkg_free(res->password);
227                 res->password = NULL;
228         }
229         if (res->host) {
230                 pkg_free(res->host);
231                 res->host = NULL;
232         }
233         if (res->database) {
234                 pkg_free(res->database);
235                 res->database = NULL;
236         }
237         return -1;
238 }
239
240
241
242 static void my_uri_free(db_uri_t* uri, struct my_uri* payload)
243 {
244         if (payload == NULL) return;
245         db_drv_free(&payload->drv);
246         if (payload->username) pkg_free(payload->username);
247         if (payload->password) pkg_free(payload->password);
248         if (payload->host) pkg_free(payload->host);
249         if (payload->database) pkg_free(payload->database);
250         pkg_free(payload);
251 }
252
253
254 int my_uri(db_uri_t* uri)
255 {
256         struct my_uri* res;
257
258         res = (struct my_uri*)pkg_malloc(sizeof(struct my_uri));
259         if (res == NULL) {
260                 PKG_MEM_ERROR;
261                 goto error;
262         }
263         memset(res, '\0', sizeof(struct my_uri));
264         if (db_drv_init(&res->drv, my_uri_free) < 0) goto error;
265         if (parse_mysql_uri(res, &uri->body) < 0) goto error;
266
267         DB_SET_PAYLOAD(uri, res);
268         uri->cmp = my_uri_cmp;
269         return 0;
270
271 error:
272         if (res) {
273                 db_drv_free(&res->drv);
274                 if (res) pkg_free(res);
275         }
276         return -1;
277 }
278