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