Используются неблокируюшие сокеты. epoll используется в режиме level-triggered (хотя в данном случае это вроде неважно). Может ли быть так, что epoll_wait сигнализировал EPOLLIN'ом, а при чтении из сокета recv вернул -1 и установил errno в EAGAIN? Аналогичный вопрос насчет EPOLLOUT и send.