Пример #1
0
static int select_poll(int maxfdp1, fd_set *readset, fd_set *writeset, fd_set *exceptset) {
	int i, cnt, s;
	fd_set nr, nw;

	FD_ZERO(&nr);
	FD_ZERO(&nw);

	// Go through and look for FDs we need to service.
	cnt = 0;
	for (i=0; i<maxfdp1; i++) {
		if (readset && FD_ISSET(i, readset)) {
			// Convert to a socket #
			s = sock_for_fd(i);
			if (s < 0) continue;
		
			// Don't screw with things that are locked
			if (mutex_is_locked(fds[s].mutex))
				continue;

			// If it's a listen socket, look for used connections.
			if (fds[s].conns) {
				if (fds[s].conncnt > 0) {
					FD_SET(i, &nr);
					cnt++;
				}
			} else {
				// Any data available? Or socket dead?
				if (fds[s].recv != 0) {
					FD_SET(i, &nr);
					cnt++;
				}
			}
		}

		if (writeset && FD_ISSET(i, writeset)) {
			// Convert to a socket #
			s = sock_for_fd(i);
			if (s < 0) continue;
		
			// Don't screw with things that are locked
			if (mutex_is_locked(fds[s].mutex))
				continue;

			// Any buffer space available? Or socket dead?
			if (fds[s].send != 0) {
				FD_SET(i, &nw);
				cnt++;
			}
		}
	}

	if (cnt > 0) {
		if (readset)
			memcpy(readset, &nr, sizeof(fd_set));
		if (writeset)
			memcpy(writeset, &nw, sizeof(fd_set));
	}

	return cnt;
}
Пример #2
0
int lwip_bind(int s, struct sockaddr *name, socklen_t namelen) {
	sockfd_t	* fd;
	struct ip_addr	ip;
	int		port, rv = 0;

	s = sock_for_fd(s);
	if (s < 0) {
		errno = EBADF;
		return -1;
	}
	fd = fds + s;

	// Make sure it's an internet address we understand.
	if (namelen != sizeof(struct sockaddr_in)) {
		errno = ENAMETOOLONG;
		return -1;
	}

	// Get access
	mutex_lock(fd->mutex);

	// Copy it over
	memcpy(&fd->name, name, namelen);

	// Convert this to an lwIP-happy format
	ip.addr = ((struct sockaddr_in *)name)->sin_addr.s_addr;
	port = ((struct sockaddr_in *)name)->sin_port;

	// Are we TCP or UDP?
	switch (fd->type) {
	case SOCK_STREAM:
		fd->tcppcb = tcp_new();
		tcp_arg(fd->tcppcb, (void *)s);
		tcp_recv(fd->tcppcb, recv_tcp);
		tcp_sent(fd->tcppcb, sent_tcp);
		tcp_poll(fd->tcppcb, poll_tcp, 4);	// 4 == 4 TCP timer intervals
		tcp_err(fd->tcppcb, err_tcp);
		if (tcp_bind(fd->tcppcb, &ip, ntohs(port)) != ERR_OK) {
			if (tcp_close(fd->tcppcb) != ERR_OK)
				tcp_abort(fd->tcppcb);
			fd->tcppcb = NULL;
			errno = EINVAL;
			rv = -1; goto out;
		}
		break;
	case SOCK_DGRAM:
		fd->udppcb = udp_new();
		udp_recv(fd->udppcb, recv_udp, (void *)s);
		udp_bind(fd->udppcb, &ip, ntohs(port));
		break;
	default:
		assert( 0 );
		errno = EINVAL;
		rv = -1; goto out;
	}

out:
	mutex_unlock(fd->mutex);
	return rv;
}
Пример #3
0
int lwip_listen(int s, int backlog) {
	struct tcp_pcb	* npcb;
	sockfd_t	* fd;
	int		rv = 0, i;

	s = sock_for_fd(s);
	if (s < 0) {
		errno = EBADF;
		return -1;
	}
	fd = fds + s;

	// Get access
	mutex_lock(fd->mutex);

	// Is it the right type?
	if (fd->type != SOCK_STREAM) {
		errno = EOPNOTSUPP;
		rv = -1; goto out;
	}

	// Verify that someone has called bind() on this socket.
	if (!fd->tcppcb) {
		// XXX Is this the right error?
		errno = EOPNOTSUPP;
		rv = -1; goto out;
	}

	// Make sure we're not already listening.
	if (fd->conns) {
		errno = EINVAL;
		rv = -1; goto out;
	}

	// Setup a listen block. We get a new one back here.
	npcb = tcp_listen(fd->tcppcb);
	if (!npcb) {
		errno = EADDRINUSE;
		rv = -1; goto out;
	}

	// Set the new pcb
	fd->tcppcb = npcb;

	// Init the connection count
	fd->conncnt = 0;
	fd->connmax = backlog;
	fd->conns = malloc(backlog * sizeof(int));
	for (i=0; i<backlog; i++)
		fd->conns[i] = -1;

	// Setup our accept callback
	tcp_accept(fd->tcppcb, accept_tcp);

out:
	mutex_unlock(fd->mutex);
	return rv;
}
Пример #4
0
int lwip_send(int s, const void *mem, int size, unsigned int flags) {
	s = sock_for_fd(s);
	if (s < 0) {
		errno = EBADF;
		return -1;
	}

	return send_common(s, mem, size, flags);
}
Пример #5
0
int lwip_recv(int s, void *mem, int len, unsigned int flags) {
	s = sock_for_fd(s);
	if (s < 0) {
		errno = EBADF;
		return -1;
	}

	return recv_common(s, mem, len, flags, 1);
}
Пример #6
0
static VALUE
my_connect(VALUE klass, int io_wait, int domain,
	const void *addr, socklen_t addrlen)
{
	int fd = my_socket(domain);

	if (connect(fd, addr, addrlen) < 0) {
		if (errno == EINPROGRESS) {
			VALUE io = sock_for_fd(klass, fd);

			if (io_wait) {
				errno = EAGAIN;
				(void)kgio_call_wait_writable(io);
			}
			return io;
		}
		close_fail(fd, "connect");
	}
	return sock_for_fd(klass, fd);
}
Пример #7
0
static VALUE
my_connect(VALUE klass, int io_wait, int domain, void *addr, socklen_t addrlen)
{
	int fd = socket(domain, MY_SOCK_STREAM, 0);

	if (fd == -1) {
		switch (errno) {
		case EMFILE:
		case ENFILE:
#ifdef ENOBUFS
		case ENOBUFS:
#endif /* ENOBUFS */
			errno = 0;
			rb_gc();
			fd = socket(domain, MY_SOCK_STREAM, 0);
		}
		if (fd == -1)
			rb_sys_fail("socket");
	}

#ifndef SOCK_NONBLOCK
	if (fcntl(fd, F_SETFL, O_RDWR | O_NONBLOCK) == -1)
		close_fail(fd, "fcntl(F_SETFL, O_RDWR | O_NONBLOCK)");
#endif /* SOCK_NONBLOCK */

	if (connect(fd, addr, addrlen) == -1) {
		if (errno == EINPROGRESS) {
			VALUE io = sock_for_fd(klass, fd);

			if (io_wait) {
				errno = EAGAIN;
				(void)kgio_call_wait_writable(io);
			}
			return io;
		}
		close_fail(fd, "connect");
	}
	return sock_for_fd(klass, fd);
}
Пример #8
0
// This is a super hacky implementation of recvfrom (and below, sendto).
// It assumes that send/recv are used on TCP only and recvfrom/sendto are
// used on UDP only. This really needs to be fixed eventually.
int lwip_recvfrom(int s, void *mem, int len, unsigned int flags,
	struct sockaddr *from, socklen_t *fromlen)
{
	s = sock_for_fd(s);
	if (s < 0) {
		errno = EBADF;
		return -1;
	}

