Byeo

listen system call 1 (__sys_listen) 본문

프로그래밍 (Programming)/네트워크 스택

listen system call 1 (__sys_listen)

BKlee 2024. 5. 11. 22:18
반응형

BSD socket API에서 server쪽은 bind를 실행한 뒤, listen을 시작합니다.

 

 Application이 listen을 시작하면  이제 받을 수 있게 됩니다. 이 때, listen은 client가 요청한 연결들을 보관하는 함수라고 볼 수 있을 것 같은데요. 그 보관 가능한 최대 개수가 listen system call의 2번째 인자인 'backlog'라고 보면 될 것 같습니다. 이 큐를 소모하는 주체(consumer)는 일반적으로 listen 다음에서 불리는 accept() system call입니다.

 

backlog와 관련된 내용은 별도의 포스트에서 다뤄보겠습니다.

 

이 번에는 BSD socket API중에서 listen를 분석해보려고 합니다.

 

이전 포스트 (bind system call)

https://byeo.tistory.com/entry/bind-system-call-1

 

bind system call 1 (__sys_bind)

BSD socket API에서 socket을 생성한 뒤에는 server-side 측에서 bind를 실행합니다. bind는 나의 ip:port를 socket과 연결하는 역할을 수행하죠. 이 번에는 BSD socket API중에서 bind를 분석해보려고 합니다. 이전

byeo.tistory.com

 

 

 

1. sys_listen()

// net/socket.c/SYSCALL_DEFINE2() :1734

SYSCALL_DEFINE2(listen, int, fd, int, backlog)
{
	return __sys_listen(fd, backlog);
}

자주 본 구조이므로 넘기겠습니다.

 

2. __sys_listen

// net/socket.c/__sys_listen() :1707

/*
 *	Perform a listen. Basically, we allow the protocol to do anything
 *	necessary for a listen, and if that works, we mark the socket as
 *	ready for listening.
 */

int __sys_listen(int fd, int backlog)
{
	struct socket *sock;
	int err, fput_needed;
	int somaxconn;

	sock = sockfd_lookup_light(fd, &err, &fput_needed);
	if (sock) {
		somaxconn = sock_net(sock->sk)->core.sysctl_somaxconn;
		if ((unsigned int)backlog > somaxconn)
			backlog = somaxconn;

		err = security_socket_listen(sock, backlog);
		if (!err)
			err = sock->ops->listen(sock, backlog);

		fput_light(sock->file, fput_needed);
	}
	return err;
}

 

 

2-1) sockfd_lookup_light

file descriptor를 인자로 받아서 struct socket* sock을 얻어오는 함수입니다. https://byeo.tistory.com/entry/bind-system-call-1 의 2) sockfd_lookup_light 와 중복되므로 넘기겠습니다.

 

2-2) backlog 최대값

backlog의 값은 namespace에서 지정된 somaxconn값을 넘길 수 없습니다.

		somaxconn = sock_net(sock->sk)->core.sysctl_somaxconn;
        	if ((unsigned int)backlog > somaxconn)
			backlog = somaxconn;

 

qemu 내에서 살펴보니 위와 같이 설정되어 있네요. 다음과 같은 자료구조에서 관리합니다.

// include/net/netns/core.h:8

struct netns_core {
	/* core sysctls */
	struct ctl_table_header	*sysctl_hdr;

	int	sysctl_somaxconn;

#ifdef CONFIG_PROC_FS
	int __percpu *sock_inuse;
	struct prot_inuse __percpu *prot_inuse;
#endif
};

 

2-3) sock->ops->listen(sock, backlog)

 listen 함수의 구조가 어째 bind랑 많이 비슷하죠? sock->ops는 &inet_stream_ops였고, 이는 inet_listen을 호출합니다.

 

 

현재까지 흐름도

반응형
Comments