my_uri.c 6.0 KB

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