Exemple #1
0
void connect_function(GtkWidget *widget,gpointer data)
{
    if(!connect_bool && connection_status() == 0) {
        if (connect_to_client() == 0) {
            gtk_button_set_label(GTK_BUTTON(widget), "Connect");
            gtk_label_set_text(GTK_LABEL(helpLabel), "client offline");
            g_timeout_add_seconds(4, reset_help_label, (gpointer) helpLabel);
            return;
        } else {
            sendMessage("100:start");
            gtk_button_set_label(GTK_BUTTON(widget), "Disconnect");
            connect_bool = 1;
        }
    } else {
        connect_bool = 0;
        sendMessage("100:stop");
        gtk_button_set_label(GTK_BUTTON(buttonDevice1), "Device1");
        gtk_button_set_label(GTK_BUTTON(buttonDevice2), "Device2");
        gtk_button_set_label(GTK_BUTTON(buttonDevice3), "Device3");
        gtk_button_set_label(GTK_BUTTON(buttonDevice4), "Device4");
        stop_audio_from_mic();
        disconnect();
        gtk_button_set_label(GTK_BUTTON(widget), "Connect");
    }
}
Exemple #2
0
gboolean stop_device(GtkWidget *widget,gpointer data)
{
    if (connection_status()==0) {
        return FALSE;
    }
    char* label_string = gtk_button_get_label(widget);

    if (!strcmp(label_string,"Device1-On") && device1_on){
        device1_on = 0;
        sendMessage("1:stop");
        g_print ("turning off device1\n");
        gtk_button_set_label(GTK_BUTTON(widget), "Device1");
    } else if (!strcmp(label_string,"Device2-On") && device2_on){
        device2_on = 0;
        sendMessage("2:stop");
        g_print ("turning off device2\n");
        gtk_button_set_label(GTK_BUTTON(widget), "Device2");
    } else if (!strcmp(label_string,"Device3-On") && device3_on) {
        device3_on = 0;
        sendMessage("3:stop");
        g_print ("turning off device3\n");
        gtk_button_set_label(GTK_BUTTON(widget), "Device3");
    } else if (!strcmp(label_string,"Device4-On")  && device4_on) {
        device4_on = 0;
        sendMessage("4:stop");
        g_print ("turning off device4\n");
        gtk_button_set_label(GTK_BUTTON(widget), "Device4");
    }
    return FALSE;
}
Exemple #3
0
gboolean check_network_connectivity(gpointer connectButton){
    if (connection_status()){
        gtk_button_set_label(GTK_BUTTON(connectButton), "Disconnect");
    } else {
        gtk_button_set_label(GTK_BUTTON(connectButton), "Connect");
    }
    return TRUE;
}
Exemple #4
0
void play_function(GtkWidget *widget,gpointer data)
{
    if (connection_status() == 0){
        gtk_label_set_text(GTK_LABEL(helpLabel), "please connect");
        g_timeout_add_seconds (4, reset_help_label, (gpointer) helpLabel);
    } else {
        play_audio_from_mic();
    }
}
Exemple #5
0
void sig_child_handler() {
  int wstat;
  int i;

  while ((i =wait_nohang(&wstat)) > 0) {
    if (phccmax) ipsvd_phcc_rem(i);
    if (cnum) cnum--;
    if (verbose) {
      bufnum[fmt_ulong(bufnum, i)] =0;
      out(INFO); out("end "); out(bufnum); out(" exit ");
      bufnum[fmt_ulong(bufnum, (unsigned long)wait_exitcode(wstat))] =0;
      out(bufnum); flush("\n");
    }
  }
  if (verbose) connection_status();
}
Exemple #6
0
static void sig_child_handler(int sig ATTRIBUTE_UNUSED)
{
	int wstat;
	int pid;

	while ((pid = wait_any_nohang(&wstat)) > 0) {
		if (max_per_host)
			ipsvd_perhost_remove(pid);
		if (cnum)
			cnum--;
		if (verbose)
			print_waitstat(pid, wstat);
	}
	if (verbose)
		connection_status();
}
Exemple #7
0
int 
manage_connect (struct tcp_socket *sk)
{
    int sd = 0;
    int cnt_status;
    struct sockaddr_in  addr4;
    struct sockaddr_in6 addr6;
    struct socks_hdr    *hdr;
    struct msgbuff      *msg;
    u_int8_t		errcode;
    socklen_t		addrlen;
    size_t		iplen;
    size_t		bufflen;

    errno = 0;
    if ( sk->kind == SOCKET_PASV && sk->state == WAITING_CONNECTION)
    {
	if ( sk->family == AF_INET )
	{
	    sd = accept_tcp_ipv4(sk->socket, &addr4);
	    iplen = 4;
		
	}
	else if ( sk->family == AF_INET6)
	{
	    sd = accept_tcp_ipv6(sk->socket, &addr6);
	    iplen = 16;
	}
	else
	{
	    return -1;
	}
	
	if ( sd == -1 )
	{
	    if (errno == EINTR)
		return 0;
	    else
		errcode = SFAILURE;
	}
	else
	{
	    close(sk->socket);
	    sk->socket = sd;
	    errcode = SUCCESS;
	}
    }
    else if ( sk->kind == SOCKET_PEER && sk->state == CONNECTING )
    {
	if (connection_status(sk->socket, &cnt_status) == -1)
	{
	    errcode = SFAILURE;
	}

	if (cnt_status == 0)
	{
	    errcode = SUCCESS;

	    if (sk->family == AF_INET)
	    {
		iplen = 4;
		addrlen = sizeof(struct sockaddr_in);    
		if ( getsockname(sk->socket, (struct sockaddr *)&addr4, &addrlen) == -1 )
		{
		    errcode = SFAILURE;
		}
	    }
	    else if (sk->family == AF_INET6)
	    {
		iplen = 16;
		addrlen = sizeof(struct sockaddr_in);
		if ( getsockname(sk->socket, (struct sockaddr *)&addr6, &addrlen) == -1 )
		{
		    errcode = SFAILURE;
		}
	    }
	    else
		return -1;
	}
	else
	{
	    if (cnt_status == EALREADY || cnt_status == EINPROGRESS )
		return 0;
	    else
	    {
		if (cnt_status == ENETUNREACH)
		    errcode = NUNREACHE;
		else if ( cnt_status == ETIMEDOUT)
		    errcode = HUNREACHE;
		else
		    errcode = SFAILURE;
	    }
	}
    }
    else
    {
	return -1;
    }
    
    bufflen = SZS5HDR + iplen + 2;
    msg = alloc_msg_buffer(bufflen);
    if (msg == NULL)
	return -1;

    hdr = (struct socks_hdr *) msg->buffer;
    hdr->ver = 0x05;
    hdr->kind.rep = errcode;
    hdr->rsv      = 0x00;
    hdr->atyp     = (sk->family == AF_INET) ? IPV4ADDR  : IPV6ADDR;
    if ( errcode == 0x00 )
    {
	memcpy(&((u_int8_t *)(msg->buffer))[SZS5HDR], 
	        (sk->family == AF_INET) ? &(addr4.sin_addr.s_addr) : &(addr6.sin6_addr.s6_addr), iplen);
	memcpy(&((u_int8_t *)(msg->buffer))[SZS5HDR+iplen], 
	        (sk->family == AF_INET) ? &(addr4.sin_port) : &(addr6.sin6_port), 2);

        sk->peer->state = PENDING_SND_REPLY;    
	sk->state = PIPELINE;
    }
    else
    {
	sk->peer->state = WAITING_CLOSE;
	sk->state = CLOSE;
	msg->nrbytes = 4;    
    }     
    enqueue_pending_msg(&(sk->peer->msgq), msg);
    return 0;
}
Exemple #8
0
void button_function(GtkWidget *widget,gpointer data)
{
    char* label_string = gtk_button_get_label(widget);

    if (connection_status() == 0){
        gtk_label_set_text(GTK_LABEL(helpLabel), "please connect");
        g_timeout_add_seconds (4, reset_help_label, (gpointer) helpLabel);
        return;
    }

    if (!strcmp(label_string,"Device1") || !strcmp(label_string,"Device1-On")){
        int value = gtk_spin_button_get_value_as_int(spinButtonDevice1);
        if (value==0)
        {
            gtk_label_set_text(GTK_LABEL(helpLabel), "set time");
            g_timeout_add_seconds (4, reset_help_label, (gpointer) helpLabel);
        } else if (!device1_on){
            sendMessage("1:start");
            device1_on = 1;
            gtk_button_set_label(GTK_BUTTON(widget), "Device1-On");
            g_print ("turning on device1 for %d seconds \n",value);
            g_timeout_add_seconds (value, stop_device, (gpointer) buttonDevice1);
        } else if (device1_on) {
            sendMessage("1:stop");
            device1_on = 0;
            gtk_button_set_label(GTK_BUTTON(widget), "Device1");
            g_print ("turning off device1\n");
        }

    } else if (!strcmp(label_string,"Device2") || !strcmp(label_string,"Device2-On")){
        int value = gtk_spin_button_get_value_as_int(spinButtonDevice2);
        if (value==0)
        {
            gtk_label_set_text(GTK_LABEL(helpLabel), "set time");
            g_timeout_add_seconds (4, reset_help_label, (gpointer) helpLabel);
        } else if (!device2_on){
            sendMessage("2:start");
            device2_on = 1;
            g_print ("turning on device2 for %d seconds \n",value);
            gtk_button_set_label(GTK_BUTTON(widget), "Device2-On");
            g_timeout_add_seconds (value, stop_device, (gpointer) buttonDevice2);

        } else if (device2_on) {
            sendMessage("2:stop");
            device2_on = 0;
            gtk_button_set_label(GTK_BUTTON(widget), "Device2");
            g_print ("turning off device2\n");
        }
    } else if (!strcmp(label_string,"Device3")  || !strcmp(label_string,"Device3-On")) {
        int value = gtk_spin_button_get_value_as_int(spinButtonDevice3);
        if (value==0)
        {
            gtk_label_set_text(GTK_LABEL(helpLabel), "set time");
            g_timeout_add_seconds (4, reset_help_label, (gpointer) helpLabel);
        } else if (!device3_on){
            sendMessage("3:start");
            device3_on = 1;
            gtk_button_set_label(GTK_BUTTON(widget), "Device3-On");
            g_print ("turning on device3 for %d seconds \n",value);
            g_timeout_add_seconds (value, stop_device, (gpointer) buttonDevice3);
        } else if (device3_on) {
            sendMessage("3:stop");
            device3_on = 0;
            gtk_button_set_label(GTK_BUTTON(widget), "Device3");
            g_print ("turning off device3\n");
        }
    } else if (!strcmp(label_string,"Device4")  || !strcmp(label_string,"Device4-On")) {
        int value = gtk_spin_button_get_value_as_int(spinButtonDevice4);
        if (value==0)
        {
            gtk_label_set_text(GTK_LABEL(helpLabel), "set time");
            g_timeout_add_seconds (4, reset_help_label, (gpointer) helpLabel);
        } else if (!device4_on){
            sendMessage("4:start");
            device4_on = 1;
            gtk_button_set_label(GTK_BUTTON(widget), "Device4-On");
            g_print ("turning on device4 for %d seconds \n",value);
            g_timeout_add_seconds (value, stop_device, (gpointer) buttonDevice4);
        } else if (device4_on) {
            sendMessage("4:stop");
            device4_on = 0;
            gtk_button_set_label(GTK_BUTTON(widget), "Device4");
            g_print ("turning off device4\n");
        }
    }
}
Exemple #9
0
void
edit_interface_rep::set_left_footer () {
  tree s= concat ();
  double base_sz= get_env_int (FONT_BASE_SIZE);
  double sz= get_env_double (FONT_SIZE);
  /*
  tree the_style= get_style ();
  for (int i=0; i<arity (the_style); i++)
    s << " " << as_string (the_style[i]);
  */
  string mode= get_env_string (MODE);
  string lan = get_env_string (MODE_LANGUAGE (mode));
  if (mode == "prog") s << "program";
  else if (as_string (get_init_value (MODE_LANGUAGE (mode))) != lan)
    s << " " << lan;
  else s << " " << mode;
  if ((mode == "text") || (mode == "src")) {
    s << " " << get_env_string (FONT);
    append_left_footer (s, FONT_FAMILY);
    s << " " << as_string ((int) ((base_sz+0.5)*sz));
    append_left_footer (s, FONT_SERIES);
    append_left_footer (s, FONT_SHAPE);
  }
  else if (mode == "math") {
    s << " " << get_env_string (MATH_FONT);
    append_left_footer (s, MATH_FONT_FAMILY);
    s << " " << as_string ((int) ((base_sz+0.5)*sz));
    append_left_footer (s, MATH_FONT_SERIES);
    append_left_footer (s, MATH_FONT_SHAPE);
  }
  else if (mode == "prog") {
    string session_name= get_env_string (PROG_SESSION);
    if (session_name != "default") s << "-" << session_name;
    s << " " << get_env_string (PROG_FONT);
    append_left_footer (s, PROG_FONT_FAMILY);
    s << " " << as_string ((int) ((base_sz+0.5)*sz));
    append_left_footer (s, PROG_FONT_SERIES);
    append_left_footer (s, PROG_FONT_SHAPE);
  }
  string r= get_env_string (COLOR);
  if (r != "black") s << " " << r;
  if (N(s) > 0 && s[0] == " ") s= s (1, N(s));
  if (inside ("session") && (lan != "scheme")) {
    string lan    = get_env_string (PROG_LANGUAGE);
    string session= get_env_string (PROG_SESSION);
    switch (connection_status (lan, session)) {
    case CONNECTION_DEAD:
      s= s << " [dead]";
      break;
    case CONNECTION_DYING:
    case WAITING_FOR_OUTPUT:
      s= s << " [busy]";
      break;
    case WAITING_FOR_INPUT:
      s= s << " [idle]";
      break;
    }
  }
  s= as_tree (call ("footer-hook", object (s)));
  set_left_footer (s);
}
Exemple #10
0
int main(int argc, char **argv) {
  int opt;
  char *user =0;
  char *host;
  unsigned long port;
  int pid;
  int s;
  int conn;
  int delim;

  progname =*argv;
  phccmax =0;

#ifdef SSLSVD
  while ((opt =getopt(argc, (const char **)argv,
                      "c:C:i:x:u:l:Eb:hpt:vVU:/:Z:K:")) != opteof) {
#else
  while ((opt =getopt(argc, (const char **)argv,
                      "c:C:i:x:u:l:Eb:hpt:vV")) != opteof) {
#endif
    switch(opt) {
    case 'c': scan_ulong(optarg, &cmax); if (cmax < 1) usage(); break;
    case 'C':
      delim =scan_ulong(optarg, &phccmax);
      if (phccmax < 1) usage();
      if (optarg[delim] == ':') {
        if (ipsvd_fmt_msg(&msg, optarg +delim +1) == -1) die_nomem();
        if (! stralloc_0(&msg)) die_nomem();
        phccmsg =msg.s;
      }
      break;
    case 'i': if (instructs) usage(); instructs =optarg; break;
    case 'x': if (instructs) usage(); instructs =optarg; iscdb =1; break;
    case 'u': user =(char*)optarg; break;
    case 'l':
      if (! stralloc_copys(&local_hostname, optarg)) die_nomem();
      if (! stralloc_0(&local_hostname)) die_nomem();
      break;
    case 'E': ucspi =0; break;
    case 'b': scan_ulong(optarg, &backlog); break;
    case 'h': lookuphost =1; break;
    case 'p': lookuphost =1; paranoid =1; break;
    case 't': scan_ulong(optarg, &timeout); break;
    case 'v': ++verbose; break;
#ifdef SSLSVD
    case 'U': ssluser =(char*)optarg; break;
    case '/': root =(char*)optarg; break;
    case 'Z': cert =(char*)optarg; break;
    case 'K': key =(char*)optarg; break;
#endif
    case 'V': strerr_warn1(VERSION, 0);
    case '?': usage();
    }
  }
  argv +=optind;

  if (! argv || ! *argv) usage();
  host =*argv++;
  if (! argv || ! *argv) usage();
  local_port =*argv++;
  if (! argv || ! *argv) usage();
  prog =(const char **)argv;
  if (phccmax > cmax) phccmax =cmax;

  if (user)
    if (! uidgids_get(&ugid, user)) {
      if (errno)
        strerr_die4sys(111, FATAL, "unable to get user/group: ", user, ": ");
      strerr_die3x(100, FATAL, "unknown user/group: ", user);
    }
#ifdef SSLSVD
  svuser =user;
  client =0;
  if ((getuid() == 0) && (! ssluser))
    strerr_die2x(100, FATAL, "-U ssluser must be set when running as root");
  if (ssluser)
    if (! uidgids_get(&sslugid, ssluser)) {
      if (errno)
        strerr_die4sys(111, FATAL, "unable to get user/group: ", ssluser, ": ");
      strerr_die3x(100, FATAL, "unknown user/group: ", ssluser);
    }
  if (! cert) cert ="./cert.pem";
  if (! key) key =cert;
  if (matrixSslOpen() < 0) fatal("unable to initialize ssl");
  if (matrixSslReadKeys(&keys, cert, key, 0, ca) < 0) {
    if (client) fatal("unable to read cert, key, or ca file");
    fatal("unable to read cert or key file");
  }
  if (matrixSslNewSession(&ssl, keys, 0, SSL_FLAGS_SERVER) < 0)
    strerr_die2x(111, FATAL, "unable to create ssl session");
#endif

  dns_random_init(seed);
  sig_block(sig_child);
  sig_catch(sig_child, sig_child_handler);
  sig_catch(sig_term, sig_term_handler);
  sig_ignore(sig_pipe);

  if (phccmax) if (ipsvd_phcc_init(cmax) == -1) die_nomem();

  if (str_equal(host, "")) host ="0.0.0.0";
  if (str_equal(host, "0")) host ="0.0.0.0";

  if (! ipsvd_scan_port(local_port, "tcp", &port))
    strerr_die3x(100, FATAL, "unknown port number or name: ", local_port);

  if (! stralloc_copys(&sa, host)) die_nomem();
  if ((dns_ip4(&ips, &sa) == -1) || (ips.len < 4))
    if (dns_ip4_qualify(&ips, &fqdn, &sa) == -1)
      fatal2("unable to look up ip address", host);
  if (ips.len < 4)
    strerr_die3x(100, FATAL, "unable to look up ip address: ", host);
  ips.len =4;
  if (! stralloc_0(&ips)) die_nomem();
  local_ip[ipsvd_fmt_ip(local_ip, ips.s)] =0;

  if (! lookuphost) {
    if (! stralloc_copys(&remote_hostname, "")) die_nomem();
    if (! stralloc_0(&remote_hostname)) die_nomem();
  }

  if ((s =socket_tcp()) == -1) fatal("unable to create socket");
  if (socket_bind4_reuse(s, ips.s, port) == -1)
    fatal("unable to bind socket");
  if (listen(s, backlog) == -1) fatal("unable to listen");
  ndelay_off(s);

#ifdef SSLSVD
#else
  if (user) {
    /* drop permissions */
    if (setgroups(ugid.gids, ugid.gid) == -1) fatal("unable to set groups");
    if (setgid(*ugid.gid) == -1) fatal("unable to set gid");
    if (prot_uid(ugid.uid) == -1) fatal("unable to set uid");
  }
#endif
  close(0);

  if (verbose) {
    out(INFO); out("listening on "); outfix(local_ip); out(":");
    outfix(local_port);
#ifdef SSLSVD
#else
    if (user) {
      bufnum[fmt_ulong(bufnum, (unsigned long)ugid.uid)] =0;
      out(", uid "); out(bufnum);
      bufnum[fmt_ulong(bufnum, (unsigned long)ugid.gid)] =0;
      out(", gid "); out(bufnum);
    }
#endif
    flush(", starting.\n");
  }
  for (;;) {
    while (cnum >= cmax) sig_pause();
    socka_size =sizeof(socka);

    sig_unblock(sig_child);
    conn =accept(s, (struct sockaddr *)&socka, &socka_size);
    sig_block(sig_child);

    if (conn == -1) {
      if (errno != error_intr) warn("unable to accept connection");
      continue;
    }
    cnum++;

    if (verbose) connection_status();
    if (phccmax) phcc =ipsvd_phcc_add((char*)&socka.sin_addr);
    if ((pid =fork()) == -1) {
      warn2("drop connection", "unable to fork");
      close(conn);
      continue;
    }
    if (pid == 0) {
      /* child */
      close(s);
#ifdef SSLSVD
      if (*progname) *progname ='\\';
#endif
      connection_accept(conn);
    }
    if (phccmax) ipsvd_phcc_setpid(pid);
    close(conn);
  }
  _exit(0);
}
Exemple #11
0
int tcpudpsvd_main(int argc ATTRIBUTE_UNUSED, char **argv)
{
	char *str_C, *str_t;
	char *user;
	struct hcc *hccp;
	const char *instructs;
	char *msg_per_host = NULL;
	unsigned len_per_host = len_per_host; /* gcc */
#ifndef SSLSVD
	struct bb_uidgid_t ugid;
#endif
	bool tcp;
	uint16_t local_port;
	char *preset_local_hostname = NULL;
	char *remote_hostname = remote_hostname; /* for compiler */
	char *remote_addr = remote_addr; /* for compiler */
	len_and_sockaddr *lsa;
	len_and_sockaddr local, remote;
	socklen_t sa_len;
	int pid;
	int sock;
	int conn;
	unsigned backlog = 20;

	INIT_G();

	tcp = (applet_name[0] == 't');

	/* 3+ args, -i at most once, -p implies -h, -v is counter, -b N, -c N */
	opt_complementary = "-3:i--i:ph:vv:b+:c+";
#ifdef SSLSVD
	getopt32(argv, "+c:C:i:x:u:l:Eb:hpt:vU:/:Z:K:",
		&cmax, &str_C, &instructs, &instructs, &user, &preset_local_hostname,
		&backlog, &str_t, &ssluser, &root, &cert, &key, &verbose
	);
#else
	/* "+": stop on first non-option */
	getopt32(argv, "+c:C:i:x:u:l:Eb:hpt:v",
		&cmax, &str_C, &instructs, &instructs, &user, &preset_local_hostname,
		&backlog, &str_t, &verbose
	);
#endif
	if (option_mask32 & OPT_C) { /* -C n[:message] */
		max_per_host = bb_strtou(str_C, &str_C, 10);
		if (str_C[0]) {
			if (str_C[0] != ':')
				bb_show_usage();
			msg_per_host = str_C + 1;
			len_per_host = strlen(msg_per_host);
		}
	}
	if (max_per_host > cmax)
		max_per_host = cmax;
	if (option_mask32 & OPT_u) {
		if (!get_uidgid(&ugid, user, 1))
			bb_error_msg_and_die("unknown user/group: %s", user);
	}
#ifdef SSLSVD
	if (option_mask32 & OPT_U) ssluser = optarg;
	if (option_mask32 & OPT_slash) root = optarg;
	if (option_mask32 & OPT_Z) cert = optarg;
	if (option_mask32 & OPT_K) key = optarg;
#endif
	argv += optind;
	if (!argv[0][0] || LONE_CHAR(argv[0], '0'))
		argv[0] = (char*)"0.0.0.0";

	/* Per-IP flood protection is not thought-out for UDP */
	if (!tcp)
		max_per_host = 0;

	bb_sanitize_stdio(); /* fd# 0,1,2 must be opened */

#ifdef SSLSVD
	sslser = user;
	client = 0;
	if ((getuid() == 0) && !(option_mask32 & OPT_u)) {
		xfunc_exitcode = 100;
		bb_error_msg_and_die("-U ssluser must be set when running as root");
	}
	if (option_mask32 & OPT_u)
		if (!uidgid_get(&sslugid, ssluser, 1)) {
			if (errno) {
				bb_perror_msg_and_die("fatal: cannot get user/group: %s", ssluser);
			}
			bb_error_msg_and_die("unknown user/group '%s'", ssluser);
		}
	if (!cert) cert = "./cert.pem";
	if (!key) key = cert;
	if (matrixSslOpen() < 0)
		fatal("cannot initialize ssl");
	if (matrixSslReadKeys(&keys, cert, key, 0, ca) < 0) {
		if (client)
			fatal("cannot read cert, key, or ca file");
		fatal("cannot read cert or key file");
	}
	if (matrixSslNewSession(&ssl, keys, 0, SSL_FLAGS_SERVER) < 0)
		fatal("cannot create ssl session");
#endif

	sig_block(SIGCHLD);
	signal(SIGCHLD, sig_child_handler);
	bb_signals(BB_FATAL_SIGS, sig_term_handler);
	signal(SIGPIPE, SIG_IGN);

	if (max_per_host)
		ipsvd_perhost_init(cmax);

	local_port = bb_lookup_port(argv[1], tcp ? "tcp" : "udp", 0);
	lsa = xhost2sockaddr(argv[0], local_port);
	argv += 2;

	sock = xsocket(lsa->u.sa.sa_family, tcp ? SOCK_STREAM : SOCK_DGRAM, 0);
	setsockopt_reuseaddr(sock);
	sa_len = lsa->len; /* I presume sockaddr len stays the same */
	xbind(sock, &lsa->u.sa, sa_len);
	if (tcp)
		xlisten(sock, backlog);
	else /* udp: needed for recv_from_to to work: */
		socket_want_pktinfo(sock);
	/* ndelay_off(sock); - it is the default I think? */

#ifndef SSLSVD
	if (option_mask32 & OPT_u) {
		/* drop permissions */
		xsetgid(ugid.gid);
		xsetuid(ugid.uid);
	}
#endif

	if (verbose) {
		char *addr = xmalloc_sockaddr2dotted(&lsa->u.sa);
		bb_error_msg("listening on %s, starting", addr);
		free(addr);
#ifndef SSLSVD
		if (option_mask32 & OPT_u)
			printf(", uid %u, gid %u",
				(unsigned)ugid.uid, (unsigned)ugid.gid);
#endif
	}

	/* Main accept() loop */

 again:
	hccp = NULL;

	while (cnum >= cmax)
		wait_for_any_sig(); /* expecting SIGCHLD */

	/* Accept a connection to fd #0 */
 again1:
	close(0);
 again2:
	sig_unblock(SIGCHLD);
	local.len = remote.len = sa_len;
	if (tcp) {
		conn = accept(sock, &remote.u.sa, &remote.len);
	} else {
		/* In case recv_from_to won't be able to recover local addr.
		 * Also sets port - recv_from_to is unable to do it. */
		local = *lsa;
		conn = recv_from_to(sock, NULL, 0, MSG_PEEK,
				&remote.u.sa, &local.u.sa, sa_len);
	}
	sig_block(SIGCHLD);
	if (conn < 0) {
		if (errno != EINTR)
			bb_perror_msg(tcp ? "accept" : "recv");
		goto again2;
	}
	xmove_fd(tcp ? conn : sock, 0);

	if (max_per_host) {
		/* Drop connection immediately if cur_per_host > max_per_host
		 * (minimizing load under SYN flood) */
		remote_addr = xmalloc_sockaddr2dotted_noport(&remote.u.sa);
		cur_per_host = ipsvd_perhost_add(remote_addr, max_per_host, &hccp);
		if (cur_per_host > max_per_host) {
			/* ipsvd_perhost_add detected that max is exceeded
			 * (and did not store ip in connection table) */
			free(remote_addr);
			if (msg_per_host) {
				/* don't block or test for errors */
				send(0, msg_per_host, len_per_host, MSG_DONTWAIT);
			}
			goto again1;
		}
		/* NB: remote_addr is not leaked, it is stored in conn table */
	}

	if (!tcp) {
		/* Voodoo magic: making udp sockets each receive its own
		 * packets is not trivial, and I still not sure
		 * I do it 100% right.
		 * 1) we have to do it before fork()
		 * 2) order is important - is it right now? */

		/* Open new non-connected UDP socket for further clients... */
		sock = xsocket(lsa->u.sa.sa_family, SOCK_DGRAM, 0);
		setsockopt_reuseaddr(sock);
		/* Make plain write/send work for old socket by supplying default
		 * destination address. This also restricts incoming packets
		 * to ones coming from this remote IP. */
		xconnect(0, &remote.u.sa, sa_len);
	/* hole? at this point we have no wildcard udp socket...
	 * can this cause clients to get "port unreachable" icmp?
	 * Yup, time window is very small, but it exists (is it?) */
		/* ..."open new socket", continued */
		xbind(sock, &lsa->u.sa, sa_len);
		socket_want_pktinfo(sock);

		/* Doesn't work:
		 * we cannot replace fd #0 - we will lose pending packet
		 * which is already buffered for us! And we cannot use fd #1
		 * instead - it will "intercept" all following packets, but child
		 * does not expect data coming *from fd #1*! */
#if 0
		/* Make it so that local addr is fixed to localp->u.sa
		 * and we don't accidentally accept packets to other local IPs. */
		/* NB: we possibly bind to the _very_ same_ address & port as the one
		 * already bound in parent! This seems to work in Linux.
		 * (otherwise we can move socket to fd #0 only if bind succeeds) */
		close(0);
		set_nport(localp, htons(local_port));
		xmove_fd(xsocket(localp->u.sa.sa_family, SOCK_DGRAM, 0), 0);
		setsockopt_reuseaddr(0); /* crucial */
		xbind(0, &localp->u.sa, localp->len);
#endif
	}

	pid = vfork();
	if (pid == -1) {
		bb_perror_msg("vfork");
		goto again;
	}

	if (pid != 0) {
		/* Parent */
		cnum++;
		if (verbose)
			connection_status();
		if (hccp)
			hccp->pid = pid;
		/* clean up changes done by vforked child */
		undo_xsetenv();
		goto again;
	}

	/* Child: prepare env, log, and exec prog */

	/* Closing tcp listening socket */
	if (tcp)
		close(sock);

	{ /* vfork alert! every xmalloc in this block should be freed! */
		char *local_hostname = local_hostname; /* for compiler */
		char *local_addr = NULL;
		char *free_me0 = NULL;
		char *free_me1 = NULL;
		char *free_me2 = NULL;

		if (verbose || !(option_mask32 & OPT_E)) {
			if (!max_per_host) /* remote_addr is not yet known */
				free_me0 = remote_addr = xmalloc_sockaddr2dotted(&remote.u.sa);
			if (option_mask32 & OPT_h) {
				free_me1 = remote_hostname = xmalloc_sockaddr2host_noport(&remote.u.sa);
				if (!remote_hostname) {
					bb_error_msg("cannot look up hostname for %s", remote_addr);
					remote_hostname = remote_addr;
				}
			}
			/* Find out local IP peer connected to.
			 * Errors ignored (I'm not paranoid enough to imagine kernel
			 * which doesn't know local IP). */
			if (tcp)
				getsockname(0, &local.u.sa, &local.len);
			/* else: for UDP it is done earlier by parent */
			local_addr = xmalloc_sockaddr2dotted(&local.u.sa);
			if (option_mask32 & OPT_h) {
				local_hostname = preset_local_hostname;
				if (!local_hostname) {
					free_me2 = local_hostname = xmalloc_sockaddr2host_noport(&local.u.sa);
					if (!local_hostname)
						bb_error_msg_and_die("cannot look up hostname for %s", local_addr);
				}
				/* else: local_hostname is not NULL, but is NOT malloced! */
			}
		}
		if (verbose) {
			pid = getpid();
			if (max_per_host) {
				bb_error_msg("concurrency %s %u/%u",
					remote_addr,
					cur_per_host, max_per_host);
			}
			bb_error_msg((option_mask32 & OPT_h)
				? "start %u %s-%s (%s-%s)"
				: "start %u %s-%s",
				pid,
				local_addr, remote_addr,
				local_hostname, remote_hostname);
		}

		if (!(option_mask32 & OPT_E)) {
			/* setup ucspi env */
			const char *proto = tcp ? "TCP" : "UDP";

			/* Extract "original" destination addr:port
			 * from Linux firewall. Useful when you redirect
			 * an outbond connection to local handler, and it needs
			 * to know where it originally tried to connect */
			if (tcp && getsockopt(0, SOL_IP, SO_ORIGINAL_DST, &local.u.sa, &local.len) == 0) {
				char *addr = xmalloc_sockaddr2dotted(&local.u.sa);
				xsetenv_plain("TCPORIGDSTADDR", addr);
				free(addr);
			}
			xsetenv_plain("PROTO", proto);
			xsetenv_proto(proto, "LOCALADDR", local_addr);
			xsetenv_proto(proto, "REMOTEADDR", remote_addr);
			if (option_mask32 & OPT_h) {
				xsetenv_proto(proto, "LOCALHOST", local_hostname);
				xsetenv_proto(proto, "REMOTEHOST", remote_hostname);
			}
			//compat? xsetenv_proto(proto, "REMOTEINFO", "");
			/* additional */
			if (cur_per_host > 0) /* can not be true for udp */
				xsetenv_plain("TCPCONCURRENCY", utoa(cur_per_host));
		}
		free(local_addr);
		free(free_me0);
		free(free_me1);
		free(free_me2);
	}

	xdup2(0, 1);

	signal(SIGTERM, SIG_DFL);
	signal(SIGPIPE, SIG_DFL);
	signal(SIGCHLD, SIG_DFL);
	sig_unblock(SIGCHLD);

#ifdef SSLSVD
	strcpy(id, utoa(pid));
	ssl_io(0, argv);
#else
	BB_EXECVP(argv[0], argv);
#endif
	bb_perror_msg_and_die("exec '%s'", argv[0]);
}