fifo_server.c 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638
  1. /*
  2. * $Id$
  3. *
  4. *
  5. * Copyright (C) 2001-2003 Fhg Fokus
  6. *
  7. * This file is part of ser, a free SIP server.
  8. *
  9. * ser 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. * For a license to use the ser software under conditions
  15. * other than those described here, or to purchase support for this
  16. * software, please contact iptel.org by e-mail at the following addresses:
  17. * [email protected]
  18. *
  19. * ser is distributed in the hope that it will be useful,
  20. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  21. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  22. * GNU General Public License for more details.
  23. *
  24. * You should have received a copy of the GNU General Public License
  25. * along with this program; if not, write to the Free Software
  26. * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  27. *
  28. * Fifo server is a very powerful tool used to access easily
  29. * ser's internals via textual interface, similarly to
  30. * how internals of many operating systems are accessible
  31. * via the proc file system. This might be used for
  32. * making ser do things for you (such as initiating new
  33. * transaction from webpages) or inspect server's health.
  34. *
  35. * FIFO server allows new functionality to be registered
  36. * with it -- thats what register_fifo_cmd is good for.
  37. * Remember, the initialization must take place before
  38. * forking; best in init_module functions. When a function
  39. * is registered, it can be always evoked by sending its
  40. * name prefixed by colon to the FIFO.
  41. *
  42. * There are few commands already implemented in core.
  43. * These are 'uptime' for looking at how long the server
  44. * is alive and 'print' for debugging purposes.
  45. *
  46. * Every command sent to FIFO must be sent atomically to
  47. * avoid intermixing with other commands and MUST be
  48. * terminated by empty line so that the server is to able
  49. * to find its end if it does not understand the command.
  50. *
  51. * File test/transaction.fifo illustrates example of use
  52. * of t_uac command (part of TM module).
  53. */
  54. #include <stdlib.h>
  55. #include <sys/types.h>
  56. #include <unistd.h>
  57. #include <stdio.h>
  58. #include <errno.h>
  59. #include <sys/types.h>
  60. #include <sys/stat.h>
  61. #include <fcntl.h>
  62. #include <signal.h>
  63. #include <string.h>
  64. #include <time.h>
  65. #include <stdarg.h>
  66. #include "dprint.h"
  67. #include "ut.h"
  68. #include "error.h"
  69. #include "config.h"
  70. #include "globals.h"
  71. #include "fifo_server.h"
  72. #include "mem/mem.h"
  73. #include "sr_module.h"
  74. #include "pt.h"
  75. /* FIFO server vars */
  76. char *fifo="/tmp/ser_fifo"; /* FIFO name */
  77. int fifo_mode=S_IRUSR | S_IWUSR | S_IRGRP |
  78. S_IWGRP | S_IROTH | S_IWOTH;
  79. pid_t fifo_pid;
  80. /* file descriptors */
  81. static int fifo_read=0;
  82. static int fifo_write=0;
  83. static FILE *fifo_stream;
  84. /* list of fifo command */
  85. static struct fifo_command *cmd_list=0;
  86. /* up time */
  87. static time_t up_since;
  88. static char up_since_ctime[MAX_CTIME_LEN];
  89. static struct fifo_command *lookup_fifo_cmd( char *name )
  90. {
  91. struct fifo_command *c;
  92. for(c=cmd_list; c; c=c->next) {
  93. if (strcasecmp(c->name, name)==0) return c;
  94. }
  95. return 0;
  96. }
  97. int register_fifo_cmd(fifo_cmd f, char *cmd_name, void *param)
  98. {
  99. struct fifo_command *new_cmd;
  100. if (lookup_fifo_cmd(cmd_name)) {
  101. LOG(L_ERR, "ERROR: register_fifo_cmd: attempt to register synonyms\n");
  102. return E_BUG;
  103. }
  104. new_cmd=malloc(sizeof(struct fifo_command));
  105. if (new_cmd==0) {
  106. LOG(L_ERR, "ERROR: register_fifo_cmd: out of mem\n");
  107. return E_OUT_OF_MEM;
  108. }
  109. new_cmd->f=f;
  110. new_cmd->name=cmd_name;
  111. new_cmd->param=param;
  112. new_cmd->next=cmd_list;
  113. cmd_list=new_cmd;
  114. DBG("DEBUG: register_fifo_cmd: new command (%s) registered\n", cmd_name );
  115. return 1;
  116. }
  117. int read_line( char *b, int max, FILE *stream, int *read )
  118. {
  119. int len;
  120. int retry_cnt;
  121. retry_cnt=0;
  122. retry:
  123. if (fgets(b, max, stream)==NULL) {
  124. LOG(L_ERR, "ERROR: fifo_server fgets failed: %s\n",
  125. strerror(errno));
  126. /* on Linux, fgets sometimes returns ESPIPE -- give
  127. it few more chances
  128. */
  129. if (errno==ESPIPE) {
  130. retry_cnt++;
  131. if (retry_cnt<4) goto retry;
  132. }
  133. kill(0, SIGTERM);
  134. }
  135. /* if we did not read whole line, our buffer is too small
  136. and we cannot process the request; consume the remainder of
  137. request
  138. */
  139. len=strlen(b);
  140. if (len && !(b[len-1]=='\n' || b[len-1]=='\r')) {
  141. LOG(L_ERR, "ERROR: read_line: request line too long\n");
  142. return 0;
  143. }
  144. /* trim from right */
  145. while(len) {
  146. if(b[len-1]=='\n' || b[len-1]=='\r'
  147. || b[len-1]==' ' || b[len-1]=='\t' ) {
  148. len--;
  149. b[len]=0;
  150. } else break;
  151. }
  152. *read=len;
  153. return 1;
  154. }
  155. static void consume_request( FILE *stream )
  156. {
  157. int len;
  158. char buffer[MAX_CONSUME_BUFFER];
  159. while(!read_line(buffer, MAX_CONSUME_BUFFER, stream, &len));
  160. #ifdef _OBSOLETED
  161. int eol_count;
  162. eol_count=0;
  163. /* each request must be terminated by two EoLs */
  164. while(eol_count!=2) {
  165. /* read until EoL is encountered */
  166. while(!read_line(buffer, MAX_CONSUME_BUFFER, stream, &len));
  167. eol_count=len==0?eol_count+1:1;
  168. }
  169. #endif
  170. }
  171. int read_eol( FILE *stream )
  172. {
  173. int len;
  174. char buffer[MAX_CONSUME_BUFFER];
  175. if (!read_line(buffer, MAX_CONSUME_BUFFER, stream, &len) || len!=0) {
  176. LOG(L_ERR, "ERROR: read_eol: EOL expected: %.10s...\n",
  177. buffer );
  178. return 0;
  179. }
  180. return 1;
  181. }
  182. /* read from input until empty line is encountered */
  183. int read_line_set(char *buf, int max_len, FILE *fifo, int *len)
  184. {
  185. int set_len;
  186. char *c;
  187. int line_len;
  188. c=buf;set_len=0;
  189. while(1) {
  190. if (!read_line(c,max_len,fifo,&line_len)) {
  191. LOG(L_ERR, "ERROR: fifo_server: line expected\n");
  192. return 0;
  193. }
  194. /* end encountered ... return */
  195. if (line_len==0) {
  196. *len=set_len;
  197. return 1;
  198. }
  199. max_len-=line_len; c+=line_len; set_len+=line_len;
  200. if (max_len<CRLF_LEN) {
  201. LOG(L_ERR, "ERROR: fifo_server: no place for CRLF\n");
  202. return 0;
  203. }
  204. memcpy(c, CRLF, CRLF_LEN);
  205. max_len-=CRLF_LEN; c+=CRLF_LEN; set_len+=CRLF_LEN;
  206. }
  207. }
  208. /* read from input until line with only dot in it is encountered */
  209. int read_body(char *buf, int max_len, FILE *fifo, int *len)
  210. {
  211. int set_len;
  212. char *c;
  213. int line_len;
  214. c=buf;set_len=0;
  215. while(1) {
  216. if (!read_line(c,max_len,fifo,&line_len)) {
  217. LOG(L_ERR, "ERROR: fifo_server: line expected\n");
  218. return 0;
  219. }
  220. /* end encountered ... return */
  221. if (line_len==1 && *c=='.') {
  222. *len=set_len;
  223. return 1;
  224. }
  225. max_len-=line_len; c+=line_len; set_len+=line_len;
  226. if (max_len<CRLF_LEN) {
  227. LOG(L_ERR, "ERROR: fifo_server: no place for CRLF\n");
  228. return 0;
  229. }
  230. memcpy(c, CRLF, CRLF_LEN);
  231. max_len-=CRLF_LEN; c+=CRLF_LEN; set_len+=CRLF_LEN;
  232. }
  233. }
  234. static char *trim_filename( char * file )
  235. {
  236. int prefix_len, fn_len;
  237. char *new_fn;
  238. /* we only allow files in "/tmp" -- any directory
  239. changes are not welcome
  240. */
  241. if (strchr(file,'.') || strchr(file,'/')
  242. || strchr(file, '\\')) {
  243. LOG(L_ERR, "ERROR: trim_filename: forbidden filename: %s\n"
  244. , file);
  245. return 0;
  246. }
  247. prefix_len=strlen(FIFO_DIR); fn_len=strlen(file);
  248. new_fn=pkg_malloc(prefix_len+fn_len+1);
  249. if (new_fn==0) {
  250. LOG(L_ERR, "ERROR: trim_filename: no mem\n");
  251. return 0;
  252. }
  253. memcpy(new_fn, FIFO_DIR, prefix_len);
  254. memcpy(new_fn+prefix_len, file, fn_len );
  255. new_fn[prefix_len+fn_len]=0;
  256. return new_fn;
  257. }
  258. /* tell FIFO client what happened via reply pipe */
  259. void fifo_reply( char *reply_fifo, char *reply_fmt, ... )
  260. {
  261. FILE *file_handle;
  262. int r;
  263. va_list ap;
  264. file_handle=open_reply_pipe(reply_fifo);
  265. if (file_handle==0) {
  266. LOG(L_ERR, "ERROR: fifo_reply: no reply pipe %s\n",
  267. fifo);
  268. return;
  269. }
  270. retry:
  271. va_start(ap, reply_fmt);
  272. r=vfprintf(file_handle, reply_fmt, ap);
  273. va_end(ap);
  274. if (r<=0) {
  275. LOG(L_ERR, "ERROR: fifo_error: write error (%s): %s\n",
  276. fifo, strerror(errno));
  277. if ((errno==EINTR)||(errno==EAGAIN)||(errno==EWOULDBLOCK)) {
  278. goto retry;
  279. }
  280. }
  281. fclose(file_handle);
  282. }
  283. FILE *open_reply_pipe( char *pipe_name )
  284. {
  285. int fifofd;
  286. FILE *file_handle;
  287. int retries=FIFO_REPLY_RETRIES;
  288. if (!pipe_name || *pipe_name==0) {
  289. DBG("DEBUG: open_reply_pipe: no file to write to about missing cmd\n");
  290. return 0;
  291. }
  292. tryagain:
  293. fifofd=open( pipe_name, O_WRONLY | O_NONBLOCK );
  294. if (fifofd==-1) {
  295. /* retry several times if client is not yet ready for getting
  296. feedback via a reply pipe
  297. */
  298. if (errno==ENXIO) {
  299. /* give up on the client - we can't afford server blocking */
  300. if (retries==0) {
  301. LOG(L_ERR, "ERROR: open_reply_pipe: no client at %s\n",
  302. pipe_name );
  303. return 0;
  304. }
  305. /* don't be noisy on the very first try */
  306. if (retries!=FIFO_REPLY_RETRIES)
  307. DBG("DEBUG: open_reply_pipe: retry countdown: %d\n", retries );
  308. sleep_us( FIFO_REPLY_WAIT );
  309. retries--;
  310. goto tryagain;
  311. }
  312. /* some other opening error */
  313. LOG(L_ERR, "ERROR: open_reply_pipe: open error (%s): %s\n",
  314. pipe_name, strerror(errno));
  315. return 0;
  316. }
  317. file_handle=fdopen( fifofd, "w");
  318. if (file_handle==NULL) {
  319. LOG(L_ERR, "ERROR: open_reply_pipe: open error (%s): %s\n",
  320. pipe_name, strerror(errno));
  321. return 0;
  322. }
  323. return file_handle;
  324. }
  325. static void fifo_server(FILE *fifo_stream)
  326. {
  327. char buf[MAX_FIFO_COMMAND];
  328. int line_len;
  329. char *file_sep, *command, *file;
  330. struct fifo_command *f;
  331. file_sep=command=file=0;
  332. while(1) {
  333. /* commands must look this way ':<command>:[filename]' */
  334. if (!read_line(buf, MAX_FIFO_COMMAND, fifo_stream, &line_len)) {
  335. /* line breaking must have failed -- consume the rest
  336. and proceed to a new request
  337. */
  338. LOG(L_ERR, "ERROR: fifo_server: command expected\n");
  339. goto consume;
  340. }
  341. if (line_len==0) {
  342. LOG(L_INFO, "INFO: fifo_server: command empty\n");
  343. continue;
  344. }
  345. if (line_len<3) {
  346. LOG(L_ERR, "ERROR: fifo_server: command must have at least 3 chars\n");
  347. goto consume;
  348. }
  349. if (*buf!=CMD_SEPARATOR) {
  350. LOG(L_ERR, "ERROR: fifo_server: command must begin with %c: %.*s\n",
  351. CMD_SEPARATOR, line_len, buf );
  352. goto consume;
  353. }
  354. command=buf+1;
  355. file_sep=strchr(command, CMD_SEPARATOR );
  356. if (file_sep==NULL) {
  357. LOG(L_ERR, "ERROR: fifo_server: file separator missing\n");
  358. goto consume;
  359. }
  360. if (file_sep==command) {
  361. LOG(L_ERR, "ERROR: fifo_server: empty command\n");
  362. goto consume;
  363. }
  364. if (*(file_sep+1)==0) file=NULL;
  365. else {
  366. file=file_sep+1;
  367. file=trim_filename(file);
  368. if (file==0) {
  369. LOG(L_ERR, "ERROR: fifo_server: trimming filename\n");
  370. goto consume;
  371. }
  372. }
  373. /* make command zero-terminated */
  374. *file_sep=0;
  375. f=lookup_fifo_cmd( command );
  376. if (f==0) {
  377. LOG(L_ERR, "ERROR: fifo_server: command %s is not available\n",
  378. command);
  379. fifo_reply(file, "[%s not available]\n", command);
  380. goto consume;
  381. }
  382. if (f->f(fifo_stream, file)<0) {
  383. LOG(L_ERR, "ERROR: fifo_server: command (%s) "
  384. "processing failed\n", command );
  385. goto consume;
  386. }
  387. consume:
  388. if (file) { pkg_free(file); file=0;}
  389. consume_request(fifo_stream);
  390. }
  391. }
  392. int open_fifo_server()
  393. {
  394. char *t;
  395. if (fifo==NULL) {
  396. DBG("TM: open_uac_fifo: no fifo will be opened\n");
  397. /* everything is ok, we just do not want to start */
  398. return 1;
  399. }
  400. if (strlen(fifo)==0) {
  401. DBG("TM: open_uac_fifo: fifo disabled\n");
  402. return 1;
  403. }
  404. DBG("TM: open_uac_fifo: opening fifo...\n");
  405. if ((mkfifo(fifo, fifo_mode)<0) && (errno!=EEXIST)) {
  406. LOG(L_ERR, "ERROR: open_fifo_server; can't create FIFO: "
  407. "%s (mode=%d)\n",
  408. strerror(errno), fifo_mode);
  409. return -1;
  410. }
  411. DBG("DEBUG: fifo %s opened, mode=%d\n", fifo, fifo_mode );
  412. time(&up_since);
  413. t=ctime(&up_since);
  414. if (strlen(t)+1>=MAX_CTIME_LEN) {
  415. LOG(L_ERR, "ERROR: open_fifo_server: "
  416. "too long date %d\n", strlen(t));
  417. return -1;
  418. }
  419. memcpy(up_since_ctime,t,strlen(t)+1);
  420. process_no++;
  421. fifo_pid=fork();
  422. if (fifo_pid<0) {
  423. LOG(L_ERR, "ERROR: open_fifo_server: failure to fork: %s\n",
  424. strerror(errno));
  425. return -1;
  426. }
  427. if (fifo_pid==0) { /* child == FIFO server */
  428. LOG(L_INFO, "INFO: fifo process starting: %d\n", getpid());
  429. /* call per-child module initialization too -- some
  430. FIFO commands may need it
  431. */
  432. if (init_child(process_no) < 0 ) {
  433. LOG(L_ERR, "ERROR: open_uac_fifo: init_child failed\n");
  434. return -1;
  435. }
  436. fifo_read=open(fifo, O_RDONLY, 0);
  437. if (fifo_read<0) {
  438. LOG(L_ERR, "ERROR: open_uac_fifo: fifo_read did not open: %s\n",
  439. strerror(errno));
  440. return -1;
  441. }
  442. fifo_stream=fdopen(fifo_read, "r" );
  443. if (fifo_stream==NULL) {
  444. LOG(L_ERR, "SER: open_uac_fifo: fdopen failed: %s\n",
  445. strerror(errno));
  446. return -1;
  447. }
  448. /* a real server doesn't die if writing to reply fifo fails */
  449. signal(SIGPIPE, SIG_IGN);
  450. LOG(L_INFO, "SER: open_uac_fifo: fifo server up at %s...\n",
  451. fifo);
  452. fifo_server( fifo_stream ); /* never retruns */
  453. }
  454. /* dad process */
  455. pt[process_no].pid=fifo_pid;
  456. strncpy(pt[process_no].desc, "fifo server", MAX_PT_DESC );
  457. /* make sure the read fifo will not close */
  458. fifo_write=open(fifo, O_WRONLY, 0);
  459. if (fifo_write<0) {
  460. LOG(L_ERR, "SER: open_uac_fifo: fifo_write did not open: %s\n",
  461. strerror(errno));
  462. return -1;
  463. }
  464. return 1;
  465. }
  466. static int print_version_cmd( FILE *stream, char *response_file )
  467. {
  468. if (response_file) {
  469. fifo_reply(response_file, SERVER_HDR CRLF );
  470. } else {
  471. LOG(L_ERR, "ERROR: no file for print_version_cmd\n");
  472. }
  473. return 1;
  474. }
  475. /* diagnostic and hello-world FIFO command */
  476. static int print_fifo_cmd( FILE *stream, char *response_file )
  477. {
  478. char text[MAX_PRINT_TEXT];
  479. int text_len;
  480. /* expect one line which will be printed out */
  481. if (response_file==0 || *response_file==0 ) {
  482. LOG(L_ERR, "ERROR: print_fifo_cmd: null file\n");
  483. return -1;
  484. }
  485. if (!read_line(text, MAX_PRINT_TEXT, stream, &text_len)) {
  486. fifo_reply(response_file,
  487. "ERROR: print_fifo_cmd: too big text");
  488. return -1;
  489. }
  490. /* now the work begins */
  491. if (response_file) {
  492. fifo_reply(response_file, text );
  493. } else {
  494. LOG(L_INFO, "INFO: print_fifo_cmd: %.*s\n",
  495. text_len, text );
  496. }
  497. return 1;
  498. }
  499. static int uptime_fifo_cmd( FILE *stream, char *response_file )
  500. {
  501. time_t now;
  502. if (response_file==0 || *response_file==0 ) {
  503. LOG(L_ERR, "ERROR: uptime_fifo_cmd: null file\n");
  504. return -1;
  505. }
  506. time(&now);
  507. fifo_reply( response_file, "Now: %sUp Since: %sUp time: %.0f [sec]\n",
  508. ctime(&now), up_since_ctime, difftime(now, up_since) );
  509. return 1;
  510. }
  511. static int which_fifo_cmd(FILE *stream, char *response_file )
  512. {
  513. FILE *reply_pipe;
  514. struct fifo_command *c;
  515. if (response_file==0 || *response_file==0 ) {
  516. LOG(L_ERR, "ERROR: which_fifo_cmd: null file\n");
  517. return -1;
  518. }
  519. reply_pipe=open_reply_pipe(response_file);
  520. if (reply_pipe==NULL) {
  521. LOG(L_ERR, "ERROR: which_fifo_cmd: opening reply pipe (%s) failed\n",
  522. response_file );
  523. return -1;
  524. }
  525. fputs( "------ Begin of registered FIFO commands -----------\n", reply_pipe);
  526. for(c=cmd_list; c; c=c->next) {
  527. fprintf( reply_pipe, "%s\n", c->name );
  528. }
  529. fputs( "------ End of registered FIFO commands -----------\n", reply_pipe);
  530. fclose(reply_pipe);
  531. return 1;
  532. }
  533. static int ps_fifo_cmd(FILE *stream, char *response_file )
  534. {
  535. FILE *reply_pipe;
  536. int p;
  537. if (response_file==0 || *response_file==0 ) {
  538. LOG(L_ERR, "ERROR: ps_fifo_cmd: null file\n");
  539. return -1;
  540. }
  541. reply_pipe=open_reply_pipe(response_file);
  542. if (reply_pipe==NULL) {
  543. LOG(L_ERR, "ERROR: ps_fifo_cmd: opening reply pipe (%s) failed\n",
  544. response_file );
  545. return -1;
  546. }
  547. for (p=0; p<process_count();p++)
  548. fprintf( reply_pipe, "%d\t%d\t%s\n",
  549. p, pt[p].pid, pt[p].desc );
  550. fclose(reply_pipe);
  551. return 1;
  552. }
  553. int register_core_fifo()
  554. {
  555. if (register_fifo_cmd(print_fifo_cmd, FIFO_PRINT, 0)<0) {
  556. LOG(L_CRIT, "unable to register '%s' FIFO cmd\n", FIFO_PRINT);
  557. return -1;
  558. }
  559. if (register_fifo_cmd(uptime_fifo_cmd, FIFO_UPTIME, 0)<0) {
  560. LOG(L_CRIT, "unable to register '%s' FIFO cmd\n", FIFO_UPTIME);
  561. return -1;
  562. }
  563. if (register_fifo_cmd(print_version_cmd, FIFO_VERSION, 0)<0) {
  564. LOG(L_CRIT, "unable to register '%s' FIFO cmd\n", FIFO_VERSION);
  565. return -1;
  566. }
  567. if (register_fifo_cmd(which_fifo_cmd, FIFO_WHICH, 0)<0) {
  568. LOG(L_CRIT, "unable to register '%s' FIFO cmd\n", FIFO_WHICH);
  569. return -1;
  570. }
  571. if (register_fifo_cmd(ps_fifo_cmd, FIFO_PS, 0)<0) {
  572. LOG(L_CRIT, "unable to register '%s' FIFO cmd\n", FIFO_PS);
  573. return -1;
  574. }
  575. return 1;
  576. }