Esempio n. 1
0
static const char *test_parse_address(void) {
  static const char *valid[] = {
    "1", "1.2.3.4:1", "tcp://123", "udp://0.0.0.0:99", "ssl://17",
    "ssl://900:a.pem:b.pem", "ssl://1.2.3.4:9000:aa.pem",
#if defined(NS_ENABLE_IPV6)
    "udp://[::1]:123", "[3ffe:2a00:100:7031::1]:900",
#endif
    NULL
  };
  static const int protos[] = {SOCK_STREAM, SOCK_STREAM, SOCK_STREAM,
    SOCK_DGRAM, SOCK_STREAM, SOCK_STREAM, SOCK_STREAM, SOCK_DGRAM, SOCK_STREAM};
  static const int use_ssls[] = {0, 0, 0, 0, 1, 1, 1, 0, 0};
  static const char *invalid[] = {
    "99999", "1k", "1.2.3", "1.2.3.4:", "1.2.3.4:2p", "blah://12", NULL
  };
  union socket_address sa;
  char cert[100], ca[100];
  int i, proto, use_ssl;

  for (i = 0; valid[i] != NULL; i++) {
    ASSERT(ns_parse_address(valid[i], &sa, &proto, &use_ssl, cert, ca) != 0);
    ASSERT(proto == protos[i]);
    ASSERT(use_ssl == use_ssls[i]);
  }

  for (i = 0; invalid[i] != NULL; i++) {
    ASSERT(ns_parse_address(invalid[i], &sa, &proto, &use_ssl, cert, ca) == 0);
  }
  ASSERT(ns_parse_address("0", &sa, &proto, &use_ssl, cert, ca) != 0);

  return NULL;
}
Esempio n. 2
0
struct ns_connection *ns_bind_opt(struct ns_mgr *srv, const char *str,
                              ns_event_handler_t callback,
                              struct ns_bind_opts opts) {
  union socket_address sa;
  struct ns_connection *nc = NULL;
  int proto;
  sock_t sock;
  struct ns_add_sock_opts add_sock_opts;

  NS_COPY_COMMON_CONNECTION_OPTIONS(&add_sock_opts, &opts);

  if (ns_parse_address(str, &sa, &proto) == 0) {
    errno = 0;
    ns_set_error_string(opts.error_string, "cannot parse address");
  } else if ((sock = ns_open_listening_socket(&sa, proto)) == INVALID_SOCKET) {
    DBG(("Failed to open listener: %d", errno));
    ns_set_error_string(opts.error_string, "failed to open listener");
  } else if ((nc = ns_add_sock_opt(srv, sock, callback, add_sock_opts)) == NULL) {
    /* opts.error_string set by ns_add_sock_opt */
    DBG(("Failed to ns_add_sock"));
    closesocket(sock);
  } else {
    nc->sa = sa;
    nc->flags |= NSF_LISTENING;
    nc->handler = callback;

    if (proto == SOCK_DGRAM) {
      nc->flags |= NSF_UDP;
    }

    DBG(("%p sock %d/%d", nc, sock, proto));
  }

  return nc;
}
Esempio n. 3
0
struct ns_connection *ns_connect_opt(struct ns_mgr *mgr, const char *address,
                                     ns_event_handler_t callback,
                                     struct ns_connect_opts opts) {
  struct ns_connection *nc = NULL;
  int proto, rc;
  struct ns_add_sock_opts add_sock_opts;
  char host[NS_MAX_HOST_LEN];

  NS_COPY_COMMON_CONNECTION_OPTIONS(&add_sock_opts, &opts);

  if ((nc = ns_create_connection(mgr, callback, add_sock_opts)) == NULL) {
    return NULL;
  } else if ((rc = ns_parse_address(address, &nc->sa, &proto, host,
                                    sizeof(host))) < 0) {
    /* Address is malformed */
    NS_SET_PTRPTR(opts.error_string, "cannot parse address");
    ns_destroy_conn(nc);
    return NULL;
  }
  nc->flags |= opts.flags & _NS_ALLOWED_CONNECT_FLAGS_MASK;
  nc->flags |= (proto == SOCK_DGRAM) ? NSF_UDP : 0;
  nc->user_data = opts.user_data;

  if (rc == 0) {
#ifndef NS_DISABLE_RESOLVER
    /*
     * DNS resolution is required for host.
     * ns_parse_address() fills port in nc->sa, which we pass to resolve_cb()
     */
    if (ns_resolve_async(nc->mgr, host, NS_DNS_A_RECORD, resolve_cb, nc) != 0) {
      NS_SET_PTRPTR(opts.error_string, "cannot schedule DNS lookup");
      ns_destroy_conn(nc);
      return NULL;
    }

    return nc;
#else
    NS_SET_PTRPTR(opts.error_string, "Resolver is disabled");
    ns_destroy_conn(nc);
    return NULL;
#endif
  } else {
    /* Address is parsed and resolved to IP. proceed with connect() */
    return ns_finish_connect(nc, proto, &nc->sa, add_sock_opts);
  }
}
Esempio n. 4
0
/*
 * Connect to a remote host.
 *
 * If successful, `NS_CONNECT` event will be delivered
 * to the new connection. `addr` format is the same as for the `ns_bind()` call,
 * just an IP address becomes mandatory: `[PROTO://]HOST:PORT`.
 *
 * `PROTO` could be `tcp://` or `udp://`. If `HOST` is not an IP
 * address, Fossa will resolve it - beware that standard blocking resolver
 * will be used. It is a good practice to pre-resolve hosts beforehands and
 * use only IP addresses to avoid blockin an IO thread.
 *
 * See the `ns_connect_opts` structure for a description of the optional
 * parameters.
 *
 * Returns a new outbound connection, or `NULL` on error.
*/
struct ns_connection *ns_connect_opt(struct ns_mgr *mgr, const char *address,
                                     ns_event_handler_t callback,
                                     struct ns_connect_opts opts) {
  sock_t sock = INVALID_SOCKET;
  struct ns_connection *nc = NULL;
  union socket_address sa;
  int rc, proto;
  struct ns_add_sock_opts add_sock_opts;

  if (ns_parse_address(address, &sa, &proto) == 0) {
    errno = 0;
    ns_set_error_string(opts.error_string, "cannot parse address");
    return NULL;
  }
  if ((sock = socket(AF_INET, proto, 0)) == INVALID_SOCKET) {
    ns_set_error_string(opts.error_string, "cannot create socket");
    return NULL;
  }

  ns_set_non_blocking_mode(sock);
  rc = (proto == SOCK_DGRAM) ? 0 : connect(sock, &sa.sa, sizeof(sa.sin));

  NS_COPY_COMMON_CONNECTION_OPTIONS(&add_sock_opts, &opts);

  if (rc != 0 && ns_is_error(rc)) {
    ns_set_error_string(opts.error_string, "cannot connect to socket");
    closesocket(sock);
    return NULL;
  } else if ((nc = ns_add_sock_opt(mgr, sock, callback, add_sock_opts)) == NULL) {
    /* opts.error_string set by ns_add_sock_opt */
    closesocket(sock);
    return NULL;
  }

  nc->sa = sa;   /* Important, cause UDP conns will use sendto() */
  nc->flags |= (proto == SOCK_DGRAM) ? NSF_UDP : NSF_CONNECTING;

  return nc;
}