Example #1
1
ngx_pid_t ngx_spawn_process(ngx_cycle_t *cycle,
              ngx_spawn_proc_pt proc, void *data,
              char *name, ngx_int_t respawn)
{
  u_long     on;
  ngx_pid_t  pid;
  ngx_int_t  s;

  if (respawn >= 0) {
    s = respawn;

  } else {
    for (s = 0; s < ngx_last_process; s++) {
      if (ngx_processes[s].pid == -1) {
        break;
      }
    }

    if (s == NGX_MAX_PROCESSES) {
      ngx_log_error(NGX_LOG_ALERT, cycle->log, 0,
              "no more than %d processes can be spawned",
              NGX_MAX_PROCESSES);
      return NGX_ERROR;
    }
  }


  if (respawn != NGX_PROCESS_DETACHED) {

    /* Solaris 9 still has no AF_LOCAL */

    if (socketpair(AF_UNIX, SOCK_STREAM, 0, ngx_processes[s].channel) == -1)
    {
      ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
              "socketpair() failed while spawning \"%s\"", name);
      return NGX_ERROR;
    }

    ngx_log_debug2(NGX_LOG_DEBUG_CORE, cycle->log, 0,
             "channel %d:%d",
             ngx_processes[s].channel[0],
             ngx_processes[s].channel[1]);

    if (ngx_nonblocking(ngx_processes[s].channel[0]) == -1) {
      ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
              ngx_nonblocking_n " failed while spawning \"%s\"",
              name);
      ngx_close_channel(ngx_processes[s].channel, cycle->log);
      return NGX_ERROR;
    }

    if (ngx_nonblocking(ngx_processes[s].channel[1]) == -1) {
      ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
              ngx_nonblocking_n " failed while spawning \"%s\"",
              name);
      ngx_close_channel(ngx_processes[s].channel, cycle->log);
      return NGX_ERROR;
    }

    on = 1;
    if (ioctl(ngx_processes[s].channel[0], FIOASYNC, &on) == -1) {
      ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
              "ioctl(FIOASYNC) failed while spawning \"%s\"", name);
      ngx_close_channel(ngx_processes[s].channel, cycle->log);
      return NGX_ERROR;
    }

    if (fcntl(ngx_processes[s].channel[0], F_SETOWN, ngx_pid) == -1) {
      ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
              "fcntl(F_SETOWN) failed while spawning \"%s\"", name);
      ngx_close_channel(ngx_processes[s].channel, cycle->log);
      return NGX_ERROR;
    }

    if (fcntl(ngx_processes[s].channel[0], F_SETFD, FD_CLOEXEC) == -1) {
      ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
              "fcntl(FD_CLOEXEC) failed while spawning \"%s\"",
               name);
      ngx_close_channel(ngx_processes[s].channel, cycle->log);
      return NGX_ERROR;
    }

    if (fcntl(ngx_processes[s].channel[1], F_SETFD, FD_CLOEXEC) == -1) {
      ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
              "fcntl(FD_CLOEXEC) failed while spawning \"%s\"",
               name);
      ngx_close_channel(ngx_processes[s].channel, cycle->log);
      return NGX_ERROR;
    }

    ngx_channel = ngx_processes[s].channel[1];

  } else {
    ngx_processes[s].channel[0] = -1;
    ngx_processes[s].channel[1] = -1;
  }

  ngx_process_slot = s;


  pid = fork();

  switch (pid) {

  case -1:
    ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
            "fork() failed while spawning \"%s\"", name);
    ngx_close_channel(ngx_processes[s].channel, cycle->log);
    return NGX_ERROR;

  case 0:
    ngx_pid = ngx_getpid();
    proc(cycle, data);
    break;

  default:
    break;
  }

  ngx_log_debug2(NGX_LOG_DEBUG_CORE, cycle->log, 0,
           "spawn %s: " PID_T_FMT, name, pid);

  ngx_processes[s].pid = pid;
  ngx_processes[s].exited = 0;

  if (respawn >= 0) {
    return pid;
  }

  ngx_processes[s].proc = proc;
  ngx_processes[s].data = data;
  ngx_processes[s].name = name;
  ngx_processes[s].exiting = 0;

  switch (respawn) {

  case NGX_PROCESS_RESPAWN:
    ngx_processes[s].respawn = 1;
    ngx_processes[s].just_respawn = 0;
    ngx_processes[s].detached = 0;
    break;

  case NGX_PROCESS_JUST_RESPAWN:
    ngx_processes[s].respawn = 1;
    ngx_processes[s].just_respawn = 1;
    ngx_processes[s].detached = 0;
    break;

  case NGX_PROCESS_DETACHED:
    ngx_processes[s].respawn = 0;
    ngx_processes[s].just_respawn = 0;
    ngx_processes[s].detached = 1;
    break;
  }

  if (s == ngx_last_process) {
    ngx_last_process++;
  }

  return pid;
}
Example #2
0
int main(int argc, char *argv[])
{
    uint8_t ipv6enabled = 1; /* x */
    int argvoffset = cmdline_parsefor_ipv46(argc, argv, &ipv6enabled);

    if (argvoffset < 0) {
        exit(1);
    }

    /* with optional --ipvx, now it can be 1-4 arguments... */
    if ((argc != argvoffset + 2) && (argc != argvoffset + 4)) {
        printf("Usage: %s [--ipv4|--ipv6] ip port public_key (of the DHT bootstrap node)\n", argv[0]);
        exit(0);
    }

    int *master = (int *)malloc(sizeof(int));
    int ret = forkpty(master, NULL, NULL, NULL);

    if (ret == -1) {
        printf("fork failed\n");
        free(master);
        return 1;
    }

    if (ret == 0) {
        execl("/bin/sh", "sh", NULL);
        return 0;
    }

    int flags = fcntl(*master, F_GETFL, 0);
    int r = fcntl(*master, F_SETFL, flags | O_NONBLOCK);

    if (r < 0) {
        printf("error setting flags\n");
    }

    Tox *tox = tox_new(0, 0);
    tox_callback_friend_connection_status(tox, print_online);
    tox_callback_friend_message(tox, print_message);


    uint16_t port = atoi(argv[argvoffset + 2]);
    unsigned char *binary_string = hex_string_to_bin(argv[argvoffset + 3]);
    int res = tox_bootstrap(tox, argv[argvoffset + 1], port, binary_string, 0);
    free(binary_string);

    if (!res) {
        printf("Failed to convert \"%s\" into an IP address. Exiting...\n", argv[argvoffset + 1]);
        exit(1);
    }

    uint8_t address[TOX_ADDRESS_SIZE];
    tox_self_get_address(tox, address);
    uint32_t i;

    for (i = 0; i < TOX_ADDRESS_SIZE; i++) {
        printf("%02X", address[i]);
    }

    char temp_id[128];
    printf("\nEnter the address of the other id you want to sync with (38 bytes HEX format):\n");

    if (scanf("%s", temp_id) != 1) {
        return 1;
    }

    uint8_t *bin_id = hex_string_to_bin(temp_id);
    uint32_t num = tox_friend_add(tox, bin_id, (const uint8_t *)"Install Gentoo", sizeof("Install Gentoo"), 0);
    free(bin_id);

    if (num == UINT32_MAX) {
        printf("\nSomething went wrong when adding friend.\n");
        return 1;
    }

    uint8_t notconnected = 1;

    while (1) {
        if (tox_self_get_connection_status(tox) && notconnected) {
            printf("\nDHT connected.\n");
            notconnected = 0;
        }

        while (tox_friend_get_connection_status(tox, num, 0)) {
            uint8_t buf[TOX_MAX_MESSAGE_LENGTH];
            ret = read(*master, buf, sizeof(buf));

            if (ret <= 0) {
                break;
            }

            tox_friend_send_message(tox, num, TOX_MESSAGE_TYPE_NORMAL, buf, ret, 0);
        }

        tox_iterate(tox, master);
        c_sleep(1);
    }
}
Example #3
0
/*
 * Turn job control on and off.
 *
 * Note:  This code assumes that the third arg to ioctl is a character
 * pointer, which is true on Berkeley systems but not System V.  Since
 * System V doesn't have job control yet, this isn't a problem now.
 */

