I use epoll to get the file descriptor that needs to be read, and when I request a page with an image, my socket only receives one request for the page, and no further events are fired.
When I requested the image individually, it successfully accepted the request and returned.
When I looked at the browser's request, it also requested twice, once for a page and once for an image.
I tried not to use epoll, but it still does.
There are times when I can request an image, such as when I go to the next page and return.
Also, when using epoll, the listening socket accepts multiple connections, shouldn't you only use the same connection? Why would it accept other connections when it seems to do nothing?
void Server::serverListen()
{
int listenfd = socket(AF_INET, SOCK_STREAM, 0);
assert(listenfd >= 0);
sockaddr_in addr;
bzero(&addr, sizeof(addr));
addr.sin_addr.s_addr = htonl(INADDR_ANY);
addr.sin_port = htons(port);
addr.sin_family = AF_INET;
int tmp = 1;
setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, &tmp, sizeof(tmp));
int ret = bind(listenfd, (sockaddr*)&addr, sizeof(addr));
assert(ret >= 0);
ret = listen(listenfd, 5);
assert(ret >= 0);
int epollfd = epoll_create(5);
assert(epollfd != -1);
epoll_event events;
events.data.fd = listenfd;
events.events = EPOLLIN;
int n = epoll_ctl(epollfd, EPOLL_CTL_ADD, listenfd, &events);
assert(n != -1);
epoll_event eve[10000];
while (true)
{
int num = epoll_wait(epollfd, eve, 10000, -1);
assert(num != -1);
for (int i = 0; i < num; ++i)
{
int fd = eve[i].data.fd;
if (fd == listenfd)
{
sockaddr_in caddr;
socklen_t tmplen = sizeof(caddr);
connfd = accept(listenfd, (sockaddr*)&caddr, &tmplen);
assert(connfd != -1);
int flag = fcntl(connfd, F_GETFL);
flag |= O_NONBLOCK;
fcntl(connfd, F_SETFL, flag);
epoll_event even;
even.data.fd = connfd;
even.events = EPOLLIN | EPOLLET | EPOLLONESHOT;
int n = epoll_ctl(epollfd, EPOLL_CTL_ADD, connfd, &even);
assert(n != -1);
}
else
{
worker.init(eve[i].data.fd, epollfd, "localhost", "us", "mm", "usersdb", 3306, 5);
threadpool->add(&worker);
}
}
}
close(epollfd);
close(listenfd);
}
Related
I am trying to obtain the packet traveling latency in hardware timestamp between 2 computers connected by 1 Ethernet cable. However the result for obtained delay is 11.5 micro-seconds, which is much higher than my expectation like several nano-seconds.
Design
The way I tried to obtain the latency is demonstrated in the following graph as delay = ((t3 - t0) - (t2 - t1)) / 2
client server
| ping |
t0|-------------->|t1
| |
| pong |
t3|<--------------|t2
| |
v v
Here t0/t2 are Linux hardware sending time recorded by NIC, and t1/t3 are hardware receiving timestamp. The detailed information about linux socket hardware time can be found here: https://docs.kernel.org/networking/timestamping.html. As my understand, t0/t2 are time that NIC transmit the first byte to wire, t1/t3 are time that NIC receive the first byte from wire. Thus the delay that I calculated is purely the propagation delay which should be within several nanoseconds. In addition to prove my assumption, I tried to change the packet size in 256/512/1400 bytes, the results have no change and are all in 11.5 microseconds. Is my understand correct on those hardware timestamp and delay computation?
Implementation
The 2 computers I am using are Dell OptiPlex-7090 on Ubuntu 20.04, the NIC version is Ethernet Connection (14) I219-LM.
The completed code for testing can be found here: https://github.com/ChuanyuXue/Hardware-RTT. It records both hardware timestamp and software timestamp.
utils.c:
void die(char *s)
{
perror(s);
exit(1);
}
int setup_receiver(int fd, int port)
{
struct sockaddr_in addr;
memset(&addr, 0, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = htonl(INADDR_ANY);
addr.sin_port = htons(port);
if (bind(fd, (struct sockaddr *)&addr, sizeof(addr)) == -1)
{
die("bind()");
}
int val = SOF_TIMESTAMPING_RX_HARDWARE | SOF_TIMESTAMPING_RAW_HARDWARE;
if (setsockopt(fd, SOL_SOCKET, SO_TIMESTAMPING, &val, sizeof(val)) == -1)
{
die("setsockopt() HW receiving");
}
int enable = 1;
if (setsockopt(fd, SOL_SOCKET, SO_TIMESTAMPNS, &enable, sizeof(enable)) < 0)
{
die("setsockopt() SW receiving");
}
return 0;
}
int setup_sender(int fd)
{
int timestamp_flags = SOF_TIMESTAMPING_TX_HARDWARE | SOF_TIMESTAMPING_RAW_HARDWARE;
if (setsockopt(fd, SOL_SOCKET, SO_TIMESTAMPING, ×tamp_flags, sizeof(timestamp_flags)) < 0)
{
die("setsockopt() HW sending");
}
int enable = 1;
if (setsockopt(fd, SOL_SOCKET, SO_TIMESTAMPNS, &enable, sizeof(enable)))
{
die("setsockopt() SW receiving");
}
}
int setup_adapter(int fd, char *dev_name)
{
struct hwtstamp_config hwts_config;
struct ifreq ifr;
memset(&hwts_config, 0, sizeof(hwts_config));
hwts_config.tx_type = HWTSTAMP_TX_ON;
hwts_config.rx_filter = HWTSTAMP_FILTER_ALL;
memset(&ifr, 0, sizeof(ifr));
snprintf(ifr.ifr_name, IFNAMSIZ, "%s", dev_name);
ifr.ifr_data = (void *)&hwts_config;
if (ioctl(fd, SIOCSHWTSTAMP, &ifr) == -1)
{
die("ioctl()");
}
}
void send_single(int fd, char *address, int port)
{
/*
Send one message
*/
struct sockaddr_in si_server;
memset(&si_server, 0, sizeof(si_server));
si_server.sin_family = AF_INET;
si_server.sin_port = htons(port);
if (inet_aton(address, &si_server.sin_addr) == 0)
{
die("inet_aton()");
}
char buffer[BUFFER_LEN];
struct iovec iov = (struct iovec){.iov_base = buffer, .iov_len = BUFFER_LEN};
struct msghdr msg = (struct msghdr){.msg_name = &si_server,
.msg_namelen = sizeof si_server,
.msg_iov = &iov,
.msg_iovlen = 1};
ssize_t send_len = sendmsg(fd, &msg, 0);
if (send_len < 0)
{
printf("[!] Error sendmsg()");
}
// -------------- obtain the loopback packet
char data[BUFFER_LEN], control[BUFFER_LEN];
struct iovec entry;
struct sockaddr_in from_addr;
int res;
memset(&msg, 0, sizeof(msg));
msg.msg_iov = &entry;
msg.msg_iovlen = 1;
entry.iov_base = data;
entry.iov_len = sizeof(data);
msg.msg_name = (caddr_t)&from_addr;
msg.msg_namelen = sizeof(from_addr);
msg.msg_control = &control;
msg.msg_controllen = sizeof(control);
// wait until get the loopback
while (recvmsg(fd, &msg, MSG_ERRQUEUE) < 0)
{
}
// encode the returned packet
struct cmsghdr *cmsg;
for (cmsg = CMSG_FIRSTHDR(&msg); cmsg != NULL;
cmsg = CMSG_NXTHDR(&msg, cmsg))
{
if (cmsg->cmsg_level == SOL_SOCKET &&
cmsg->cmsg_type == SCM_TIMESTAMPING)
{
struct timespec *ts =
(struct timespec *)CMSG_DATA(cmsg);
printf("HD-SEND TIMESTAMP %ld.%09ld\n", ts[2].tv_sec, ts[2].tv_nsec);
}
if (cmsg->cmsg_level == SOL_SOCKET &&
cmsg->cmsg_type == SO_TIMESTAMPNS)
{
struct timespec *ts =
(struct timespec *)CMSG_DATA(cmsg);
printf("SW-SEND TIMESTAMP %ld.%09ld\n", ts->tv_sec, ts->tv_nsec);
}
}
}
void recv_single(int fd)
{
char data[BUFFER_LEN], ctrl[BUFFER_LEN];
struct msghdr msg;
struct iovec iov;
ssize_t len;
struct cmsghdr *cmsg;
memset(&msg, 0, sizeof(msg));
msg.msg_iov = &iov;
msg.msg_iovlen = 1;
msg.msg_control = ctrl;
msg.msg_controllen = sizeof(ctrl);
iov.iov_base = data;
iov.iov_len = sizeof(data);
struct timespec start;
if (recvmsg(fd, &msg, 0) < 0)
{
printf("[!] Error recvmsg()");
}
for (cmsg = CMSG_FIRSTHDR(&msg); cmsg != NULL;
cmsg = CMSG_NXTHDR(&msg, cmsg))
{
if (cmsg->cmsg_level == SOL_SOCKET &&
cmsg->cmsg_type == SCM_TIMESTAMPING)
{
struct timespec *ts =
(struct timespec *)CMSG_DATA(cmsg);
printf("HW-RECV TIMESTAMP %ld.%09ld\n", ts[2].tv_sec, ts[2].tv_nsec);
}
if (cmsg->cmsg_level == SOL_SOCKET &&
cmsg->cmsg_type == SCM_TIMESTAMPNS)
{
struct timespec *ts =
(struct timespec *)CMSG_DATA(cmsg);
printf("SW-RECV TIMESTAMP %ld.%09ld\n", ts->tv_sec, ts->tv_nsec);
}
}
}
client.c
int main(int argc, char *argv[])
{
const char *address = "192.168.0.23";
const int port = 54321;
int fd_in = socket(AF_INET, SOCK_DGRAM, 0);
int fd_out = socket(AF_INET, SOCK_DGRAM, 0);
setup_adapter(fd_in, "eth0");
setup_adapter(fd_out, "eth0");
setup_sender(fd_out);
setup_receiver(fd_in, port);
int count = 0;
while (1)
{
printf("[ ---- Iter-%5d ----------------------------- ]\n", count++);
send_single(fd_out, (char *)address, port);
recv_single(fd_in);
usleep(10000);
}
}
server.c
int main(int argc, char *argv[])
{
const char *address = "192.168.0.22";
const int port = 54321;
int fd_in = socket(AF_INET, SOCK_DGRAM, 0);
int fd_out = socket(AF_INET, SOCK_DGRAM, 0);
setup_adapter(fd_in, "eth0");
setup_adapter(fd_out, "eth0");
setup_sender(fd_out);
setup_receiver(fd_in, port);
int count = 0;
while (1)
{
printf("[ ---- Iter-%5d ----------------------------- ]\n", count++);
recv_single(fd_in);
usleep(10000);
send_single(fd_out, (char *)address, port);
}
}
From the results, I can see the hardware timestamp is much more stable and has very low jitter compared with software timestamp(I am sorry my account is not allowed to embed picture into question):
https://github.com/ChuanyuXue/Hardware-RTT/blob/main/0301_exp_hwtime/01.png
https://github.com/ChuanyuXue/Hardware-RTT/blob/main/0301_exp_hwtime/02.png
https://github.com/ChuanyuXue/Hardware-RTT/blob/main/0301_exp_hwtime/03.png
https://github.com/ChuanyuXue/Hardware-RTT/blob/main/0301_exp_hwtime/04.png
https://github.com/ChuanyuXue/Hardware-RTT/blob/main/0301_exp_hwtime/06.png
Above results make me feel the timestamp I obtained is correct as the HW latency has smaller delay and very low jitter, but there are some issues I neglect when I compute delay = ((t3 - t0) - (t2 - t1)) / 2. Is there anyone who can let me know why or test my code on other environment?
Is it possible to use select for packet sockets? I mean whether its necessary for the socket to be connection-based in order to use select function on it properly?
I'm seeing that the behavior of a socket which I got it by the following socket function call:
int socket_fd = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
is not as I expect. For example, I see that a ping packet which is 60 bytes long when received and read into a 20 bytes length buffer, it waits about a second between each recv function call. I used recvfrom and it didn't help. For this, I ask whether it's correct to use select for a packet socket?
Update
I'm going to include the code to discuss about it:
int MakeBridge(const char *if1, const char *if2)
{
int sock[2];
sock[0] = OpenSocket(if1);
sock[1] = OpenSocket(if2);
int activity;
char buf[20];
const int numSocks = 2;
int nfds = sock[0];
for (int i = 1; i < numSocks; i++)
if (sock[i] > nfds)
nfds = sock[i];
nfds++;
while (true)
{
FD_ZERO(&readfds);
for (int i = 0; i < numSocks; i++)
FD_SET(sock[i], &readfds);
activity = select(nfds, &readfds, NULL, NULL, NULL);
if (activity == -1) // sockets closed
break;
for (int i = 0; i < numSocks; i++)
if (FD_ISSET(_sock[i], &readfds))
{
int len;
CHECK(ioctl(_sock[i], FIONREAD, &len) != -1, "%s", strerror(errno));
printf("socket %d is set\n", i);
printf("total bytes available to read: %d\n", len);
CHECK(len > 0, "");
do
{
int n = min(len, sizeof(buf));
int nbr = recvfrom(_sock[i], buf, n, 0, NULL, NULL);
printf("n %d nbr %d\n", n, nbr);
CHECK(n == nbr, "");
len -= n;
} while (len);
}
}
return 0;
}
Update 2
Not going to segment messages and using large enough buffer makes the code as follows:
// This is a program which is going to make the bridge between two interfaces. brctl is going to be replaced by this program.
#define Uses_CHECK
#define Uses_close
#define Uses_errno
#define Uses_ETH_P_ALL
#define Uses_FD_SET
#define Uses_htons
#define Uses_ifreq
#define Uses_ioctl
#define Uses_printf
#define Uses_signal
#define Uses_sockaddr_ll
#define Uses_socket
#define Uses_strerror
#include <general.dep>
int _sock[2];
int _CtrlCHandler()
{
printf(" terminating...\n");
CHECK(close(_sock[0]) != -1, "");
CHECK(close(_sock[1]) != -1, "");
printf("all sockets closed successfully.\n");
}
void CtrlCHandler(int dummy)
{
_CtrlCHandler();
}
int OpenSocket(const char *ifname)
{
// getting socket
int socket_fd = socket(PF_PACKET, SOCK_RAW/*|SOCK_NONBLOCK*/, htons(ETH_P_ALL));
CHECK(socket_fd != -1, "%s", strerror(errno));
// init interface options struct with the interface name
struct ifreq if_options;
memset(&if_options, 0, sizeof(struct ifreq));
strncpy(if_options.ifr_name, ifname, sizeof(if_options.ifr_name) - 1);
if_options.ifr_name[sizeof(if_options.ifr_name) - 1] = 0;
// enable promiscuous mode
CHECK(ioctl(socket_fd, SIOCGIFFLAGS, &if_options) != -1, "%s", strerror(errno));
if_options.ifr_flags |= IFF_PROMISC;
CHECK(ioctl(socket_fd, SIOCSIFFLAGS, &if_options) != -1, "%s", strerror(errno));
// get interface index
CHECK(ioctl(socket_fd, SIOCGIFINDEX, &if_options) != -1, "%s", strerror(errno));
// bind socket to the interface
struct sockaddr_ll my_addr;
memset(&my_addr, 0, sizeof(my_addr));
my_addr.sll_family = AF_PACKET;
my_addr.sll_ifindex = if_options.ifr_ifindex;
CHECK(bind(socket_fd, (struct sockaddr *)&my_addr, sizeof(my_addr)) != -1, "%s", strerror(errno));
// socket is ready
return socket_fd;
}
int MakeBridge(const char *if1, const char *if2)
{
_sock[0] = OpenSocket(if1);
CHECK_NO_MSG(_sock[0]);
_sock[1] = OpenSocket(if2);
CHECK_NO_MSG(_sock[1]);
printf("sockets %d and %d opened successfully\n", _sock[0], _sock[1]);
fd_set readfds, orig;
int activity;
char buf[1<<16];
signal(SIGINT, CtrlCHandler);
int packetNumber = 0;
const int numSocks = _countof(_sock);
int nfds = _sock[0];
for (int i = 1; i < numSocks; i++)
if (_sock[i] > nfds)
nfds = _sock[i];
nfds++;
FD_ZERO(&orig);
for (int i = 0; i < numSocks; i++)
FD_SET(_sock[i], &orig);
while (true)
{
readfds = orig;
activity = select(nfds, &readfds, NULL, NULL, NULL);
if (activity == -1) // sockets closed
break;
CHECK(activity > 0, "");
for (int i = 0; i < numSocks; i++)
if (FD_ISSET(_sock[i], &readfds))
{
int len = recvfrom(_sock[i], buf, sizeof(buf), MSG_TRUNC, NULL, NULL);
CHECK(len > 0, "");
CHECK(len <= sizeof(buf), "small size buffer");
printf("%10d %d %d\n", ++packetNumber, i, len);
CHECK(sendto(_sock[!i], buf, len, 0, NULL, 0) == len, "");
}
}
return 0;
}
int Usage(int argc, const char *argv[])
{
printf("Usage: %s <if1> <if2>\n", argv[0]);
printf("Bridges two interfaces with the names specified.\n");
return 0;
}
int main(int argc, const char *argv[])
{
if (argc != 3)
return Usage(argc, argv);
CHECK_NO_MSG(MakeBridge(argv[1], argv[2]));
return 0;
}
I try to use connect() & O_NONBLOCK to connect to a port in localhost asynchronously. In order to get the connect result, I use getsockopt to check the socket error status. I can sure no one listen to this port, so ECONNREFUSED should be returned. But in my test, this error may not be returned in some cases.
My test program:
int main() {
uint64_t p = 0;
while (1) {
int fd = ::socket(PF_INET, SOCK_STREAM, 0);
assert(fd > 0);
int flags = ::fcntl(fd, F_GETFL, 0);
flags |= O_NONBLOCK;
int ret = ::fcntl(fd, F_SETFL, flags);
assert(ret != -1);
sockaddr_in addr;
bzero(&addr, sizeof(sockaddr_in));
addr.sin_family = AF_INET;
addr.sin_port = htons(25400);
addr.sin_addr.s_addr = inet_addr("127.0.0.1");
ret = ::connect(fd, (sockaddr *)&addr, sizeof(sockaddr));
assert(ret != 0);
switch (errno) {
case EINPROGRESS:
case EINTR:
case EISCONN:
break;
default:
assert(false);
}
int epfd = epoll_create1(0);
assert(epfd > 0);
epoll_event ev;
ev.events = EPOLLOUT;
ev.data.fd = fd;
ret = epoll_ctl(epfd, EPOLL_CTL_ADD, fd, &ev);
assert(ret == 0);
epoll_event events;
auto nfds = epoll_wait(epfd, &events, 1, -1);
assert(nfds == 1);
assert(events.data.fd == fd);
int err;
socklen_t optlen = static_cast<socklen_t>(sizeof err);
ret = ::getsockopt(fd, SOL_SOCKET, SO_ERROR, &err, &optlen);
assert(ret == 0);
assert(err != 0);
::close(fd);
::close(epfd);
if (p++ % 10000 == 0) {
std::cout << p << std::endl;
}
}
}
assert(err != 0); will be triggered.
In this test code, I use connect() without bind(), in this case, the source port is choosen by kernel. So the source port may be the same as destination port 25400. Due to the destination ip address is localhost, this TCP connection can be established in this case.
I use netlink to receive an interrupt number from kernel. The application in user space uses libevent to handle TCP/IP request and netlink message. Does libevent support Linux netlink socket? I will appreciate for a simple example.
Yes, libevent supports netlink socket.
There is https://github.com/libevent/libevent/blob/master/sample/hello-world.c, it is modified below to listen to netlink socket.
The basic example listens to Linux network interface creation/deletion and can be executed with sudo to gain privilege needed. It listens to same events as ip monitor link.
Another example of listening to RAW sockets with libevent is here https://github.com/bodgit/libevent-natpmp/blob/master/natpmp.c.
static void link_recvmsg(int fd, short event, void *arg)
{
char buf[NLMSG_SPACE(BUF_SIZE)] = {0};
socklen_t socklen;
struct iovec iov = {.iov_base = buf, .iov_len = sizeof(buf)};
struct sockaddr addr;
memset(&addr, 0, sizeof(struct sockaddr));
if (!fd || -1 == fd)
return;
int status = getsockname(fd, &addr, &socklen);
if(-1 == status)
return;
struct msghdr mh = {.msg_name = NULL, .msg_namelen = 0, .msg_iov = &iov, .msg_iovlen = 1,
.msg_flags = 0, .msg_name = &addr, .msg_namelen = sizeof(struct sockaddr)};
status = recvmsg(fd, &mh, 0);
if ((-1 == status) && ((EINTR == errno) || (EAGAIN == errno)))
return;
if(-1 == status)
return;
if ((mh.msg_flags & MSG_TRUNC) == MSG_TRUNC)
return;
if ((mh.msg_flags & MSG_CTRUNC) == MSG_CTRUNC)
return;
for (const struct nlmsghdr *h = (struct nlmsghdr *)buf; NLMSG_OK(h, status); h = NLMSG_NEXT(h, status)) {
switch (h->nlmsg_type) {
case RTM_NEWLINK:
fprintf(stderr, "got RTM_NEWLINK\n");
break;
case RTM_DELLINK:
fprintf(stderr, "got RTM_DELLINK\n");
break;
default:
fprintf(stderr, "unexpected case in swtch statement\n");
break;
}
}
}
int main(int argc, char **argv)
{
/* some init code here */
/* NETLINK socket */
int status;
int buf_size = BUF_SIZE;
struct sockaddr_nl src_addr;
int socket_nl = socket(AF_NETLINK, SOCK_RAW | SOCK_NONBLOCK, NETLINK_ROUTE);
if(-1 == socket_nl) return -1;
memset(&src_addr, 0, sizeof(struct sockaddr_nl));
src_addr.nl_family = AF_NETLINK;
src_addr.nl_pid = getpid();
src_addr.nl_groups |= RTNLGRP_LINK;
status = setsockopt(socket_nl, SOL_SOCKET, SO_RCVBUF,
&buf_size, sizeof(buf_size));
if(-1 == status) return -1;
status = bind(socket_nl, (struct sockaddr *)&src_addr, sizeof(struct sockaddr_nl));
if(status < 0) return -1;
static struct event nl_ev;
event_set(&nl_ev, socket_nl, EV_READ|EV_PERSIST, link_recvmsg,
NULL);
if (base) {
event_base_set(base, &nl_ev);
}
event_add(&nl_ev, NULL);
/* some other code, dispatch event and deinit */
}
I run a Linux program written in C that would periodically receive data by parsing an HTTP response, crunch some numbers and then report the result by HTTP GET of another web page.
My problem is that sometimes, one of the instances would "freeze".
Looking at top I can see that it is in sk_wait_data state and attaching a debugger reveals that it is blocked by a recv call.
Here is a minimal version of the code that does the TCP connection (it was adapted from http://www.linuxhowtos.org/C_C++/socket.htm):
int connectTCP(const char* host, const char* page, int portno) {
int sockfd;
struct sockaddr_in serv_addr;
struct hostent *server;
// Create socket //
sockfd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (sockfd < 0)
error("ERROR opening socket");
// Get ip from hostname //
server = gethostbyname(host);
if (server == NULL)
error("ERROR, can not find host\n");
memset((char *) &serv_addr, 0, sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
memcpy((char *)&serv_addr.sin_addr.s_addr, // Destination
(char *)server->h_addr, // Source
server->h_length); // Size
serv_addr.sin_port = htons(portno);
// Conect to socket //
if (connect(sockfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0)
error("ERROR connecting");
return sockfd;
}
char* httpGet(const char* host, const char* page, int portno) {
int sockfd, n;
sockfd = connectTCP(host, page, portno);
memset(buffer, 0, sizeof(buffer));
sprintf(buffer, "GET /%s HTTP/1.0\r\nHost: %s\r\n\r\n", page, host);
n = send(sockfd,buffer,strlen(buffer), 0);
if (n < 0)
error("ERROR writing to socket");
int count = 0;
do {
n = recv(sockfd, buffer + count, BUFFER_MAX_SIZE - count, 0);
if (n < 0) {
error("ERROR reading from socket");
}
count += n;
} while(n != 0);
close(sockfd);
return buffer;
}
Bugs in your code:
If recv() returns zero you whould close the socket and stop reading.
If recv() returns -1 you should report the error, close the socket, and stop reading, unless you had set a read timeout and errno was EAGAIN/EWOULDBLOCK, in which case you should handle the timeout however is appropriate for your application.