void binrpc_free_rpc_array(struct binrpc_val* a, int size) { int r; for (r=0; r<size; r++){ if (a[r].name.s) binrpc_free(a[r].name.s); if ((a[r].type==BINRPC_T_STR || a[r].type==BINRPC_T_BYTES) && a[r].u.strval.s){ binrpc_free(a[r].u.strval.s); } } binrpc_free(a); }
void binrpc_close_connection(struct binrpc_handle* handle) { if (handle->socket != -1) { close(handle->socket); handle->socket = -1; } if (handle->buf) { binrpc_free(handle->buf); handle->buf = NULL; } }
int binrpc_parse_response(struct binrpc_val** vals, int* val_count, struct binrpc_response_handle *resp_handle) { struct binrpc_val val; unsigned char *p, *end; int ret, i; resp_handle->in_pkt.offset = resp_handle->in_pkt.in_struct = resp_handle->in_pkt.in_array = 0; if (*val_count==0){ *val_count=VAL_ARRAY_CHUNK; /* start with a reasonable size */ } *vals = (struct binrpc_val*) binrpc_malloc(*val_count*sizeof(**vals)); if (*vals == 0) goto error_mem; p = resp_handle->reply_buf; end = p + resp_handle->in_pkt.tlen; i=0; /* read body */ while(p < end){ val.type = BINRPC_T_ALL; val.name.s = 0; val.name.len = 0; p = binrpc_read_record(&resp_handle->in_pkt, p, end, &val, &ret); if (ret<0){ if (ret==E_BINRPC_EOP){ break; } snprintf(binrpc_last_errs, sizeof(binrpc_last_errs)-1, "ERROR while parsing the record %d," " @%d: %02x : %s", i, resp_handle->in_pkt.offset, *p, binrpc_error(ret)); goto error; } if (i >= *val_count){ struct binrpc_val *t; t= (struct binrpc_val*) binrpc_realloc(*vals, (VAL_ARRAY_CHUNK+(*val_count))*sizeof(**vals)); if (t==0) goto error_mem; *vals = t; *val_count += VAL_ARRAY_CHUNK; } (*vals)[i] = val; i++; } if (i == 0) { binrpc_free(*vals); *vals = NULL; } else if (i<*val_count){ /* do not try to save memory because it causes fragmentation when used ser mem utils and "regualar" memory leak struct binrpc_val *t; t = (struct binrpc_val*) binrpc_realloc(*vals, i*sizeof(**vals)); if (t) *vals = t; */ } *val_count = i; return 0; error_mem: snprintf(binrpc_last_errs, sizeof(binrpc_last_errs)-1, "parse_response: out of memory"); error: if (*vals){ binrpc_free(*vals); *vals = NULL; } *val_count=0; return FATAL_ERROR; }
void binrpc_release_response(struct binrpc_response_handle *resp_handle) { if (resp_handle->reply_buf) { binrpc_free(resp_handle->reply_buf); resp_handle->reply_buf = NULL; } }
/* parse the body into a malloc allocated, binrpc_val array */ int binrpc_send_command( struct binrpc_handle* handle, char* method, char** args, int arg_count, struct binrpc_response_handle *resp_handle) { struct binrpc_pkt req_pkt; struct binrpc_val v; int i, size, res = FATAL_ERROR, ret = 0; unsigned char *req_buf = NULL; memset(&resp_handle->in_pkt, 0, sizeof(resp_handle->in_pkt)); if (!method || strlen(method) == 0) { snprintf(binrpc_last_errs, sizeof(binrpc_last_errs)-1, "send_command: method name not specified"); goto fail; } size = BINRPC_MIN_RECORD_SIZE + 8 + strlen(method) + 1; /*max.possible optional value len */ for (i=0; i<arg_count; i++) { if (parse_arg(&v, args[i]) < 0) goto fail; switch (v.type) { case BINRPC_T_STR: size += v.u.strval.len + 1; break; case BINRPC_T_INT: case BINRPC_T_DOUBLE: size += sizeof(int); break; default: snprintf(binrpc_last_errs, sizeof(binrpc_last_errs)-1, "BUG: send_command: unexpected value type"); goto fail; } size += BINRPC_MIN_RECORD_SIZE + 8; } req_buf = binrpc_malloc(size); if (!req_buf) { snprintf(binrpc_last_errs, sizeof(binrpc_last_errs)-1, "send_command: not enough memory to allocate buffer. Needed %d bytes", size); goto fail; } if ((ret = binrpc_init_pkt(&req_pkt, req_buf, size)) < 0) goto fail2; if ((ret = binrpc_addstr(&req_pkt, method, strlen(method))) < 0) goto fail2; for (i=0; i<arg_count; i++) { if (parse_arg(&v, args[i]) < 0) goto fail; switch (v.type) { case BINRPC_T_STR: if ((ret = binrpc_addstr(&req_pkt, v.u.strval.s, v.u.strval.len)) < 0) goto fail2; break; case BINRPC_T_INT: if ((ret = binrpc_addint(&req_pkt, v.u.intval)) < 0) goto fail2; break; case BINRPC_T_DOUBLE: if ((ret = binrpc_adddouble(&req_pkt, v.u.fval)) < 0) goto fail2; break; default: break; } } if (binrpc_send_command_ex(handle, &req_pkt, resp_handle) < 0) { goto fail; } res = 0; fail: if (req_buf) binrpc_free(req_buf); return res; fail2: snprintf(binrpc_last_errs, sizeof(binrpc_last_errs)-1, "send_command: error when preparing params: %s", binrpc_error(ret)); goto fail; }
/* reads the whole reply * returns < 0 on error, reply size on success + initializes resp_handle */ static int get_reply(struct binrpc_handle *handle, int cookie, struct binrpc_response_handle *resp_handle) { unsigned char *crt, *hdr_end; int n, ret, tl; ret = 0; resp_handle->reply_buf = NULL; hdr_end = crt = handle->buf; do { n = read(handle->socket, crt, handle->buf_size - (crt-handle->buf)); if (n < 0){ if (errno==EINTR) continue; snprintf(binrpc_last_errs, sizeof(binrpc_last_errs)-1, "get_reply: read reply failed: %s (%d)", strerror(errno), errno); return FATAL_ERROR; } if (verbose >= 3){ /* dump it in hex */ printf("received %d bytes in reply (@offset %d):\n", n, (int)(crt-handle->buf)); hexdump(crt, n, 1); } crt += n; hdr_end = binrpc_parse_init(&resp_handle->in_pkt, handle->buf, crt - handle->buf, &ret); } while (ret == E_BINRPC_MORE_DATA); if (ret < 0){ snprintf(binrpc_last_errs, sizeof(binrpc_last_errs)-1, "get_reply: reply parsing error: %s", binrpc_error(ret)); return FATAL_ERROR; } if (verbose>1){ printf("new packet: type %02x, len %d, cookie %02x\n", resp_handle->in_pkt.type, resp_handle->in_pkt.tlen, resp_handle->in_pkt.cookie); } if (resp_handle->in_pkt.cookie!=cookie){ snprintf(binrpc_last_errs, sizeof(binrpc_last_errs)-1, "get_reply: reply parsing error: " "cookie doesn't match: sent: %02x, received: %02x", cookie, resp_handle->in_pkt.cookie); return FATAL_ERROR; } /* we know total size and we can allocate buffer for received data */ tl = resp_handle->in_pkt.tlen; if (handle->sock_type == SOCK_DGRAM) { /* we must read all datagram in one read call, otherwise unread part is truncated and lost. Read will block execution */ if (crt - hdr_end < tl) { snprintf(binrpc_last_errs, sizeof(binrpc_last_errs)-1, "get_reply: datagram truncated. Received: %d, Expected: %d.", crt-hdr_end, tl); return FATAL_ERROR; } } if (crt - hdr_end > tl) { /* header contains probably data from next message, in case of STREAM it could be unread but it's waste of time */ crt = hdr_end + tl; } resp_handle->reply_buf = (unsigned char *) binrpc_malloc(tl); if (!resp_handle->reply_buf) { snprintf(binrpc_last_errs, sizeof(binrpc_last_errs)-1, "get_reply: not enough memory to allocate reply buffer. %d bytes needed.", resp_handle->in_pkt.tlen); return FATAL_ERROR; } crt = resp_handle->reply_buf + (crt-hdr_end); memcpy(resp_handle->reply_buf, hdr_end, crt - resp_handle->reply_buf); tl -= crt - resp_handle->reply_buf; while (tl > 0) { n=read(handle->socket, crt, tl); if (n < 0){ if (errno==EINTR) continue; snprintf(binrpc_last_errs, sizeof(binrpc_last_errs)-1, "get_reply: read reply failed: %s (%d)", strerror(errno), errno); binrpc_free(resp_handle->reply_buf); resp_handle->reply_buf = NULL; return FATAL_ERROR; } if (verbose >= 3){ /* dump it in hex */ printf("received %d bytes in reply (@offset %d):\n", n, (int)(crt-resp_handle->reply_buf)); hexdump(crt, n, 1); } crt += n; tl -= n; } return (int)(crt-resp_handle->reply_buf); }
int main(int argc, char** argv) { struct binrpc_response_handle resp_handle; unsigned char* txt_rsp = NULL; int txt_rsp_len = 0; struct binrpc_handle handle; struct binrpc_val *vals = NULL; int cnt, i, err_no; char *errs; if (argc < 2) goto err; if (binrpc_open_connection_url(&handle, argv[1]) < 0) goto err2; if (binrpc_send_command(&handle, argv[2], argv+3, argc-3, &resp_handle) < 0) { binrpc_close_connection(&handle); goto err2; } binrpc_close_connection(&handle); if (binrpc_response_to_text(&resp_handle, &txt_rsp, &txt_rsp_len, '\n') < 0) goto err3; fprintf(stdout, "binrpc_response_to_text():\n--------------------------\n%s\n", txt_rsp); fprintf(stdout, "\nbinrpc_print_response():\n------------------------\n"); binrpc_print_response(&resp_handle, NULL); fprintf(stdout, "\nbinrpc_parse_response():\n------------------------\n"); cnt = 0; switch (binrpc_get_response_type(&resp_handle)) { case 0: if (binrpc_parse_response(&vals, &cnt, &resp_handle) < 0) goto err3; fprintf(stdout, "#Records: %d\n", cnt); for (i = 0; i < cnt; i++) { fprintf(stdout, "#%.2d: type:%d name:%.*s\n", i, vals[i].type, vals[i].name.len, vals[i].name.s); } break; case 1: if (binrpc_parse_error_response(&resp_handle, &err_no, &errs) <0) goto err3; fprintf(stdout, "%d %s\n", err_no, errs); break; default: fprintf(stdout, "Unknown response type: %d\n", binrpc_get_response_type(&resp_handle)); break; } if (vals != NULL) { binrpc_free(vals); } if (txt_rsp != NULL) { binrpc_free(txt_rsp); } binrpc_release_response(&resp_handle); return 0; err: fprintf(stderr, "Usage: %s url mathod [params]\n", NAME); return -1; err3: if (vals != NULL) { binrpc_free(vals); } if (txt_rsp) { binrpc_free(txt_rsp); } binrpc_release_response(&resp_handle); err2: fprintf(stderr, "ERROR: %s\n", binrpc_get_last_errs()); return -2; }