void nn_chunkref_cp (struct nn_chunkref *dst, struct nn_chunkref *src) { /* TODO: At the moment, copy is made. Do it via reference count. */ nn_chunkref_init (dst, nn_chunkref_size (src)); memcpy (nn_chunkref_data (dst), nn_chunkref_data (src), nn_chunkref_size (src)); }
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; }
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; }
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; }
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; }
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_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; }
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 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; }
static int nn_respondent_recv (struct nn_sockbase *self, struct nn_msg *msg) { int rc; struct nn_respondent *respondent; respondent = nn_cont (self, struct nn_respondent, xrespondent.sockbase); /* Cancel current survey, if it exists. */ respondent->flags &= ~NN_RESPONDENT_INPROGRESS; /* Get next survey. */ rc = nn_xrespondent_recv (&respondent->xrespondent.sockbase, msg); if (nn_slow (rc == -EAGAIN)) return -EAGAIN; errnum_assert (rc == 0, -rc); /* Remember the survey ID. */ nn_assert (nn_chunkref_size (&msg->sphdr) == sizeof (uint32_t)); respondent->surveyid = nn_getl (nn_chunkref_data (&msg->sphdr)); nn_chunkref_term (&msg->sphdr); nn_chunkref_init (&msg->sphdr, 0); /* Remember that survey is being processed. */ respondent->flags |= NN_RESPONDENT_INPROGRESS; 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); } }
static int nn_surveyor_send (struct nn_sockbase *self, struct nn_msg *msg) { int rc; struct nn_surveyor *surveyor; surveyor = nn_cont (self, struct nn_surveyor, xsurveyor.sockbase); /* Cancel any ongoing survey. */ if (nn_slow (surveyor->flags & NN_SURVEYOR_INPROGRESS)) { surveyor->flags &= ~NN_SURVEYOR_INPROGRESS; nn_timer_stop (&surveyor->deadline_timer); } /* Generate new survey ID. */ ++surveyor->surveyid; /* Tag the survey body with survey ID. */ 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), surveyor->surveyid); /* Send the survey. */ rc = nn_xsurveyor_send (&surveyor->xsurveyor.sockbase, msg); errnum_assert (rc == 0, -rc); surveyor->flags |= NN_SURVEYOR_INPROGRESS; /* Set up the re-send timer. */ nn_timer_start (&surveyor->deadline_timer, surveyor->deadline); 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_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; }
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; } }
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; } }
/* Allocate a new message chunk, append it to message array, and return pointer to its buffer. */ static void *nn_msg_chunk_new (size_t size, struct nn_list *msg_array) { struct msg_chunk *self; self = nn_alloc (sizeof (struct msg_chunk), "msg_chunk"); alloc_assert (self); nn_chunkref_init (&self->chunk, size); nn_list_item_init (&self->item); nn_list_insert (msg_array, &self->item, nn_list_end (msg_array)); return nn_chunkref_data (&self->chunk); }
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; }
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_xbus_send (struct nn_sockbase *self, struct nn_msg *msg) { size_t hdrsz; struct nn_pipe *exclude; hdrsz = nn_chunkref_size (&msg->hdr); if (hdrsz == 0) exclude = NULL; else if (hdrsz == sizeof (uint64_t)) { memcpy (&exclude, nn_chunkref_data (&msg->hdr), sizeof (exclude)); nn_chunkref_term (&msg->hdr); nn_chunkref_init (&msg->hdr, 0); } else return -EINVAL; return nn_dist_send (&nn_cont (self, struct nn_xbus, sockbase)->outpipes, msg, exclude); }
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_cws_start_resolving (struct nn_cws *self) { int ipv4only; size_t ipv4onlylen; char *host; /* Check whether IPv6 is to be used. */ ipv4onlylen = sizeof (ipv4only); nn_epbase_getopt (&self->epbase, NN_SOL_SOCKET, NN_IPV4ONLY, &ipv4only, &ipv4onlylen); nn_assert (ipv4onlylen == sizeof (ipv4only)); host = nn_chunkref_data (&self->remote_host); nn_assert (strlen (host) > 0); nn_dns_start (&self->dns, host, self->remote_hostname_len, ipv4only, &self->dns_result); self->state = NN_CWS_STATE_RESOLVING; }
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 (!nn_surveyor_inprogress (surveyor))) { if (surveyor->timedout == NN_SURVEYOR_TIMEDOUT) { surveyor->timedout = 0; return -ETIMEDOUT; } else 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. */ /* TODO: This should be done asynchronously! */ if (nn_slow (nn_chunkref_size (&msg->sphdr) != sizeof (uint32_t))) continue; surveyid = nn_getl (nn_chunkref_data (&msg->sphdr)); if (nn_slow (surveyid != surveyor->surveyid)) continue; /* Discard the header and return the message to the user. */ nn_chunkref_term (&msg->sphdr); nn_chunkref_init (&msg->sphdr, 0); break; } return 0; }
static int nn_surveyor_send (struct nn_sockbase *self, struct nn_msg *msg) { struct nn_surveyor *surveyor; surveyor = nn_cont (self, struct nn_surveyor, xsurveyor.sockbase); /* Generate new survey ID. */ ++surveyor->surveyid; surveyor->surveyid |= 0x80000000; /* Tag the survey body 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), surveyor->surveyid); /* Store the survey, so that it can be sent later on. */ nn_msg_term (&surveyor->tosend); nn_msg_mv (&surveyor->tosend, msg); nn_msg_init (msg, 0); /* Cancel any ongoing survey, if any. */ if (nn_slow (nn_surveyor_inprogress (surveyor))) { /* First check whether the survey can be sent at all. */ if (!(nn_xsurveyor_events (&surveyor->xsurveyor.sockbase) & NN_SOCKBASE_EVENT_OUT)) return -EAGAIN; /* Cancel the current survey. */ nn_fsm_action (&surveyor->fsm, NN_SURVEYOR_ACTION_CANCEL); return 0; } /* Notify the state machine that the survey was started. */ nn_fsm_action (&surveyor->fsm, NN_SURVEYOR_ACTION_START); return 0; }
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; 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); } 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; }
int nn_recv (int s, void *buf, size_t len, int flags) { int rc; struct nn_msg msg; size_t sz; struct nn_chunk *ch; 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) { ch = nn_chunkref_getchunk (&msg.body); *(void**) buf = nn_chunk_data (ch); sz = nn_chunk_size (ch); } else { sz = nn_chunkref_size (&msg.body); memcpy (buf, nn_chunkref_data (&msg.body), len < sz ? len : sz); } nn_msg_term (&msg); #if defined NN_LATENCY_MONITOR nn_latmon_measure (NN_LATMON_RECV); #endif return (int) sz; }
static int nn_req_send (struct nn_sockbase *self, struct nn_msg *msg) { struct nn_req *req; req = nn_cont (self, struct nn_req, xreq.sockbase); /* 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. */ nn_msg_term (&req->request); nn_msg_mv (&req->request, msg); /* Notify the state machine. */ nn_fsm_action (&req->fsm, NN_REQ_ACTION_SENT); return 0; }
static void nn_stcp_handler(struct nn_fsm *self,int32_t src,int32_t type,NN_UNUSED void *srcptr) { int32_t rc,opt; struct nn_stcp *stcp; uint64_t size; size_t opt_sz = sizeof(opt); stcp = nn_cont(self,struct nn_stcp,fsm); switch (stcp->state) { /******************************************************************************/ /* IDLE state. */ /******************************************************************************/ case NN_STCP_STATE_IDLE: switch (src) { case NN_FSM_ACTION: switch (type) { case NN_FSM_START: //printf("streamhdr start\n"); nn_streamhdr_start(&stcp->streamhdr,stcp->usock,&stcp->pipebase); stcp->state = NN_STCP_STATE_PROTOHDR; return; default: nn_fsm_bad_action (stcp->state,src,type); } default: nn_fsm_bad_source (stcp->state, src, type); } /******************************************************************************/ /* PROTOHDR state. */ /******************************************************************************/ case NN_STCP_STATE_PROTOHDR: switch ( src ) { case NN_STCP_SRC_STREAMHDR: switch ( type ) { case NN_STREAMHDR_OK: // Before moving to the active state stop the streamhdr state machine nn_streamhdr_stop(&stcp->streamhdr); stcp->state = NN_STCP_STATE_STOPPING_STREAMHDR; return; case NN_STREAMHDR_ERROR: // Raise the error and move directly to the DONE state. streamhdr object will be stopped later on stcp->state = NN_STCP_STATE_DONE; nn_fsm_raise(&stcp->fsm,&stcp->done,NN_STCP_ERROR); return; default: nn_fsm_bad_action (stcp->state, src, type); } default: nn_fsm_bad_source(stcp->state,src,type); } /******************************************************************************/ /* STOPPING_STREAMHDR state. */ /******************************************************************************/ case NN_STCP_STATE_STOPPING_STREAMHDR: switch ( src ) { case NN_STCP_SRC_STREAMHDR: switch ( type ) { case NN_STREAMHDR_STOPPED: /* Start the pipe. */ rc = nn_pipebase_start(&stcp->pipebase); if ( nn_slow (rc < 0) ) { stcp->state = NN_STCP_STATE_DONE; nn_fsm_raise(&stcp->fsm, &stcp->done, NN_STCP_ERROR); return; } // Start receiving a message in asynchronous manner stcp->instate = NN_STCP_INSTATE_HDR; nn_usock_recv(stcp->usock,&stcp->inhdr,sizeof(stcp->inhdr),NULL); //printf("STCP recv.[%d %d %d %d]\n",stcp->inhdr[0],stcp->inhdr[1],stcp->inhdr[2],stcp->inhdr[3]); // Mark the pipe as available for sending stcp->outstate = NN_STCP_OUTSTATE_IDLE; stcp->state = NN_STCP_STATE_ACTIVE; return; default: nn_fsm_bad_action (stcp->state, src, type); } default: nn_fsm_bad_source (stcp->state, src, type); } /******************************************************************************/ /* ACTIVE state. */ /******************************************************************************/ case NN_STCP_STATE_ACTIVE: switch ( src ) { case NN_STCP_SRC_USOCK: switch ( type ) { case NN_USOCK_SENT: // The message is now fully sent nn_assert (stcp->outstate == NN_STCP_OUTSTATE_SENDING); stcp->outstate = NN_STCP_OUTSTATE_IDLE; nn_msg_term(&stcp->outmsg); nn_msg_init(&stcp->outmsg,0); nn_pipebase_sent(&stcp->pipebase); return; case NN_USOCK_RECEIVED: switch ( stcp->instate ) { case NN_STCP_INSTATE_HDR: // Message header was received. Check that message size is acceptable by comparing with NN_RCVMAXSIZE; if it's too large, drop the connection size = nn_getll(stcp->inhdr); nn_pipebase_getopt(&stcp->pipebase,NN_SOL_SOCKET,NN_RCVMAXSIZE,&opt,&opt_sz); if ( opt != -1 && size > opt ) { stcp->state = NN_STCP_STATE_DONE; nn_fsm_raise(&stcp->fsm,&stcp->done,NN_STCP_ERROR); return; } // Allocate memory for the message nn_msg_term(&stcp->inmsg); nn_msg_init(&stcp->inmsg,(size_t)size); // Special case when size of the message body is 0 if ( !size ) { printf("STCP: zero size pipebase recv\n"); stcp->instate = NN_STCP_INSTATE_HASMSG; nn_pipebase_received (&stcp->pipebase); return; } // Start receiving the message body stcp->instate = NN_STCP_INSTATE_BODY; nn_usock_recv (stcp->usock,nn_chunkref_data(&stcp->inmsg.body),(size_t)size,NULL); return; case NN_STCP_INSTATE_BODY: // Message body was received. Notify the owner that it can receive it stcp->instate = NN_STCP_INSTATE_HASMSG; nn_pipebase_received(&stcp->pipebase); return; default: nn_fsm_error("Unexpected socket instate",stcp->state,src,type); } case NN_USOCK_SHUTDOWN: nn_pipebase_stop(&stcp->pipebase); stcp->state = NN_STCP_STATE_SHUTTING_DOWN; return; case NN_USOCK_ERROR: nn_pipebase_stop(&stcp->pipebase); stcp->state = NN_STCP_STATE_DONE; nn_fsm_raise(&stcp->fsm,&stcp->done,NN_STCP_ERROR); return; default: nn_fsm_bad_action(stcp->state,src,type); } default: nn_fsm_bad_source(stcp->state,src,type); } /******************************************************************************/ /* SHUTTING_DOWN state. */ /* The underlying connection is closed. We are just waiting that underlying */ /* usock being closed */ /******************************************************************************/ case NN_STCP_STATE_SHUTTING_DOWN: switch (src) { case NN_STCP_SRC_USOCK: switch (type) { case NN_USOCK_ERROR: stcp->state = NN_STCP_STATE_DONE; nn_fsm_raise (&stcp->fsm, &stcp->done, NN_STCP_ERROR); return; default: nn_fsm_bad_action (stcp->state, src, type); } default: nn_fsm_bad_source (stcp->state, src, type); } /******************************************************************************/ /* DONE state. */ /* The underlying connection is closed. There's nothing that can be done in */ /* this state except stopping the object. */ /******************************************************************************/ case NN_STCP_STATE_DONE: nn_fsm_bad_source (stcp->state, src, type); /******************************************************************************/ /* Invalid state. */ /******************************************************************************/ default: nn_fsm_bad_state (stcp->state, src, type); } }
int nn_recvmsg (int s, struct nn_msghdr *msghdr, int flags) { int rc; struct nn_msg msg; uint8_t *data; size_t sz; int i; struct nn_iovec *iov; void *chunk; NN_BASIC_CHECKS; if (nn_slow (!msghdr)) { errno = EINVAL; return -1; } if (nn_slow (msghdr->msg_iovlen < 0)) { errno = EMSGSIZE; return -1; } /* Get a message. */ rc = nn_sock_recv (self.socks [s], &msg, flags); if (nn_slow (rc < 0)) { errno = -rc; return -1; } if (msghdr->msg_iovlen == 1 && msghdr->msg_iov [0].iov_len == NN_MSG) { chunk = nn_chunkref_getchunk (&msg.body); *(void**) (msghdr->msg_iov [0].iov_base) = chunk; sz = nn_chunk_size (chunk); } else { /* Copy the message content into the supplied gather array. */ data = nn_chunkref_data (&msg.body); sz = nn_chunkref_size (&msg.body); for (i = 0; i != msghdr->msg_iovlen; ++i) { iov = &msghdr->msg_iov [i]; if (nn_slow (iov->iov_len == NN_MSG)) { nn_msg_term (&msg); errno = EINVAL; return -1; } if (iov->iov_len > sz) { memcpy (iov->iov_base, data, sz); break; } memcpy (iov->iov_base, data, iov->iov_len); data += iov->iov_len; sz -= iov->iov_len; } sz = nn_chunkref_size (&msg.body); } /* Retrieve the ancillary data from the message. */ if (msghdr->msg_control) { if (msghdr->msg_controllen == NN_MSG) { chunk = nn_chunkref_getchunk (&msg.hdr); *((void**) msghdr->msg_control) = chunk; } else { /* TODO: Copy the data to the supplied buffer, prefix them with size. */ nn_assert (0); } } nn_msg_term (&msg); return (int) sz; }