static void fifo_close_async( struct mi_root *mi_rpl, struct mi_handler *hdl, int done) { FILE *reply_stream; char *name; name = (char*)hdl->param; if ( mi_rpl!=0 || done ) { /*open fifo reply*/ reply_stream = mi_open_reply_pipe( name ); if (reply_stream==NULL) { LM_ERR("cannot open reply pipe %s\n", name ); return; } if (mi_rpl!=0) { mi_write_tree( reply_stream, mi_rpl); free_mi_tree( mi_rpl ); } else { mi_fifo_reply( reply_stream, "500 command failed\n"); } fclose(reply_stream); } if (done) free_async_handler( hdl ); return; }
static int recur_write_tree(FILE *stream, struct mi_node *tree, str *buf, int level) { for( ; tree ; tree=tree->next ) { if (!(tree->flags & MI_WRITTEN)) { if (mi_write_node( buf, tree, level)!=0) { /* buffer is full -> write it and reset buffer */ if (mi_fifo_reply( stream,"%.*s", buf->s-mi_write_buffer, mi_write_buffer)!=0) return -1; buf->s = mi_write_buffer; buf->len = mi_write_buffer_len; if (mi_write_node( buf, tree, level)!=0) { LM_ERR("failed to write - line too long!\n"); return -1; } } } if (tree->kids) { if (recur_write_tree(stream, tree->kids, buf, level+1)<0) return -1; } } return 0; }
static int recur_flush_tree(FILE *stream, struct mi_node *tree, str *buf, int level) { struct mi_node *kid, *tmp; int ret; for(kid = tree->kids ; kid ; ){ /* write the current kid */ if (!(kid->flags & MI_WRITTEN)){ if (mi_write_node( buf, kid, level)!=0) { /* buffer is full -> write it and reset buffer */ if (mi_fifo_reply( stream,"%.*s", buf->s-mi_write_buffer, mi_write_buffer)!=0) return -1; buf->s = mi_write_buffer; buf->len = mi_write_buffer_len; if (mi_write_node( buf, kid, level)!=0) { LM_ERR("failed to write - line too long!\n"); return -1; } } /* we are sure that this node has been written * => avoid writing it again */ kid->flags |= MI_WRITTEN; } /* write the current kid's children */ if ((ret = recur_flush_tree(stream, kid, buf, level+1))<0) return -1; else if (ret > 0) return ret; if (!(kid->flags & MI_NOT_COMPLETED)){ tmp = kid; kid = kid->next; tree->kids = kid; if(!tmp->kids){ /* this node does not have any kids */ free_mi_node(tmp); } } else{ /* the node will have more kids => to keep the tree shape, do not * flush any other node for now */ return 1; } } return 0; }
int mi_flush_tree(FILE *stream, struct mi_root *tree) { str buf; str code; buf.s = mi_write_buffer; buf.len = mi_write_buffer_len; if (!(tree->node.flags & MI_WRITTEN)) { /* write the root node */ code.s = int2str((unsigned long)tree->code, &code.len); if (code.len+tree->reason.len+1>buf.len) { LM_ERR("failed to write - reason too long!\n"); return -1; } memcpy( buf.s, code.s, code.len); buf.s += code.len; *(buf.s++) = ' '; if (tree->reason.len) { memcpy( buf.s, tree->reason.s, tree->reason.len); buf.s += tree->reason.len; } *(buf.s++) = '\n'; buf.len -= code.len + 1 + tree->reason.len+1; /* we are sure that this node has been written * => avoid writing it again */ tree->node.flags |= MI_WRITTEN; } if (recur_flush_tree(stream, &tree->node, &buf, 0)<0) return -1; if (buf.len<=0) { LM_ERR("failed to write - EOC does not fit in!\n"); return -1; } *(buf.s++)='\n'; buf.len--; if (mi_fifo_reply(stream,"%.*s",buf.s-mi_write_buffer,mi_write_buffer)!=0) return -1; return 0; }
void mi_fifo_server(FILE *fifo_stream) { struct mi_root *mi_cmd; struct mi_root *mi_rpl; struct mi_handler *hdl; int line_len; char *file_sep, *command, *file; struct mi_cmd *f; FILE *reply_stream; while(1) { reply_stream = NULL; /* commands must look this way ':<command>:[filename]' */ if (mi_read_line(mi_buf,MAX_MI_FIFO_BUFFER,fifo_stream, &line_len)) { LM_ERR("failed to read command\n"); continue; } /* trim from right */ while(line_len) { if(mi_buf[line_len-1]=='\n' || mi_buf[line_len-1]=='\r' || mi_buf[line_len-1]==' ' || mi_buf[line_len-1]=='\t' ) { line_len--; mi_buf[line_len]=0; } else break; } if (line_len==0) { LM_DBG("command empty\n"); continue; } if (line_len<3) { LM_ERR("command must have at least 3 chars\n"); continue; } if (*mi_buf!=MI_CMD_SEPARATOR) { LM_ERR("command must begin with %c: %.*s\n", MI_CMD_SEPARATOR, line_len, mi_buf ); goto consume1; } command = mi_buf+1; file_sep=strchr(command, MI_CMD_SEPARATOR ); if (file_sep==NULL) { LM_ERR("file separator missing\n"); goto consume1; } if (file_sep==command) { LM_ERR("empty command\n"); goto consume1; } if (*(file_sep+1)==0) { file = NULL; } else { file = file_sep+1; file = get_reply_filename(file, mi_buf+line_len-file); if (file==NULL) { LM_ERR("trimming filename\n"); goto consume1; } } /* make command zero-terminated */ *file_sep=0; f=lookup_mi_cmd( command, strlen(command) ); if (f==0) { LM_ERR("command %s is not available\n", command); mi_open_reply( file, reply_stream, consume1); mi_fifo_reply( reply_stream, "500 command '%s' not available\n", command); goto consume2; } /* if asyncron cmd, build the async handler */ if (f->flags&MI_ASYNC_RPL_FLAG) { hdl = build_async_handler( file, strlen(file) ); if (hdl==0) { LM_ERR("failed to build async handler\n"); mi_open_reply( file, reply_stream, consume1); mi_fifo_reply( reply_stream, "500 Internal server error\n"); goto consume2; } } else { hdl = 0; mi_open_reply( file, reply_stream, consume1); } if (f->flags&MI_NO_INPUT_FLAG) { mi_cmd = 0; mi_do_consume(); } else { mi_cmd = mi_parse_tree(fifo_stream); if (mi_cmd==NULL) { LM_ERR("error parsing MI tree\n"); if (!reply_stream) mi_open_reply( file, reply_stream, consume3); mi_fifo_reply( reply_stream, "400 parse error in " "command '%s'\n", command); goto consume3; } mi_cmd->async_hdl = hdl; } LM_DBG("done parsing the mi tree\n"); if ( (mi_rpl=run_mi_cmd(f, mi_cmd, (mi_flush_f *)mi_flush_tree, reply_stream))==0 ) { if (!reply_stream) mi_open_reply( file, reply_stream, failure); mi_fifo_reply(reply_stream, "500 command '%s' failed\n", command); LM_ERR("command (%s) processing failed\n", command ); } else if (mi_rpl!=MI_ROOT_ASYNC_RPL) { if (!reply_stream) mi_open_reply( file, reply_stream, failure); mi_write_tree( reply_stream, mi_rpl); free_mi_tree( mi_rpl ); } else { if (mi_cmd) free_mi_tree( mi_cmd ); continue; } free_async_handler(hdl); /* close reply fifo */ fclose(reply_stream); /* destroy request tree */ if (mi_cmd) free_mi_tree( mi_cmd ); continue; failure: free_async_handler(hdl); /* destroy request tree */ if (mi_cmd) free_mi_tree( mi_cmd ); /* destroy the reply tree */ if (mi_rpl) free_mi_tree(mi_rpl); continue; consume3: free_async_handler(hdl); if (reply_stream) consume2: fclose(reply_stream); consume1: mi_do_consume(); } }