/katcp/kurl.c

https://github.com/adambarta/katcp · C · 587 lines · 481 code · 98 blank · 8 comment · 103 complexity · 14822e983fe2ddc93c10c2a5aae697b6 MD5 · raw file

  1. /* (c) 2011 SKA SA */
  2. /* Released under the GNU GPLv3 - see COPYING */
  3. #include <stdio.h>
  4. #include <stdlib.h>
  5. #include <string.h>
  6. #include <katpriv.h>
  7. #include <katcp.h>
  8. #define COL ':'
  9. #define WAK '/'
  10. #define HASH '#'
  11. #define S_SCHEME 2
  12. #define S_HOST 3
  13. #define S_PORT 4
  14. #define S_PATH 5
  15. #define S_END 0
  16. #define S_CMD 6
  17. #define S_HASH 7
  18. static struct katcp_url *allocate_kurl_katcp()
  19. {
  20. struct katcp_url *ku;
  21. ku = malloc(sizeof(struct katcp_url));
  22. if(ku == NULL){
  23. return NULL;
  24. }
  25. ku->u_use = 0;
  26. ku->u_str = NULL;
  27. ku->u_scheme = NULL;
  28. ku->u_host = NULL;
  29. ku->u_port = 0;
  30. ku->u_path = NULL;
  31. ku->u_pcount = 0;
  32. ku->u_cmd = NULL;
  33. return ku;
  34. }
  35. char *copy_kurl_string_katcp(struct katcp_url *ku, char *path){
  36. char *str;
  37. int i, found=0;
  38. #ifdef DEBUG
  39. fprintf(stderr,"kurl: copy string\n");
  40. #endif
  41. #ifdef DEBUG
  42. if(ku->u_scheme == NULL){
  43. fprintf(stderr, "kurl: no scheme in url\n");
  44. return NULL;
  45. }
  46. #endif
  47. if(ku->u_cmd){
  48. i = strlen(ku->u_scheme) + 3 + strlen(ku->u_cmd);
  49. str = malloc(sizeof(char) * (i + 1));
  50. if(str == NULL){
  51. return NULL;
  52. }
  53. snprintf(str, i + 1, "%s://%s", ku->u_scheme, ku->u_cmd);
  54. str[i] = '\0';
  55. } else {
  56. i = snprintf(NULL,0,"%s://%s:%d/", ku->u_scheme, ku->u_host, ku->u_port);
  57. if(i <= 0){
  58. return NULL;
  59. }
  60. str = malloc(sizeof(char) * (i + 1));
  61. if(str == NULL){
  62. return NULL;
  63. }
  64. i = snprintf(str, i + 1, "%s://%s:%d/", ku->u_scheme, ku->u_host, ku->u_port);
  65. str[i] = '\0';
  66. }
  67. if (!path){
  68. #ifdef DEBUG
  69. fprintf(stderr, "no path component, returning url %s\n", str);
  70. #endif
  71. return str;
  72. }
  73. for(i = 0; i < ku->u_pcount; i++){
  74. if(strcmp(ku->u_path[i], path) == 0){
  75. found = i;
  76. break;
  77. }
  78. }
  79. if (!found){
  80. free(str);
  81. return NULL;
  82. }
  83. i = snprintf(NULL,0,"%s%s",str,ku->u_path[found]);
  84. str = realloc(str,sizeof(char)*(i+1));
  85. str = strcat(str,ku->u_path[found]);
  86. str[i] = '\0';
  87. #ifdef DEBUG
  88. fprintf(stderr,"Found the path in the kurl returning %s\n",str);
  89. #endif
  90. return str;
  91. }
  92. char *kurl_string_with_path_id(struct katcp_url *ku, int id){
  93. char * str;
  94. int len;
  95. str = NULL;
  96. len = snprintf(NULL,0,"%s://%s:%d/%s",ku->u_scheme,ku->u_host,ku->u_port,ku->u_path[id]);
  97. if(len <= 0){
  98. return NULL;
  99. }
  100. str = malloc(sizeof(char)*(len+1));
  101. if(str == NULL){
  102. return NULL;
  103. }
  104. snprintf(str, len + 1, "%s://%s:%d/%s", ku->u_scheme, ku->u_host, ku->u_port, ku->u_path[id]);
  105. #ifdef DEBUG
  106. fprintf(stderr,"kurl_string_with_id len: %d returning: %s\n", len, str);
  107. #endif
  108. return str;
  109. }
  110. struct katcp_url *create_kurl_from_string_katcp(char *url)
  111. {
  112. int i, j, state, spos, epos, len, max;
  113. char c, *temp;
  114. struct katcp_url *ku;
  115. if(url == NULL){
  116. return NULL;
  117. }
  118. #ifdef DEBUG
  119. fprintf(stderr,"katcp_url about to parse: %s\n", url);
  120. #endif
  121. ku = allocate_kurl_katcp();
  122. if(ku == NULL){
  123. return NULL;
  124. }
  125. ku->u_str = strdup(url);
  126. if(ku->u_str == NULL){
  127. destroy_kurl_katcp(ku);
  128. return NULL;
  129. }
  130. state = S_SCHEME;
  131. spos = 0;
  132. epos = 0;
  133. len = 0;
  134. temp = NULL;
  135. j = 0;
  136. max = strlen(url);
  137. for (i=0; state != S_END; ){
  138. switch(state){
  139. case S_SCHEME:
  140. c = url[i];
  141. switch(c){
  142. case '\0':
  143. #ifdef DEBUG
  144. fprintf(stderr,"katcp_url: null char while parsing scheme");
  145. #endif
  146. destroy_kurl_katcp(ku);
  147. return NULL;
  148. case COL:
  149. epos = i+1;
  150. len = epos-spos;
  151. ku->u_scheme = malloc(sizeof(char)*len);
  152. ku->u_scheme = strncpy(ku->u_scheme,url+spos,len-1);
  153. ku->u_scheme[len-1] = '\0';
  154. //fprintf(stderr,"scheme: %s %d\n",ku->scheme,epos);
  155. if (strcasecmp(ku->u_scheme,"katcp") == 0)
  156. state = S_HOST;
  157. else if (strcasecmp(ku->u_scheme,"exec") == 0)
  158. state = S_CMD;
  159. else if (strcasecmp(ku->u_scheme,"xport") == 0)
  160. state = S_HOST;
  161. else {
  162. #ifdef DEBUG
  163. fprintf(stderr,"katcp_url: scheme is not of expected katcp, exec or xport");
  164. #endif
  165. destroy_kurl_katcp(ku);
  166. return NULL;
  167. }
  168. spos = i+1;
  169. break;
  170. }
  171. i++;
  172. break;
  173. case S_CMD:
  174. c = url[i];
  175. switch (c){
  176. case WAK:
  177. j++;
  178. if (j < 3)
  179. spos = i+1;
  180. break;
  181. case HASH:
  182. case '\r':
  183. case '\n':
  184. case '\0':
  185. epos = i+1;
  186. len = epos-spos;
  187. ku->u_cmd = malloc(sizeof(char)*len);
  188. ku->u_cmd = strncpy(ku->u_cmd,url+spos,len-1);
  189. ku->u_cmd[len-1] = '\0';
  190. state = (i+1 < max) ? S_HASH : S_END;
  191. spos = i+1;
  192. break;
  193. }
  194. i++;
  195. break;
  196. case S_HASH:
  197. c = url[i];
  198. switch (c){
  199. case '\r':
  200. case '\n':
  201. case '\0':
  202. epos = i+1;
  203. len = epos-spos;
  204. ku->u_path = malloc(sizeof(char *));
  205. ku->u_path[ku->u_pcount] = malloc(sizeof(char)*len);
  206. ku->u_path[ku->u_pcount] = strncpy(ku->u_path[ku->u_pcount], url+spos, len-1);
  207. ku->u_path[ku->u_pcount][len-1] = '\0';
  208. ku->u_pcount++;
  209. state = S_END;
  210. break;
  211. }
  212. i++;
  213. break;
  214. case S_HOST:
  215. c = url[i];
  216. switch(c){
  217. case '\0':
  218. #ifdef DEBUG
  219. fprintf(stderr,"katcp_url: null char while parsing host");
  220. #endif
  221. destroy_kurl_katcp(ku);
  222. return NULL;
  223. case WAK:
  224. spos = i+1;
  225. break;
  226. free(temp);
  227. temp = NULL;
  228. case COL:
  229. epos = i+1;
  230. len = epos-spos;
  231. ku->u_host = malloc(sizeof(char)*len);
  232. ku->u_host = strncpy(ku->u_host,url+spos,len-1);
  233. ku->u_host[len-1] = '\0';
  234. // fprintf(stderr,"host: %s %d\n",ku->host,epos);
  235. state = S_PORT;
  236. spos = i+1;
  237. break;
  238. }
  239. i++;
  240. break;
  241. case S_PORT:
  242. c = url[i];
  243. switch(c){
  244. case COL:
  245. spos = i+1;
  246. break;
  247. case WAK:
  248. state = S_PATH;
  249. case '\0':
  250. case '\n':
  251. case '\r':
  252. epos = i+1;
  253. len = epos-spos;
  254. temp = malloc(sizeof(char)*len);
  255. temp = strncpy(temp,url+spos,len-1);
  256. temp[len-1] = '\0';
  257. ku->u_port = atoi(temp);
  258. //fprintf(stderr,"port: %s %d %d\n",temp,ku->port,epos);
  259. state = (state == S_PATH) ? state : S_END;
  260. free(temp);
  261. temp = NULL;
  262. spos = i+1;
  263. break;
  264. }
  265. i++;
  266. break;
  267. case S_PATH:
  268. c = url[i];
  269. switch(c){
  270. case '\0':
  271. case '\n':
  272. case '\r':
  273. epos = i+1;
  274. len = epos-spos;
  275. ku->u_path = malloc(sizeof(char *));
  276. ku->u_path[ku->u_pcount] = malloc(sizeof(char)*len);
  277. ku->u_path[ku->u_pcount] = strncpy(ku->u_path[ku->u_pcount],url+spos,len-1);
  278. ku->u_path[ku->u_pcount][len-1] = '\0';
  279. ku->u_pcount++;
  280. // fprintf(stderr,"path: %s %d\n",ku->path,epos);
  281. state = S_END;
  282. break;
  283. }
  284. i++;
  285. break;
  286. }
  287. }
  288. //fprintf(stderr,"\n");
  289. return ku;
  290. }
  291. struct katcp_url *create_kurl_katcp(char *scheme, char *host, int port, char *path){
  292. struct katcp_url *ku;
  293. //char **tmp;
  294. ku = allocate_kurl_katcp();
  295. if(ku == NULL){
  296. return NULL;
  297. }
  298. ku->u_scheme = strdup(scheme);
  299. ku->u_host = strdup(host);
  300. ku->u_port = port;
  301. if((ku->u_scheme == NULL) || (ku->u_host == NULL)){
  302. destroy_kurl_katcp(ku);
  303. return NULL;
  304. }
  305. ku->u_str = copy_kurl_string_katcp(ku, NULL);
  306. #if 0
  307. tmp = realloc(ku->u_path, sizeof(char*)*(ku->u_pcount));
  308. if(tmp == NULL){
  309. destroy_kurl_katcp(ku);
  310. return NULL;
  311. }
  312. #endif
  313. if (path != NULL){
  314. ku->u_path = malloc(sizeof(char*)*(ku->u_pcount+1));
  315. if (ku->u_path == NULL){
  316. destroy_kurl_katcp(ku);
  317. return NULL;
  318. }
  319. ku->u_path[ku->u_pcount] = strdup(path);
  320. ku->u_pcount++;
  321. }
  322. return ku;
  323. }
  324. struct katcp_url *create_exec_kurl_katcp(char *cmd)
  325. {
  326. struct katcp_url *ku;
  327. ku = allocate_kurl_katcp();
  328. if (ku == NULL){
  329. return NULL;
  330. }
  331. ku->u_scheme = strdup("exec");
  332. ku->u_cmd = strdup(cmd);
  333. if((ku->u_scheme == NULL) || (ku->u_cmd == NULL)){
  334. destroy_kurl_katcp(ku);
  335. return NULL;
  336. }
  337. ku->u_str = copy_kurl_string_katcp(ku, NULL);
  338. if(ku->u_str == NULL){
  339. destroy_kurl_katcp(ku);
  340. return NULL;
  341. }
  342. return ku;
  343. }
  344. char *add_kurl_path_copy_string_katcp(struct katcp_url *ku, char *npath){
  345. ku->u_path = realloc(ku->u_path,sizeof(char*)*++ku->u_pcount);
  346. ku->u_path[ku->u_pcount-1] = strdup(npath);
  347. return kurl_string_with_path_id(ku,ku->u_pcount-1);
  348. }
  349. static int prefix_match_kurl_katcp(char *target, char *prefix)
  350. {
  351. int i;
  352. for(i = 0; prefix[i] != '\0'; i++){
  353. if(prefix[i] != target[i]){
  354. #ifdef DEBUG
  355. fprintf(stderr, "kurl: prefix match <%s> failed against <%s> at %d\n", prefix, target, i);
  356. #endif
  357. return -1;
  358. }
  359. }
  360. return i;
  361. }
  362. int containing_kurl_katcp(struct katcp_url *ku, char *string)
  363. {
  364. #define BUFFER 8
  365. int len, offset;
  366. char buffer[BUFFER];
  367. if(string == NULL){
  368. return 0;
  369. }
  370. if(ku->u_host){
  371. offset = 8;
  372. if(strncmp(string, "katcp://", offset)){
  373. return 0;
  374. }
  375. len = prefix_match_kurl_katcp(string + offset, ku->u_host);
  376. if(len < 0){
  377. return 0;
  378. }
  379. offset += len;
  380. if(string[offset] != ':'){
  381. return 0;
  382. }
  383. offset++;
  384. snprintf(buffer, BUFFER, "%d", ku->u_port);
  385. buffer[BUFFER - 1] = '\0';
  386. len = prefix_match_kurl_katcp(string + offset, buffer);
  387. if(len < 0){
  388. return 0;
  389. }
  390. offset += len;
  391. return offset;
  392. } else if(ku->u_cmd){
  393. offset = 7;
  394. if(strncmp(string, "exec://", offset)){
  395. return 0;
  396. }
  397. len = prefix_match_kurl_katcp(string + offset, ku->u_cmd);
  398. if(len < 0){
  399. return 0;
  400. }
  401. offset += len;
  402. return offset;
  403. }
  404. #ifdef DEBUG
  405. fprintf(stderr, "kurl: string %s can not be matched, neither cmd nor host are set\n", string);
  406. #endif
  407. return 0;
  408. #undef BUFFER
  409. }
  410. void destroy_kurl_katcp(struct katcp_url *ku){
  411. int i;
  412. if (ku == NULL){
  413. return;
  414. }
  415. if (ku->u_use > 1){
  416. ku->u_use--;
  417. return;
  418. }
  419. if (ku->u_str) { free(ku->u_str); ku->u_str = NULL; }
  420. if (ku->u_scheme) { free(ku->u_scheme); ku->u_scheme = NULL; }
  421. if (ku->u_host) { free(ku->u_host); ku->u_host = NULL; }
  422. ku->u_port = 0;
  423. if (ku->u_path) {
  424. for (i=0;i<ku->u_pcount;i++){
  425. if (ku->u_path[i]) {
  426. free(ku->u_path[i]);
  427. ku->u_path[i] = NULL;
  428. }
  429. }
  430. free(ku->u_path);
  431. ku->u_path = NULL;
  432. }
  433. if (ku->u_cmd) { free(ku->u_cmd); ku->u_cmd = NULL; }
  434. if (ku) { free(ku); ku = NULL; }
  435. #ifdef DEBUG
  436. fprintf(stderr,"KURL: Destroyed a kurl\n");
  437. #endif
  438. }
  439. #ifdef UNIT_TEST_KURL
  440. void kurl_print(struct katcp_url *ku){
  441. int i;
  442. fprintf(stderr,"KURL Scheme: %s\n",ku->u_scheme);
  443. fprintf(stderr,"KURL Host : %s\n",ku->u_host);
  444. fprintf(stderr,"KURL Port : %d\n",ku->u_port);
  445. for (i=0; i<ku->u_pcount; i++){
  446. fprintf(stderr,"KURL Path%d : %s\n",i,ku->u_path[i]);
  447. }
  448. fprintf(stderr,"KURL String: %s\n",ku->u_str);
  449. fprintf(stderr,"KURL CMD : %s\n",ku->u_cmd);
  450. }
  451. int main(int argc, char **argv){
  452. struct katcp_url *ku, *ku2;
  453. char *temp;
  454. ku = create_kurl_from_string_katcp("katcp://host.domain:7147/");
  455. ku2 = create_kurl_from_string_katcp("exec:///bin/ls#thisisatest");
  456. kurl_print(ku2);
  457. if((ku == NULL) || (ku2 == NULL)){
  458. fprintf(stderr, "test: unable to assemble urls from strings\n");
  459. return 1;
  460. }
  461. if (!(temp = copy_kurl_string_katcp(ku,"?disconnect"))) temp = add_kurl_path_copy_string_katcp(ku,"?disconnect");
  462. fprintf(stderr,"%s\n",temp);
  463. free(temp);
  464. if(containing_kurl_katcp(ku, "katcp://host.domain:7147") <= 0){
  465. fprintf(stderr, "match failed \n");
  466. return 1;
  467. }
  468. if(containing_kurl_katcp(ku, "katcp://host.domain:7147/") <= 0){
  469. fprintf(stderr, "match failed\n");
  470. return 1;
  471. }
  472. if(containing_kurl_katcp(ku, "katcp://host.domain:7147/?example") <= 0){
  473. fprintf(stderr, "match failed\n");
  474. return 1;
  475. }
  476. if(containing_kurl_katcp(ku, "katcp://host.domain:7247/") > 0){
  477. fprintf(stderr, "match should not work\n");
  478. return 1;
  479. }
  480. if(containing_kurl_katcp(ku, "katcp://hxst.domain:7247/") > 0){
  481. fprintf(stderr, "match should not work\n");
  482. return 1;
  483. }
  484. kurl_print(ku);
  485. destroy_kurl_katcp(ku);
  486. destroy_kurl_katcp(ku2);
  487. return 0;
  488. }
  489. #endif