SOCK_STREAM socket in kernel space

Mohammad Hedayati hedayati.mo at gmail.com
Tue Dec 21 15:24:23 UTC 2010


On Tue, Dec 21, 2010 at 4:23 PM, John Baldwin <jhb at freebsd.org> wrote:
> On Tuesday, December 21, 2010 6:39:26 am Mohammad Hedayati wrote:
>> I'm about to use a char device for a kind of distributed processing,
>> so I've coded the open function as follows. The problem is that
>> soaccept returns 0 without populating the raddr. I've checked netstat,
>> everything seems to be fine, the socket is created, bound and the
>> state is LISTENING. Even the remote is connection is ESTABLISHED. But,
>> it cannot receive anything. it says that socket  (sock variable) is
>> not connected.
>
> Yes, you are calling soaccept() on the wrong socket.  You need to wait for a
> connection and dequeue the socket that connected and then call soaccept() on
> that new socket.  Look at kern_accept() in sys/kern/uipc_syscalls.c.
>
> I wonder though if you wouldn't rather be calling soconnect instead?  Do you
> really need to listen for new connections?
>
> --
> John Baldwin
>

Thanks, I have corrected it as follows. It now works fine.

int
open(struct cdev *dev, int flag, int otyp, struct thread *td)
{
	uprintf("in open...\n");
	
	int error = -1;	
	socktd = td;
	
	error = socreate(AF_INET, &sock, SOCK_STREAM, IPPROTO_TCP,
td->td_proc->p_ucred, socktd);
	if(error != 0)
		return error;
	
	sockaddr.sin_len = sizeof(struct sockaddr_in);
	sockaddr.sin_family = AF_INET;
	sockaddr.sin_port = htons(1234);
	sockaddr.sin_addr.s_addr = INADDR_ANY;
	error = sobind(sock, (struct sockaddr *)&sockaddr, socktd);
	uprintf("sobind error = %d\n", error);
	
	error = solisten(sock, 5, socktd);
	uprintf("solisten error = %d\n", error);
	
	/* Accepting the connection */	
	ACCEPT_LOCK();
	// Block, waiting for connection ...
	while (TAILQ_EMPTY(&sock->so_comp) && sock->so_error == 0)
	{
		// Check if the connection is already aborted?
		if (sock->so_rcv.sb_state & SBS_CANTRCVMORE) {
			sock->so_error = ECONNABORTED;
			error = sock->so_error;
			sock->so_error = 0;
			ACCEPT_UNLOCK();
			return(error);
		}
		error = msleep(&sock->so_timeo, &accept_mtx, PSOCK | PCATCH, "accept", 0);
		if (error) {
			ACCEPT_UNLOCK();
			return(error);
		}
	}
	rsock = TAILQ_FIRST(&sock->so_comp);
	SOCK_LOCK(rsock);
	soref(rsock);
	TAILQ_REMOVE(&sock->so_comp, rsock, so_list);
	sock->so_qlen--;
	rsock->so_state |= (sock->so_state & SS_NBIO);
	rsock->so_qstate &= ~SQ_COMP;
	rsock->so_head = NULL;
	SOCK_UNLOCK(rsock);
	ACCEPT_UNLOCK();	
	error = soaccept(rsock, (struct sockaddr **)&raddr);
	uprintf("soaccept error = %d, ip=%s\n", error, inet_ntoa(raddr->sin_addr));
	
	uprintf("out open...\n");
	
	return(error);
}


More information about the freebsd-net mailing list