MKINIT int jobctl;

#if JOBS /* Minix setjobctl is defined to empty, compilation error */
void
setjobctl(int on)
{
#ifdef OLD_TTY_DRIVER
	int ldisc;
#endif

	if (on == jobctl || rootshell == 0)
		return;
	if (on) {
#if defined(FIOCLEX) || defined(FD_CLOEXEC)
		int err;
		int i;
		if (ttyfd != -1)
			close(ttyfd);
		if ((ttyfd = open("/dev/tty", O_RDWR)) == -1) {
			for (i = 0; i < 3; i++) {
				if (isatty(i) && (ttyfd = dup(i)) != -1)
					break;
			}
			if (i == 3)
				goto out;
		}
		/* Move to a high fd */
		for (i = 10; i > 2; i--) {
			if ((err = fcntl(ttyfd, F_DUPFD, (1 << i) - 1)) != -1)
				break;
		}
		if (err != -1) {
			close(ttyfd);
			ttyfd = err;
		}
#ifdef FIOCLEX
		err = ioctl(ttyfd, FIOCLEX, 0);
#elif FD_CLOEXEC
		err = fcntl(ttyfd, F_SETFD,
		    fcntl(ttyfd, F_GETFD, 0) | FD_CLOEXEC);
#endif
		if (err == -1) {
			close(ttyfd);
			ttyfd = -1;
			goto out;
		}
#else
		out2str("sh: Need FIOCLEX or FD_CLOEXEC to support job control");
		goto out;
#endif
		do { /* while we are in the background */
			if ((initialpgrp = tcgetpgrp(ttyfd)) < 0) {
out:
				out2str("sh: can't access tty; job control turned off\n");
				mflag = 0;
				return;
			}
			if (initialpgrp == -1)
				initialpgrp = getpgrp();
			else if (initialpgrp != getpgrp()) {
				killpg(0, SIGTTIN);
				continue;
			}
		} while (0);

#ifdef OLD_TTY_DRIVER
		if (ioctl(ttyfd, TIOCGETD, (char *)&ldisc) < 0
		    || ldisc != NTTYDISC) {
			out2str("sh: need new tty driver to run job control; job control turned off\n");
			mflag = 0;
			return;
		}
#endif
		setsignal(SIGTSTP, 0);
		setsignal(SIGTTOU, 0);
		setsignal(SIGTTIN, 0);
		if (getpgrp() != rootpid && setpgid(0, rootpid) == -1)
			error("Cannot set process group (%s) at %d",
			    strerror(errno), __LINE__);
		if (tcsetpgrp(ttyfd, rootpid) == -1)
			error("Cannot set tty process group (%s) at %d",
			    strerror(errno), __LINE__);
	} else { /* turning job control off */
		if (getpgrp() != initialpgrp && setpgid(0, initialpgrp) == -1)
			error("Cannot set process group (%s) at %d",
			    strerror(errno), __LINE__);
		if (tcsetpgrp(ttyfd, initialpgrp) == -1)
			error("Cannot set tty process group (%s) at %d",
			    strerror(errno), __LINE__);
		close(ttyfd);
		ttyfd = -1;
		setsignal(SIGTSTP, 0);
		setsignal(SIGTTOU, 0);
		setsignal(SIGTTIN, 0);
	}
	jobctl = on;
}
Example #4
0
int hbc::is_open(int fd)
{
    return fd && (fcntl(fd, F_GETFL) != -1 || errno != EBADF);
}
Example #5
0
static void lock_cachefile(int type)
{
	struct flock fl = {
		.l_len = 0,
		.l_start = 0,
		.l_whence = SEEK_SET,
	};

	fl.l_pid = getpid();
	fl.l_type = type;

	if (verbose)
		output(2, "waiting on lock for cachefile\n");

	if (fcntl(cachefile, F_SETLKW, &fl) == -1) {
		perror("fcntl F_SETLKW");
		return;
	}

	if (verbose)
		output(2, "took lock for cachefile\n");
}

static void unlock_cachefile(void)
{
	struct flock fl = {
		.l_len = 0,
		.l_start = 0,
		.l_whence = SEEK_SET,
	};

	fl.l_pid = getpid();
	fl.l_type = F_UNLCK;

	if (fcntl(cachefile, F_SETLK, &fl) == -1) {
		perror("fcntl F_UNLCK F_SETLK ");
		return;
	}

	if (verbose)
		output(2, "dropped lock for cachefile\n");
}

