selfboot / AnnotatedShadowSocks

Annotated shadowsocks(python version)

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Use FD_CLOEXEC flag to implement close-on-exec

selfboot opened this issue · comments

The fcntl function can change the properties of a file that is already open. Unix POSIX says:

#include <fcntl.h> 
int fcntl(int fd, int cmd, ... /* int arg */ );
      // Returns: depends on cmd if OK (see following), −1 on error

The fcntl function is used for five different purposes.

  1. Duplicate an existing descriptor (cmd = F_DUPFD or F_DUPFD_CLOEXEC)
  2. Get/set file descriptor flags (cmd = F_GETFD or F_SETFD)
  3. Get/set file status flags (cmd = F_GETFL or F_SETFL)
  4. Get/set asynchronous I/O ownership (cmd = F_GETOWN or F_SETOWN)
  5. Get/set record locks (cmd = F_GETLK, F_SETLK, or F_SETLKW)

Fle descriptor flags

When the command is F_GETFD, fcntl return the file descriptor flags for fd as the value of the function. When the command is F_SETFD, set the file descriptor flags for fd. The new flag value is set from the third argument (taken as an integer). (Used in shadowsocks).

About file descriptor flags, GNU manual says:

File descriptor flags are miscellaneous attributes of a file descriptor. These flags are associated with particular file descriptors, so that if you have created duplicate file descriptors from a single opening of a file, each descriptor has its own set of flags.

Currently there is just one file descriptor flag: FD_CLOEXEC, which causes the descriptor to be closed if you use any of the exec… functions (see Executing a File).

Macro: int FD_CLOEXEC
This flag specifies that the file descriptor should be closed when an exec... function is invoked. When a file descriptor is allocated (as with open or dup), this bit is initially cleared on the new file descriptor, meaning that descriptor will survive into the new program after exec.

If you want to modify the file descriptor flags, you should get the current flags with F_GETFD and modify the value. Don’t assume that the flags listed here are the only ones that are implemented; your program may be run years from now and more flags may exist then.

Python fcntl

In python, fcntl.fcntl(fd, op[, arg]) perform the operation op on file descriptor fd (file objects providing a fileno() method are accepted as well). The values used for for op are operating system dependent, and are available as constants in the fcntl module, using the same names as used in the relevant C header files.

The argument arg is optional, and defaults to the integer value 0. When present, it can either be an integer value, or a string. With the argument missing or an integer value, the return value of this function is the integer return value of the C fcntl() call.

In function shadowsocks.daemon.write_pid_file, we can see the code as follows:

flags = fcntl.fcntl(fd, fcntl.F_GETFD)
assert flags != -1
flags |= fcntl.FD_CLOEXEC
r = fcntl.fcntl(fd, fcntl.F_SETFD, flags)
assert r != -1

The snippet firstly get the original file descriptor flags, append FD_CLOEXEC to it, and then set the new flags to the file descriptor.

Ref
《APUE 3》 3.14 fcntl Function
What does the FD_CLOEXEC fcntl() flag do?
使用FD_CLOEXEC实现close-on-exec,关闭子进程无用文件描述符