	// XXX from / fromlen aren't filled in.

	return recv_common(s, mem, len, flags, 0);
}
Пример #9
0
static VALUE
my_accept(struct accept_args *a, int force_nonblock)
{
	int client_fd;
	VALUE client_io;
	int retried = 0;

retry:
	client_fd = thread_accept(a, force_nonblock);
	if (client_fd == -1) {
		switch (errno) {
		case EAGAIN:
			if (force_nonblock)
				return Qnil;
			a->fd = my_fileno(a->accept_io);
			set_blocking_or_block(a->fd);
#ifdef ECONNABORTED
		case ECONNABORTED:
#endif /* ECONNABORTED */
#ifdef EPROTO
		case EPROTO:
#endif /* EPROTO */
		case EINTR:
			a->fd = my_fileno(a->accept_io);
			goto retry;
		case ENOMEM:
		case EMFILE:
		case ENFILE:
#ifdef ENOBUFS
		case ENOBUFS:
#endif /* ENOBUFS */
			if (!retried) {
				retried = 1;
				errno = 0;
				rb_gc();
				goto retry;
			}
		default:
			rb_sys_fail("accept");
		}
	}
	client_io = sock_for_fd(a->accepted_class, client_fd);
	post_accept(a->accept_io, client_io);

	if (a->addr)
		in_addr_set(client_io,
		            (struct sockaddr_storage *)a->addr, *a->addrlen);
	else
		rb_ivar_set(client_io, iv_kgio_addr, localhost);
	return client_io;
}
Пример #10
0
int lwip_accept(int s, struct sockaddr *addr, socklen_t *addrlen) {
	sockfd_t	* fd;
	int		rv = 0, i, ns;

	s = sock_for_fd(s);
	if (s < 0) {
		errno = EBADF;
		return -1;
	}
	fd = fds + s;

	// Make sure it's an internet address we understand.
	if (addrlen && *addrlen != sizeof(struct sockaddr_in)) {
		errno = ENAMETOOLONG;
		return -1;
	}

	// Get access
	mutex_lock(fd->mutex);

	// Is it the right type?
	if (fd->type != SOCK_STREAM) {
		errno = EINVAL;
		rv = -1; goto out;
	}

	// Loop until we've got one
	while (fd->conncnt <= 0) {
		// Make sure we're listen()'ing
		if (fd->conncnt < 0) {
			///
			rv = -1; goto out;
		}

		// Wait for a connection
		// printf("lwip_accept(%d): waiting\n", s);
		cond_wait(fd->connect, fd->mutex);
	}

	// Ok, we've got a connection. Find the first available one
	// in the list and we'll take it.
	for (i=0; i<fd->connmax; i++) {
		if (fd->conns[i] >= 0) break;
	}
	if (i >= fd->connmax) {
		// This shouldn't happen...
		assert( 0 );
		errno = EAGAIN;
		goto out;
	}

	ns = fd->conns[i];
	fd->conns[i] = -1; fd->conncnt--;

	// Copy out the peer address as well
	if (addr)
		memcpy(addr, &fds[ns].name, sizeof(struct sockaddr_in));
	if (addrlen)
		*addrlen = sizeof(struct sockaddr_in);

	// Ok, everything should be ready to go! Just need to make a VFS
	// fd for this socket.
	rv = fs_open_handle(&socketvfs, (void *)(ns + 1));
	if (rv < 0) {
		close_common(ns);
	}

out:
	mutex_unlock(fd->mutex);
	return rv;
}
Пример #11
0
int lwip_connect(int s, struct sockaddr *name, socklen_t namelen) {
	sockfd_t	* fd;
	struct ip_addr	ip;
	int		port, rv = 0;

	s = sock_for_fd(s);
	if (s < 0) {
		errno = EBADF;
		return -1;
	}
	fd = fds + s;

	// Make sure it's an internet address we understand.
	if (namelen != sizeof(struct sockaddr_in)) {
		errno = ENAMETOOLONG;
		return -1;
	}

	// Get access
	mutex_lock(fd->mutex);

	// Copy it over
	memcpy(&fd->name, name, namelen);

	// Convert this to an lwIP-happy format
	ip.addr = ((struct sockaddr_in *)name)->sin_addr.s_addr;
	port = ((struct sockaddr_in *)name)->sin_port;

	// Are we TCP or UDP?
	switch (fd->type) {
	case SOCK_STREAM:
		// This might have gotten made already, bind is valid on
		// outgoing sockets too.
		if (!fd->tcppcb)
			fd->tcppcb = tcp_new();
		tcp_arg(fd->tcppcb, (void *)s);
		tcp_recv(fd->tcppcb, recv_tcp);
		tcp_sent(fd->tcppcb, sent_tcp);
		tcp_poll(fd->tcppcb, poll_tcp, 4);	// 4 == 4 TCP timer intervals
		tcp_err(fd->tcppcb, err_tcp);
		if (tcp_connect(fd->tcppcb, &ip, ntohs(port), connect_tcp) != ERR_OK) {
			if (tcp_close(fd->tcppcb) != ERR_OK)
				tcp_abort(fd->tcppcb);
			fd->tcppcb = NULL;
			errno = EINVAL;
			rv = -1; goto out;
		}
		break;
	case SOCK_DGRAM:
		// This might have gotten made already, bind is valid on
		// outgoing sockets too.
		if (!fd->udppcb)
			fd->udppcb = udp_new();
		udp_recv(fd->udppcb, recv_udp, (void *)s);
		udp_connect(fd->udppcb, &ip, ntohs(port));
		break;
	default:
		assert( 0 );
		errno = EINVAL;
		rv = -1; goto out;
	}

	// If we are doing a TCP connect, we need to wait for the results
	// of the operation.
	if (fd->type == SOCK_STREAM) {
		// Wait for the result
		fd->connerr = 10;
		while (fd->connerr > 0) {
			cond_wait(fd->connect, fd->mutex);
		}

		// Convert error codes
		switch (fd->connerr) {
		case ERR_OK: break;
		
		case ERR_MEM:
		case ERR_BUF:
		case ERR_VAL:
		case ERR_ARG:
		case ERR_IF:
			errno = EINVAL;
			rv = -1;
			goto out;

		case ERR_ABRT:
		case ERR_RST:
		case ERR_CLSD:
		case ERR_CONN:
			errno = ECONNREFUSED;
			rv = -1;
			goto out;

		case ERR_RTE:
			errno = ENETUNREACH;
			rv = -1;
			goto out;

		case ERR_USE:
			errno = EADDRINUSE;
			rv = -1;
			goto out;
		}

		if (fd->connerr == ERR_OK) {
			// Init our counters
			fd->recv = 0;
			fd->send = tcp_sndbuf(fd->tcppcb);
		}
	}

out:
	mutex_unlock(fd->mutex);
	return rv;
}
Пример #12
0
int lwip_sendto(int s, const void *dataptr, int size, unsigned int flags, 
	struct sockaddr *to, socklen_t tolen)
{
	sockfd_t	* fd;
	struct ip_addr	ip;
	struct pbuf	* pbuf = NULL;
	int		port, rv = 0;
	err_t		err;

