/* * Create a new text chunk, the input text * will be unescaped first. */ struct text_chunk* new_chunk_unescape(str* src) { struct text_chunk* l; if (!src) return 0; l = ctl_malloc(sizeof(struct text_chunk)); if (!l) { ERR("No Memory Left\n"); return 0; } l->s.s = ctl_malloc(src->len + 1); if (!l->s.s) { ERR("No Memory Left\n"); ctl_free(l); return 0; } l->next = 0; l->flags = 0; if (unescape(&l->s, src->s, src->len) < 0) { ctl_free(l->s.s); ctl_free(l); return 0; } l->s.s[l->s.len] = '\0'; return l; }
void ctl_free(struct control *ctrl) { if (!ctrl) return; wl_free(ctrl->co_cond); ctrl->co_cond = NULL; tfree(ctrl->co_foreachvar); ctrl->co_foreachvar = NULL; wl_free(ctrl->co_text); ctrl->co_text = NULL; ctl_free(ctrl->co_children); ctrl->co_children = NULL; ctl_free(ctrl->co_elseblock); ctrl->co_elseblock = NULL; ctl_free(ctrl->co_next); ctrl->co_next = NULL; tfree(ctrl); ctrl = NULL; }
void free_ctrl_socket_list(struct ctrl_socket* l) { struct ctrl_socket* nxt; for (;l; l=nxt){ nxt=l->next; if (l->data) ctl_free(l->data); ctl_free(l); } }
/** free all the tracked pointer from ctx->gc. */ inline static void binrpc_gc_collect(struct binrpc_ctx* ctx) { struct binrpc_gc_block* b; struct binrpc_gc_block* next; int i; for(b=ctx->gc; b; b=next){ next=b->next; for (i=0; i<b->idx; i++) ctl_free(b->p[i]); ctl_free(b); } ctx->gc=0; }
void free_id_list_elem(struct id_list* id) { if (id->buf){ ctl_free(id->buf); id->buf=0; } }
void free_id_list(struct id_list* l) { struct id_list* nxt; for (;l; l=nxt){ nxt=l->next; free_id_list_elem(l); ctl_free(l); } }
static void free_struct(struct rpc_struct* s) { struct text_chunk* c; if (!s) return; while(s->names) { c = s->names; s->names = s->names->next; free_chunk(c); } while(s->values) { c = s->values; s->values = s->values->next; free_chunk(c); } ctl_free(s); }
static struct rpc_struct_l* new_rpc_struct() { struct rpc_struct_l* rs; /* alloc everything in one chunk */ rs=ctl_malloc(sizeof(struct rpc_struct_l)+STRUCT_MAX_BODY); if (rs==0) goto error; memset(rs, 0, sizeof(struct rpc_struct_l)); clist_init(&rs->substructs, next, prev); if (binrpc_init_pkt(&rs->pkt, (unsigned char*)rs+sizeof(struct rpc_struct_l), STRUCT_MAX_BODY)<0){ ctl_free(rs); goto error; } return rs; error: return 0; }
/* * Create a new text chunk, the input text * will not be escaped. The function returns * 0 on an error */ struct text_chunk* new_chunk(str* src) { struct text_chunk* l; if (!src) return 0; l = ctl_malloc(sizeof(struct text_chunk)); if (!l) { ERR("No Memory Left\n"); return 0; } l->s.s = ctl_malloc(src->len + 1); if (!l->s.s) { ERR("No Memory Left\n"); ctl_free(l); return 0; } l->next = 0; l->flags = 0; memcpy(l->s.s, src->s, src->len); l->s.len = src->len; l->s.s[l->s.len] = '\0'; return l; }
/* * Man FIFO routine running in the FIFO * processes requests received * through the FIFO file repeatedly */ int fifo_process(char* msg_buf, int size, int* bytes_needed, void *sh, void** saved_state) { rpc_export_t* exp; char* buf; int line_len; char *file_sep; struct text_chunk* p; struct rpc_struct* s; int r; int req_size; static rpc_ctx_t context; DBG("process_fifo: called with %d bytes, offset %d: %.*s\n", size, (int)(long)*saved_state, size, msg_buf); /* search for the end of the request (\n\r) */ if (size < 6){ /* min fifo request */ *bytes_needed=6-size; return 0; /* we want more bytes, nothing processed */ } for (r=1+(int)(long)*saved_state;r<size;r++){ if ((msg_buf[r]=='\n' || msg_buf[r]=='\r') && (msg_buf[r-1]=='\n'|| msg_buf[r-1]=='\r')){ /* found double cr, or double lf => end of request */ req_size=r; goto process; } } /* no end of request found => ask for more bytes */ *bytes_needed=1; /* save current offset, to optimize search */ *saved_state=(void*)(long)(r-1); return 0; /* we want again the whole buffer */ process: DBG("process_fifo %d bytes request: %.*s\n", req_size, req_size, msg_buf); file_sep = 0; context.method = 0; context.reply_file = 0; context.body = 0; context.code = 200; context.reason = "OK"; context.reply_sent = 0; context.last = 0; context.line_no = 0; context.read_h.s=msg_buf; context.read_h.end=msg_buf+size; context.read_h.crt=msg_buf; context.send_h=(struct send_handle*)sh; /* commands must look this way ':<command>:[filename]' */ if (read_line(&buf, &line_len, &context.read_h) < 0) { /* line breaking must have failed -- consume the rest * and proceed to a new request */ ERR("Command expected\n"); goto consume; } context.line_no++; if (line_len == 0) { DBG("Empty command received\n"); goto consume; } if (line_len < 3) { ERR("Command must have at least 3 chars\n"); goto consume; } if (*buf != CMD_SEPARATOR) { ERR("Command must begin with %c: %.*s\n", CMD_SEPARATOR, line_len, buf); goto consume; } context.method = buf + 1; file_sep = strchr(context.method, CMD_SEPARATOR); if (file_sep == NULL) { ERR("File separator missing\n"); goto consume; } if (file_sep == context.method) { ERR("Empty command\n"); goto consume; } if (*(file_sep + 1) == 0) context.reply_file = NULL; else { context.reply_file = file_sep + 1; context.reply_file = trim_filename(context.reply_file); if (context.reply_file == 0) { ERR("Trimming filename\n"); goto consume; } } /* make command zero-terminated */ *file_sep = 0; exp = find_rpc_export(context.method, 0); if (!exp || !exp->function) { DBG("Command %s not found\n", context.method); rpc_fault(&context, 500, "Command '%s' not found", context.method); goto consume; } exp->function(&func_param, &context); consume: if (!context.reply_sent) { rpc_send(&context); } if (context.reply_file) { ctl_free(context.reply_file); context.reply_file = 0; } /* Collect garbage (unescaped strings and structures) */ while(context.strs) { p = context.strs; context.strs = context.strs->next; free_chunk(p); } while(context.structs) { s = context.structs; context.structs = context.structs->next; free_struct(s); } *bytes_needed=0; DBG("Command consumed\n"); DBG("process_fifo: returning %d, bytes_needed 0\n", req_size+1); return req_size+1; /* all was processed (including terminating \n)*/ }
static void free_chunk(struct text_chunk* c) { if (c && c->s.s) ctl_free(c->s.s); if (c) ctl_free(c); }
/* parses: * tcp|udp|unix:host_name:port * tcp|udp|unix:host_name * host_name:port * host_name * * * where host_name=string, ipv4 address, [ipv6 address], * unix socket path (starts with '/') */ struct id_list* parse_listen_id(char* l, int len, enum socket_protos def) { char* p; enum socket_protos proto; char* name; char* port_str; int port; int err; struct servent* se; char* s; struct id_list* id; s=ctl_malloc((len+1)*sizeof(char)); if (s==0){ LOG(L_ERR, "ERROR:parse_listen_id: out of memory\n"); goto error; } memcpy(s, l, len); s[len]=0; /* null terminate */ /* duplicate */ proto=UNKNOWN_SOCK; port=0; name=0; port_str=0; p=s; if ((*p)=='[') goto ipv6; /* find proto or name */ for (; *p; p++){ if (*p==':'){ *p=0; if (strcasecmp("tcp", s)==0){ proto=TCP_SOCK; goto find_host; }else if (strcasecmp("udp", s)==0){ proto=UDP_SOCK; goto find_host; }else if (strcasecmp("unixd", s)==0){ proto=UNIXD_SOCK; goto find_host; }else if ((strcasecmp("unix", s)==0)||(strcasecmp("unixs", s)==0)){ proto=UNIXS_SOCK; goto find_host; #ifdef USE_FIFO }else if (strcasecmp("fifo", s)==0){ proto=FIFO_SOCK; goto find_host; #endif }else{ proto=UNKNOWN_SOCK; /* this might be the host */ name=s; goto find_port; } } } name=s; goto end; /* only name found */ find_host: p++; if (*p=='[') goto ipv6; name=p; for (; *p; p++){ if ((*p)==':'){ *p=0; goto find_port; } } goto end; /* nothing after name */ ipv6: name=p; p++; for(;*p;p++){ if(*p==']'){ if(*(p+1)==':'){ p++; *p=0; goto find_port; }else if (*(p+1)==0) goto end; }else{ goto error; } } find_port: p++; port_str=(*p)?p:0; end: /* fix all the stuff */ if (name==0) goto error; if (proto==UNKNOWN_SOCK){ /* try to guess */ if (port_str){ switch(def){ case TCP_SOCK: case UDP_SOCK: proto=def; break; default: proto=UDP_SOCK; DBG("guess:%s is a tcp socket\n", name); } }else if (name && strchr(name, '/')){ switch(def){ case TCP_SOCK: case UDP_SOCK: DBG("guess:%s is a unix socket\n", name); proto=UNIXS_SOCK; break; default: /* def is filename based => use default */ proto=def; } }else{ /* using default */ proto=def; } } if (port_str){ port=str2s(port_str, strlen(port_str), &err); if (err){ /* try getservbyname */ se=getservbyname(port_str, (proto==TCP_SOCK)?"tcp":(proto==UDP_SOCK)?"udp":0); if (se) port=ntohs(se->s_port); else goto error; } }else{ /* no port, check if the hostname is a port * (e.g. tcp:3012 == tcp:*:3012 */ if (proto==TCP_SOCK|| proto==UDP_SOCK){ port=str2s(name, strlen(name), &err); if (err){ port=0; }else{ name="*"; /* inaddr any */ } } } id=ctl_malloc(sizeof(struct id_list)); if (id==0){ LOG(L_ERR, "ERROR:parse_listen_id: out of memory\n"); goto error; } id->name=name; id->proto=proto; id->data_proto=P_BINRPC; id->port=port; id->buf=s; id->next=0; return id; error: if (s) ctl_free(s); return 0; }