Asmlinkage long sys_socketcall (INT call, unsigned long _ User * ARGs );
{
Unsigned long a [6];
/* Obtain information from the user space. This function is SMP secure */
If (copy_from_user (A, argS, nargs [Call])
Return-efault;
Switch (CALL ){
Case sys_socket:
Err = sys_socket (A [0], a [1], a [2]);
Break;
Case sys_bind:
Err = sys_bind (A [0], (struct sockaddr _ User *) A [1], a [2]);
Break;
Case sys_connect:
Err = sys_connect (A [0], (struct sockaddr _ User *) A [1], a [2]);
Break;
....
}
}
/*
* The following describes the sys_listen function.
*
* This function first calls the sockfd_lookup_light function,
* Obtain the struct file * file structure with the descriptor Based on the descriptor, and then obtain the struct socket * sock structure based on the file structure.
* Get FD and backlog from user space
* Call the sock-> OPS-> listen () function, which is inet_listen [net/IPv4/af_inet.c] in TCP.
* For UDP, sock-> OPS-> Listen = sock_no_listen is returned directly.
*/
Asmlinkage long sys_listen (int fd, int backlog)
{
Struct socket * sock;
Int err, fput_needed;
/*
* Find the struct socket * sock structure with this descriptor
*/
Sock = sockfd_lookup_light (FD, & err, & fput_needed );
If (sock ){
If (unsigned) Backlog> sysctl_somaxconn)
Backlog = sysctl_somaxconn;
/*
* Sock-> Ops = & inet_stream_ops | & inet_dgram_ops,
*
* TCP: sock-> OPS-> Listen = inet_listen
* UDP: sock-> OPS-> Listen = sock_no_listen
*/
Err = sock-> OPS-> listen (sock, backlog );
Fput_light (sock-> file, fput_needed );
}
Return err;
}
/*
* In the inet_listen function, first determine whether the sock status is ss_unconnected and whether the type is sock_stream. If not, exit directly.
* Then judge whether the sock-> SK is in the listened status. If yes, set the backlog directly and exit.
* Otherwise, call inet_csk_listen_start [net/IPv4/inet_connection_sock.c].
*/
Int inet_listen (struct socket * sock, int backlog)
{
Struct sock * Sk = sock-> SK;
Unsigned char old_state;
Int err;
Lock_sock (SK );
Err =-einval;
If (sock-> state! = Ss_unconnected | sock-> type! = Sock_stream)
Goto out;
Old_state = Sk-> sk_state;
If (! (1 <old_state) & (tcpf_close | tcpf_listen )))
Goto out;
/* Really, if the socket is already in listen state
* We can only allow the backlog to be adjusted.
*/
If (old_state! = Tcp_listen ){
Err = inet_csk_listen_start (SK, backlog );
If (ERR)
Goto out;
}
SK-> sk_max_ack_backlog = backlog;
Err = 0;
Out:
Release_sock (SK );
Return err;
}
/*
* Inet_csk_listen_start [net/IPv4/inet_connection_sock.c]
* This function first calls reqsk_queue_alloc [net/CORE/request_sock.c] To apply for a piece of memory and store the listener queue for accept;
* Set the listening status and put the struct sock * SK into tcp_hashinfo.ehash.
*/
Int inet_csk_listen_start (struct sock * SK, const int nr_table_entries)
{
Struct inet_sock * Inet = inet_sk (SK );
Struct inet_connection_sock * icsk = inet_csk (SK );
Int rc = reqsk_queue_alloc (& icsk-> icsk_accept_queue, nr_table_entries );
If (RC! = 0)
Return RC;
SK-> sk_max_ack_backlog = 0;
SK-> sk_ack_backlog = 0;
/*
* Only memset
* Memset (& inet_csk (SK)-> icsk_ack, 0, sizeof (inet_csk (SK)-> icsk_ack ));
*/
Inet_csk_delack_init (SK );
/*
* Set the listening status and determine whether the port is not used
* Add it to tcp_hashinfo.ehash.
* Return 0;
*/
SK-> sk_state = tcp_listen;
If (! SK-> sk_prot-> get_port (SK, iNet-> num )){
INet-> sport = htons (iNet-> num );
Sk_dst_reset (SK );
SK-> sk_prot-> Hash (SK );
Return 0;
}
SK-> sk_state = tcp_close;
_ Reqsk_queue_destroy (& icsk-> icsk_accept_queue );
Return-eaddrinuse;
}
A comprehensive website for Linux application development, www.linuxhao.com, and www.linuxhao.com provides Linux video tutorials, Linux training courses, and Linux technical materials for free.