static void nn_req_term (struct nn_req *self) { nn_timer_term (&self->timer); nn_msg_term (&self->reply); nn_msg_term (&self->request); nn_fsm_term (&self->fsm); nn_xreq_term (&self->xreq); }
static void nn_req_term (struct nn_req *self) { if (self->state == NN_REQ_STATE_UNSENT || self->state == NN_REQ_STATE_SENT) nn_msg_term (&self->request); if (self->state == NN_REQ_STATE_RECEIVED) nn_msg_term (&self->reply); nn_timer_term (&self->resend_timer); nn_xreq_term (&self->xreq); }
void nn_req_term (struct nn_req *self) { nn_timer_term (&self->task.timer); nn_task_term (&self->task); nn_msg_term (&self->task.reply); nn_msg_term (&self->task.request); nn_fsm_term (&self->fsm); nn_xreq_term (&self->xreq); }
void nn_req_in (struct nn_sockbase *self, struct nn_pipe *pipe) { int rc; struct nn_req *req; uint32_t reqid; req = nn_cont (self, struct nn_req, xreq.sockbase); /* Pass the pipe to the raw REQ socket. */ nn_xreq_in (&req->xreq.sockbase, pipe); while (1) { /* Get new reply. */ rc = nn_xreq_recv (&req->xreq.sockbase, &req->task.reply); if (nn_slow (rc == -EAGAIN)) return; errnum_assert (rc == 0, -rc); /* No request was sent. Getting a reply doesn't make sense. */ if (nn_slow (!nn_req_inprogress (req))) { nn_msg_term (&req->task.reply); continue; } /* Ignore malformed replies. */ if (nn_slow (nn_chunkref_size (&req->task.reply.sphdr) != sizeof (uint32_t))) { nn_msg_term (&req->task.reply); continue; } /* Ignore replies with incorrect request IDs. */ reqid = nn_getl (nn_chunkref_data (&req->task.reply.sphdr)); if (nn_slow (!(reqid & 0x80000000))) { nn_msg_term (&req->task.reply); continue; } if (nn_slow (reqid != (req->task.id | 0x80000000))) { nn_msg_term (&req->task.reply); continue; } /* Trim the request ID. */ nn_chunkref_term (&req->task.reply.sphdr); nn_chunkref_init (&req->task.reply.sphdr, 0); /* TODO: Deallocate the request here? */ /* Notify the state machine. */ if (req->state == NN_REQ_STATE_ACTIVE) nn_fsm_action (&req->fsm, NN_REQ_ACTION_IN); return; } }
void nn_stcp_term(struct nn_stcp *self) { nn_assert_state(self,NN_STCP_STATE_IDLE); nn_fsm_event_term(&self->done); nn_msg_term(&self->outmsg); nn_msg_term(&self->inmsg); nn_pipebase_term(&self->pipebase); nn_streamhdr_term(&self->streamhdr); nn_fsm_term(&self->fsm); }
static void nn_req_in (struct nn_sockbase *self, struct nn_pipe *pipe) { int rc; struct nn_req *req; uint32_t reqid; req = nn_cont (self, struct nn_req, xreq.sockbase); /* Pass the pipe to the raw REQ socket. */ nn_xreq_in (&req->xreq.sockbase, pipe); while (1) { /* Get new reply. */ rc = nn_xreq_recv (&req->xreq.sockbase, &req->reply); if (nn_slow (rc == -EAGAIN)) return; errnum_assert (rc == 0, -rc); /* No request was sent. Getting a reply doesn't make sense. */ if (nn_slow (req->state != NN_REQ_STATE_SENT)) { nn_msg_term (&req->reply); continue; } /* Ignore malformed replies. */ if (nn_slow (nn_chunkref_size (&req->reply.hdr) != sizeof (uint32_t))) { nn_msg_term (&req->reply); continue; } /* Ignore replies with incorrect request IDs. */ reqid = nn_getl (nn_chunkref_data (&req->reply.hdr)); if (nn_slow (!(reqid & 0x80000000))) { nn_msg_term (&req->reply); continue; } if (nn_slow (reqid != (req->reqid | 0x80000000))) { nn_msg_term (&req->reply); continue; } /* Trim the request ID. */ nn_chunkref_term (&req->reply.hdr); nn_chunkref_init (&req->reply.hdr, 0); /* Swtich to RECEIVED state. */ nn_timer_stop (&req->resend_timer); nn_msg_term (&req->request); req->state = NN_REQ_STATE_RECEIVED; return; } }
void nn_slibfabric_term (struct nn_slibfabric *self) { nn_assert_state (self, NN_SLIBFABRIC_STATE_IDLE); nn_fsm_event_term (&self->done); nn_msg_term (&self->outmsg); nn_msg_term (&self->inmsg); nn_pipebase_term (&self->pipebase); nn_streamhdr_term (&self->streamhdr); nn_fsm_term (&self->fsm); }
void nn_sipc_term (struct nn_sipc *self) { nn_assert (self->state == NN_SIPC_STATE_IDLE); nn_fsm_event_term (&self->done); nn_msg_term (&self->outmsg); nn_msg_term (&self->inmsg); nn_pipebase_term (&self->pipebase); nn_streamhdr_term (&self->streamhdr); nn_fsm_term (&self->fsm); }
void nn_stream_term (struct nn_stream *self) { /* Close the messages in progress. */ nn_msg_term (&self->inmsg); nn_msg_term (&self->outmsg); nn_timer_term (&self->hdr_timeout); nn_pipebase_term (&self->pipebase); /* Return control to the parent state machine. */ nn_usock_setsink (self->usock, self->original_sink); }
static int nn_req_send (struct nn_sockbase *self, struct nn_msg *msg) { int rc; struct nn_req *req; req = nn_cont (self, struct nn_req, xreq.sockbase); /* If there's a request in progress, cancel it. */ if (nn_slow (req->state != NN_REQ_STATE_IDLE)) { if (req->state == NN_REQ_STATE_UNSENT || req->state == NN_REQ_STATE_SENT) nn_msg_term (&req->request); if (req->state == NN_REQ_STATE_RECEIVED) nn_msg_term (&req->reply); nn_timer_term (&req->resend_timer); req->state = NN_REQ_STATE_IDLE; } /* Generate new request ID for the new request and put it into message header. The most important bit is set to 1 to indicate that this is the bottom of the backtrace stack. */ ++req->reqid; nn_assert (nn_chunkref_size (&msg->hdr) == 0); nn_chunkref_term (&msg->hdr); nn_chunkref_init (&msg->hdr, 4); nn_putl (nn_chunkref_data (&msg->hdr), req->reqid | 0x80000000); /* Store the message so that it can be re-sent if there's no reply. Then make a copy of it and send it. */ nn_msg_cp (&req->request, msg); rc = nn_xreq_send (&req->xreq.sockbase, msg); errnum_assert (rc == 0 || rc == -EAGAIN, -rc); /* If the request cannot be sent at the moment switch to UNSENT state. It will be sent as soon as a new outbound pipe arrives. */ if (nn_slow (rc == -EAGAIN)) { nn_msg_term (msg); req->state = NN_REQ_STATE_UNSENT; return 0; } /* If the request was successgfully sent set up the re-send timer in case it get lost somewhere further out in the topology. */ nn_timer_start (&req->resend_timer, req->resend_ivl); req->state = NN_REQ_STATE_SENT; return 0; }
int nn_xreq_recv (struct nn_sockbase *self, struct nn_msg *msg) { int rc; rc = nn_fq_recv (&nn_cont (self, struct nn_xreq, sockbase)->fq, msg, NULL); if (rc == -EAGAIN) return -EAGAIN; errnum_assert (rc >= 0, -rc); if (!(rc & NN_PIPE_PARSED)) { /* Ignore malformed replies. */ if (nn_slow (nn_chunkref_size (&msg->body) < sizeof (uint32_t))) { nn_msg_term (msg); return -EAGAIN; } /* Split the message into the header and the body. */ nn_assert (nn_chunkref_size (&msg->sphdr) == 0); nn_chunkref_term (&msg->sphdr); nn_chunkref_init (&msg->sphdr, sizeof (uint32_t)); memcpy (nn_chunkref_data (&msg->sphdr), nn_chunkref_data (&msg->body), sizeof (uint32_t)); nn_chunkref_trim (&msg->body, sizeof (uint32_t)); } return 0; }
static int nn_xsub_recv (struct nn_sockbase *self, struct nn_msg *msg) { int rc; struct nn_xsub *xsub; xsub = nn_cont (self, struct nn_xsub, sockbase); /* Loop while a matching message is found or when there are no more messages to receive. */ while (1) { rc = nn_fq_recv (&xsub->fq, msg, NULL); if (nn_slow (rc == -EAGAIN)) return -EAGAIN; errnum_assert (rc >= 0, -rc); rc = nn_trie_match (&xsub->trie, nn_chunkref_data (&msg->body), nn_chunkref_size (&msg->body)); if (rc == 0) { nn_msg_term (msg); continue; } if (rc == 1) return 0; errnum_assert (0, -rc); } }
int nn_xbus_recv (struct nn_sockbase *self, struct nn_msg *msg) { int rc; struct nn_xbus *xbus; struct nn_pipe *pipe; xbus = nn_cont (self, struct nn_xbus, sockbase); while (1) { /* Get next message in fair-queued manner. */ rc = nn_fq_recv (&xbus->inpipes, msg, &pipe); if (nn_slow (rc < 0)) return rc; /* The message should have no header. Drop malformed messages. */ if (nn_chunkref_size (&msg->hdr) == 0) break; nn_msg_term (msg); } /* Add pipe ID to the message header. */ nn_chunkref_term (&msg->hdr); nn_chunkref_init (&msg->hdr, sizeof (uint64_t)); memset (nn_chunkref_data (&msg->hdr), 0, sizeof (uint64_t)); memcpy (nn_chunkref_data (&msg->hdr), &pipe, sizeof (pipe)); return 0; }
static void nn_surveyor_term (struct nn_surveyor *self) { nn_msg_term (&self->tosend); nn_timer_term (&self->timer); nn_fsm_term (&self->fsm); nn_xsurveyor_term (&self->xsurveyor); }
static int nn_sipc_send (struct nn_pipebase *self, struct nn_msg *msg) { struct nn_sipc *sipc; struct nn_iovec iov [3]; sipc = nn_cont (self, struct nn_sipc, pipebase); nn_assert (sipc->state == NN_SIPC_STATE_ACTIVE); nn_assert (sipc->outstate == NN_SIPC_OUTSTATE_IDLE); /* Move the message to the local storage. */ nn_msg_term (&sipc->outmsg); nn_msg_mv (&sipc->outmsg, msg); /* Serialise the message header. */ sipc->outhdr [0] = NN_SIPC_MSG_NORMAL; nn_putll (sipc->outhdr + 1, nn_chunkref_size (&sipc->outmsg.hdr) + nn_chunkref_size (&sipc->outmsg.body)); /* Start async sending. */ iov [0].iov_base = sipc->outhdr; iov [0].iov_len = sizeof (sipc->outhdr); iov [1].iov_base = nn_chunkref_data (&sipc->outmsg.hdr); iov [1].iov_len = nn_chunkref_size (&sipc->outmsg.hdr); iov [2].iov_base = nn_chunkref_data (&sipc->outmsg.body); iov [2].iov_len = nn_chunkref_size (&sipc->outmsg.body); nn_usock_send (sipc->usock, iov, 3); sipc->outstate = NN_SIPC_OUTSTATE_SENDING; return 0; }
int nn_xsurveyor_recv (struct nn_sockbase *self, struct nn_msg *msg) { int rc; struct nn_xsurveyor *xsurveyor; xsurveyor = nn_cont (self, struct nn_xsurveyor, sockbase); rc = nn_fq_recv (&xsurveyor->inpipes, msg, NULL); if (nn_slow (rc < 0)) return rc; /* Split the header from the body, if needed. */ if (!(rc & NN_PIPE_PARSED)) { if (nn_slow (nn_chunkref_size (&msg->body) < sizeof (uint32_t))) { nn_msg_term (msg); return -EAGAIN; } nn_assert (nn_chunkref_size (&msg->hdr) == 0); nn_chunkref_term (&msg->hdr); nn_chunkref_init (&msg->hdr, sizeof (uint32_t)); memcpy (nn_chunkref_data (&msg->hdr), nn_chunkref_data (&msg->body), sizeof (uint32_t)); nn_chunkref_trim (&msg->body, sizeof (uint32_t)); } return 0; }
static void nn_req_action_send (struct nn_req *self) { int rc; struct nn_msg msg; /* Send the request. */ nn_msg_cp (&msg, &self->request); rc = nn_xreq_send (&self->xreq.sockbase, &msg); /* If the request cannot be sent at the moment wait till new outbound pipe arrives. */ if (nn_slow (rc == -EAGAIN)) { nn_msg_term (&msg); self->state = NN_REQ_STATE_DELAYED; return; } /* Request was successfully sent. Set up the re-send timer in case the request gets lost somewhere further out in the topology. */ if (nn_fast (rc == 0)) { nn_timer_start (&self->timer, self->resend_ivl); self->state = NN_REQ_STATE_ACTIVE; return; } /* Unexpected error. */ errnum_assert (0, -rc); }
static int nn_stcp_send (struct nn_pipebase *self, struct nn_msg *msg) { struct nn_stcp *stcp; struct nn_iovec iov [3]; stcp = nn_cont (self, struct nn_stcp, pipebase); nn_assert (stcp); nn_assert_state (stcp, NN_STCP_STATE_ACTIVE); nn_assert (stcp->outstate == NN_STCP_OUTSTATE_IDLE); /* Move the message to the local storage. */ nn_msg_term (&stcp->outmsg); nn_msg_mv (&stcp->outmsg, msg); /* Serialise the message header. */ nn_putll (stcp->outhdr, nn_chunkref_size (&stcp->outmsg.sphdr) + nn_chunkref_size (&stcp->outmsg.body)); /* Start async sending. */ iov [0].iov_base = stcp->outhdr; iov [0].iov_len = sizeof (stcp->outhdr); iov [1].iov_base = nn_chunkref_data (&stcp->outmsg.sphdr); iov [1].iov_len = nn_chunkref_size (&stcp->outmsg.sphdr); iov [2].iov_base = nn_chunkref_data (&stcp->outmsg.body); iov [2].iov_len = nn_chunkref_size (&stcp->outmsg.body); nn_usock_send (stcp->usock, iov, 3); stcp->outstate = NN_STCP_OUTSTATE_SENDING; return 0; }
static int nn_stream_send (struct nn_pipebase *self, struct nn_msg *msg) { struct nn_stream *stream; struct nn_iobuf iov [3]; stream = nn_cont (self, struct nn_stream, pipebase); /* Mave the message to the local storage. */ nn_msg_term (&stream->outmsg); nn_msg_mv (&stream->outmsg, msg); /* Serialise the message header. */ nn_putll (stream->outhdr, nn_chunkref_size (&stream->outmsg.hdr) + nn_chunkref_size (&stream->outmsg.body)); /* Start async sending. */ iov [0].iov_base = stream->outhdr; iov [0].iov_len = sizeof (stream->outhdr); iov [1].iov_base = nn_chunkref_data (&stream->outmsg.hdr); iov [1].iov_len = nn_chunkref_size (&stream->outmsg.hdr); iov [2].iov_base = nn_chunkref_data (&stream->outmsg.body); iov [2].iov_len = nn_chunkref_size (&stream->outmsg.body);; nn_usock_send (stream->usock, iov, 3); return 0; }
static void nn_stream_received (const struct nn_cp_sink **self, struct nn_usock *usock) { struct nn_stream *stream; uint64_t size; stream = nn_cont (self, struct nn_stream, sink); switch (stream->instate) { case NN_STREAM_INSTATE_HDR: size = nn_getll (stream->inhdr); nn_msg_term (&stream->inmsg); nn_msg_init (&stream->inmsg, (size_t) size); if (!size) { nn_pipebase_received (&stream->pipebase); break; } stream->instate = NN_STREAM_INSTATE_BODY; nn_usock_recv (stream->usock, nn_chunkref_data (&stream->inmsg.body), (size_t) size); break; case NN_STREAM_INSTATE_BODY: nn_pipebase_received (&stream->pipebase); break; default: nn_assert (0); } }
int nn_recv (int s, void *buf, size_t len, int flags) { int rc; struct nn_msg msg; size_t sz; void *chunk; NN_BASIC_CHECKS; if (nn_slow (!buf && len)) { errno = EFAULT; return -1; } rc = nn_sock_recv (self.socks [s], &msg, flags); if (nn_slow (rc < 0)) { errno = -rc; return -1; } if (len == NN_MSG) { chunk = nn_chunkref_getchunk (&msg.body); *(void**) buf = chunk; sz = nn_chunk_size (chunk); } else { sz = nn_chunkref_size (&msg.body); memcpy (buf, nn_chunkref_data (&msg.body), len < sz ? len : sz); } nn_msg_term (&msg); return (int) sz; }
static int nn_respondent_send (struct nn_sockbase *self, struct nn_msg *msg) { int rc; struct nn_respondent *respondent; respondent = nn_cont (self, struct nn_respondent, xrespondent.sockbase); /* If there's no survey going on, report EFSM error. */ if (nn_slow (!(respondent->flags & NN_RESPONDENT_INPROGRESS))) return -EFSM; /* Tag the message with survey ID. */ nn_assert (nn_chunkref_size (&msg->sphdr) == 0); nn_chunkref_term (&msg->sphdr); nn_chunkref_init (&msg->sphdr, 4); nn_putl (nn_chunkref_data (&msg->sphdr), respondent->surveyid); /* Try to send the message. If it cannot be sent due to pushback, drop it silently. */ rc = nn_xrespondent_send (&respondent->xrespondent.sockbase, msg); if (nn_slow (rc == -EAGAIN)) { nn_msg_term (msg); return -EAGAIN; } errnum_assert (rc == 0, -rc); /* Remember that no survey is being processed. */ respondent->flags &= ~NN_RESPONDENT_INPROGRESS; return 0; }
int nn_xrespondent_recv (struct nn_sockbase *self, struct nn_msg *msg) { int rc; struct nn_xrespondent *xrespondent; xrespondent = nn_cont (self, struct nn_xrespondent, sockbase); /* Get the survey. */ rc = nn_excl_recv (&xrespondent->excl, msg); if (rc == -EAGAIN) return -EAGAIN; errnum_assert (rc >= 0, -rc); /* Split the survey ID from the body, if needed. */ if (!(rc & NN_PIPE_PARSED)) { if (nn_slow (nn_chunkref_size (&msg->body) < sizeof (uint32_t))) { nn_msg_term (msg); return -EAGAIN; } nn_chunkref_term (&msg->hdr); nn_chunkref_init (&msg->hdr, sizeof (uint32_t)); memcpy (nn_chunkref_data (&msg->hdr), nn_chunkref_data (&msg->body), sizeof (uint32_t)); nn_chunkref_trim (&msg->body, sizeof (uint32_t)); } return 0; }
static void nn_stream_sent (const struct nn_cp_sink **self, struct nn_usock *usock) { struct nn_stream *stream; stream = nn_cont (self, struct nn_stream, sink); nn_pipebase_sent (&stream->pipebase); nn_msg_term (&stream->outmsg); nn_msg_init (&stream->outmsg, 0); }
int nn_dist_send (struct nn_dist *self, struct nn_msg *msg, struct nn_pipe *exclude) { int rc; struct nn_list_item *it; struct nn_dist_data *data; struct nn_msg copy; /* TODO: We can optimise for the case when there's only one outbound pipe here. No message copying is needed in such case. */ /* In the specific case when there are no outbound pipes. There's nowhere to send the message to. Deallocate it. */ if (nn_slow (self->count) == 0) { nn_msg_term (msg); return 0; } /* Send the message to all the subscribers. */ nn_msg_bulkcopy_start (msg, self->count); it = nn_list_begin (&self->pipes); while (it != nn_list_end (&self->pipes)) { data = nn_cont (it, struct nn_dist_data, item); nn_msg_bulkcopy_cp (©, msg); if (nn_fast (data->pipe == exclude)) { nn_msg_term (©); } else { rc = nn_pipe_send (data->pipe, ©); errnum_assert (rc >= 0, -rc); if (rc & NN_PIPE_RELEASE) { --self->count; it = nn_list_erase (&self->pipes, it); continue; } } it = nn_list_next (&self->pipes, it); } nn_msg_term (msg); return 0; }
void nn_sws_term (struct nn_sws *self) { nn_assert_state (self, NN_SWS_STATE_IDLE); nn_fsm_event_term (&self->done); nn_msg_term (&self->outmsg); nn_msg_array_term (&self->inmsg_array); nn_pipebase_term (&self->pipebase); nn_wshdr_term (&self->wshdr); nn_fsm_term (&self->fsm); }
static int nn_surveyor_recv (struct nn_sockbase *self, struct nn_msg *msg) { int rc; struct nn_surveyor *surveyor; uint32_t surveyid; surveyor = nn_cont (self, struct nn_surveyor, xsurveyor.sockbase); /* If no survey is going on return EFSM error. */ if (nn_slow (!(surveyor->flags & NN_SURVEYOR_INPROGRESS))) return -EFSM; while (1) { /* Get next response. */ rc = nn_xsurveyor_recv (&surveyor->xsurveyor.sockbase, msg); if (nn_slow (rc == -EAGAIN)) return -EAGAIN; errnum_assert (rc == 0, -rc); /* Get the survey ID. Ignore any stale responses. */ if (nn_slow (nn_chunkref_size (&msg->hdr) != sizeof (uint32_t))) { nn_msg_term (msg); continue; } surveyid = nn_getl (nn_chunkref_data (&msg->hdr)); if (nn_slow (surveyid != surveyor->surveyid)) { nn_msg_term (msg); continue; } /* Discard the header and return the message to the user. */ nn_chunkref_term (&msg->hdr); nn_chunkref_init (&msg->hdr, 0); break; } return 0; }
int nn_send (int s, const void *buf, size_t len, int flags) { int rc; struct nn_msg msg; void *chunk; int nnmsg; NN_BASIC_CHECKS; if (nn_slow (!buf && len)) { errno = EFAULT; return -1; } /* Create a message object. */ if (len == NN_MSG) { chunk = *(void**) buf; if (nn_slow (chunk == NULL)) { errno = EFAULT; return -1; } len = nn_chunk_size (chunk); nn_msg_init_chunk (&msg, chunk); nnmsg = 1; } else { nn_msg_init (&msg, len); memcpy (nn_chunkref_data (&msg.body), buf, len); nnmsg = 0; } /* Send it further down the stack. */ rc = nn_sock_send (self.socks [s], &msg, flags); if (nn_slow (rc < 0)) { /* If we are dealing with user-supplied buffer, detach it from the message object. */ if (nnmsg) nn_chunkref_init (&msg.body, 0); nn_msg_term (&msg); errno = -rc; return -1; } nn_sock_stat_increment (self.socks [s], NN_STAT_MESSAGES_SENT, 1); nn_sock_stat_increment (self.socks [s], NN_STAT_BYTES_SENT, len); return (int) len; }
int nn_send (int s, const void *buf, size_t len, int flags) { int rc; struct nn_msg msg; struct nn_chunk *ch; NN_BASIC_CHECKS; #if defined NN_LATENCY_MONITOR nn_latmon_measure (NN_LATMON_SEND); #endif if (nn_slow (!buf && len)) { errno = EFAULT; return -1; } /* Create a message object. */ if (len == NN_MSG) { ch = nn_chunk_from_data (*(void**) buf); if (nn_slow (ch == NULL)) { errno = EFAULT; return -1; } len = nn_chunk_size (ch); nn_msg_init_chunk (&msg, ch); } else { nn_msg_init (&msg, len); memcpy (nn_chunkref_data (&msg.body), buf, len); } /* Send it further down the stack. */ rc = nn_sock_send (self.socks [s], &msg, flags); if (nn_slow (rc < 0)) { nn_msg_term (&msg); errno = -rc; return -1; } return (int) len; }
static void nn_req_timeout (const struct nn_cp_sink **self, struct nn_timer *timer) { int rc; struct nn_req *req; struct nn_msg msg; req = nn_cont (self, struct nn_req, sink); nn_assert (req->state == NN_REQ_STATE_SENT); /* Re-send the request. If it cannot be sent, just drop it. */ nn_msg_cp (&msg, &req->request); rc = nn_xreq_send (&req->xreq.sockbase, &msg); errnum_assert (rc == 0 || rc == -EAGAIN, -rc); if (nn_slow (rc == -EAGAIN)) nn_msg_term (&msg); /* Set up the next re-send timer. */ nn_timer_start (&req->resend_timer, req->resend_ivl); }