int rpc_pmap_callit_async(struct rpc_context *rpc, int program, int version, int procedure, const char *data, int datalen, rpc_cb cb, void *private_data) { struct rpc_pdu *pdu; struct pmap_call_args ca; pdu = rpc_allocate_pdu(rpc, PMAP_PROGRAM, PMAP_V2, PMAP_CALLIT, cb, private_data, (xdrproc_t)xdr_pmap_call_result, sizeof(pmap_call_result)); if (pdu == NULL) { rpc_set_error(rpc, "Out of memory. Failed to allocate pdu for portmap/callit call"); return -1; } ca.prog = program; ca.vers = version; ca.proc = procedure; ca.args.args_len = datalen; ca.args.args_val = data; if (xdr_pmap_call_args(&pdu->xdr, &ca) == 0) { rpc_set_error(rpc, "XDR error: Failed to encode data for portmap/callit call"); rpc_free_pdu(rpc, pdu); return -1; } if (rpc_queue_pdu(rpc, pdu) != 0) { rpc_set_error(rpc, "Failed to queue portmap/callit pdu: %s", rpc_get_error(rpc)); return -1; } return 0; }
int rpc_register_service(struct rpc_context *rpc, int program, int version, struct service_proc *procs, int num_procs) { struct rpc_endpoint *endpoint; assert(rpc->magic == RPC_CONTEXT_MAGIC); if (!rpc->is_server_context) { rpc_set_error(rpc, "Not a server context."); return -1; } endpoint = malloc(sizeof(*endpoint)); if (endpoint == NULL) { rpc_set_error(rpc, "Out of memory: Failed to allocate endpoint " "structure"); return -1; } endpoint->program = program; endpoint->version = version; endpoint->procs = procs; endpoint->num_procs = num_procs; endpoint->next = rpc->endpoints; rpc->endpoints = endpoint; return 0; }
int rpc_pmap_set_async(struct rpc_context *rpc, int program, int version, int protocol, int port, rpc_cb cb, void *private_data) { struct rpc_pdu *pdu; struct pmap_mapping m; pdu = rpc_allocate_pdu(rpc, PMAP_PROGRAM, PMAP_V2, PMAP_SET, cb, private_data, (zdrproc_t)zdr_int, sizeof(uint32_t)); if (pdu == NULL) { rpc_set_error(rpc, "Out of memory. Failed to allocate pdu for portmap/set call"); return -1; } m.prog = program; m.vers = version; m.prot = protocol; m.port = port; if (zdr_pmap_mapping(&pdu->zdr, &m) == 0) { rpc_set_error(rpc, "ZDR error: Failed to encode data for portmap/set call"); rpc_free_pdu(rpc, pdu); return -1; } if (rpc_queue_pdu(rpc, pdu) != 0) { rpc_set_error(rpc, "Failed to queue portmap/set pdu"); rpc_free_pdu(rpc, pdu); return -1; } return 0; }
static void wait_for_reply(struct rpc_context *rpc, struct sync_cb_data *cb_data) { struct pollfd pfd; assert(rpc->magic == RPC_CONTEXT_MAGIC); while (!cb_data->is_finished) { pfd.fd = rpc_get_fd(rpc); pfd.events = rpc_which_events(rpc); if (poll(&pfd, 1, -1) < 0) { rpc_set_error(rpc, "Poll failed"); cb_data->status = -EIO; break; } if (rpc_service(rpc, pfd.revents) < 0) { rpc_set_error(rpc, "rpc_service failed"); cb_data->status = -EIO; break; } if (rpc_get_fd(rpc) == -1) { rpc_set_error(rpc, "Socket closed\n"); break; } } }
static int rpc_write_to_socket(struct rpc_context *rpc) { int32_t count; assert(rpc->magic == RPC_CONTEXT_MAGIC); if (rpc->fd == -1) { rpc_set_error(rpc, "trying to write but not connected"); return -1; } while (rpc->outqueue != NULL) { int64_t total; total = rpc->outqueue->outdata.size; count = send(rpc->fd, rpc->outqueue->outdata.data + rpc->outqueue->written, total - rpc->outqueue->written, 0); if (count == -1) { if (errno == EAGAIN || errno == EWOULDBLOCK) { return 0; } rpc_set_error(rpc, "Error when writing to socket :%s(%d)", strerror(errno), errno); return -1; } rpc->outqueue->written += count; if (rpc->outqueue->written == total) { struct rpc_pdu *pdu = rpc->outqueue; SLIST_REMOVE(&rpc->outqueue, pdu); SLIST_ADD_END(&rpc->waitpdu, pdu); } } return 0; }
static bool_t libnfs_rpc_reply_body(struct rpc_context *rpc, ZDR *zdrs, struct reply_body *rmb) { if (!libnfs_zdr_u_int(zdrs, &rmb->stat)) { rpc_set_error(rpc, "libnfs_rpc_reply_body failed to decode " "STAT"); return FALSE; } switch (rmb->stat) { case MSG_ACCEPTED: if (!libnfs_accepted_reply(zdrs, &rmb->reply.areply)) { rpc_set_error(rpc, "libnfs_rpc_reply_body failed to " "decode ACCEPTED"); return FALSE; } return TRUE; case MSG_DENIED: if (!libnfs_rejected_reply(zdrs, &rmb->reply.rreply)) { rpc_set_error(rpc, "libnfs_rpc_reply_body failed to " "decode DENIED"); return FALSE; } return TRUE; } rpc_set_error(rpc, "libnfs_rpc_reply_body failed to " "decode. Neither ACCEPTED nor DENIED"); return FALSE; }
int rpc_pmap_getport_async(struct rpc_context *rpc, int program, int version, rpc_cb cb, void *private_data) { struct rpc_pdu *pdu; struct mapping m; pdu = rpc_allocate_pdu(rpc, PMAP_PROGRAM, PMAP_V2, PMAP_GETPORT, cb, private_data, (xdrproc_t)xdr_int, sizeof(uint32_t)); if (pdu == NULL) { rpc_set_error(rpc, "Out of memory. Failed to allocate pdu for portmap/getport call"); return -1; } m.prog = program; m.vers = version; m.prot = IPPROTO_TCP; m.port = 0; if (xdr_mapping(&pdu->xdr, &m) == 0) { rpc_set_error(rpc, "XDR error: Failed to encode data for portmap/getport call"); rpc_free_pdu(rpc, pdu); return -1; } if (rpc_queue_pdu(rpc, pdu) != 0) { rpc_set_error(rpc, "Failed to queue portmap/getport pdu"); rpc_free_pdu(rpc, pdu); return -1; } return 0; }
static bool_t libnfs_rpc_msg(struct rpc_context *rpc, ZDR *zdrs, struct rpc_msg *msg) { int ret; if (!libnfs_zdr_u_int(zdrs, &msg->xid)) { rpc_set_error(rpc, "libnfs_rpc_msg failed to decode XID"); return FALSE; } if (!libnfs_zdr_u_int(zdrs, &msg->direction)) { rpc_set_error(rpc, "libnfs_rpc_msg failed to decode DIRECTION"); return FALSE; } switch (msg->direction) { case CALL: ret = libnfs_rpc_call_body(rpc, zdrs, &msg->body.cbody); if (!ret) { rpc_set_error(rpc, "libnfs_rpc_msg failed to encode " "CALL, ret=%d: %s", ret, rpc_get_error(rpc)); } return ret; case REPLY: ret = libnfs_rpc_reply_body(rpc, zdrs, &msg->body.rbody); if (!ret) { rpc_set_error(rpc, "libnfs_rpc_msg failed to decode " "REPLY, ret=%d: %s", ret, rpc_get_error(rpc)); } return ret; default: rpc_set_error(rpc, "libnfs_rpc_msg failed to decode. " "Neither CALL not REPLY"); return FALSE; } }
struct rpc_pdu *rpc_allocate_pdu2(struct rpc_context *rpc, int program, int version, int procedure, rpc_cb cb, void *private_data, zdrproc_t zdr_decode_fn, int zdr_decode_bufsize, size_t alloc_hint) { struct rpc_pdu *pdu; struct rpc_msg msg; int pdu_size; assert(rpc->magic == RPC_CONTEXT_MAGIC); /* Since we already know how much buffer we need for the decoding * we can just piggyback in the same alloc as for the pdu. */ pdu_size = PAD_TO_8_BYTES(sizeof(struct rpc_pdu)); pdu_size += PAD_TO_8_BYTES(zdr_decode_bufsize); pdu = malloc(pdu_size); if (pdu == NULL) { rpc_set_error(rpc, "Out of memory: Failed to allocate pdu structure"); return NULL; } memset(pdu, 0, pdu_size); pdu->xid = rpc->xid++; pdu->cb = cb; pdu->private_data = private_data; pdu->zdr_decode_fn = zdr_decode_fn; pdu->zdr_decode_bufsize = zdr_decode_bufsize; pdu->outdata.data = malloc(ZDR_ENCODEBUF_MINSIZE + alloc_hint); if (pdu->outdata.data == NULL) { rpc_set_error(rpc, "Out of memory: Failed to allocate encode buffer"); free(pdu); return NULL; } zdrmem_create(&pdu->zdr, pdu->outdata.data, ZDR_ENCODEBUF_MINSIZE + alloc_hint, ZDR_ENCODE); if (rpc->is_udp == 0) { zdr_setpos(&pdu->zdr, 4); /* skip past the record marker */ } memset(&msg, 0, sizeof(struct rpc_msg)); msg.xid = pdu->xid; msg.direction = CALL; msg.body.cbody.rpcvers = RPC_MSG_VERSION; msg.body.cbody.prog = program; msg.body.cbody.vers = version; msg.body.cbody.proc = procedure; msg.body.cbody.cred = rpc->auth->ah_cred; msg.body.cbody.verf = rpc->auth->ah_verf; if (zdr_callmsg(rpc, &pdu->zdr, &msg) == 0) { rpc_set_error(rpc, "zdr_callmsg failed with %s", rpc_get_error(rpc)); zdr_destroy(&pdu->zdr); free(pdu->outdata.data); free(pdu); return NULL; } return pdu; }
static int rpc_process_call(struct rpc_context *rpc, ZDR *zdr) { struct rpc_msg call; struct rpc_endpoint *endpoint; int i, min_version = 0, max_version = 0, found_program = 0; assert(rpc->magic == RPC_CONTEXT_MAGIC); memset(&call, 0, sizeof(struct rpc_msg)); if (zdr_callmsg(rpc, zdr, &call) == 0) { rpc_set_error(rpc, "Failed to decode CALL message. %s", rpc_get_error(rpc)); return rpc_send_error_reply(rpc, &call, GARBAGE_ARGS, 0, 0); } for (endpoint = rpc->endpoints; endpoint; endpoint = endpoint->next) { if (call.body.cbody.prog == endpoint->program) { if (!found_program) { min_version = max_version = endpoint->version; } if (endpoint->version < min_version) { min_version = endpoint->version; } if (endpoint->version > max_version) { max_version = endpoint->version; } found_program = 1; if (call.body.cbody.vers == endpoint->version) { break; } } } if (endpoint == NULL) { rpc_set_error(rpc, "No endpoint found for CALL " "program:0x%08x version:%d\n", call.body.cbody.prog, call.body.cbody.vers); if (!found_program) { return rpc_send_error_reply(rpc, &call, PROG_UNAVAIL, 0, 0); } return rpc_send_error_reply(rpc, &call, PROG_MISMATCH, min_version, max_version); } for (i = 0; i < endpoint->num_procs; i++) { if (endpoint->procs[i].proc == call.body.cbody.proc) { if (endpoint->procs[i].decode_buf_size) { call.body.cbody.args = zdr_malloc(zdr, endpoint->procs[i].decode_buf_size); } if (!endpoint->procs[i].decode_fn(zdr, call.body.cbody.args)) { rpc_set_error(rpc, "Failed to unmarshall " "call payload"); return rpc_send_error_reply(rpc, &call, GARBAGE_ARGS, 0 ,0); } return endpoint->procs[i].func(rpc, &call); } } return rpc_send_error_reply(rpc, &call, PROC_UNAVAIL, 0 ,0); }
int rpc_connect_async(struct rpc_context *rpc, const char *server, int port, rpc_cb cb, void *private_data) { struct addrinfo *ai = NULL; assert(rpc->magic == RPC_CONTEXT_MAGIC); if (rpc->fd != -1) { rpc_set_error(rpc, "Trying to connect while already connected"); return -1; } if (rpc->is_udp != 0) { rpc_set_error(rpc, "Trying to connect on UDP socket"); return -1; } rpc->auto_reconnect = 0; if (getaddrinfo(server, NULL, NULL, &ai) != 0) { rpc_set_error(rpc, "Invalid address:%s. " "Can not resolv into IPv4/v6 structure.", server); return -1; } switch (ai->ai_family) { case AF_INET: ((struct sockaddr_in *)&rpc->s)->sin_family = ai->ai_family; ((struct sockaddr_in *)&rpc->s)->sin_port = htons(port); ((struct sockaddr_in *)&rpc->s)->sin_addr = ((struct sockaddr_in *)(ai->ai_addr))->sin_addr; #ifdef HAVE_SOCKADDR_LEN ((struct sockaddr_in *)&rpc->s)->sin_len = sizeof(struct sockaddr_in); #endif break; case AF_INET6: ((struct sockaddr_in6 *)&rpc->s)->sin6_family = ai->ai_family; ((struct sockaddr_in6 *)&rpc->s)->sin6_port = htons(port); ((struct sockaddr_in6 *)&rpc->s)->sin6_addr = ((struct sockaddr_in6 *)(ai->ai_addr))->sin6_addr; #ifdef HAVE_SOCKADDR_LEN ((struct sockaddr_in6 *)&rpc->s)->sin6_len = sizeof(struct sockaddr_in6); #endif break; } rpc->connect_cb = cb; rpc->connect_data = private_data; freeaddrinfo(ai); if (rpc_connect_sockaddr_async(rpc, &rpc->s) != 0) { return -1; } return 0; }
static int rpc_send_error_reply(struct rpc_context *rpc, struct rpc_msg *call, enum accept_stat err, int min_vers, int max_vers) { struct rpc_pdu *pdu; struct rpc_msg res; assert(rpc->magic == RPC_CONTEXT_MAGIC); memset(&res, 0, sizeof(struct rpc_msg)); res.xid = call->xid; res.direction = REPLY; res.body.rbody.stat = MSG_ACCEPTED; res.body.rbody.reply.areply.reply_data.mismatch_info.low = min_vers; res.body.rbody.reply.areply.reply_data.mismatch_info.high = max_vers; res.body.rbody.reply.areply.verf = _null_auth; res.body.rbody.reply.areply.stat = err; if (rpc->is_udp) { /* send the reply back to the client */ memcpy(&rpc->udp_dest, &rpc->udp_src, sizeof(rpc->udp_dest)); } pdu = rpc_allocate_reply_pdu(rpc, &res, 0); if (pdu == NULL) { rpc_set_error(rpc, "Failed to send error_reply: %s", rpc_get_error(rpc)); return -1; } rpc_queue_pdu(rpc, pdu); return 0; }
int rpc_mount3_null_async(struct rpc_context *rpc, rpc_cb cb, void *private_data) { struct rpc_pdu *pdu; pdu = rpc_allocate_pdu(rpc, MOUNT_PROGRAM, MOUNT_V3, MOUNT3_NULL, cb, private_data, (zdrproc_t)zdr_void, 0); if (pdu == NULL) { rpc_set_error(rpc, "Out of memory. Failed to allocate pdu for mount/null call"); return -1; } if (rpc_queue_pdu(rpc, pdu) != 0) { rpc_set_error(rpc, "Out of memory. Failed to queue pdu for mount/null call"); return -1; } return 0; }
int rpc_pmap_null_async(struct rpc_context *rpc, rpc_cb cb, void *private_data) { struct rpc_pdu *pdu; pdu = rpc_allocate_pdu(rpc, PMAP_PROGRAM, PMAP_V2, PMAP_NULL, cb, private_data, (xdrproc_t)xdr_void, 0); if (pdu == NULL) { rpc_set_error(rpc, "Out of memory. Failed to allocate pdu for portmap/null call"); return -1; } if (rpc_queue_pdu(rpc, pdu) != 0) { rpc_set_error(rpc, "Out of memory. Failed to queue pdu for portmap/null call"); rpc_free_pdu(rpc, pdu); return -1; } return 0; }
int rpc_rquota1_null_async(struct rpc_context *rpc, rpc_cb cb, void *private_data) { struct rpc_pdu *pdu; pdu = rpc_allocate_pdu(rpc, RQUOTA_PROGRAM, RQUOTA_V1, RQUOTA1_NULL, cb, private_data, (xdrproc_t)xdr_void, 0); if (pdu == NULL) { rpc_set_error(rpc, "Out of memory. Failed to allocate pdu for rquota1/null call"); return -1; } if (rpc_queue_pdu(rpc, pdu) != 0) { rpc_set_error(rpc, "Out of memory. Failed to queue pdu for rquota1/null call"); rpc_free_pdu(rpc, pdu); return -2; } return 0; }
int rpc_nfsacl_null_async(struct rpc_context *rpc, rpc_cb cb, void *private_data) { struct rpc_pdu *pdu; pdu = rpc_allocate_pdu(rpc, NFSACL_PROGRAM, NFSACL_V3, NFSACL3_NULL, cb, private_data, (xdrproc_t)xdr_void, 0); if (pdu == NULL) { rpc_set_error(rpc, "Out of memory. Failed to allocate pdu for nfsacl/null call"); return -1; } if (rpc_queue_pdu(rpc, pdu) != 0) { rpc_set_error(rpc, "Out of memory. Failed to queue pdu for nfsacl/null call"); rpc_free_pdu(rpc, pdu); return -2; } return 0; }
int rpc_nlm4_null_async(struct rpc_context *rpc, rpc_cb cb, void *private_data) { struct rpc_pdu *pdu; pdu = rpc_allocate_pdu(rpc, NLM_PROGRAM, NLM_V4, NLM4_NULL, cb, private_data, (zdrproc_t)zdr_void, 0); if (pdu == NULL) { rpc_set_error(rpc, "Out of memory. Failed to allocate pdu for nlm/null call"); return -1; } if (rpc_queue_pdu(rpc, pdu) != 0) { rpc_set_error(rpc, "Out of memory. Failed to queue pdu for nlm/null call"); rpc_free_pdu(rpc, pdu); return -1; } return 0; }
static struct rpc_pdu *rpc_allocate_reply_pdu(struct rpc_context *rpc, struct rpc_msg *res, size_t alloc_hint) { struct rpc_pdu *pdu; assert(rpc->magic == RPC_CONTEXT_MAGIC); pdu = malloc(sizeof(struct rpc_pdu)); if (pdu == NULL) { rpc_set_error(rpc, "Out of memory: Failed to allocate pdu structure"); return NULL; } memset(pdu, 0, sizeof(struct rpc_pdu)); pdu->flags = PDU_DISCARD_AFTER_SENDING; pdu->xid = 0; pdu->cb = NULL; pdu->private_data = NULL; pdu->zdr_decode_fn = NULL; pdu->zdr_decode_bufsize = 0; pdu->outdata.data = malloc(ZDR_ENCODEBUF_MINSIZE + alloc_hint); if (pdu->outdata.data == NULL) { rpc_set_error(rpc, "Out of memory: Failed to allocate encode buffer"); free(pdu); return NULL; } zdrmem_create(&pdu->zdr, pdu->outdata.data, ZDR_ENCODEBUF_MINSIZE + alloc_hint, ZDR_ENCODE); if (rpc->is_udp == 0) { zdr_setpos(&pdu->zdr, 4); /* skip past the record marker */ } if (zdr_replymsg(rpc, &pdu->zdr, res) == 0) { rpc_set_error(rpc, "zdr_replymsg failed with %s", rpc_get_error(rpc)); zdr_destroy(&pdu->zdr); free(pdu->outdata.data); free(pdu); return NULL; } return pdu; }
int rpc_connect_async(struct rpc_context *rpc, const char *server, int port, rpc_cb cb, void *private_data) { struct sockaddr_in *sin = (struct sockaddr_in *)&rpc->s; assert(rpc->magic == RPC_CONTEXT_MAGIC); if (rpc->fd != -1) { rpc_set_error(rpc, "Trying to connect while already connected"); return -1; } if (rpc->is_udp != 0) { rpc_set_error(rpc, "Trying to connect on UDP socket"); return -1; } rpc->auto_reconnect = 0; sin->sin_family = AF_INET; sin->sin_port = htons(port); if (inet_pton(AF_INET, server, &sin->sin_addr) != 1) { rpc_set_error(rpc, "Not a valid server ip address"); return -1; } switch (rpc->s.ss_family) { case AF_INET: #ifdef HAVE_SOCKADDR_LEN sin->sin_len = sizeof(struct sockaddr_in); #endif break; } rpc->connect_cb = cb; rpc->connect_data = private_data; if (rpc_connect_sockaddr_async(rpc, &rpc->s) != 0) { return -1; } return 0; }
int rpc_queue_pdu(struct rpc_context *rpc, struct rpc_pdu *pdu) { int size, recordmarker; assert(rpc->magic == RPC_CONTEXT_MAGIC); if (rpc->timeout > 0) { pdu->timeout = rpc_current_time() + rpc->timeout; #ifndef HAVE_CLOCK_GETTIME /* If we do not have GETTIME we fallback to time() which * has 1s granularity for its timestamps. * We thus need to bump the timeout by 1000ms * so that the PDU will timeout within 1.0 - 2.0 seconds. * Otherwise setting a 1s timeout would trigger within * 0.001 - 1.0s. */ pdu->timeout += 1000; #endif } else { pdu->timeout = 0; } size = zdr_getpos(&pdu->zdr); /* for udp we dont queue, we just send it straight away */ if (rpc->is_udp != 0) { unsigned int hash; // XXX add a rpc->udp_dest_sock_size and get rid of sys/socket.h and netinet/in.h if (sendto(rpc->fd, pdu->zdr.buf, size, MSG_DONTWAIT, (struct sockaddr *)&rpc->udp_dest, sizeof(rpc->udp_dest)) < 0) { rpc_set_error(rpc, "Sendto failed with errno %s", strerror(errno)); rpc_free_pdu(rpc, pdu); return -1; } hash = rpc_hash_xid(pdu->xid); rpc_enqueue(&rpc->waitpdu[hash], pdu); rpc->waitpdu_len++; return 0; } /* write recordmarker */ zdr_setpos(&pdu->zdr, 0); recordmarker = (size - 4) | 0x80000000; zdr_int(&pdu->zdr, &recordmarker); pdu->outdata.size = size; rpc_enqueue(&rpc->outqueue, pdu); return 0; }
static int rpc_process_reply(struct rpc_context *rpc, struct rpc_pdu *pdu, ZDR *zdr) { struct rpc_msg msg; assert(rpc->magic == RPC_CONTEXT_MAGIC); memset(&msg, 0, sizeof(struct rpc_msg)); msg.body.rbody.reply.areply.verf = _null_auth; if (pdu->zdr_decode_bufsize > 0) { pdu->zdr_decode_buf = (char *)pdu + PAD_TO_8_BYTES(sizeof(struct rpc_pdu)); } msg.body.rbody.reply.areply.reply_data.results.where = pdu->zdr_decode_buf; msg.body.rbody.reply.areply.reply_data.results.proc = pdu->zdr_decode_fn; if (zdr_replymsg(rpc, zdr, &msg) == 0) { rpc_set_error(rpc, "zdr_replymsg failed in rpc_process_reply: " "%s", rpc_get_error(rpc)); pdu->cb(rpc, RPC_STATUS_ERROR, "Message rejected by server", pdu->private_data); if (pdu->zdr_decode_buf != NULL) { pdu->zdr_decode_buf = NULL; } return 0; } if (msg.body.rbody.stat != MSG_ACCEPTED) { pdu->cb(rpc, RPC_STATUS_ERROR, "RPC Packet not accepted by the server", pdu->private_data); return 0; } switch (msg.body.rbody.reply.areply.stat) { case SUCCESS: pdu->cb(rpc, RPC_STATUS_SUCCESS, pdu->zdr_decode_buf, pdu->private_data); break; case PROG_UNAVAIL: pdu->cb(rpc, RPC_STATUS_ERROR, "Server responded: Program not available", pdu->private_data); break; case PROG_MISMATCH: pdu->cb(rpc, RPC_STATUS_ERROR, "Server responded: Program version mismatch", pdu->private_data); break; case PROC_UNAVAIL: pdu->cb(rpc, RPC_STATUS_ERROR, "Server responded: Procedure not available", pdu->private_data); break; case GARBAGE_ARGS: pdu->cb(rpc, RPC_STATUS_ERROR, "Server responded: Garbage arguments", pdu->private_data); break; case SYSTEM_ERR: pdu->cb(rpc, RPC_STATUS_ERROR, "Server responded: System Error", pdu->private_data); break; default: pdu->cb(rpc, RPC_STATUS_ERROR, "Unknown rpc response from server", pdu->private_data); break; } return 0; }
static int rpc_write_to_socket(struct rpc_context *rpc) { int32_t count; struct rpc_pdu *pdu; assert(rpc->magic == RPC_CONTEXT_MAGIC); if (rpc->fd == -1) { rpc_set_error(rpc, "trying to write but not connected"); return -1; } while ((pdu = rpc->outqueue.head) != NULL) { int64_t total; total = pdu->outdata.size; count = send(rpc->fd, pdu->outdata.data + pdu->written, total - pdu->written, 0); if (count == -1) { if (errno == EAGAIN || errno == EWOULDBLOCK) { return 0; } rpc_set_error(rpc, "Error when writing to socket :%s(%d)", strerror(errno), errno); return -1; } pdu->written += count; if (pdu->written == total) { unsigned int hash; rpc->outqueue.head = pdu->next; if (pdu->next == NULL) rpc->outqueue.tail = NULL; hash = rpc_hash_xid(pdu->xid); rpc_enqueue(&rpc->waitpdu[hash], pdu); } } return 0; }
int rpc_nlm4_cancel_async(struct rpc_context *rpc, rpc_cb cb, struct NLM4_CANCargs *args, void *private_data) { struct rpc_pdu *pdu; pdu = rpc_allocate_pdu(rpc, NLM_PROGRAM, NLM_V4, NLM4_CANCEL, cb, private_data, (zdrproc_t)zdr_NLM4_CANCres, sizeof(NLM4_CANCres)); if (pdu == NULL) { rpc_set_error(rpc, "Out of memory. Failed to allocate pdu for nlm/cancel call"); return -1; } if (zdr_NLM4_CANCargs(&pdu->zdr, args) == 0) { rpc_set_error(rpc, "ZDR error: Failed to encode NLM4_CANCargs"); rpc_free_pdu(rpc, pdu); return -2; } if (rpc_queue_pdu(rpc, pdu) != 0) { rpc_set_error(rpc, "Out of memory. Failed to queue pdu for nlm/cancel call"); return -1; } return 0; }
static void wait_for_reply(struct rpc_context *rpc, struct sync_cb_data *cb_data) { struct pollfd pfd; for (;;) { if (cb_data->is_finished) { break; } pfd.fd = rpc_get_fd(rpc); pfd.events = rpc_which_events(rpc); if (poll(&pfd, 1, -1) < 0) { rpc_set_error(rpc, "Poll failed"); cb_data->status = -EIO; break; } if (rpc_service(rpc, pfd.revents) < 0) { rpc_set_error(rpc, "rpc_service failed"); cb_data->status = -EIO; break; } } }
int rpc_nfsacl_setacl_async(struct rpc_context *rpc, rpc_cb cb, struct SETACL3args *args, void *private_data) { struct rpc_pdu *pdu; pdu = rpc_allocate_pdu(rpc, NFSACL_PROGRAM, NFSACL_V3, NFSACL3_SETACL, cb, private_data, (xdrproc_t)xdr_SETACL3res, sizeof(SETACL3res)); if (pdu == NULL) { rpc_set_error(rpc, "Out of memory. Failed to allocate pdu for nfsacl/setacl call"); return -1; } if (xdr_SETACL3args(&pdu->xdr, args) == 0) { rpc_set_error(rpc, "XDR error: Failed to encode SETACL3args"); rpc_free_pdu(rpc, pdu); return -2; } if (rpc_queue_pdu(rpc, pdu) != 0) { rpc_set_error(rpc, "Out of memory. Failed to queue pdu for nfsacl/setacl call"); rpc_free_pdu(rpc, pdu); return -2; } return 0; }
int rpc_nfs2_write_async(struct rpc_context *rpc, rpc_cb cb, struct WRITE2args *args, void *private_data) { struct rpc_pdu *pdu; pdu = rpc_allocate_pdu2(rpc, NFS_PROGRAM, NFS_V2, NFS2_WRITE, cb, private_data, (zdrproc_t)zdr_WRITE2res, sizeof(WRITE2res), args->totalcount); if (pdu == NULL) { rpc_set_error(rpc, "Out of memory. Failed to allocate pdu for NFS2/WRITE call"); return -1; } if (zdr_WRITE2args(&pdu->zdr, args) == 0) { rpc_set_error(rpc, "ZDR error: Failed to encode WRITE2args"); rpc_free_pdu(rpc, pdu); return -2; } if (rpc_queue_pdu(rpc, pdu) != 0) { rpc_set_error(rpc, "Out of memory. Failed to queue pdu for NFS2/WRITE call"); rpc_free_pdu(rpc, pdu); return -3; } return 0; }
int rpc_nfs2_lookup_async(struct rpc_context *rpc, rpc_cb cb, struct LOOKUP2args *args, void *private_data) { struct rpc_pdu *pdu; pdu = rpc_allocate_pdu(rpc, NFS_PROGRAM, NFS_V2, NFS2_LOOKUP, cb, private_data, (zdrproc_t)zdr_LOOKUP2res, sizeof(LOOKUP2res)); if (pdu == NULL) { rpc_set_error(rpc, "Out of memory. Failed to allocate pdu for NFS2/LOOKUP call"); return -1; } if (zdr_LOOKUP2args(&pdu->zdr, args) == 0) { rpc_set_error(rpc, "ZDR error: Failed to encode LOOKUP2args"); rpc_free_pdu(rpc, pdu); return -2; } if (rpc_queue_pdu(rpc, pdu) != 0) { rpc_set_error(rpc, "Out of memory. Failed to queue pdu for NFS2/LOOKUP call"); rpc_free_pdu(rpc, pdu); return -3; } return 0; }
int rpc_nfs3_rename_async(struct rpc_context *rpc, rpc_cb cb, struct RENAME3args *args, void *private_data) { struct rpc_pdu *pdu; pdu = rpc_allocate_pdu(rpc, NFS_PROGRAM, NFS_V3, NFS3_RENAME, cb, private_data, (zdrproc_t)zdr_RENAME3res, sizeof(RENAME3res)); if (pdu == NULL) { rpc_set_error(rpc, "Out of memory. Failed to allocate pdu for NFS3/RENAME call"); return -1; } if (zdr_RENAME3args(&pdu->zdr, args) == 0) { rpc_set_error(rpc, "ZDR error: Failed to encode RENAME3args"); rpc_free_pdu(rpc, pdu); return -2; } if (rpc_queue_pdu(rpc, pdu) != 0) { rpc_set_error(rpc, "Out of memory. Failed to queue pdu for NFS3/RENAME call"); rpc_free_pdu(rpc, pdu); return -3; } return 0; }
int rpc_nlm4_unlock_async(struct rpc_context *rpc, rpc_cb cb, struct NLM4_UNLOCKargs *args, void *private_data) { struct rpc_pdu *pdu; pdu = rpc_allocate_pdu(rpc, NLM_PROGRAM, NLM_V4, NLM4_UNLOCK, cb, private_data, (xdrproc_t)xdr_NLM4_UNLOCKres, sizeof(NLM4_UNLOCKres)); if (pdu == NULL) { rpc_set_error(rpc, "Out of memory. Failed to allocate pdu for nlm/unlock call"); return -1; } if (xdr_NLM4_UNLOCKargs(&pdu->xdr, args) == 0) { rpc_set_error(rpc, "XDR error: Failed to encode NLM4_UNLOCKargs"); rpc_free_pdu(rpc, pdu); return -2; } if (rpc_queue_pdu(rpc, pdu) != 0) { rpc_set_error(rpc, "Out of memory. Failed to queue pdu for nlm/unlock call"); rpc_free_pdu(rpc, pdu); return -1; } return 0; }
int rpc_nfs_mknod_async(struct rpc_context *rpc, rpc_cb cb, struct nfs_fh3 *fh, char *file, int mode, int major, int minor, void *private_data) { MKNOD3args args; memset(&args, 0, sizeof(MKNOD3args)); args.where.dir.data.data_len = fh->data.data_len; args.where.dir.data.data_val = fh->data.data_val; args.where.name = file; switch (mode & S_IFMT) { case S_IFCHR: args.what.type = NF3CHR; args.what.mknoddata3_u.chr_device.dev_attributes.mode.set_it = 1; args.what.mknoddata3_u.chr_device.dev_attributes.mode.set_mode3_u.mode = mode & (S_IRUSR|S_IWUSR|S_IXUSR|S_IRGRP|S_IWGRP|S_IXGRP|S_IROTH|S_IWOTH|S_IXOTH); args.what.mknoddata3_u.chr_device.spec.specdata1 = major; args.what.mknoddata3_u.chr_device.spec.specdata2 = minor; break; case S_IFBLK: args.what.type = NF3BLK; args.what.mknoddata3_u.blk_device.dev_attributes.mode.set_it = 1; args.what.mknoddata3_u.blk_device.dev_attributes.mode.set_mode3_u.mode = mode & (S_IRUSR|S_IWUSR|S_IXUSR|S_IRGRP|S_IWGRP|S_IXGRP|S_IROTH|S_IWOTH|S_IXOTH); args.what.mknoddata3_u.blk_device.spec.specdata1 = major; args.what.mknoddata3_u.blk_device.spec.specdata2 = minor; case S_IFSOCK: args.what.type = NF3SOCK; args.what.mknoddata3_u.sock_attributes.mode.set_it = 1; args.what.mknoddata3_u.sock_attributes.mode.set_mode3_u.mode = mode & (S_IRUSR|S_IWUSR|S_IXUSR|S_IRGRP|S_IWGRP|S_IXGRP|S_IROTH|S_IWOTH|S_IXOTH); break; case S_IFIFO: args.what.type = NF3FIFO; args.what.mknoddata3_u.pipe_attributes.mode.set_it = 1; args.what.mknoddata3_u.pipe_attributes.mode.set_mode3_u.mode = mode & (S_IRUSR|S_IWUSR|S_IXUSR|S_IRGRP|S_IWGRP|S_IXGRP|S_IROTH|S_IWOTH|S_IXOTH); break; default: rpc_set_error(rpc, "Invalid file type for NFS3/MKNOD call"); return -1; } return rpc_nfs3_mknod_async(rpc, cb, &args, private_data); }