	if (flags != 0) {
		errno = EINVAL;
		return -1;
	}

	s = sock_for_fd(s);
	if (s < 0) {
		errno = EBADF;
		return -1;
	}
	fd = fds + s;

	// Get access
	mutex_lock(fd->mutex);

	// Make sure we're doing UDP here... we don't support sendto for TCP.
	if (fd->tcppcb) {
		errno = EINVAL;
		rv = -1; goto out;
	}

	// We might not have a udppcb still, if we just did socket().
	if (!fd->udppcb)
		fd->udppcb = udp_new();

	// Convert the address to an lwIP-happy format
	ip.addr = ((struct sockaddr_in *)to)->sin_addr.s_addr;
	port = ((struct sockaddr_in *)to)->sin_port;

	// Make sure we have the recv callback setup.
	fd->recv = 0;
	udp_recv(fd->udppcb, recv_udp, (void *)s);

	// Connect this to the specified destination.
	if ((err = udp_connect(fd->udppcb, &ip, ntohs(port))) != ERR_OK) {
		printf("connect: err is %d\n", err);
		// XXX Imprecise
		errno = ENOMEM;
		rv = -1; goto out;
	}

	// Make a pbuf for the data we want to send.
	pbuf = pbuf_alloc(PBUF_RAW, size, PBUF_POOL);
	if (pbuf == NULL) {
		printf("couldn't alloc pbuf of size %d\n", size);
		errno = ENOMEM;
		rv = -1; goto out;
	}
	{
		struct pbuf *q;
		const uint8 * src = (const uint8 *)dataptr;
		int i;
		for (q=pbuf; q; q=q->next) {
			//printf("putting %d bytes into pbuf @ %p\n",
			//	q->len, q);
			for (i=0; i<q->len; i++)
				((u8_t *)q->payload)[i] = *(src++);
		}
	}
	//memcpy(pbuf->payload, dataptr, size);

	// Send the data on the socket.
	if ((err = udp_send(fd->udppcb, pbuf)) != ERR_OK) {
		printf("send: err is %d\n", err);
		// XXX Imprecise
		errno = ENOMEM;
		rv = -1; goto out;
	}

	// Let go of the pbuf before returning.
	pbuf_free(pbuf); pbuf = NULL;

out:
	if (pbuf)
		pbuf_free(pbuf);
	mutex_unlock(fd->mutex);	
	return rv;
}