[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; }