my_uri.c 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284
  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. * [email protected]
  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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  29. */
  30. #include "my_uri.h"
  31. #include "../../dprint.h"
  32. #include "../../mem/mem.h"
  33. #include "../../ut.h"
  34. #include "../../lib/srdb2/db_gen.h"
  35. #include <stdlib.h>
  36. #include <string.h>
  37. /* compare s1 & s2 with a function f (which should return 0 if ==);
  38. * s1 & s2 can be null
  39. * return 0 if match, 1 if not */
  40. #define cmpstr(s1, s2, f) \
  41. ((s1)!=(s2)) && ((s1)==0 || (s2)==0 || (f)((s1), (s2))!=0)
  42. /*
  43. * Compare two connection identifiers
  44. */
  45. static unsigned char my_uri_cmp(db_uri_t* uri1, db_uri_t* uri2)
  46. {
  47. struct my_uri* muri1, *muri2;
  48. if (!uri1 || !uri2) return 0;
  49. muri1 = DB_GET_PAYLOAD(uri1);
  50. muri2 = DB_GET_PAYLOAD(uri2);
  51. if (muri1->port != muri2->port) return 0;
  52. if (cmpstr(muri1->username, muri2->username, strcmp)) return 0;
  53. if (cmpstr(muri1->password, muri2->password, strcmp)) return 0;
  54. if (cmpstr(muri1->host, muri2->host, strcasecmp)) return 0;
  55. if (cmpstr(muri1->database, muri2->database, strcmp)) return 0;
  56. return 1;
  57. }
  58. /*
  59. * Duplicate a string
  60. */
  61. static int dupl_string(char** dst, const char* begin, const char* end)
  62. {
  63. if (*dst) pkg_free(*dst);
  64. *dst = pkg_malloc(end - begin + 1);
  65. if ((*dst) == NULL) {
  66. return -1;
  67. }
  68. memcpy(*dst, begin, end - begin);
  69. (*dst)[end - begin] = '\0';
  70. return 0;
  71. }
  72. /*
  73. * Parse mysql URI of form
  74. * //[username[:password]@]hostname[:port]/database
  75. *
  76. * Returns 0 if parsing was successful and -1 otherwise
  77. */
  78. static int parse_mysql_uri(struct my_uri* res, str* uri)
  79. {
  80. #define SHORTEST_DB_URL "//a/b"
  81. #define SHORTEST_DB_URL_LEN (sizeof(SHORTEST_DB_URL) - 1)
  82. enum state {
  83. ST_SLASH1, /* First slash */
  84. ST_SLASH2, /* Second slash */
  85. ST_USER_HOST, /* Username or hostname */
  86. ST_PASS_PORT, /* Password or port part */
  87. ST_HOST, /* Hostname part */
  88. ST_PORT, /* Port part */
  89. ST_DB /* Database part */
  90. };
  91. enum state st;
  92. int i;
  93. const char* begin;
  94. char* prev_token;
  95. prev_token = 0;
  96. if (!res || !uri) {
  97. goto err;
  98. }
  99. if (uri->len < SHORTEST_DB_URL_LEN) {
  100. goto err;
  101. }
  102. st = ST_SLASH1;
  103. begin = uri->s;
  104. for(i = 0; i < uri->len; i++) {
  105. switch(st) {
  106. case ST_SLASH1:
  107. switch(uri->s[i]) {
  108. case '/':
  109. st = ST_SLASH2;
  110. break;
  111. default:
  112. goto err;
  113. }
  114. break;
  115. case ST_SLASH2:
  116. switch(uri->s[i]) {
  117. case '/':
  118. st = ST_USER_HOST;
  119. begin = uri->s + i + 1;
  120. break;
  121. default:
  122. goto err;
  123. }
  124. break;
  125. case ST_USER_HOST:
  126. switch(uri->s[i]) {
  127. case '@':
  128. st = ST_HOST;
  129. if (dupl_string(&res->username, begin, uri->s + i) < 0) goto err;
  130. begin = uri->s + i + 1;
  131. break;
  132. case ':':
  133. st = ST_PASS_PORT;
  134. if (dupl_string(&prev_token, begin, uri->s + i) < 0) goto err;
  135. begin = uri->s + i + 1;
  136. break;
  137. case '/':
  138. if (dupl_string(&res->host, begin, uri->s + i) < 0) goto err;
  139. if (dupl_string(&res->database, uri->s + i + 1, uri->s + uri->len) < 0) goto err;
  140. return 0;
  141. }
  142. break;
  143. case ST_PASS_PORT:
  144. switch(uri->s[i]) {
  145. case '@':
  146. st = ST_HOST;
  147. res->username = prev_token;
  148. prev_token = 0;
  149. if (dupl_string(&res->password, begin, uri->s + i) < 0) goto err;
  150. begin = uri->s + i + 1;
  151. break;
  152. case '/':
  153. res->host = prev_token;
  154. prev_token = 0;
  155. res->port = str2s(begin, uri->s + i - begin, 0);
  156. if (dupl_string(&res->database, uri->s + i + 1, uri->s + uri->len) < 0) goto err;
  157. return 0;
  158. }
  159. break;
  160. case ST_HOST:
  161. switch(uri->s[i]) {
  162. case ':':
  163. st = ST_PORT;
  164. if (dupl_string(&res->host, begin, uri->s + i) < 0) goto err;
  165. begin = uri->s + i + 1;
  166. break;
  167. case '/':
  168. if (dupl_string(&res->host, begin, uri->s + i) < 0) goto err;
  169. if (dupl_string(&res->database, uri->s + i + 1, uri->s + uri->len) < 0) goto err;
  170. return 0;
  171. }
  172. break;
  173. case ST_PORT:
  174. switch(uri->s[i]) {
  175. case '/':
  176. res->port = str2s(begin, uri->s + i - begin, 0);
  177. if (dupl_string(&res->database, uri->s + i + 1, uri->s + uri->len) < 0) goto err;
  178. return 0;
  179. }
  180. break;
  181. case ST_DB:
  182. break;
  183. }
  184. }
  185. if (st != ST_DB) goto err;
  186. return 0;
  187. err:
  188. if (prev_token) pkg_free(prev_token);
  189. if (res == NULL) return -1;
  190. if (res->username) {
  191. pkg_free(res->username);
  192. res->username = NULL;
  193. }
  194. if (res->password) {
  195. pkg_free(res->password);
  196. res->password = NULL;
  197. }
  198. if (res->host) {
  199. pkg_free(res->host);
  200. res->host = NULL;
  201. }
  202. if (res->database) {
  203. pkg_free(res->database);
  204. res->database = NULL;
  205. }
  206. return -1;
  207. }
  208. static void my_uri_free(db_uri_t* uri, struct my_uri* payload)
  209. {
  210. if (payload == NULL) return;
  211. db_drv_free(&payload->drv);
  212. if (payload->username) pkg_free(payload->username);
  213. if (payload->password) pkg_free(payload->password);
  214. if (payload->host) pkg_free(payload->host);
  215. if (payload->database) pkg_free(payload->database);
  216. pkg_free(payload);
  217. }
  218. int my_uri(db_uri_t* uri)
  219. {
  220. struct my_uri* res;
  221. res = (struct my_uri*)pkg_malloc(sizeof(struct my_uri));
  222. if (res == NULL) {
  223. ERR("mysql: No memory left\n");
  224. goto error;
  225. }
  226. memset(res, '\0', sizeof(struct my_uri));
  227. if (db_drv_init(&res->drv, my_uri_free) < 0) goto error;
  228. if (parse_mysql_uri(res, &uri->body) < 0) goto error;
  229. DB_SET_PAYLOAD(uri, res);
  230. uri->cmp = my_uri_cmp;
  231. return 0;
  232. error:
  233. if (res) {
  234. db_drv_free(&res->drv);
  235. if (res) pkg_free(res);
  236. }
  237. return -1;
  238. }