[an error occurred while processing this directive]
[an error occurred while processing this directive]
RECV(2) Linux Programmer’s Manual RECV(2)
NAME
recv, recvfrom, recvmsg - receive a message from a socket
SYNOPSIS
#include
#include
ssize_t recv(int s, void *buf, size_t len, int flags);
__extern_always_inline ssize_t
recv (int __fd, void *__buf, size_t __n, int __flags)
{
if (__bos0 (__buf) != (size_t) -1)
{
if (!__builtin_constant_p (__n))
return __recv_chk (__fd, __buf, __n, __bos0 (__buf), __flags);
if (__n > __bos0 (__buf))
return __recv_chk_warn (__fd, __buf, __n, __bos0 (__buf), __flags);
}
return __recv_alias (__fd, __buf, __n, __flags);
}
ssize_t
recv_chk (int fd, void *buf, size_t n, size_t buflen, int flags)
{
if (n > buflen)
__chk_fail ();
return __recv (fd, buf, n, flags);
}
#define socket recv #define __socket __libc_recv #define NARGS 4 #define NEED_CANCELLATION #includeweak_alias (__libc_recv, __recv)
関数 (実際には recv() や send() に展開される)#define SOCKOP_recv 10関数の定義になる、socket.S は以下の通りである。
glibc :: sysdeps/unix/sysv/linux/i386/socket.S/* C からは __socket() という関数に見える。 */ /* 引数は .globl __socket ENTRY (__socket) #if defined NEED_CANCELLATION && defined CENABLE SINGLE_THREAD_P jne 1f #endif /* Save registers. */ movl %ebx, %edx cfi_register (3, 2) /* ここで、%eax に socketcall のシステムコール番号 (102) がセットされる */ movl $SYS_ify(socketcall), %eax /* System call number in %eax. */ /* Use ## so `socket' is a separate token that might be #define'd. */ /* ここに、socketcall 内で分岐するための番号が入る */ /* (socket, send, recv, accept, listen など) */ /* SOCKOP_ と socket が結合されて、 SOCKOP_recv みたいになる。*/ /* この値は sysdeps/sysv/linux/socketcall.h で定義されている。 */ movl $P(SOCKOP_,socket), %ebx /* Subcode is first arg to syscall. */ lea 4(%esp), %ecx /* Address of args is 2nd arg. */ /* Do the system call trap. */ /* ここでトラップ命令 (sysenter か 0x80) が呼ばれて、*/ /* 特権モードに入る。*/ ENTER_KERNEL /* 特権モードから戻ってきた後の処理。*/ /* Restore registers. */ movl %edx, %ebx cfi_restore (3) /* %eax is < 0 if there was an error. */ cmpl $-125, %eax jae SYSCALL_ERROR_LABEL /* Successful; return the syscall's value. */ L(pseudo_end): ret
ENTRY(sys_call_table)
.long sys_restart_syscall /* 0 - old "setup()" system call, used for restarting */
...
...
.long sys_fstatfs /* 100 */
.long sys_ioperm
.long sys_socketcall
%eax に 102 をセットしてトラップ命令を呼ぶと、sys_socketcall に飛びます。
asmlinkage long sys_socketcall(int call, unsigned long __user *args)
{
unsigned long a[6];
unsigned long a0, a1;
int err;
if (call < 1 || call > SYS_PACCEPT)
return -EINVAL;
/* copy_from_user should be SMP safe. */
if (copy_from_user(a, args, nargs[call]))
return -EFAULT;
err = audit_socketcall(nargs[call] / sizeof(unsigned long), a);
if (err)
return err;
a0 = a[0];
a1 = a[1];
switch (call) {
case SYS_SOCKET:
err = sys_socket(a0, a1, a[2]);
break;
case SYS_BIND:
err = sys_bind(a0, (struct sockaddr __user *)a1, a[2]);
break;
...
case SYS_RECV:
err = sys_recv(a0, (void __user *)a1, a[2], a[3]);
break;
/*
* Receive a datagram from a socket.
*/
asmlinkage long sys_recv(int fd, void __user *ubuf, size_t size,
unsigned flags)
{
return sys_recvfrom(fd, ubuf, size, flags, NULL, NULL);
}
/*
* Receive a frame from the socket and optionally record the address of the
* sender. We verify the buffers are writable and if needed move the
* sender address from kernel to user space.
*/
asmlinkage long sys_recvfrom(int fd, void __user *ubuf, size_t size,
unsigned flags, struct sockaddr __user *addr,
int __user *addr_len)
{
struct socket *sock;
struct iovec iov;
struct msghdr msg;
struct sockaddr_storage address;
int err, err2;
int fput_needed;
sock = sockfd_lookup_light(fd, &err, &fput_needed);
if (!sock)
goto out;
msg.msg_control = NULL;
msg.msg_controllen = 0;
msg.msg_iovlen = 1;
msg.msg_iov = &iov;
iov.iov_len = size;
iov.iov_base = ubuf;
msg.msg_name = (struct sockaddr *)&address;
msg.msg_namelen = sizeof(address);
if (sock->file->f_flags & O_NONBLOCK)
flags |= MSG_DONTWAIT;
=> err = sock_recvmsg(sock, &msg, size, flags);
if (err >= 0 && addr != NULL) {
err2 = move_addr_to_user((struct sockaddr *)&address,
msg.msg_namelen, addr, addr_len);
if (err2 < 0)
err = err2;
}
fput_light(sock->file, fput_needed);
out:
return err;
}