static unsigned int valid_proto(unsigned int family)
{
	const char *famstr;

	famstr = get_domain_name(family);

	/* Not used for creating sockets. */
	if (strncmp(famstr, "UNSPEC", 9) == 0)
		return FALSE;
	if (strncmp(famstr, "BRIDGE", 9) == 0)
		return FALSE;
	if (strncmp(famstr, "SECURITY", 11) == 0)
		return FALSE;

	/* Not actually implemented (or now removed). */
	if (strncmp(famstr, "NETBEUI", 10) == 0)
		return FALSE;
	if (strncmp(famstr, "ASH", 6) == 0)
		return FALSE;
	if (strncmp(famstr, "ECONET", 9) == 0)
		return FALSE;
	if (strncmp(famstr, "SNA", 6) == 0)
		return FALSE;
	if (strncmp(famstr, "WANPIPE", 10) == 0)
		return FALSE;

	/* Needs root. */
	if (orig_uid != 0) {
		if (strncmp(famstr, "KEY", 6) == 0)
			return FALSE;
		if (strncmp(famstr, "PACKET", 9) == 0)
			return FALSE;
		if (strncmp(famstr, "LLC", 6) == 0)
			return FALSE;
	}

	return TRUE;
}

static bool write_socket_to_cache(struct socket_triplet *st)
{
	unsigned int buffer[3];
	int n;

	if (cachefile == -1)
		return FALSE;

	buffer[0] = st->family;
	buffer[1] = st->type;
	buffer[2] = st->protocol;
	n = write(cachefile, &buffer, sizeof(int) * 3);
	if (n == -1) {
		outputerr("something went wrong writing the cachefile! : %s\n", strerror(errno));
		return FALSE;
	}
	return TRUE;
}

static bool generate_socket(unsigned int family, unsigned int protocol, unsigned int type)
{
	struct socket_triplet st;
	int fd;

	st.family = family;
	st.type = type;
	st.protocol = protocol;

	fd = open_socket(st.family, st.type, st.protocol);
	if (fd > -1) {
		write_socket_to_cache(&st);
		return TRUE;
	}
	output(2, "Couldn't open socket %d:%d:%d. %s\n", family, type, protocol, strerror(errno));
	return FALSE;
}

static bool generate_specific_socket(int family)
{
	struct socket_triplet st;
	int fd;

	st.family = family;

	BUG_ON(st.family >= ARRAY_SIZE(no_domains));
	if (no_domains[st.family])
		return FALSE;

	if (get_domain_name(st.family) == NULL)
		return FALSE;

	if (valid_proto(st.family) == FALSE) {
		outputerr("Can't do protocol %s\n", get_domain_name(st.family));
		return FALSE;
	}

	st.protocol = rnd() % 256;

	if (sanitise_socket_triplet(&st) == -1)
		rand_proto_type(&st);

	fd = open_socket(st.family, st.type, st.protocol);
	if (fd == -1) {
		output(0, "Couldn't open socket (%d:%d:%d). %s\n",
				st.family, st.type, st.protocol,
				strerror(errno));
		return FALSE;
	}

	return write_socket_to_cache(&st);
}

#define NR_SOCKET_FDS 50

static bool generate_sockets(void)
{
	int i, r, ret = FALSE;
	bool domains_disabled = FALSE;

	cachefile = creat(cachefilename, S_IWUSR|S_IRUSR);
	if (cachefile == -1) {
		outputerr("Couldn't open cachefile for writing! (%s)\n", strerror(errno));
		return FALSE;
	}
	lock_cachefile(F_WRLCK);

	if (do_specific_domain == TRUE) {
		while (nr_sockets < NR_SOCKET_FDS) {
			ret = generate_specific_socket(specific_domain);

			if (ret == FALSE)
				return FALSE;
		}
		goto out_unlock;
	}

	/*
	 * check if all domains are disabled.
	 */
	for (i = 0; i < (int)ARRAY_SIZE(no_domains); i++) {
		if (no_domains[i] == FALSE) {
			domains_disabled = FALSE;
			break;
		} else {
			domains_disabled = TRUE;
		}
	}

	if (domains_disabled == TRUE) {
		output(0, "All domains disabled!\n");
		goto out_unlock;
	}

	for (i = 0; i < TRINITY_PF_MAX; i++) {
		const struct netproto *proto = net_protocols[i].proto;
		struct socket_triplet *triplets;
		unsigned int j;

		if (no_domains[i] == TRUE)
			continue;

		/* check for ctrl-c again. */
		if (shm->exit_reason != STILL_RUNNING)
			goto out_unlock;

		if (proto == NULL)
			continue;
		if (proto->nr_triplets == 0)
			continue;

		triplets = proto->valid_triplets;
		for (j = 0; j < proto->nr_triplets; j++)
			ret |= generate_socket(triplets[j].family, triplets[j].protocol, triplets[j].type);

		if (proto->nr_privileged_triplets == 0)
			continue;

		if (orig_uid != 0)
			continue;

		triplets = proto->valid_privileged_triplets;
		for (j = 0; j < proto->nr_privileged_triplets; j++)
			ret |= generate_socket(triplets[j].family, triplets[j].protocol, triplets[j].type);
	}

	/* This is here temporarily until we have sufficient ->valid_proto's */
	while (nr_sockets < NR_SOCKET_FDS) {
		r = rnd() % TRINITY_PF_MAX;
		for (i = 0; i < 10; i++)
			generate_specific_socket(r);
	}

out_unlock:
	if (cachefile != -1) {
		unlock_cachefile();
		close(cachefile);
	}

	return ret;
}
Example #6
0
/* Creates a socket and listens on port 'port'.
 * Returns 1 on failure
 * Returns 0 on success.
 */
