SilcNetListener
silc_net_tcp_create_listener2(const char *local_ip_addr, int *ports,
			      SilcUInt32 port_count,
			      SilcBool ignore_port_error,
			      SilcBool lookup, SilcBool require_fqdn,
			      SilcSchedule schedule,
			      SilcNetCallback callback, void *context)
{
  SilcNetListener listener = NULL;
  SilcSymbianTCPListener *l = NULL;
  TInetAddr server;
  TInt ret;
  int i;

  SILC_LOG_DEBUG(("Creating TCP listener"));

  if (!schedule) {
    schedule = silc_schedule_get_global();
    if (!schedule) {
      silc_set_errno(SILC_ERR_INVALID_ARGUMENT);
      goto err;
    }
  }

  if (!callback) {
    silc_set_errno(SILC_ERR_INVALID_ARGUMENT);
    goto err;
  }

  listener = (SilcNetListener)silc_calloc(1, sizeof(*listener));
  if (!listener) {
    callback(SILC_ERR_OUT_OF_MEMORY, NULL, context);
    return NULL;
  }
  listener->schedule = schedule;
  listener->callback = callback;
  listener->context = context;
  listener->require_fqdn = require_fqdn;
  listener->lookup = lookup;

  if (port_count > 0) {
    listener->socks = (SilcSocket *)silc_calloc(port_count,
					        sizeof(*listener->socks));
    if (!listener->socks) {
      callback(SILC_ERR_OUT_OF_MEMORY, NULL, context);
      return NULL;
    }
  } else {
    listener->socks = (SilcSocket *)silc_calloc(1, sizeof(*listener->socks));
    if (!listener->socks) {
      callback(SILC_ERR_OUT_OF_MEMORY, NULL, context);
      return NULL;
    }

    port_count = 1;
  }

  /* Bind to ports */
  for (i = 0; i < port_count; i++) {
    SILC_LOG_DEBUG(("Binding to local address %s:%d",
		    local_ip_addr ? local_ip_addr : "0.0.0.0",
		    ports ? ports[i] : 0));

    l = new SilcSymbianTCPListener;
    if (!l)
      goto err;

    /* Connect to socket server */
    ret = l->ss.Connect();
    if (ret != KErrNone)
      goto err;

#ifdef SILC_THREADS
    /* Make our socket shareable between threads */
    l->ss.ShareAuto();
#endif /* SILC_THREADS */

    /* Set listener address */
    if (!silc_net_set_sockaddr(&server, local_ip_addr, ports ? ports[i] : 0)) {
      if (ignore_port_error) {
	delete l;
	continue;
      }
      goto err;
    }

    /* Create the socket */
    ret = l->sock.Open(l->ss, KAfInet, KSockStream, KProtocolInetTcp);
    if (ret != KErrNone) {
      if (ignore_port_error) {
	delete l;
	continue;
      }
      SILC_LOG_ERROR(("Cannot create socket, error %d", ret));
      goto err;
    }

    /* Set the socket options */
    ret = l->sock.SetOpt(KSoReuseAddr, KSolInetIp, 1);
    if (ret != KErrNone) {
      if (ignore_port_error) {
	delete l;
	continue;
      }
      SILC_LOG_ERROR(("Cannot set socket options, error %d", ret));
      goto err;
    }

    /* Bind the listener socket */
    ret = l->sock.Bind(server);
    if (ret != KErrNone) {
      if (ignore_port_error) {
	delete l;
	continue;
      }
      SILC_LOG_DEBUG(("Cannot bind socket, error %d", ret));
      goto err;
    }

    /* Specify that we are listenning */
    ret = l->sock.Listen(5);
    if (ret != KErrNone) {
      if (ignore_port_error) {
	delete l;
	continue;
      }
      SILC_LOG_ERROR(("Cannot set socket listenning, error %d", ret));
      goto err;
    }
    l->Listen();

    l->listener = listener;
    listener->socks[i] = (SilcSocket)l;
    listener->socks_count++;
  }

  if (ignore_port_error && !listener->socks_count) {
    l = NULL;
    goto err;
  }

  SILC_LOG_DEBUG(("TCP listener created"));

  return listener;

 err:
  if (l)
    delete l;
  if (callback)
    callback(SILC_ERR, NULL, context);
  if (listener)
    silc_net_close_listener(listener);
  return NULL;
}
Exemple #2
0
SilcNetListener
silc_net_tcp_create_listener(const char **local_ip_addr,
			     SilcUInt32 local_ip_count, int port,
			     SilcBool lookup, SilcBool require_fqdn,
			     SilcSchedule schedule,
			     SilcNetCallback callback, void *context)
{
  SilcNetListener listener = NULL;
  SilcSockaddr server;
  int i, sock, rval;
  const char *ipany = "0.0.0.0";

  SILC_LOG_DEBUG(("Creating TCP listener"));

  if (port < 0 || !schedule || !callback)
    goto err;

  listener = silc_calloc(1, sizeof(*listener));
  if (!listener)
    return NULL;
  listener->schedule = schedule;
  listener->callback = callback;
  listener->context = context;
  listener->require_fqdn = require_fqdn;
  listener->lookup = lookup;

  if (local_ip_count > 0) {
    listener->socks = silc_calloc(local_ip_count, sizeof(*listener->socks));
    if (!listener->socks)
      return NULL;
  } else {
    listener->socks = silc_calloc(1, sizeof(*listener->socks));
    if (!listener->socks)
      return NULL;

    local_ip_count = 1;
  }

  /* Bind to local addresses */
  for (i = 0; i < local_ip_count; i++) {
    SILC_LOG_DEBUG(("Binding to local address %s:%d",
		    local_ip_addr ? local_ip_addr[i] : ipany, port));

    /* Set sockaddr for server */
    if (!silc_net_set_sockaddr(&server,
			       local_ip_addr ? local_ip_addr[i] : ipany,
			       port))
      goto err;

    /* Create the socket */
    sock = socket(server.sin.sin_family, SOCK_STREAM, 0);
    if (sock < 0) {
      SILC_LOG_ERROR(("Cannot create socket: %s", strerror(errno)));
      goto err;
    }

    /* Set the socket options */
    rval = silc_net_set_socket_opt(sock, SOL_SOCKET, SO_REUSEADDR, 1);
    if (rval < 0) {
      SILC_LOG_ERROR(("Cannot set socket options: %s", strerror(errno)));
      close(sock);
      goto err;
    }

    /* Bind the listener socket */
    rval = bind(sock, &server.sa, SIZEOF_SOCKADDR(server));
    if (rval < 0) {
      SILC_LOG_ERROR(("Cannot bind socket: %s", strerror(errno)));
      close(sock);
      goto err;
    }

    /* Specify that we are listenning */
    rval = listen(sock, 64);
    if (rval < 0) {
      SILC_LOG_ERROR(("Cannot set socket listenning: %s", strerror(errno)));
      close(sock);
      goto err;
    }

    /* Set the server socket to non-blocking mode */
    silc_net_set_socket_nonblock(sock);

    /* Schedule for incoming connections */
    silc_schedule_task_add_fd(schedule, sock, silc_net_accept, listener);

    SILC_LOG_DEBUG(("TCP listener created, fd=%d", sock));
    listener->socks[i] = sock;
    listener->socks_count++;
  }

  return listener;

 err:
  if (listener)
    silc_net_close_listener(listener);
  return NULL;
}