int dnet_trans_send_fail(struct dnet_session *s, struct dnet_addr *addr, struct dnet_trans_control *ctl, int err, int destroy) { struct dnet_cmd cmd; memset(&cmd, 0, sizeof(cmd)); dnet_trans_control_fill_cmd(s, ctl, &cmd); cmd.status = err; cmd.size = 0; if (ctl->complete) { cmd.flags &= ~DNET_FLAGS_REPLY; ctl->complete(addr, &cmd, ctl->priv); if (destroy) { cmd.flags |= DNET_FLAGS_DESTROY; ctl->complete(addr, &cmd, ctl->priv); } } return 0; }
/* * Allocates and sends transaction into given @st network state/connection. * Uses @s session only to get wait timeout for transaction, if it is NULL, global node timeout (@dnet_node::wait_ts) is used. * * If something fails, completion handler from @ctl will be invoked with (NULL, NULL, @ctl->priv) arguments */ int dnet_trans_alloc_send_state(struct dnet_session *s, struct dnet_net_state *st, struct dnet_trans_control *ctl) { struct dnet_io_req req; struct dnet_node *n = st->n; struct dnet_cmd *cmd; struct dnet_trans *t; int err; t = dnet_trans_alloc(n, sizeof(struct dnet_cmd) + ctl->size); if (!t) { err = dnet_trans_send_fail(s, dnet_state_addr(st), ctl, -ENOMEM, 1); goto err_out_exit; } t->complete = ctl->complete; t->priv = ctl->priv; if (s) { t->wait_ts = *dnet_session_get_timeout(s); } else { t->wait_ts = n->wait_ts; } cmd = (struct dnet_cmd *)(t + 1); dnet_trans_control_fill_cmd(s, ctl, cmd); t->command = cmd->cmd; cmd->trans = t->rcv_trans = t->trans = atomic_inc(&n->trans); memcpy(&t->cmd, cmd, sizeof(struct dnet_cmd)); if (ctl->size && ctl->data) memcpy(cmd + 1, ctl->data, ctl->size); dnet_convert_cmd(cmd); t->st = dnet_state_get(st); memset(&req, 0, sizeof(req)); req.st = st; req.header = cmd; req.hsize = sizeof(struct dnet_cmd) + ctl->size; req.fd = -1; dnet_log(n, DNET_LOG_INFO, "%s: %s: created %s", dnet_dump_id(&cmd->id), dnet_cmd_string(cmd->cmd), dnet_print_trans(t) ); err = dnet_trans_send(t, &req); if (err) goto err_out_put; return 0; err_out_put: dnet_trans_send_fail(s, dnet_state_addr(st), ctl, err, 0); dnet_trans_put(t); err_out_exit: return 0; }