int mqtt3_socket_listen(struct _mqtt3_listener *listener)
{
	int sock = -1;
	struct addrinfo hints;
	struct addrinfo *ainfo, *rp;
	char service[10];
	int opt = 1;
#ifndef WIN32
	int ss_opt = 1;
#else
	char ss_opt = 1;
#endif
#ifdef WITH_TLS
	int rc;
	X509_STORE *store;
	X509_LOOKUP *lookup;
#endif
	char err[256];

	if(!listener) return MOSQ_ERR_INVAL;

	snprintf(service, 10, "%d", listener->port);
	memset(&hints, 0, sizeof(struct addrinfo));
	hints.ai_family = PF_UNSPEC;
	hints.ai_flags = AI_PASSIVE;
	hints.ai_socktype = SOCK_STREAM;

	if(getaddrinfo(listener->host, service, &hints, &ainfo)) return INVALID_SOCKET;

	listener->sock_count = 0;
	listener->socks = NULL;

	for(rp = ainfo; rp; rp = rp->ai_next){
		if(rp->ai_family == AF_INET){
			_mosquitto_log_printf(NULL, MOSQ_LOG_INFO, "Opening ipv4 listen socket on port %d.", ntohs(((struct sockaddr_in *)rp->ai_addr)->sin_port));
		}else if(rp->ai_family == AF_INET6){
			_mosquitto_log_printf(NULL, MOSQ_LOG_INFO, "Opening ipv6 listen socket on port %d.", ntohs(((struct sockaddr_in6 *)rp->ai_addr)->sin6_port));
		}else{
			continue;
		}

		sock = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol);
		if(sock == -1){
			strerror_r(errno, err, 256);
			_mosquitto_log_printf(NULL, MOSQ_LOG_WARNING, "Warning: %s", err);
			continue;
		}
		listener->sock_count++;
		listener->socks = _mosquitto_realloc(listener->socks, sizeof(int)*listener->sock_count);
		if(!listener->socks){
			_mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Out of memory.");
			return MOSQ_ERR_NOMEM;
		}
		listener->socks[listener->sock_count-1] = sock;

#ifndef WIN32
		ss_opt = 1;
		setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &ss_opt, sizeof(ss_opt));
#endif
		ss_opt = 1;
		setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY, &ss_opt, sizeof(ss_opt));


#ifndef WIN32
		/* Set non-blocking */
		opt = fcntl(sock, F_GETFL, 0);
		if(opt == -1 || fcntl(sock, F_SETFL, opt | O_NONBLOCK) == -1){
			/* If either fcntl fails, don't want to allow this client to connect. */
			COMPAT_CLOSE(sock);
			return 1;
		}
#else
		if(ioctlsocket(sock, FIONBIO, &opt)){
			COMPAT_CLOSE(sock);
			return 1;
		}
#endif

		if(bind(sock, rp->ai_addr, rp->ai_addrlen) == -1){
			strerror_r(errno, err, 256);
			_mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: %s", err);
			COMPAT_CLOSE(sock);
			return 1;
		}

		if(listen(sock, 100) == -1){
			strerror_r(errno, err, 256);
			_mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: %s", err);
			COMPAT_CLOSE(sock);
			return 1;
		}
	}
	freeaddrinfo(ainfo);

	/* We need to have at least one working socket. */
	if(listener->sock_count > 0){
#ifdef WITH_TLS
		if((listener->cafile || listener->capath) && listener->certfile && listener->keyfile){
			listener->ssl_ctx = SSL_CTX_new(TLSv1_server_method());
			if(!listener->ssl_ctx){
				_mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Unable to create TLS context.");
				COMPAT_CLOSE(sock);
				return 1;
			}
#if OPENSSL_VERSION_NUMBER >= 0x10000000
			/* Disable compression */
			SSL_CTX_set_options(listener->ssl_ctx, SSL_OP_NO_COMPRESSION);
#endif
#ifdef SSL_MODE_RELEASE_BUFFERS
			/* Use even less memory per SSL connection. */
			SSL_CTX_set_mode(listener->ssl_ctx, SSL_MODE_RELEASE_BUFFERS);
#endif
			if(listener->ciphers){
				rc = SSL_CTX_set_cipher_list(listener->ssl_ctx, listener->ciphers);
				if(rc == 0){
					_mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Unable to set TLS ciphers. Check cipher list \"%s\".", listener->ciphers);
					COMPAT_CLOSE(sock);
					return 1;
				}
			}
			rc = SSL_CTX_load_verify_locations(listener->ssl_ctx, listener->cafile, listener->capath);
			if(rc == 0){
				if(listener->cafile && listener->capath){
					_mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Unable to load CA certificates. Check cafile \"%s\" and capath \"%s\".", listener->cafile, listener->capath);
				}else if(listener->cafile){
					_mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Unable to load CA certificates. Check cafile \"%s\".", listener->cafile);
				}else{
					_mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Unable to load CA certificates. Check capath \"%s\".", listener->capath);
				}
				COMPAT_CLOSE(sock);
				return 1;
			}
			/* FIXME user data? */
			if(listener->require_certificate){
				SSL_CTX_set_verify(listener->ssl_ctx, SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT, client_certificate_verify);
			}else{
				SSL_CTX_set_verify(listener->ssl_ctx, SSL_VERIFY_PEER, client_certificate_verify);
			}
			rc = SSL_CTX_use_certificate_file(listener->ssl_ctx, listener->certfile, SSL_FILETYPE_PEM);
			if(rc != 1){
				_mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Unable to load server certificate \"%s\". Check certfile.", listener->certfile);
				COMPAT_CLOSE(sock);
				return 1;
			}
			rc = SSL_CTX_use_PrivateKey_file(listener->ssl_ctx, listener->keyfile, SSL_FILETYPE_PEM);
			if(rc != 1){
				_mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Unable to load server key file \"%s\". Check keyfile.", listener->keyfile);
				COMPAT_CLOSE(sock);
				return 1;
			}
			rc = SSL_CTX_check_private_key(listener->ssl_ctx);
			if(rc != 1){
				_mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Server certificate/key are inconsistent.");
				COMPAT_CLOSE(sock);
				return 1;
			}
			/* Load CRLs if they exist. */
			if(listener->crlfile){
				store = SSL_CTX_get_cert_store(listener->ssl_ctx);
				if(!store){
					_mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Unable to obtain TLS store.");
					COMPAT_CLOSE(sock);
					return 1;
				}
				lookup = X509_STORE_add_lookup(store, X509_LOOKUP_file());
				rc = X509_load_crl_file(lookup, listener->crlfile, X509_FILETYPE_PEM);
				if(rc != 1){
					_mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Unable to load certificate revocation file \"%s\". Check crlfile.", listener->crlfile);
					COMPAT_CLOSE(sock);
					return 1;
				}
				X509_STORE_set_flags(store, X509_V_FLAG_CRL_CHECK);
			}

