static void nn_btcp_start_listening (struct nn_btcp *self) { int rc; struct sockaddr_storage ss; size_t sslen; int ipv4only; size_t ipv4onlylen; const char *addr; const char *end; const char *pos; uint16_t port; /* First, resolve the IP address. */ addr = nn_epbase_getaddr (&self->epbase); memset (&ss, 0, sizeof (ss)); /* Parse the port. */ end = addr + strlen (addr); pos = strrchr (addr, ':'); nn_assert (pos); ++pos; rc = nn_port_resolve (pos, end - pos); nn_assert (rc >= 0); port = rc; /* Parse the address. */ ipv4onlylen = sizeof (ipv4only); nn_epbase_getopt (&self->epbase, NN_SOL_SOCKET, NN_IPV4ONLY, &ipv4only, &ipv4onlylen); nn_assert (ipv4onlylen == sizeof (ipv4only)); rc = nn_iface_resolve (addr, pos - addr - 1, ipv4only, &ss, &sslen); errnum_assert (rc == 0, -rc); /* Combine the port and the address. */ if (ss.ss_family == AF_INET) { ((struct sockaddr_in*) &ss)->sin_port = htons (port); sslen = sizeof (struct sockaddr_in); } else if (ss.ss_family == AF_INET6) { ((struct sockaddr_in6*) &ss)->sin6_port = htons (port); sslen = sizeof (struct sockaddr_in6); } else nn_assert (0); /* Start listening for incoming connections. */ rc = nn_usock_start (&self->usock, ss.ss_family, SOCK_STREAM, 0); /* TODO: EMFILE error can happen here. We can wait a bit and re-try. */ errnum_assert (rc == 0, -rc); rc = nn_usock_bind (&self->usock, (struct sockaddr*) &ss, (size_t) sslen); errnum_assert (rc == 0, -rc); rc = nn_usock_listen (&self->usock, NN_BTCP_BACKLOG); errnum_assert (rc == 0, -rc); }
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; }
static void nn_ctcp_start_connecting (struct nn_ctcp *self, struct sockaddr_storage *ss, size_t sslen) { int rc; struct sockaddr_storage remote; size_t remotelen; struct sockaddr_storage local; size_t locallen; const char *addr; const char *end; const char *colon; const char *semicolon; uint16_t port; int ipv4only; size_t ipv4onlylen; int val; size_t sz; /* Create IP address from the address string. */ addr = nn_epbase_getaddr (&self->epbase); memset (&remote, 0, sizeof (remote)); /* Parse the port. */ end = addr + strlen (addr); colon = strrchr (addr, ':'); rc = nn_port_resolve (colon + 1, end - colon - 1); errnum_assert (rc > 0, -rc); port = rc; /* 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 local address, if any. */ semicolon = strchr (addr, ';'); memset (&local, 0, sizeof (local)); if (semicolon) rc = nn_iface_resolve (addr, semicolon - addr, ipv4only, &local, &locallen); else rc = nn_iface_resolve ("*", 1, ipv4only, &local, &locallen); if (nn_slow (rc < 0)) { nn_backoff_start (&self->retry); self->state = NN_CTCP_STATE_WAITING; return; } /* Combine the remote address and the port. */ remote = *ss; remotelen = sslen; if (remote.ss_family == AF_INET) ((struct sockaddr_in*) &remote)->sin_port = htons (port); else if (remote.ss_family == AF_INET6) ((struct sockaddr_in6*) &remote)->sin6_port = htons (port); else nn_assert (0); /* Try to start the underlying socket. */ rc = nn_usock_start (&self->usock, remote.ss_family, SOCK_STREAM, 0); if (nn_slow (rc < 0)) { nn_backoff_start (&self->retry); self->state = NN_CTCP_STATE_WAITING; return; } /* Set the relevant socket options. */ sz = sizeof (val); nn_epbase_getopt (&self->epbase, NN_SOL_SOCKET, NN_SNDBUF, &val, &sz); nn_assert (sz == sizeof (val)); nn_usock_setsockopt (&self->usock, SOL_SOCKET, SO_SNDBUF, &val, sizeof (val)); sz = sizeof (val); nn_epbase_getopt (&self->epbase, NN_SOL_SOCKET, NN_RCVBUF, &val, &sz); nn_assert (sz == sizeof (val)); nn_usock_setsockopt (&self->usock, SOL_SOCKET, SO_RCVBUF, &val, sizeof (val)); /* Bind the socket to the local network interface. */ rc = nn_usock_bind (&self->usock, (struct sockaddr*) &local, locallen); if (nn_slow (rc != 0)) { nn_backoff_start (&self->retry); self->state = NN_CTCP_STATE_WAITING; return; } /* Start connecting. */ nn_usock_connect (&self->usock, (struct sockaddr*) &remote, remotelen); self->state = NN_CTCP_STATE_CONNECTING; nn_epbase_stat_increment (&self->epbase, NN_STAT_INPROGRESS_CONNECTIONS, 1); }
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; }
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; }
static int nn_bws_listen (struct nn_bws *self) { int rc; struct sockaddr_storage ss; size_t sslen; int ipv4only; size_t ipv4onlylen; const char *addr; const char *end; const char *pos; uint16_t port; /* First, resolve the IP address. */ addr = nn_epbase_getaddr (&self->epbase); memset (&ss, 0, sizeof (ss)); /* Parse the port. */ end = addr + strlen (addr); pos = strrchr (addr, ':'); nn_assert (pos); ++pos; rc = nn_port_resolve (pos, end - pos); if (rc < 0) { return rc; } port = (uint16_t) rc; /* Parse the address. */ ipv4onlylen = sizeof (ipv4only); nn_epbase_getopt (&self->epbase, NN_SOL_SOCKET, NN_IPV4ONLY, &ipv4only, &ipv4onlylen); nn_assert (ipv4onlylen == sizeof (ipv4only)); rc = nn_iface_resolve (addr, pos - addr - 1, ipv4only, &ss, &sslen); if (rc < 0) { return rc; } /* Combine the port and the address. */ if (ss.ss_family == AF_INET) { ((struct sockaddr_in*) &ss)->sin_port = htons (port); sslen = sizeof (struct sockaddr_in); } else if (ss.ss_family == AF_INET6) { ((struct sockaddr_in6*) &ss)->sin6_port = htons (port); sslen = sizeof (struct sockaddr_in6); } else nn_assert (0); /* Start listening for incoming connections. */ rc = nn_usock_start (&self->usock, ss.ss_family, SOCK_STREAM, 0); if (rc < 0) { return rc; } rc = nn_usock_bind (&self->usock, (struct sockaddr*) &ss, (size_t) sslen); if (rc < 0) { nn_usock_stop (&self->usock); return rc; } rc = nn_usock_listen (&self->usock, NN_BWS_BACKLOG); if (rc < 0) { nn_usock_stop (&self->usock); return rc; } nn_bws_start_accepting(self); return 0; }