# SOME DESCRIPTIVE TITLE # Copyright (C) YEAR Free Software Foundation, Inc. # This file is distributed under the same license as the PACKAGE package. # FIRST AUTHOR , YEAR. # #, fuzzy msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "POT-Creation-Date: 2024-06-01 06:20+0200\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" "Language: \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #. type: TH #: archlinux debian-bookworm debian-unstable fedora-40 fedora-rawhide #: mageia-cauldron opensuse-leap-15-6 opensuse-tumbleweed #, no-wrap msgid "SELECT_TUT" msgstr "" #. type: TH #: archlinux debian-unstable opensuse-tumbleweed #, no-wrap msgid "2024-05-02" msgstr "" #. type: TH #: archlinux debian-unstable #, no-wrap msgid "Linux man-pages 6.8" msgstr "" #. type: SH #: archlinux debian-bookworm debian-unstable fedora-40 fedora-rawhide #: mageia-cauldron opensuse-leap-15-6 opensuse-tumbleweed #, no-wrap msgid "NAME" msgstr "" #. type: Plain text #: archlinux debian-bookworm debian-unstable fedora-40 fedora-rawhide #: mageia-cauldron opensuse-leap-15-6 opensuse-tumbleweed msgid "select, pselect - synchronous I/O multiplexing" msgstr "" #. type: SH #: archlinux debian-bookworm debian-unstable fedora-40 fedora-rawhide #: mageia-cauldron opensuse-leap-15-6 opensuse-tumbleweed #, no-wrap msgid "LIBRARY" msgstr "" #. type: Plain text #: archlinux debian-bookworm debian-unstable fedora-40 fedora-rawhide #: mageia-cauldron opensuse-leap-15-6 opensuse-tumbleweed msgid "Standard C library (I, I<-lc>)" msgstr "" #. type: SH #: archlinux debian-bookworm debian-unstable fedora-40 fedora-rawhide #: mageia-cauldron opensuse-leap-15-6 opensuse-tumbleweed #, no-wrap msgid "SYNOPSIS" msgstr "" #. type: Plain text #: archlinux debian-bookworm debian-unstable fedora-40 fedora-rawhide #: mageia-cauldron opensuse-leap-15-6 opensuse-tumbleweed msgid "See B() and B() system calls are used to efficiently " "monitor multiple file descriptors, to see if any of them is, or becomes, " "\"ready\"; that is, to see whether I/O becomes possible, or an \"exceptional " "condition\" has occurred on any of the file descriptors." msgstr "" #. type: Plain text #: archlinux debian-bookworm debian-unstable fedora-40 fedora-rawhide #: mageia-cauldron opensuse-leap-15-6 opensuse-tumbleweed msgid "" "This page provides background and tutorial information on the use of these " "system calls. For details of the arguments and semantics of B(2)." msgstr "" #. type: SS #: archlinux debian-bookworm debian-unstable fedora-40 fedora-rawhide #: mageia-cauldron opensuse-leap-15-6 opensuse-tumbleweed #, no-wrap msgid "Combining signal and data events" msgstr "" #. type: Plain text #: archlinux debian-bookworm debian-unstable fedora-40 fedora-rawhide #: mageia-cauldron opensuse-leap-15-6 opensuse-tumbleweed msgid "" "B() is useful if you are waiting for a signal as well as for file " "descriptor(s) to become ready for I/O. Programs that receive signals " "normally use the signal handler only to raise a global flag. The global " "flag will indicate that the event must be processed in the main loop of the " "program. A signal will cause the B() would block indefinitely." msgstr "" #. type: Plain text #: archlinux debian-bookworm debian-unstable fedora-40 fedora-rawhide #: mageia-cauldron opensuse-leap-15-6 opensuse-tumbleweed msgid "" "Now, somewhere in the main loop will be a conditional to check the global " "flag. So we must ask: what if a signal arrives after the conditional, but " "before the B() would block " "indefinitely, even though an event is actually pending. This race condition " "is solved by the B() call. This call can be used to set the " "signal mask to a set of signals that are to be received only within the " "B() call. For instance, let us say that the event in question was " "the exit of a child process. Before the start of the main loop, we would " "block B using B(2). Our B() call would " "enable B by using an empty signal mask. Our program would look " "like:" msgstr "" #. type: Plain text #: archlinux debian-unstable fedora-40 fedora-rawhide mageia-cauldron #: opensuse-tumbleweed #, no-wrap msgid "" "static volatile sig_atomic_t got_SIGCHLD = 0;\n" "\\&\n" "static void\n" "child_sig_handler(int sig)\n" "{\n" " got_SIGCHLD = 1;\n" "}\n" "\\&\n" "int\n" "main(int argc, char *argv[])\n" "{\n" " sigset_t sigmask, empty_mask;\n" " struct sigaction sa;\n" " fd_set readfds, writefds, exceptfds;\n" " int r;\n" "\\&\n" " sigemptyset(&sigmask);\n" " sigaddset(&sigmask, SIGCHLD);\n" " if (sigprocmask(SIG_BLOCK, &sigmask, NULL) == -1) {\n" " perror(\"sigprocmask\");\n" " exit(EXIT_FAILURE);\n" " }\n" "\\&\n" " sa.sa_flags = 0;\n" " sa.sa_handler = child_sig_handler;\n" " sigemptyset(&sa.sa_mask);\n" " if (sigaction(SIGCHLD, &sa, NULL) == -1) {\n" " perror(\"sigaction\");\n" " exit(EXIT_FAILURE);\n" " }\n" "\\&\n" " sigemptyset(&empty_mask);\n" "\\&\n" " for (;;) { /* main loop */\n" " /* Initialize readfds, writefds, and exceptfds\n" " before the pselect() call. (Code omitted.) */\n" "\\&\n" " r = pselect(nfds, &readfds, &writefds, &exceptfds,\n" " NULL, &empty_mask);\n" " if (r == -1 && errno != EINTR) {\n" " /* Handle error */\n" " }\n" "\\&\n" " if (got_SIGCHLD) {\n" " got_SIGCHLD = 0;\n" "\\&\n" " /* Handle signalled event here; e.g., wait() for all\n" " terminated children. (Code omitted.) */\n" " }\n" "\\&\n" " /* main body of program */\n" " }\n" "}\n" msgstr "" #. type: SS #: archlinux debian-bookworm debian-unstable fedora-40 fedora-rawhide #: mageia-cauldron opensuse-leap-15-6 opensuse-tumbleweed #, no-wrap msgid "Practical" msgstr "" #. type: Plain text #: archlinux debian-bookworm debian-unstable fedora-40 fedora-rawhide #: mageia-cauldron opensuse-leap-15-6 opensuse-tumbleweed msgid "" "So what is the point of B() is that it watches " "multiple descriptors at the same time and properly puts the process to sleep " "if there is no activity. UNIX programmers often find themselves in a " "position where they have to handle I/O from more than one file descriptor " "where the data flow may be intermittent. If you were to merely create a " "sequence of B(2) and B(2) calls, you would find that one of " "your calls may block waiting for data from/to a file descriptor, while " "another file descriptor is unused though ready for I/O. B() come across behavior that is " "difficult to understand and produces nonportable or borderline results. For " "instance, the above program is carefully written not to block at any point, " "even though it does not set its file descriptors to nonblocking mode. It is " "easy to introduce subtle errors that will remove the advantage of using " "B()." msgstr "" #. type: TP #: archlinux debian-bookworm debian-unstable fedora-40 fedora-rawhide #: mageia-cauldron opensuse-leap-15-6 opensuse-tumbleweed #, no-wrap msgid "1." msgstr "" #. type: Plain text #: archlinux debian-bookworm debian-unstable fedora-40 fedora-rawhide #: mageia-cauldron opensuse-leap-15-6 opensuse-tumbleweed msgid "" "You should always try to use B() call, and respond appropriately. See next " "rule." msgstr "" #. type: TP #: archlinux debian-bookworm debian-unstable fedora-40 fedora-rawhide #: mageia-cauldron opensuse-leap-15-6 opensuse-tumbleweed #, no-wrap msgid "4." msgstr "" #. type: Plain text #: archlinux debian-bookworm debian-unstable fedora-40 fedora-rawhide #: mageia-cauldron opensuse-leap-15-6 opensuse-tumbleweed msgid "" "After B() " "can fail with the error B, and calls to B(2), B(2), " "B(2), and B(2) can fail with I set to B " "(B). These results must be properly managed (not done properly " "above). If your program is not going to receive any signals, then it is " "unlikely you will get B. If your program does not set nonblocking I/" "O, you will not get B." msgstr "" #. type: TP #: archlinux debian-bookworm debian-unstable fedora-40 fedora-rawhide #: mageia-cauldron opensuse-leap-15-6 opensuse-tumbleweed #, no-wrap msgid "8." msgstr "" #. type: Plain text #: archlinux debian-bookworm debian-unstable fedora-40 fedora-rawhide #: mageia-cauldron opensuse-leap-15-6 opensuse-tumbleweed msgid "" "Never call B(2), B(2), B(2), or B(2) with a buffer " "length of zero." msgstr "" #. type: TP #: archlinux debian-bookworm debian-unstable fedora-40 fedora-rawhide #: mageia-cauldron opensuse-leap-15-6 opensuse-tumbleweed #, no-wrap msgid "9." msgstr "" #. type: Plain text #: archlinux debian-bookworm debian-unstable fedora-40 fedora-rawhide #: mageia-cauldron opensuse-leap-15-6 opensuse-tumbleweed msgid "" "If the functions B(2), B(2), B(2), and B(2) fail " "with errors other than those listed in B<7.>, or one of the input functions " "returns 0, indicating end of file, then you should I pass that file " "descriptor to B(), " "since some operating systems modify the structure. B() however " "does not modify its timeout structure." msgstr "" #. type: TP #: archlinux debian-bookworm debian-unstable fedora-40 fedora-rawhide #: mageia-cauldron opensuse-leap-15-6 opensuse-tumbleweed #, no-wrap msgid "11." msgstr "" #. "I have heard" does not fill me with confidence, and doesn't #. belong in a man page, so I've commented this point out. #. .TP #. 11. #. I have heard that the Windows socket layer does not cope with OOB data #. properly. #. It also does not cope with #. .BR select () #. calls when no file descriptors are set at all. #. Having no file descriptors set is a useful #. way to sleep the process with subsecond precision by using the timeout. #. (See further on.) #. type: Plain text #: archlinux debian-bookworm debian-unstable fedora-40 fedora-rawhide #: mageia-cauldron opensuse-leap-15-6 opensuse-tumbleweed msgid "" "Since B(2)." msgstr "" #. type: SH #: archlinux debian-bookworm debian-unstable fedora-40 fedora-rawhide #: mageia-cauldron opensuse-leap-15-6 opensuse-tumbleweed #, no-wrap msgid "NOTES" msgstr "" #. type: Plain text #: archlinux debian-bookworm debian-unstable fedora-40 fedora-rawhide #: mageia-cauldron opensuse-leap-15-6 opensuse-tumbleweed msgid "" "Generally speaking, all operating systems that support sockets also support " "B() can be used to solve many problems in a portable " "and efficient way that naive programmers try to solve in a more complicated " "manner using threads, forking, IPCs, signals, memory sharing, and so on." msgstr "" #. type: Plain text #: archlinux debian-bookworm debian-unstable fedora-40 fedora-rawhide #: mageia-cauldron opensuse-leap-15-6 opensuse-tumbleweed msgid "" "The B(2) system call has the same functionality as B()." msgstr "" #. type: Plain text #: archlinux debian-bookworm debian-unstable fedora-40 fedora-rawhide #: mageia-cauldron opensuse-leap-15-6 opensuse-tumbleweed msgid "" "The Linux-specific B(7) API provides an interface that is more " "efficient than B(). The listing below is a TCP forwarding program that forwards " "from one TCP port to another." msgstr "" #. type: Plain text #: archlinux debian-unstable opensuse-tumbleweed #, no-wrap msgid "" "#include Earpa/inet.hE\n" "#include Eerrno.hE\n" "#include Enetinet/in.hE\n" "#include Esignal.hE\n" "#include Estdio.hE\n" "#include Estdlib.hE\n" "#include Estring.hE\n" "#include Esys/select.hE\n" "#include Esys/socket.hE\n" "#include Esys/types.hE\n" "#include Eunistd.hE\n" "\\&\n" "static int forward_port;\n" "\\&\n" "#undef max\n" "#define max(x, y) ((x) E (y) ? (x) : (y))\n" "\\&\n" "static int\n" "listen_socket(int listen_port)\n" "{\n" " int lfd;\n" " int yes;\n" " struct sockaddr_in addr;\n" "\\&\n" " lfd = socket(AF_INET, SOCK_STREAM, 0);\n" " if (lfd == -1) {\n" " perror(\"socket\");\n" " return -1;\n" " }\n" "\\&\n" " yes = 1;\n" " if (setsockopt(lfd, SOL_SOCKET, SO_REUSEADDR,\n" " &yes, sizeof(yes)) == -1)\n" " {\n" " perror(\"setsockopt\");\n" " close(lfd);\n" " return -1;\n" " }\n" "\\&\n" " memset(&addr, 0, sizeof(addr));\n" " addr.sin_port = htons(listen_port);\n" " addr.sin_family = AF_INET;\n" " if (bind(lfd, (struct sockaddr *) &addr, sizeof(addr)) == -1) {\n" " perror(\"bind\");\n" " close(lfd);\n" " return -1;\n" " }\n" "\\&\n" " printf(\"accepting connections on port %d\\en\", listen_port);\n" " listen(lfd, 10);\n" " return lfd;\n" "}\n" "\\&\n" "static int\n" "connect_socket(int connect_port, char *address)\n" "{\n" " int cfd;\n" " struct sockaddr_in addr;\n" "\\&\n" " cfd = socket(AF_INET, SOCK_STREAM, 0);\n" " if (cfd == -1) {\n" " perror(\"socket\");\n" " return -1;\n" " }\n" "\\&\n" " memset(&addr, 0, sizeof(addr));\n" " addr.sin_port = htons(connect_port);\n" " addr.sin_family = AF_INET;\n" "\\&\n" " if (!inet_aton(address, (struct in_addr *) &addr.sin_addr.s_addr)) {\n" " fprintf(stderr, \"inet_aton(): bad IP address format\\en\");\n" " close(cfd);\n" " return -1;\n" " }\n" "\\&\n" " if (connect(cfd, (struct sockaddr *) &addr, sizeof(addr)) == -1) {\n" " perror(\"connect()\");\n" " shutdown(cfd, SHUT_RDWR);\n" " close(cfd);\n" " return -1;\n" " }\n" " return cfd;\n" "}\n" "\\&\n" "#define SHUT_FD1 do { \\e\n" " if (fd1 E= 0) { \\e\n" " shutdown(fd1, SHUT_RDWR); \\e\n" " close(fd1); \\e\n" " fd1 = -1; \\e\n" " } \\e\n" " } while (0)\n" "\\&\n" "#define SHUT_FD2 do { \\e\n" " if (fd2 E= 0) { \\e\n" " shutdown(fd2, SHUT_RDWR); \\e\n" " close(fd2); \\e\n" " fd2 = -1; \\e\n" " } \\e\n" " } while (0)\n" "\\&\n" "#define BUF_SIZE 1024\n" "\\&\n" "int\n" "main(int argc, char *argv[])\n" "{\n" " int h;\n" " int ready, nfds;\n" " int fd1 = -1, fd2 = -1;\n" " int buf1_avail = 0, buf1_written = 0;\n" " int buf2_avail = 0, buf2_written = 0;\n" " char buf1[BUF_SIZE], buf2[BUF_SIZE];\n" " fd_set readfds, writefds, exceptfds;\n" " ssize_t nbytes;\n" "\\&\n" " if (argc != 4) {\n" " fprintf(stderr, \"Usage\\en\\etfwd Elisten-portE \"\n" " \"Eforward-to-portE Eforward-to-ip-addressE\\en\");\n" " exit(EXIT_FAILURE);\n" " }\n" "\\&\n" " signal(SIGPIPE, SIG_IGN);\n" "\\&\n" " forward_port = atoi(argv[2]);\n" "\\&\n" " h = listen_socket(atoi(argv[1]));\n" " if (h == -1)\n" " exit(EXIT_FAILURE);\n" "\\&\n" " for (;;) {\n" " nfds = 0;\n" "\\&\n" " FD_ZERO(&readfds);\n" " FD_ZERO(&writefds);\n" " FD_ZERO(&exceptfds);\n" " FD_SET(h, &readfds);\n" " nfds = max(nfds, h);\n" "\\&\n" " if (fd1 E 0 && buf1_avail E BUF_SIZE)\n" " FD_SET(fd1, &readfds);\n" " /* Note: nfds is updated below, when fd1 is added to\n" " exceptfds. */\n" " if (fd2 E 0 && buf2_avail E BUF_SIZE)\n" " FD_SET(fd2, &readfds);\n" "\\&\n" " if (fd1 E 0 && buf2_avail - buf2_written E 0)\n" " FD_SET(fd1, &writefds);\n" " if (fd2 E 0 && buf1_avail - buf1_written E 0)\n" " FD_SET(fd2, &writefds);\n" "\\&\n" " if (fd1 E 0) {\n" " FD_SET(fd1, &exceptfds);\n" " nfds = max(nfds, fd1);\n" " }\n" " if (fd2 E 0) {\n" " FD_SET(fd2, &exceptfds);\n" " nfds = max(nfds, fd2);\n" " }\n" "\\&\n" " ready = select(nfds + 1, &readfds, &writefds, &exceptfds, NULL);\n" "\\&\n" " if (ready == -1 && errno == EINTR)\n" " continue;\n" "\\&\n" " if (ready == -1) {\n" " perror(\"select()\");\n" " exit(EXIT_FAILURE);\n" " }\n" "\\&\n" " if (FD_ISSET(h, &readfds)) {\n" " socklen_t addrlen;\n" " struct sockaddr_in client_addr;\n" " int fd;\n" "\\&\n" " addrlen = sizeof(client_addr);\n" " memset(&client_addr, 0, addrlen);\n" " fd = accept(h, (struct sockaddr *) &client_addr, &addrlen);\n" " if (fd == -1) {\n" " perror(\"accept()\");\n" " } else {\n" " SHUT_FD1;\n" " SHUT_FD2;\n" " buf1_avail = buf1_written = 0;\n" " buf2_avail = buf2_written = 0;\n" " fd1 = fd;\n" " fd2 = connect_socket(forward_port, argv[3]);\n" " if (fd2 == -1)\n" " SHUT_FD1;\n" " else\n" " printf(\"connect from %s\\en\",\n" " inet_ntoa(client_addr.sin_addr));\n" "\\&\n" " /* Skip any events on the old, closed file\n" " descriptors. */\n" "\\&\n" " continue;\n" " }\n" " }\n" "\\&\n" " /* NB: read OOB data before normal reads. */\n" "\\&\n" " if (fd1 E 0 && FD_ISSET(fd1, &exceptfds)) {\n" " char c;\n" "\\&\n" " nbytes = recv(fd1, &c, 1, MSG_OOB);\n" " if (nbytes E 1)\n" " SHUT_FD1;\n" " else\n" " send(fd2, &c, 1, MSG_OOB);\n" " }\n" " if (fd2 E 0 && FD_ISSET(fd2, &exceptfds)) {\n" " char c;\n" "\\&\n" " nbytes = recv(fd2, &c, 1, MSG_OOB);\n" " if (nbytes E 1)\n" " SHUT_FD2;\n" " else\n" " send(fd1, &c, 1, MSG_OOB);\n" " }\n" " if (fd1 E 0 && FD_ISSET(fd1, &readfds)) {\n" " nbytes = read(fd1, buf1 + buf1_avail,\n" " BUF_SIZE - buf1_avail);\n" " if (nbytes E 1)\n" " SHUT_FD1;\n" " else\n" " buf1_avail += nbytes;\n" " }\n" " if (fd2 E 0 && FD_ISSET(fd2, &readfds)) {\n" " nbytes = read(fd2, buf2 + buf2_avail,\n" " BUF_SIZE - buf2_avail);\n" " if (nbytes E 1)\n" " SHUT_FD2;\n" " else\n" " buf2_avail += nbytes;\n" " }\n" " if (fd1 E 0 && FD_ISSET(fd1, &writefds) && buf2_avail E 0) {\n" " nbytes = write(fd1, buf2 + buf2_written,\n" " buf2_avail - buf2_written);\n" " if (nbytes E 1)\n" " SHUT_FD1;\n" " else\n" " buf2_written += nbytes;\n" " }\n" " if (fd2 E 0 && FD_ISSET(fd2, &writefds) && buf1_avail E 0) {\n" " nbytes = write(fd2, buf1 + buf1_written,\n" " buf1_avail - buf1_written);\n" " if (nbytes E 1)\n" " SHUT_FD2;\n" " else\n" " buf1_written += nbytes;\n" " }\n" "\\&\n" " /* Check if write data has caught read data. */\n" "\\&\n" " if (buf1_written == buf1_avail)\n" " buf1_written = buf1_avail = 0;\n" " if (buf2_written == buf2_avail)\n" " buf2_written = buf2_avail = 0;\n" "\\&\n" " /* One side has closed the connection, keep\n" " writing to the other side until empty. */\n" "\\&\n" " if (fd1 E 0 && buf1_avail - buf1_written == 0)\n" " SHUT_FD2;\n" " if (fd2 E 0 && buf2_avail - buf2_written == 0)\n" " SHUT_FD1;\n" " }\n" " exit(EXIT_SUCCESS);\n" "}\n" msgstr "" #. type: Plain text #: archlinux debian-bookworm debian-unstable fedora-40 fedora-rawhide #: mageia-cauldron opensuse-leap-15-6 opensuse-tumbleweed msgid "" "The above program properly forwards most kinds of TCP connections including " "OOB signal data transmitted by B servers. It handles the tricky " "problem of having data flow in both directions simultaneously. You might " "think it more efficient to use a B(2) call and devote a thread to " "each stream. This becomes more tricky than you might suspect. Another idea " "is to set nonblocking I/O using B(2). This also has its problems " "because you end up using inefficient timeouts." msgstr "" #. type: Plain text #: archlinux debian-bookworm debian-unstable fedora-40 fedora-rawhide #: mageia-cauldron opensuse-leap-15-6 opensuse-tumbleweed msgid "" "The program does not handle more than one simultaneous connection at a time, " "although it could easily be extended to do this with a linked list of " "buffers\\[em]one for each connection. At the moment, new connections cause " "the current connection to be dropped." msgstr "" #. type: SH #: archlinux debian-bookworm debian-unstable fedora-40 fedora-rawhide #: mageia-cauldron opensuse-leap-15-6 opensuse-tumbleweed #, no-wrap msgid "SEE ALSO" msgstr "" #. type: Plain text #: archlinux debian-bookworm debian-unstable fedora-40 fedora-rawhide #: mageia-cauldron opensuse-leap-15-6 opensuse-tumbleweed msgid "" "B(2), B(2), B(2), B(2), B(2), " "B