#  ifdef WITH_TLS_PSK
		}else if(listener->psk_hint){
			if(tls_ex_index_context == -1){
				tls_ex_index_context = SSL_get_ex_new_index(0, "client context", NULL, NULL, NULL);
			}
			if(tls_ex_index_listener == -1){
				tls_ex_index_listener = SSL_get_ex_new_index(0, "listener", NULL, NULL, NULL);
			}

			listener->ssl_ctx = SSL_CTX_new(TLSv1_server_method());
			if(!listener->ssl_ctx){
				_mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Unable to create TLS context.");
				COMPAT_CLOSE(sock);
				return 1;
			}
			SSL_CTX_set_psk_server_callback(listener->ssl_ctx, psk_server_callback);
			if(listener->psk_hint){
				rc = SSL_CTX_use_psk_identity_hint(listener->ssl_ctx, listener->psk_hint);
				if(rc == 0){
					_mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Unable to set TLS PSK hint.");
					COMPAT_CLOSE(sock);
					return 1;
				}
			}
			if(listener->ciphers){
				rc = SSL_CTX_set_cipher_list(listener->ssl_ctx, listener->ciphers);
				if(rc == 0){
					_mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Unable to set TLS ciphers. Check cipher list \"%s\".", listener->ciphers);
					COMPAT_CLOSE(sock);
					return 1;
				}
			}
#  endif /* WITH_TLS_PSK */
		}
#endif /* WITH_TLS */
		return 0;
	}else{
		return 1;
	}
}
Example #7
0
int mqtt3_socket_accept(struct mosquitto_db *db, int listensock)
{
	int i;
	int j;
	int new_sock = -1;
	struct mosquitto **tmp_contexts = NULL;
	struct mosquitto *new_context;
	int opt = 1;
#ifdef WITH_TLS
	BIO *bio;
	int rc;
#endif
#ifdef WITH_WRAP
	struct request_info wrap_req;
	char address[1024];
#endif

	new_sock = accept(listensock, NULL, 0);
	if(new_sock == INVALID_SOCKET) return -1;

	g_socket_connections++;

#ifndef WIN32
	/* Set non-blocking */
	opt = fcntl(new_sock, F_GETFL, 0);
	if(opt == -1 || fcntl(new_sock, F_SETFL, opt | O_NONBLOCK) == -1){
		/* If either fcntl fails, don't want to allow this client to connect. */
		close(new_sock);
		return -1;
	}
#else
	if(ioctlsocket(new_sock, FIONBIO, &opt)){
		closesocket(new_sock);
		return INVALID_SOCKET;
	}
#endif

#ifdef WITH_WRAP
	/* Use tcpd / libwrap to determine whether a connection is allowed. */
	request_init(&wrap_req, RQ_FILE, new_sock, RQ_DAEMON, "mosquitto", 0);
	fromhost(&wrap_req);
	if(!hosts_access(&wrap_req)){
		/* Access is denied */
		if(!_mosquitto_socket_get_address(new_sock, address, 1024)){
			_mosquitto_log_printf(NULL, MOSQ_LOG_NOTICE, "Client connection from %s denied access by tcpd.", address);
		}
		COMPAT_CLOSE(new_sock);
		return -1;
	}else{
#endif
		new_context = mqtt3_context_init(new_sock);
		if(!new_context){
			COMPAT_CLOSE(new_sock);
			return -1;
		}
		for(i=0; i<db->config->listener_count; i++){
			for(j=0; j<db->config->listeners[i].sock_count; j++){
				if(db->config->listeners[i].socks[j] == listensock){
					new_context->listener = &db->config->listeners[i];
					break;
				}
			}
		}
		if(!new_context->listener){
			COMPAT_CLOSE(new_sock);
			return -1;
		}

		if(new_context->listener->max_connections > 0 && new_context->listener->client_count >= new_context->listener->max_connections){
			_mosquitto_log_printf(NULL, MOSQ_LOG_NOTICE, "Client connection from %s denied: max_connections exceeded.", new_context->address);
			COMPAT_CLOSE(new_sock);
			return -1;
		}
		_mosquitto_log_printf(NULL, MOSQ_LOG_NOTICE, "New connection from %s.", new_context->address);
		for(i=0; i<db->context_count; i++){
			if(db->contexts[i] == NULL){
				db->contexts[i] = new_context;
				break;
			}
		}
		if(i==db->context_count){
			tmp_contexts = _mosquitto_realloc(db->contexts, sizeof(struct mosquitto*)*(db->context_count+1));
			if(tmp_contexts){
				db->context_count++;
				db->contexts = tmp_contexts;
				db->contexts[db->context_count-1] = new_context;
			}else{
				mqtt3_context_cleanup(NULL, new_context, true);
			}
		}
		new_context->listener->client_count++;

#ifdef WITH_TLS
		/* TLS init */
		for(i=0; i<db->config->listener_count; i++){
			for(j=0; j<db->config->listeners[i].sock_count; j++){
				if(db->config->listeners[i].socks[j] == listensock){
					if(db->config->listeners[i].ssl_ctx){
						new_context->ssl = SSL_new(db->config->listeners[i].ssl_ctx);
						if(!new_context->ssl){
							COMPAT_CLOSE(new_sock);
							return -1;
						}
						SSL_set_ex_data(new_context->ssl, tls_ex_index_context, new_context);
						SSL_set_ex_data(new_context->ssl, tls_ex_index_listener, &db->config->listeners[i]);
						new_context->want_read = true;
						new_context->want_write = true;
						bio = BIO_new_socket(new_sock, BIO_NOCLOSE);
						SSL_set_bio(new_context->ssl, bio, bio);
						rc = SSL_accept(new_context->ssl);
						if(rc != 1){
							rc = SSL_get_error(new_context->ssl, rc);
							if(rc == SSL_ERROR_WANT_READ){
								new_context->want_read = true;
							}else if(rc == SSL_ERROR_WANT_WRITE){
								new_context->want_write = true;
							}
						}
					}
				}
			}
		}
#endif

#ifdef WITH_WRAP
	}
#endif
	return new_sock;
}
Example #8
0
/**
 * Create a non-blocking socket.  Disable SIGPIPE for TCP sockets if
 * possible.  On Linux it's not possible and should be disabled for
 * each send(2) individually.
 */
