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; }
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_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 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; }
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; }
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)); }
int nn_rep_recv (struct nn_sockbase *self, struct nn_msg *msg) { int rc; struct nn_rep *rep; rep = nn_cont (self, struct nn_rep, xrep.sockbase); /* If a request is already being processed, cancel it. */ if (nn_slow (rep->flags & NN_REP_INPROGRESS)) { nn_chunkref_term (&rep->backtrace); rep->flags &= ~NN_REP_INPROGRESS; } /* Receive the request. */ rc = nn_xrep_recv (&rep->xrep.sockbase, msg); if (nn_slow (rc == -EAGAIN)) return -EAGAIN; errnum_assert (rc == 0, -rc); /* Store the backtrace. */ nn_chunkref_mv (&rep->backtrace, &msg->sphdr); nn_chunkref_init (&msg->sphdr, 0); rep->flags |= NN_REP_INPROGRESS; return 0; }
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); }
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; }
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; }
void nn_msg_init (struct nn_msg *self, size_t size) { nn_chunkref_init (&self->hdr, 0); nn_chunkref_init (&self->body, size); }
int nn_cws_create (void *hint, struct nn_epbase **epbase) { int rc; const char *addr; size_t addrlen; const char *semicolon; const char *hostname; size_t hostlen; const char *colon; const char *slash; const char *resource; size_t resourcelen; struct sockaddr_storage ss; size_t sslen; int ipv4only; size_t ipv4onlylen; struct nn_cws *self; int reconnect_ivl; int reconnect_ivl_max; int msg_type; size_t sz; /* Allocate the new endpoint object. */ self = nn_alloc (sizeof (struct nn_cws), "cws"); alloc_assert (self); /* Initalise the endpoint. */ nn_epbase_init (&self->epbase, &nn_cws_epbase_vfptr, hint); /* 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)); /* Start parsing the address. */ addr = nn_epbase_getaddr (&self->epbase); addrlen = strlen (addr); semicolon = strchr (addr, ';'); hostname = semicolon ? semicolon + 1 : addr; colon = strrchr (addr, ':'); slash = colon ? strchr (colon, '/') : strchr (addr, '/'); resource = slash ? slash : addr + addrlen; self->remote_hostname_len = colon ? colon - hostname : resource - hostname; /* Host contains both hostname and port. */ hostlen = resource - hostname; /* Parse the port; assume port 80 if not explicitly declared. */ if (nn_slow (colon != NULL)) { rc = nn_port_resolve (colon + 1, resource - colon - 1); if (nn_slow (rc < 0)) { nn_epbase_term (&self->epbase); return -EINVAL; } self->remote_port = rc; } else { self->remote_port = 80; } /* Check whether the host portion of the address is either a literal or a valid hostname. */ if (nn_dns_check_hostname (hostname, self->remote_hostname_len) < 0 && nn_literal_resolve (hostname, self->remote_hostname_len, ipv4only, &ss, &sslen) < 0) { nn_epbase_term (&self->epbase); return -EINVAL; } /* If local address is specified, check whether it is valid. */ if (semicolon) { rc = nn_iface_resolve (addr, semicolon - addr, ipv4only, &ss, &sslen); if (rc < 0) { nn_epbase_term (&self->epbase); return -ENODEV; } } /* At this point, the address is valid, so begin allocating resources. */ nn_chunkref_init (&self->remote_host, hostlen + 1); memcpy (nn_chunkref_data (&self->remote_host), hostname, hostlen); ((uint8_t *) nn_chunkref_data (&self->remote_host)) [hostlen] = '\0'; if (semicolon) { nn_chunkref_init (&self->nic, semicolon - addr); memcpy (nn_chunkref_data (&self->nic), addr, semicolon - addr); } else { nn_chunkref_init (&self->nic, 1); memcpy (nn_chunkref_data (&self->nic), "*", 1); } /* The requested resource is used in opening handshake. */ resourcelen = strlen (resource); if (resourcelen) { nn_chunkref_init (&self->resource, resourcelen + 1); strncpy (nn_chunkref_data (&self->resource), resource, resourcelen + 1); } else { /* No resource specified, so allocate base path. */ nn_chunkref_init (&self->resource, 2); strncpy (nn_chunkref_data (&self->resource), "/", 2); } /* Initialise the structure. */ nn_fsm_init_root (&self->fsm, nn_cws_handler, nn_cws_shutdown, nn_epbase_getctx (&self->epbase)); self->state = NN_CWS_STATE_IDLE; nn_usock_init (&self->usock, NN_CWS_SRC_USOCK, &self->fsm); sz = sizeof (msg_type); nn_epbase_getopt (&self->epbase, NN_WS, NN_WS_MSG_TYPE, &msg_type, &sz); nn_assert (sz == sizeof (msg_type)); self->msg_type = (uint8_t) msg_type; sz = sizeof (reconnect_ivl); nn_epbase_getopt (&self->epbase, NN_SOL_SOCKET, NN_RECONNECT_IVL, &reconnect_ivl, &sz); nn_assert (sz == sizeof (reconnect_ivl)); sz = sizeof (reconnect_ivl_max); nn_epbase_getopt (&self->epbase, NN_SOL_SOCKET, NN_RECONNECT_IVL_MAX, &reconnect_ivl_max, &sz); nn_assert (sz == sizeof (reconnect_ivl_max)); if (reconnect_ivl_max == 0) reconnect_ivl_max = reconnect_ivl; nn_backoff_init (&self->retry, NN_CWS_SRC_RECONNECT_TIMER, reconnect_ivl, reconnect_ivl_max, &self->fsm); nn_sws_init (&self->sws, NN_CWS_SRC_SWS, &self->epbase, &self->fsm); nn_dns_init (&self->dns, NN_CWS_SRC_DNS, &self->fsm); /* Start the state machine. */ nn_fsm_start (&self->fsm); /* Return the base class as an out parameter. */ *epbase = &self->epbase; return 0; }
int nn_sendmsg (int s, const struct nn_msghdr *msghdr, int flags) { int rc; size_t sz; int i; struct nn_iovec *iov; struct nn_msg msg; void *chunk; int nnmsg; NN_BASIC_CHECKS; if (nn_slow (!msghdr)) { errno = EINVAL; return -1; } if (nn_slow (msghdr->msg_iovlen < 0)) { errno = EMSGSIZE; return -1; } if (msghdr->msg_iovlen == 1 && msghdr->msg_iov [0].iov_len == NN_MSG) { chunk = *(void**) msghdr->msg_iov [0].iov_base; if (nn_slow (chunk == NULL)) { errno = EFAULT; return -1; } sz = nn_chunk_size (chunk); nn_msg_init_chunk (&msg, chunk); nnmsg = 1; } else { /* Compute the total size of the message. */ sz = 0; for (i = 0; i != msghdr->msg_iovlen; ++i) { iov = &msghdr->msg_iov [i]; if (nn_slow (iov->iov_len == NN_MSG)) { errno = EINVAL; return -1; } if (nn_slow (!iov->iov_base && iov->iov_len)) { errno = EFAULT; return -1; } if (nn_slow (sz + iov->iov_len < sz)) { errno = EINVAL; return -1; } sz += iov->iov_len; } /* Create a message object from the supplied scatter array. */ nn_msg_init (&msg, sz); sz = 0; for (i = 0; i != msghdr->msg_iovlen; ++i) { iov = &msghdr->msg_iov [i]; memcpy (((uint8_t*) nn_chunkref_data (&msg.body)) + sz, iov->iov_base, iov->iov_len); sz += iov->iov_len; } nnmsg = 0; } /* Add ancillary data to the message. */ if (msghdr->msg_control) { if (msghdr->msg_controllen == NN_MSG) { chunk = *((void**) msghdr->msg_control); nn_chunkref_term (&msg.hdr); nn_chunkref_init_chunk (&msg.hdr, chunk); } else { /* TODO: Copy the control data to the message. */ nn_assert (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; } return (int) sz; }
void nn_msg_init_chunk (struct nn_msg *self, void *chunk) { nn_chunkref_init (&self->hdr, 0); nn_chunkref_init_chunk (&self->body, chunk); }
int nn_sendmsg (int s, const struct nn_msghdr *msghdr, int flags) { int rc; size_t sz; size_t spsz; int i; struct nn_iovec *iov; struct nn_msg msg; void *chunk; int nnmsg; struct nn_cmsghdr *cmsg; NN_BASIC_CHECKS; if (nn_slow (!msghdr)) { errno = EINVAL; return -1; } if (nn_slow (msghdr->msg_iovlen < 0)) { errno = EMSGSIZE; return -1; } if (msghdr->msg_iovlen == 1 && msghdr->msg_iov [0].iov_len == NN_MSG) { chunk = *(void**) msghdr->msg_iov [0].iov_base; if (nn_slow (chunk == NULL)) { errno = EFAULT; return -1; } sz = nn_chunk_size (chunk); nn_msg_init_chunk (&msg, chunk); nnmsg = 1; } else { /* Compute the total size of the message. */ sz = 0; for (i = 0; i != msghdr->msg_iovlen; ++i) { iov = &msghdr->msg_iov [i]; if (nn_slow (iov->iov_len == NN_MSG)) { errno = EINVAL; return -1; } if (nn_slow (!iov->iov_base && iov->iov_len)) { errno = EFAULT; return -1; } if (nn_slow (sz + iov->iov_len < sz)) { errno = EINVAL; return -1; } sz += iov->iov_len; } /* Create a message object from the supplied scatter array. */ nn_msg_init (&msg, sz); sz = 0; for (i = 0; i != msghdr->msg_iovlen; ++i) { iov = &msghdr->msg_iov [i]; memcpy (((uint8_t*) nn_chunkref_data (&msg.body)) + sz, iov->iov_base, iov->iov_len); sz += iov->iov_len; } nnmsg = 0; } /* Add ancillary data to the message. */ if (msghdr->msg_control) { /* Copy all headers. */ /* TODO: SP_HDR should not be copied here! */ if (msghdr->msg_controllen == NN_MSG) { chunk = *((void**) msghdr->msg_control); nn_chunkref_term (&msg.hdrs); nn_chunkref_init_chunk (&msg.hdrs, chunk); } else { nn_chunkref_term (&msg.hdrs); nn_chunkref_init (&msg.hdrs, msghdr->msg_controllen); memcpy (nn_chunkref_data (&msg.hdrs), msghdr->msg_control, msghdr->msg_controllen); } /* Search for SP_HDR property. */ cmsg = NN_CMSG_FIRSTHDR (msghdr); while (cmsg) { if (cmsg->cmsg_level == PROTO_SP && cmsg->cmsg_type == SP_HDR) { /* Copy body of SP_HDR property into 'sphdr'. */ nn_chunkref_term (&msg.sphdr); spsz = cmsg->cmsg_len - NN_CMSG_SPACE (0); nn_chunkref_init (&msg.sphdr, spsz); memcpy (nn_chunkref_data (&msg.sphdr), NN_CMSG_DATA (cmsg), spsz); break; } cmsg = NN_CMSG_NXTHDR (msghdr, cmsg); } } /* 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; } /* Adjust the statistics. */ nn_sock_stat_increment (self.socks [s], NN_STAT_MESSAGES_SENT, 1); nn_sock_stat_increment (self.socks [s], NN_STAT_BYTES_SENT, sz); return (int) sz; }