| Summary: | CPU-eating loop when stdin pipe is closed | ||
|---|---|---|---|
| Product: | Sisyphus | Reporter: | Sergey Vlasov <vsu> |
| Component: | netcat | Assignee: | placeholder <placeholder> |
| Status: | CLOSED FIXED | QA Contact: | qa-sisyphus |
| Severity: | normal | ||
| Priority: | P3 | CC: | glebfm, ldv, placeholder, rider, stanv, vt |
| Version: | unstable | ||
| Hardware: | all | ||
| OS: | Linux | ||
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND 27097 stanv 20 0 8556 724 596 R 99.7 0.0 0:06.36 nc 27080 stanv 20 0 6324 456 356 R 92.1 0.0 0:05.92 nc Дима, очень нужно исправление этой ошибки. |
netcat-4.0.20100420-alt1 В случае, если в качестве stdin передаётся pipe, и затем все дескрипторы для записи закрываются, netcat зацикливается, пока не будет закрыто сетевое соединение: 17160 poll([{fd=3, events=POLLIN}, {fd=0, events=POLLIN}], 2, -1) = 1 ([{fd=0, revents=POLLHUP}]) 17160 poll([{fd=3, events=POLLIN}, {fd=0, events=POLLIN}], 2, -1) = 1 ([{fd=0, revents=POLLHUP}]) 17160 poll([{fd=3, events=POLLIN}, {fd=0, events=POLLIN}], 2, -1) = 1 ([{fd=0, revents=POLLHUP}]) ... (при отсутствии активности сетевого соединения продолжается бесконечно) (после закрытия сокета с другой стороны) 17160 poll([{fd=3, events=POLLIN}, {fd=0, events=POLLIN}], 2, -1) = 2 ([{fd=3, revents=POLLIN}, {fd=0, revents=POLLHUP}]) 17160 read(3, "", 2048) = 0 17160 shutdown(3, 0 /* receive */) = 0 17160 close(3) = 0 17160 exit_group(0) = ? Наблюдать это можно, например, при использовании ssh $host nc 127.0.0.1 $port; после этого нормальное закрытие входного потока ssh приводит к зацикливанию nc, причём данные в противоположном направлении в этом состоянии продолжают проходить. Такой вызов nc через ssh используется в libvirt (virt-manager, virt-viewer) для соединения с VNC-сервером qemu при подключении qemu+ssh://, в результате на сервере остаются висеть процессы nc, потребляющие процессорное время. (Для основного соединения с сокетом libvirtd в нормальной ситуации эта проблема не наблюдается из-за наличия в протоколе явной команды закрытия соединения, в результате nc завершает работу при закрытии сокета со стороны libvirtd.) В Linux для pipe или fifo в случае, если все дескрипторы для записи закрыты, и при этом в буфере нет данных, poll() возвращает для дескриптора чтения флаг POLLHUP без установки флага POLLIN; однако netcat не проверяет флаг POLLHUP - видимо, поведение ядра OpenBSD в такой ситуации отличается от Linux (похоже, там по EOF выставляется и POLLIN|POLLRDNORM). В Fedora подобная проблема была починена ещё в 2005 году: https://bugzilla.redhat.com/show_bug.cgi?id=156835 В январе 2010 года была попытка протолкнуть в апстрим патчи, среди которых был и чинящий обработку POLLHUP, но ответа не последовало: http://kerneltrap.org/mailarchive/openbsd-tech/2010/1/12/6700583 http://jzeleny.fedorapeople.org/patches/nc/01-pollhup.patch