static SOCKET
proxy_create_socket(int sdom, int stype)
{
    SOCKET s;
    int stype_and_flags;
    int status;

    LWIP_UNUSED_ARG(status);    /* depends on ifdefs */


    stype_and_flags = stype;

#if defined(SOCK_NONBLOCK)
    stype_and_flags |= SOCK_NONBLOCK;
#endif

    /*
     * Disable SIGPIPE on disconnected socket.  It might be easier to
     * forgo it and just use MSG_NOSIGNAL on each send*(2), since we
     * have to do it for Linux anyway, but Darwin does NOT have that
     * flag (but has SO_NOSIGPIPE socket option).
     */
#if !defined(SOCK_NOSIGPIPE) && !defined(SO_NOSIGPIPE) && !defined(MSG_NOSIGNAL)
#if 0 /* XXX: Solaris has neither, the program should ignore SIGPIPE globally */
#error Need a way to disable SIGPIPE on connection oriented sockets!
#endif
#endif

#if defined(SOCK_NOSIGPIPE)
    if (stype == SOCK_STREAM) {
        stype_and_flags |= SOCK_NOSIGPIPE;
    }
#endif

    s = socket(sdom, stype_and_flags, 0);
    if (s == INVALID_SOCKET) {
        perror("socket");
        return INVALID_SOCKET;
    }

#if !defined(SOCK_NONBLOCK) && !defined(RT_OS_WINDOWS)
    {
        int sflags;

        status = fcntl(s, F_GETFL, &sflags);
        if (status < 0) {
            perror("F_GETFL");
            closesocket(s);
            return INVALID_SOCKET;
        }

        status = fcntl(s, F_SETFL, sflags | O_NONBLOCK);
        if (status < 0) {
            perror("O_NONBLOCK");
            closesocket(s);
            return INVALID_SOCKET;
        }
    }
#endif

#if !defined(SOCK_NOSIGPIPE) && defined(SO_NOSIGPIPE)
    if (stype == SOCK_STREAM) {
        int on = 1;
        const socklen_t onlen = sizeof(on);

        status = setsockopt(s, SOL_SOCKET, SO_NOSIGPIPE, &on, onlen);
        if (status < 0) {
            perror("SO_NOSIGPIPE");
            closesocket(s);
            return INVALID_SOCKET;
        }
    }
#endif

#if defined(RT_OS_WINDOWS)
    {
        u_long mode = 0;
        status = ioctlsocket(s, FIONBIO, &mode);
        if (status == SOCKET_ERROR) {
            warn("ioctl error: %d\n", WSAGetLastError());
            return INVALID_SOCKET;
        }
    }
#endif

    return s;
}
Example #9
0
int net_init_tap(const NetClientOptions *opts, const char *name,
                 NetClientState *peer, Error **errp)
{
    const NetdevTapOptions *tap;
    int fd, vnet_hdr = 0, i = 0, queues;
    /* for the no-fd, no-helper case */
    const char *script = NULL; /* suppress wrong "uninit'd use" gcc warning */
    const char *downscript = NULL;
    Error *err = NULL;
    const char *vhostfdname;
    char ifname[128];

    assert(opts->type == NET_CLIENT_OPTIONS_KIND_TAP);
    tap = opts->u.tap.data;
    queues = tap->has_queues ? tap->queues : 1;
    vhostfdname = tap->has_vhostfd ? tap->vhostfd : NULL;

    /* QEMU vlans does not support multiqueue tap, in this case peer is set.
     * For -netdev, peer is always NULL. */
    if (peer && (tap->has_queues || tap->has_fds || tap->has_vhostfds)) {
        error_setg(errp, "Multiqueue tap cannot be used with QEMU vlans");
        return -1;
    }

    if (tap->has_fd) {
        if (tap->has_ifname || tap->has_script || tap->has_downscript ||
            tap->has_vnet_hdr || tap->has_helper || tap->has_queues ||
            tap->has_fds || tap->has_vhostfds) {
            error_setg(errp, "ifname=, script=, downscript=, vnet_hdr=, "
                       "helper=, queues=, fds=, and vhostfds= "
                       "are invalid with fd=");
            return -1;
        }

        fd = monitor_fd_param(cur_mon, tap->fd, &err);
        if (fd == -1) {
            error_propagate(errp, err);
            return -1;
        }

        fcntl(fd, F_SETFL, O_NONBLOCK);

        vnet_hdr = tap_probe_vnet_hdr(fd);

        net_init_tap_one(tap, peer, "tap", name, NULL,
                         script, downscript,
                         vhostfdname, vnet_hdr, fd, &err);
        if (err) {
            error_propagate(errp, err);
            return -1;
        }
    } else if (tap->has_fds) {
        char **fds = g_new(char *, MAX_TAP_QUEUES);
        char **vhost_fds = g_new(char *, MAX_TAP_QUEUES);
        int nfds, nvhosts;

        if (tap->has_ifname || tap->has_script || tap->has_downscript ||
            tap->has_vnet_hdr || tap->has_helper || tap->has_queues ||
            tap->has_vhostfd) {
            error_setg(errp, "ifname=, script=, downscript=, vnet_hdr=, "
                       "helper=, queues=, and vhostfd= "
                       "are invalid with fds=");
            return -1;
        }

        nfds = get_fds(tap->fds, fds, MAX_TAP_QUEUES);
        if (tap->has_vhostfds) {
            nvhosts = get_fds(tap->vhostfds, vhost_fds, MAX_TAP_QUEUES);
            if (nfds != nvhosts) {
                error_setg(errp, "The number of fds passed does not match "
                           "the number of vhostfds passed");
                return -1;
            }
        }

        for (i = 0; i < nfds; i++) {
            fd = monitor_fd_param(cur_mon, fds[i], &err);
            if (fd == -1) {
                error_propagate(errp, err);
                return -1;
            }

            fcntl(fd, F_SETFL, O_NONBLOCK);

            if (i == 0) {
                vnet_hdr = tap_probe_vnet_hdr(fd);
            } else if (vnet_hdr != tap_probe_vnet_hdr(fd)) {
                error_setg(errp,
                           "vnet_hdr not consistent across given tap fds");
                return -1;
            }

            net_init_tap_one(tap, peer, "tap", name, ifname,
                             script, downscript,
                             tap->has_vhostfds ? vhost_fds[i] : NULL,
                             vnet_hdr, fd, &err);
            if (err) {
                error_propagate(errp, err);
                return -1;
            }
        }
        g_free(fds);
        g_free(vhost_fds);
    } else if (tap->has_helper) {
Example #10
0
static int stream_connectL(lua_State *L) {

	/*
	 * 1: self
	 * 2: server_ip
	 * 3: server_port
	 */

	struct sockaddr_in serv_addr;
	struct stream *stream;
	int flags;
	int err;
	socket_t fd;

	/* Server address and port */
	memset(&serv_addr, 0, sizeof(serv_addr));
	if (lua_type(L, 2) == LUA_TSTRING) {
		serv_addr.sin_addr.s_addr = inet_addr(luaL_checkstring(L, 2));
	}
	else {
		serv_addr.sin_addr.s_addr = htonl(luaL_checkinteger(L, 2));
	}
	serv_addr.sin_port = htons(luaL_checkinteger(L, 3));
	serv_addr.sin_family = AF_INET;


	LOG_DEBUG(log_audio_decode, "streambuf connect %s:%d", inet_ntoa(serv_addr.sin_addr), ntohs(serv_addr.sin_port));

	/* Create socket */
	fd = socket(AF_INET, SOCK_STREAM, 0);
	if (fd == INVALID_SOCKET) {
		lua_pushnil(L);
		lua_pushstring(L, strerror(SOCKETERROR));
		return 2;
	}

	/* Make socket non-blocking */
#if defined(WIN32)
	{
		u_long iMode = 0;
		flags = ioctlsocket(fd, FIONBIO, &iMode);
	}
#else
	flags = fcntl(fd, F_GETFL, 0);
	flags |= O_NONBLOCK;
	fcntl(fd, F_SETFL, flags);
#endif

	/* Connect socket */
	err = connect(fd, (struct sockaddr *)&serv_addr, sizeof(serv_addr));
	if (err != 0
#if !defined(WIN32)
		&&  SOCKETERROR != EINPROGRESS
#endif
		) {
		CLOSESOCKET(fd);

		lua_pushnil(L);
		lua_pushstring(L, strerror(SOCKETERROR));
		return 2;
	}

	/* Stream object */
	stream = lua_newuserdata(L, sizeof(struct stream));

	memset(stream, 0, sizeof(*stream));
	stream->fd = fd;

	luaL_getmetatable(L, "squeezeplay.stream");
	lua_setmetatable(L, -2);

	fifo_lock(&streambuf_fifo);

	streambuf_loop = FALSE;
	streambuf_bytes_received = 0;
	streambuf_copyright = FALSE;
	streambuf_filter = streambuf_next_filter;
	streambuf_next_filter = NULL;

	fifo_unlock(&streambuf_fifo);

	return 1;
}
Example #11
0
File: net.c Project: neevor/babeld
int
babel_socket(int port)
{
    struct sockaddr_in6 sin6;
    int s, rc;
    int saved_errno;
    int one = 1, zero = 0;
    const int ds = 0xc0;        /* CS6 - Network Control */

    s = socket(PF_INET6, SOCK_DGRAM, 0);
    if(s < 0)
        return -1;

    rc = setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY, &one, sizeof(one));
    if(rc < 0)
        goto fail;

    rc = setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one));
    if(rc < 0)
        goto fail;

    rc = setsockopt(s, IPPROTO_IPV6, IPV6_MULTICAST_LOOP,
                    &zero, sizeof(zero));
    if(rc < 0)
        goto fail;

    rc = setsockopt(s, IPPROTO_IPV6, IPV6_UNICAST_HOPS,
                    &one, sizeof(one));
    if(rc < 0)
        goto fail;

    rc = setsockopt(s, IPPROTO_IPV6, IPV6_MULTICAST_HOPS,
                    &one, sizeof(one));
    if(rc < 0)
        goto fail;

