int nn_binproc_create (void *hint, struct nn_epbase **epbase) { int rc; struct nn_binproc *self; self = nn_alloc (sizeof (struct nn_binproc), "binproc"); alloc_assert (self); nn_ins_item_init (&self->item, &nn_binproc_vfptr, hint); nn_fsm_init_root (&self->fsm, nn_binproc_handler, nn_binproc_shutdown, nn_epbase_getctx (&self->item.epbase)); self->state = NN_BINPROC_STATE_IDLE; nn_list_init (&self->sinprocs); /* Start the state machine. */ nn_fsm_start (&self->fsm); /* Register the inproc endpoint into a global repository. */ rc = nn_ins_bind (&self->item, nn_binproc_connect); if (nn_slow (rc < 0)) { nn_list_term (&self->sinprocs); /* TODO: Now, this is ugly! We are getting the state machine into the idle state manually. How should it be done correctly? */ self->fsm.state = 1; nn_fsm_term (&self->fsm); nn_ins_item_term (&self->item); nn_free (self); return rc; } *epbase = &self->item.epbase; return 0; }
struct nn_binproc *nn_binproc_create (void *hint) { struct nn_binproc *self; size_t sz; self = nn_alloc (sizeof (struct nn_binproc), "binproc"); alloc_assert (self); nn_epbase_init (&self->epbase, &nn_binproc_vfptr, hint); nn_fsm_init_root (&self->fsm, nn_binproc_handler, nn_epbase_getctx (&self->epbase)); self->state = NN_BINPROC_STATE_IDLE; nn_list_init (&self->sinprocs); nn_list_item_init (&self->item); sz = sizeof (self->protocol); nn_epbase_getopt (&self->epbase, NN_SOL_SOCKET, NN_PROTOCOL, &self->protocol, &sz); nn_assert (sz == sizeof (self->protocol)); self->connects = 0; /* Start the state machine. */ nn_fsm_start (&self->fsm); return self; }
int nn_bipc_create (void *hint, struct nn_epbase **epbase) { struct nn_bipc *self; /* Allocate the new endpoint object. */ self = nn_alloc (sizeof (struct nn_bipc), "bipc"); alloc_assert (self); /* Initialise the structure. */ nn_epbase_init (&self->epbase, &nn_bipc_epbase_vfptr, hint); nn_fsm_init_root (&self->fsm, nn_bipc_handler, nn_epbase_getctx (&self->epbase)); self->state = NN_BIPC_STATE_IDLE; nn_usock_init (&self->usock, NN_BIPC_SRC_USOCK, &self->fsm); self->aipc = NULL; nn_list_init (&self->aipcs); /* Start the state machine. */ nn_fsm_start (&self->fsm); /* Return the base class as an out parameter. */ *epbase = &self->epbase; return 0; }
int nn_cinproc_create (struct nn_ep *ep) { struct nn_cinproc *self; self = nn_alloc (sizeof (struct nn_cinproc), "cinproc"); alloc_assert (self); nn_ep_tran_setup (ep, &nn_cinproc_ops, self); nn_ins_item_init (&self->item, ep); nn_fsm_init_root (&self->fsm, nn_cinproc_handler, nn_cinproc_shutdown, nn_ep_getctx (ep)); self->state = NN_CINPROC_STATE_IDLE; nn_list_init (&self->sinprocs); nn_ep_stat_increment (ep, NN_STAT_INPROGRESS_CONNECTIONS, 1); /* Start the state machine. */ nn_fsm_start (&self->fsm); /* Register the inproc endpoint into a global repository. */ nn_ins_connect (&self->item, nn_cinproc_connect); return 0; }
void nn_req_init (struct nn_req *self, const struct nn_sockbase_vfptr *vfptr, void *hint) { nn_req_handle hndl; nn_xreq_init (&self->xreq, vfptr, hint); nn_fsm_init_root (&self->fsm, nn_req_handler, nn_req_shutdown, nn_sockbase_getctx (&self->xreq.sockbase)); self->state = NN_REQ_STATE_IDLE; /* Start assigning request IDs beginning with a random number. This way there should be no key clashes even if the executable is re-started. */ nn_random_generate (&self->lastid, sizeof (self->lastid)); self->task.sent_to = NULL; nn_msg_init (&self->task.request, 0); nn_msg_init (&self->task.reply, 0); nn_timer_init (&self->task.timer, NN_REQ_SRC_RESEND_TIMER, &self->fsm); self->resend_ivl = NN_REQ_DEFAULT_RESEND_IVL; /* For now, handle is empty. */ memset (&hndl, 0, sizeof (hndl)); nn_task_init (&self->task, self->lastid, hndl); /* Start the state machine. */ nn_fsm_start (&self->fsm); }
static void nn_surveyor_init (struct nn_surveyor *self, const struct nn_sockbase_vfptr *vfptr, void *hint) { nn_xsurveyor_init (&self->xsurveyor, vfptr, hint); nn_fsm_init_root (&self->fsm, nn_surveyor_handler, nn_sockbase_getctx (&self->xsurveyor.sockbase)); self->state = NN_SURVEYOR_STATE_IDLE; /* Start assigning survey IDs beginning with a random number. This way there should be no key clashes even if the executable is re-started. */ nn_random_generate (&self->surveyid, sizeof (self->surveyid)); nn_timer_init (&self->timer, NN_SURVEYOR_SRC_DEADLINE_TIMER, &self->fsm); nn_msg_init (&self->tosend, 0); self->deadline = NN_SURVEYOR_DEFAULT_DEADLINE; /* Start the state machine. */ nn_fsm_start (&self->fsm); }
int nn_bipc_create (void *hint, struct nn_epbase **epbase) { struct nn_bipc *self; int reconnect_ivl; int reconnect_ivl_max; size_t sz; /* Allocate the new endpoint object. */ self = nn_alloc (sizeof (struct nn_bipc), "bipc"); alloc_assert (self); /* Initialise the structure. */ nn_epbase_init (&self->epbase, &nn_bipc_epbase_vfptr, hint); nn_fsm_init_root (&self->fsm, nn_bipc_handler, nn_bipc_shutdown, nn_epbase_getctx (&self->epbase)); self->state = NN_BIPC_STATE_IDLE; 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_BIPC_SRC_RECONNECT_TIMER, reconnect_ivl, reconnect_ivl_max, &self->fsm); nn_usock_init (&self->usock, NN_BIPC_SRC_USOCK, &self->fsm); self->aipc = NULL; nn_list_init (&self->aipcs); /* Start the state machine. */ nn_fsm_start (&self->fsm); /* Return the base class as an out parameter. */ *epbase = &self->epbase; return 0; }
int nn_cinproc_create (void *hint, struct nn_epbase **epbase) { struct nn_cinproc *self; self = nn_alloc (sizeof (struct nn_cinproc), "cinproc"); alloc_assert (self); nn_ins_item_init (&self->item, &nn_cinproc_vfptr, hint); nn_fsm_init_root (&self->fsm, nn_cinproc_handler, nn_cinproc_shutdown, nn_epbase_getctx (&self->item.epbase)); self->state = NN_CINPROC_STATE_IDLE; nn_sinproc_init (&self->sinproc, NN_CINPROC_SRC_SINPROC, &self->item.epbase, &self->fsm); /* Start the state machine. */ nn_fsm_start (&self->fsm); /* Register the inproc endpoint into a global repository. */ nn_ins_connect (&self->item, nn_cinproc_connect); *epbase = &self->item.epbase; return 0; }
int nn_cipc_create (struct nn_ep *ep) { struct nn_cipc *self; int reconnect_ivl; int reconnect_ivl_max; size_t sz; /* Allocate the new endpoint object. */ self = nn_alloc (sizeof (struct nn_cipc), "cipc"); alloc_assert (self); /* Initialise the structure. */ self->ep = ep; nn_ep_tran_setup (ep, &nn_cipc_ep_ops, self); nn_fsm_init_root (&self->fsm, nn_cipc_handler, nn_cipc_shutdown, nn_ep_getctx (ep)); self->state = NN_CIPC_STATE_IDLE; nn_usock_init (&self->usock, NN_CIPC_SRC_USOCK, &self->fsm); sz = sizeof (reconnect_ivl); nn_ep_getopt (ep, NN_SOL_SOCKET, NN_RECONNECT_IVL, &reconnect_ivl, &sz); nn_assert (sz == sizeof (reconnect_ivl)); sz = sizeof (reconnect_ivl_max); nn_ep_getopt (ep, 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_CIPC_SRC_RECONNECT_TIMER, reconnect_ivl, reconnect_ivl_max, &self->fsm); nn_sipc_init (&self->sipc, NN_CIPC_SRC_SIPC, ep, &self->fsm); /* Start the state machine. */ nn_fsm_start (&self->fsm); return 0; }
int nn_btcp_create (void *hint, struct nn_epbase **epbase) { int rc; struct nn_btcp *self; const char *addr; const char *end; const char *pos; struct sockaddr_storage ss; size_t sslen; int ipv4only; size_t ipv4onlylen; /* Allocate the new endpoint object. */ self = nn_alloc (sizeof (struct nn_btcp), "btcp"); alloc_assert (self); /* Initalise the epbase. */ nn_epbase_init (&self->epbase, &nn_btcp_epbase_vfptr, hint); addr = nn_epbase_getaddr (&self->epbase); /* Parse the port. */ end = addr + strlen (addr); pos = strrchr (addr, ':'); if (nn_slow (!pos)) { nn_epbase_term (&self->epbase); return -EINVAL; } ++pos; rc = nn_port_resolve (pos, end - pos); if (nn_slow (rc < 0)) { nn_epbase_term (&self->epbase); return -EINVAL; } /* 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)); /* Parse the address. */ rc = nn_iface_resolve (addr, pos - addr - 1, ipv4only, &ss, &sslen); if (nn_slow (rc < 0)) { nn_epbase_term (&self->epbase); return -ENODEV; } /* Initialise the structure. */ nn_fsm_init_root (&self->fsm, nn_btcp_handler, nn_btcp_shutdown, nn_epbase_getctx (&self->epbase)); self->state = NN_BTCP_STATE_IDLE; nn_usock_init (&self->usock, NN_BTCP_SRC_USOCK, &self->fsm); self->atcp = NULL; nn_list_init (&self->atcps); /* Start the state machine. */ nn_fsm_start (&self->fsm); /* Return the base class as an out parameter. */ *epbase = &self->epbase; return 0; }
/* Initialize a socket. A hold is placed on the initialized socket for the caller as well. */ int nn_sock_init (struct nn_sock *self, struct nn_socktype *socktype, int fd) { int rc; int i; /* Make sure that at least one message direction is supported. */ nn_assert (!(socktype->flags & NN_SOCKTYPE_FLAG_NOSEND) || !(socktype->flags & NN_SOCKTYPE_FLAG_NORECV)); /* Create the AIO context for the SP socket. */ nn_ctx_init (&self->ctx, nn_global_getpool (), nn_sock_onleave); /* Initialise the state machine. */ nn_fsm_init_root (&self->fsm, nn_sock_handler, nn_sock_shutdown, &self->ctx); self->state = NN_SOCK_STATE_INIT; /* Open the NN_SNDFD and NN_RCVFD efds. Do so, only if the socket type supports send/recv, as appropriate. */ if (socktype->flags & NN_SOCKTYPE_FLAG_NOSEND) memset (&self->sndfd, 0xcd, sizeof (self->sndfd)); else { rc = nn_efd_init (&self->sndfd); if (nn_slow (rc < 0)) return rc; } if (socktype->flags & NN_SOCKTYPE_FLAG_NORECV) memset (&self->rcvfd, 0xcd, sizeof (self->rcvfd)); else { rc = nn_efd_init (&self->rcvfd); if (nn_slow (rc < 0)) { if (!(socktype->flags & NN_SOCKTYPE_FLAG_NOSEND)) nn_efd_term (&self->sndfd); return rc; } } nn_sem_init (&self->termsem); nn_sem_init (&self->relesem); if (nn_slow (rc < 0)) { if (!(socktype->flags & NN_SOCKTYPE_FLAG_NORECV)) nn_efd_term (&self->rcvfd); if (!(socktype->flags & NN_SOCKTYPE_FLAG_NOSEND)) nn_efd_term (&self->sndfd); return rc; } self->holds = 1; /* Callers hold. */ self->flags = 0; nn_clock_init (&self->clock); nn_list_init (&self->eps); nn_list_init (&self->sdeps); self->eid = 1; /* Default values for NN_SOL_SOCKET options. */ self->linger = 1000; self->sndbuf = 128 * 1024; self->rcvbuf = 128 * 1024; self->rcvmaxsize = 1024 * 1024; self->sndtimeo = -1; self->rcvtimeo = -1; self->reconnect_ivl = 100; self->reconnect_ivl_max = 0; self->ep_template.sndprio = 8; self->ep_template.rcvprio = 8; self->ep_template.ipv4only = 1; /* Initialize statistic entries */ self->statistics.established_connections = 0; self->statistics.accepted_connections = 0; self->statistics.dropped_connections = 0; self->statistics.broken_connections = 0; self->statistics.connect_errors = 0; self->statistics.bind_errors = 0; self->statistics.accept_errors = 0; self->statistics.messages_sent = 0; self->statistics.messages_received = 0; self->statistics.bytes_sent = 0; self->statistics.bytes_received = 0; self->statistics.current_connections = 0; self->statistics.inprogress_connections = 0; self->statistics.current_snd_priority = 0; self->statistics.current_ep_errors = 0; /* Should be pretty much enough space for just the number */ sprintf(self->socket_name, "%d", fd); /* The transport-specific options are not initialised immediately, rather, they are allocated later on when needed. */ for (i = 0; i != NN_MAX_TRANSPORT; ++i) self->optsets [i] = NULL; /* Create the specific socket type itself. */ rc = socktype->create ((void*) self, &self->sockbase); errnum_assert (rc == 0, -rc); self->socktype = socktype; /* Launch the state machine. */ nn_ctx_enter (&self->ctx); nn_fsm_start (&self->fsm); nn_ctx_leave (&self->ctx); return 0; }
int nn_ctcp_create (void *hint, struct nn_epbase **epbase) { int rc; const char *addr; size_t addrlen; const char *semicolon; const char *hostname; const char *colon; const char *end; struct sockaddr_storage ss; size_t sslen; int ipv4only; size_t ipv4onlylen; struct nn_ctcp *self; int reconnect_ivl; int reconnect_ivl_max; size_t sz; /* Allocate the new endpoint object. */ self = nn_alloc (sizeof (struct nn_ctcp), "ctcp"); alloc_assert (self); /* Initalise the endpoint. */ nn_epbase_init (&self->epbase, &nn_ctcp_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, ':'); end = addr + addrlen; /* Parse the port. */ if (nn_slow (!colon)) { nn_epbase_term (&self->epbase); return -EINVAL; } rc = nn_port_resolve (colon + 1, end - colon - 1); if (nn_slow (rc < 0)) { nn_epbase_term (&self->epbase); return -EINVAL; } /* Check whether the host portion of the address is either a literal or a valid hostname. */ if (nn_dns_check_hostname (hostname, colon - hostname) < 0 && nn_literal_resolve (hostname, colon - hostname, 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; } } /* Initialise the structure. */ nn_fsm_init_root (&self->fsm, nn_ctcp_handler, nn_ctcp_shutdown, nn_epbase_getctx (&self->epbase)); self->state = NN_CTCP_STATE_IDLE; nn_usock_init (&self->usock, NN_CTCP_SRC_USOCK, &self->fsm); 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_CTCP_SRC_RECONNECT_TIMER, reconnect_ivl, reconnect_ivl_max, &self->fsm); nn_stcp_init (&self->stcp, NN_CTCP_SRC_STCP, &self->epbase, &self->fsm); nn_dns_init (&self->dns, NN_CTCP_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; }
static void nn_global_init (void) { int i; char *envvar; int rc; char *addr; #if defined NN_HAVE_WINDOWS WSADATA data; #endif /* Check whether the library was already initialised. If so, do nothing. */ if (self.socks) return; /* On Windows, initialise the socket library. */ #if defined NN_HAVE_WINDOWS rc = WSAStartup (MAKEWORD (2, 2), &data); nn_assert (rc == 0); nn_assert (LOBYTE (data.wVersion) == 2 && HIBYTE (data.wVersion) == 2); #endif /* Initialise the memory allocation subsystem. */ nn_alloc_init (); /* Seed the pseudo-random number generator. */ nn_random_seed (); /* Allocate the global table of SP sockets. */ self.socks = nn_alloc ((sizeof (struct nn_sock*) * NN_MAX_SOCKETS) + (sizeof (uint16_t) * NN_MAX_SOCKETS), "socket table"); alloc_assert (self.socks); for (i = 0; i != NN_MAX_SOCKETS; ++i) self.socks [i] = NULL; self.nsocks = 0; self.flags = 0; /* Print connection and accepting errors to the stderr */ envvar = getenv("NN_PRINT_ERRORS"); /* any non-empty string is true */ self.print_errors = envvar && *envvar; /* Print socket statistics to stderr */ envvar = getenv("NN_PRINT_STATISTICS"); self.print_statistics = envvar && *envvar; /* Allocate the stack of unused file descriptors. */ self.unused = (uint16_t*) (self.socks + NN_MAX_SOCKETS); alloc_assert (self.unused); for (i = 0; i != NN_MAX_SOCKETS; ++i) self.unused [i] = NN_MAX_SOCKETS - i - 1; /* Initialise other parts of the global state. */ nn_list_init (&self.transports); nn_list_init (&self.socktypes); /* Plug in individual transports. */ nn_global_add_transport (nn_inproc); nn_global_add_transport (nn_ipc); nn_global_add_transport (nn_tcp); nn_global_add_transport (nn_ws); nn_global_add_transport (nn_tcpmux); /* Plug in individual socktypes. */ nn_global_add_socktype (nn_pair_socktype); nn_global_add_socktype (nn_xpair_socktype); nn_global_add_socktype (nn_pub_socktype); nn_global_add_socktype (nn_sub_socktype); nn_global_add_socktype (nn_xpub_socktype); nn_global_add_socktype (nn_xsub_socktype); nn_global_add_socktype (nn_rep_socktype); nn_global_add_socktype (nn_req_socktype); nn_global_add_socktype (nn_xrep_socktype); nn_global_add_socktype (nn_xreq_socktype); nn_global_add_socktype (nn_push_socktype); nn_global_add_socktype (nn_xpush_socktype); nn_global_add_socktype (nn_pull_socktype); nn_global_add_socktype (nn_xpull_socktype); nn_global_add_socktype (nn_respondent_socktype); nn_global_add_socktype (nn_surveyor_socktype); nn_global_add_socktype (nn_xrespondent_socktype); nn_global_add_socktype (nn_xsurveyor_socktype); nn_global_add_socktype (nn_bus_socktype); nn_global_add_socktype (nn_xbus_socktype); /* Start the worker threads. */ nn_pool_init (&self.pool); /* Start FSM */ nn_fsm_init_root (&self.fsm, nn_global_handler, nn_global_shutdown, &self.ctx); self.state = NN_GLOBAL_STATE_IDLE; nn_ctx_init (&self.ctx, nn_global_getpool (), NULL); nn_timer_init (&self.stat_timer, NN_GLOBAL_SRC_STAT_TIMER, &self.fsm); nn_fsm_start (&self.fsm); /* Initializing special sockets. */ addr = getenv ("NN_STATISTICS_SOCKET"); if (addr) { self.statistics_socket = nn_global_create_socket (AF_SP, NN_PUB); errno_assert (self.statistics_socket >= 0); rc = nn_global_create_ep (self.statistics_socket, addr, 0); errno_assert (rc >= 0); } else { self.statistics_socket = -1; } addr = getenv ("NN_APPLICATION_NAME"); if (addr) { strncpy (self.appname, addr, 63); self.appname[63] = '\0'; } else { /* No cross-platform way to find out application binary. Also, MSVC suggests using _getpid() instead of getpid(), however, it's not clear whether the former is supported by older versions of Windows/MSVC. */ #if defined _MSC_VER #pragma warning (push) #pragma warning (disable:4996) #endif sprintf (self.appname, "nanomsg.%d", getpid()); #if defined _MSC_VER #pragma warning (pop) #endif } addr = getenv ("NN_HOSTNAME"); if (addr) { strncpy (self.hostname, addr, 63); self.hostname[63] = '\0'; } else { rc = gethostname (self.hostname, 63); errno_assert (rc == 0); self.hostname[63] = '\0'; } }
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; }