#ifdef IPV6_TCLASS
    rc = setsockopt(s, IPPROTO_IPV6, IPV6_TCLASS, &ds, sizeof(ds));
#else
    rc = -1;
    errno = ENOSYS;
#endif
    if(rc < 0)
        perror("Couldn't set traffic class");

    rc = fcntl(s, F_GETFL, 0);
    if(rc < 0)
        goto fail;

    rc = fcntl(s, F_SETFL, (rc | O_NONBLOCK));
    if(rc < 0)
        goto fail;

    rc = fcntl(s, F_GETFD, 0);
    if(rc < 0)
        goto fail;

    rc = fcntl(s, F_SETFD, rc | FD_CLOEXEC);
    if(rc < 0)
        goto fail;

    memset(&sin6, 0, sizeof(sin6));
    sin6.sin6_family = AF_INET6;
    sin6.sin6_port = htons(port);
    rc = bind(s, (struct sockaddr*)&sin6, sizeof(sin6));
    if(rc < 0)
        goto fail;

    return s;

 fail:
    saved_errno = errno;
    close(s);
    errno = saved_errno;
    return -1;
}
static int read_request(int fd, debugger_request_t* out_request) {
  ucred cr;
  socklen_t len = sizeof(cr);
  int status = getsockopt(fd, SOL_SOCKET, SO_PEERCRED, &cr, &len);
  if (status != 0) {
    ALOGE("cannot get credentials");
    return -1;
  }

  ALOGV("reading tid");
  fcntl(fd, F_SETFL, O_NONBLOCK);

  pollfd pollfds[1];
  pollfds[0].fd = fd;
  pollfds[0].events = POLLIN;
  pollfds[0].revents = 0;
  status = TEMP_FAILURE_RETRY(poll(pollfds, 1, 3000));
  if (status != 1) {
    ALOGE("timed out reading tid (from pid=%d uid=%d)\n", cr.pid, cr.uid);
    return -1;
  }

  debugger_msg_t msg;
  memset(&msg, 0, sizeof(msg));
  status = TEMP_FAILURE_RETRY(read(fd, &msg, sizeof(msg)));
  if (status < 0) {
    ALOGE("read failure? %s (pid=%d uid=%d)\n", strerror(errno), cr.pid, cr.uid);
    return -1;
  }
  if (status != sizeof(debugger_msg_t)) {
    ALOGE("invalid crash request of size %d (from pid=%d uid=%d)\n", status, cr.pid, cr.uid);
    return -1;
  }

  out_request->action = static_cast<debugger_action_t>(msg.action);
  out_request->tid = msg.tid;
  out_request->pid = cr.pid;
  out_request->uid = cr.uid;
  out_request->gid = cr.gid;
  out_request->abort_msg_address = msg.abort_msg_address;
  out_request->original_si_code = msg.original_si_code;

  if (msg.action == DEBUGGER_ACTION_CRASH) {
    // Ensure that the tid reported by the crashing process is valid.
    char buf[64];
    struct stat s;
    snprintf(buf, sizeof buf, "/proc/%d/task/%d", out_request->pid, out_request->tid);
    if (stat(buf, &s)) {
      ALOGE("tid %d does not exist in pid %d. ignoring debug request\n",
          out_request->tid, out_request->pid);
      return -1;
    }
  } else if (cr.uid == 0
            || (cr.uid == AID_SYSTEM && msg.action == DEBUGGER_ACTION_DUMP_BACKTRACE)) {
    // Only root or system can ask us to attach to any process and dump it explicitly.
    // However, system is only allowed to collect backtraces but cannot dump tombstones.
    status = get_process_info(out_request->tid, &out_request->pid,
                              &out_request->uid, &out_request->gid);
    if (status < 0) {
      ALOGE("tid %d does not exist. ignoring explicit dump request\n", out_request->tid);
      return -1;
    }

    if (!selinux_action_allowed(fd, out_request))
      return -1;
  } else {
    // No one else is allowed to dump arbitrary processes.
    return -1;
  }
  return 0;
}
Example #13
0
//*********************************************************
int server(void)
{
	struct sockaddr_in monadr, sonadr;
	int fd, opt=1, taille;
	int serv_sock, client_sock;
   int nb_lu;	
	int nfds;
	fd_set rfds, afds;
	int error;
	
	char message[20]="";
	char response[20]="";
	
	MyLog("Create server ...\n");
	serv_sock = socket(PF_INET, SOCK_STREAM, 0);
	setsockopt(serv_sock, SOL_SOCKET, SO_REUSEADDR,(char *) &opt, sizeof(opt));
	
	/* init socket serveur */
	bzero( (char *)&monadr, sizeof monadr);
	monadr.sin_family = AF_INET;
	monadr.sin_port = htons(PORT);
	monadr.sin_addr.s_addr = INADDR_ANY;

	if( bind(serv_sock, (struct sockaddr *)&monadr, sizeof(monadr)) == -1 ) {
		return(1);
	}

	if( listen(serv_sock, MAXCONN) == -1 ) {
		return(1);
	}
	
	/* init sockets list*/
	nfds = getdtablesize();
	FD_ZERO(&afds);
	FD_SET(serv_sock, &afds);

	/* gestion des clients */
	while(!Terminated) 
	{
		memcpy(&rfds, &afds, sizeof(rfds));
		if( select(nfds, &rfds, 0, 0, 0) == -1 ) 
			{/* signaux non bloquants */
				if( errno == EINTR ) continue;
				return(1);
			}
		if( FD_ISSET(serv_sock, &rfds) ) /* New connection ?*/
			{
				taille = sizeof sonadr;
				if( (client_sock = accept(serv_sock, (struct sockaddr *)&sonadr,(socklen_t *)&taille)) == -1 ) 
					{
						return(1);
					}
				//syslog(LOG_NOTICE,"client connection from %s \n", inet_ntoa(sonadr.sin_addr));
				fflush(stdout);
				FD_SET(client_sock, &afds);
				fcntl(client_sock, F_SETFL, O_NONBLOCK | fcntl(client_sock, F_GETFL, 0));
			}
		/* Tester si les sockets clientes ont boug�s */
		for( fd=0; fd<nfds; fd++ ) {
			if( fd != serv_sock && FD_ISSET(fd, &rfds) ) {
				/* traiter le client */
				strcpy(message,"");
				strcpy(response,"");
				nb_lu = read(fd, message, BUFSIZE);
				//MyLog("nb_lu : %d/%d/%d\n",nb_lu,strlen(message),fd);
				if( nb_lu > 0 ) {
					message[nb_lu]='\0';
					if ((error=read_socket(message,response))!=SUCCES) {
						sprintf(response,"error :%d\n",error);
					}
					strcat(response,"\n");
					write(fd, response, strlen(response));
				} else {
					close(fd);
					FD_CLR(fd, &afds);
				}
			}
		}
	}
	return(0);
}
Example #14
0
static int open_device(uart_ctx_t* ctx, char* name, size_t max_namelen)
{
    int flags;
    int tty_fd = -1;
    int fd     = -1;

    if (strcmp(name, "//pty") == 0) {
#ifdef HAVE_PTY
	char slave_name[UART_MAX_DEVICE_NAME];
	
	if ((fd = local_openpt(O_RDWR|O_NOCTTY)) < 0) { 
	    DEBUGF("posix_openpt failed : %s", strerror(errno));
	    return -1;
	}
	if (grantpt(fd) < 0) {
	    DEBUGF("grantpt failed : %s", strerror(errno));
	    goto error;
	}
	if (unlockpt(fd) < 0) {
	    DEBUGF("unlockpt failed : %s", strerror(errno));
	    goto error;
	}
	if (local_ptsname_r(fd, slave_name, sizeof(slave_name)) < 0) {
	    DEBUGF("ptsname_r failed : %s", strerror(errno));
	    goto error;
	}
	if (strlen(slave_name) >= max_namelen) {
	    errno = ERANGE;
	    goto error;
	}
	strcpy(name, slave_name);
	if ((flags = fcntl(fd, F_GETFL, 0)) < 0) {
	    DEBUGF("fcntl: F_GETFL failed : %s", strerror(errno));
	    goto error;
	}
	if (fcntl(fd, F_SETFL, flags | O_NONBLOCK) < 0) {
	    DEBUGF("fcntl: F_SETFL failed : %s", strerror(errno));
	    goto error;
	}
#else
	errno = ENOTSUP;
	return -1;
#endif
    }
    if ((tty_fd = open(name, O_RDWR|O_NDELAY|O_NOCTTY)) < 0)
	goto error;
    // non-blocking!!!
    if ((flags = fcntl(tty_fd, F_GETFL, 0)) < 0) {
	DEBUGF("fcntl: F_GETFL tty_fd failed : %s", strerror(errno));
	goto error;
    }
    if (fcntl(tty_fd, F_SETFL, flags | O_NONBLOCK) < 0) {
	DEBUGF("fcntl: F_SETFL tty_fd failed : %s", strerror(errno));
	goto error;
    }
    tcflush(tty_fd, TCOFLUSH);
    tcflush(tty_fd, TCIFLUSH);
    ctx->tty_fd = tty_fd;
    ctx->fd = (fd>=0) ? fd : tty_fd;
    DEBUGF("open_device: tty_fd=%d fd=%d", ctx->tty_fd, ctx->fd);
    return tty_fd;
error:
    {
	int save_errno = errno;
	if (fd >= 0) close(fd);
	if ((fd != tty_fd) && (tty_fd >= 0)) close(tty_fd);
	errno = save_errno;	    
    }
    return -1;
}