recv() not triggering with libevent - c

I am trying to connect to the local openvpn client over its managment socket and query its state/status.
I have implemented the follow program with libevent support.
#include <stdio.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <event2/event.h>
#include <fcntl.h>
#include <string.h>
char message[1000], server_reply[2000];
struct event *ev, *ev1, *ev2;
int fd_set_blocking(int fd, int blocking)
{
int flags = fcntl(fd, F_GETFL, 0);
if (flags == -1) {
return 0;
}
if (blocking) {
flags &= ~O_NONBLOCK;
} else {
flags |= O_NONBLOCK;
}
return fcntl(fd, F_SETFL, flags) != -1;
}
void cb_func_hold_release(evutil_socket_t fd, short what, void *arg)
{
int sock = *(int *)arg;
struct timeval one_seconds = {1,0};
printf("IN CB CONNECT\n");
sprintf (message, "hold release\n");
if (send (sock, message, strlen (message), 0) < 0) {
printf("send failed\n");
}
event_add(ev1, NULL);
}
void cb_func_write(evutil_socket_t fd, short what, void *arg)
{
int sock = *(int *)arg;
printf("IN CB CHECKSTATUS\n");
sprintf (message, "status\n");
if (send (sock, message, strlen (message), 0) < 0) {
printf("send failed\n");
}
/*
int reclen = recv (sock, server_reply, 2000, 0);
if (reclen < 0) {
printf("recving failed");
} else {
if (reclen > 1) {
server_reply[reclen-1] = '\0';
}
printf("SERVER REPLT< %s\n", server_reply);
}
if (strstr(message, "CONNECTED")) {
printf("VPN CONNECTED");
}
*/
event_add(ev2, NULL);
if (event_pending(ev2,EV_READ|EV_PERSIST, NULL)) {
printf("ADDED READ EVENT\n");
}
}
void cb_func_read(evutil_socket_t fd, short what, void *arg)
{
int sock = *(int *)arg;
printf("IN CB READ\n");
int reclen = recv (sock, server_reply, 2000, 0);
if (reclen < 0) {
printf("recving failed");
} else {
if (reclen > 1) {
server_reply[reclen-1] = '\0';
}
printf("SERVER REPLY %s\n", server_reply);
}
if (strstr(message, "CONNECTED")) {
printf("VPN CONNECTED");
}
}
int main(void)
{
int flags;
int mgmretry = 0;
int sock = 0;
struct sockaddr_in server;
struct timeval five_seconds = {1,0};
struct event_base *base = event_base_new();
ev = event_new(base, sock, EV_TIMEOUT, cb_func_hold_release, &sock);
ev1 = event_new(base, sock, EV_WRITE, cb_func_write, &sock);
ev2 = event_new(base, sock, EV_READ, cb_func_read, &sock);
sock = socket (AF_INET, SOCK_STREAM, 0);
if (sock == -1) {
printf("COUILD NOT CREATE SOCKET\n");
exit(0);
}
fd_set_blocking(sock, 1);
server.sin_addr.s_addr = inet_addr("127.0.0.1");
server.sin_family = AF_INET;
server.sin_port = htons (12345);
if (connect (sock, (struct sockaddr *)&server, sizeof (server)) < 0) {
printf("connecting failed\n");
exit(0);
}
event_add(ev, &five_seconds);
printf("DISPATCHING\n");
event_base_dispatch(base);
}
The issue is the the read callback "cb_func_read" is not being triggered. My expectation is that after I send the "status" message to the vpn from cb_func_write(), there is some data sent back which should trigger the read callback but that's not happening.
If I recv() directly after send() in the write callback(the commented portion) I can print the response sent from openvpn so the communication between these two are working.

The event will not trigger unless you armed it using event_add().
You have only done this for the ev event, but not for ev1 and ev2.

silly ,mistake...events ev,ev1,ev2 with event_new() come AFTER creating a socket+making it nonblock... not before

Related

Linux sockets: second read() fails on localhost

I have a server that acknowledges a command and then sends data. It works fine with the command line: echo "show version" | nc -q1 127.0.0.1 5000 gives:
Command received: show version
Beta
I have a client that should behave exactly the same as the command line test, but it hangs on the second read() call unless I run it on a different server. I've had the same issue with unix domain sockets, except that they occasionally work.
Why would it fail only on localhost?
Client Source
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#define ERR_FAIL_CONNECT -1
#define ERR_SOCK_SELECT -2
#define ERR_SOCK_READ -3
#define ERR_SOCK_WRITE -3
#define ERR_SOCK_REMOTE_CLOSED -4
int tcpConnect (char *ipAddr, int port);
int sendCommand (char *buf, int bufSize);
int readWithTimeout (int sock, char *buf, int bufSize, struct timeval *timeout);
int main() {
char buf[64];
int nBytes;
strcpy(buf, "show version");
nBytes = sendCommand(buf, sizeof(buf));
printf("Response: %s\n", buf);
return 0;
}
int sendCommand (char *buf, int bufSize) {
int apiSock;
int nBytes = ERR_SOCK_SELECT;
int len;
struct timeval timeout;
apiSock = tcpConnect("127.0.0.1", 5000);
if (!apiSock) return ERR_FAIL_CONNECT;
len = strlen(buf);
nBytes = write(apiSock, buf, len);
if (nBytes < 0) {
perror("ERROR writing to socket");
nBytes = ERR_SOCK_WRITE;
}
else if (nBytes < len) {
fprintf(stderr, "Command truncated at %d/%d\n", nBytes, len);
nBytes = ERR_SOCK_WRITE;
}
else {
timeout.tv_sec = 3;
timeout.tv_usec = 0;
nBytes = readWithTimeout(apiSock, buf, bufSize, &timeout);
if (nBytes > 0) {
timeout.tv_sec = 20;
timeout.tv_usec = 0;
nBytes = readWithTimeout(apiSock, buf, bufSize, &timeout);
}
}
close(apiSock);
return nBytes;
}
int tcpConnect (char *ipAddr, int port) {
struct sockaddr_in addr;
int sock;
sock = socket(AF_INET, SOCK_STREAM, 0);
if (sock == -1) {
perror("ERROR: Could not create TCP socket");
return 0;
}
addr.sin_addr.s_addr = inet_addr(ipAddr);
addr.sin_family = AF_INET;
addr.sin_port = htons(port);
if (connect(sock, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
perror("ERROR: Could not connect");
return 0;
}
return sock;
}
int readWithTimeout (int sock, char *buf, int bufSize, struct timeval *timeout) {
int res;
int nBytes = ERR_SOCK_SELECT;
fd_set set;
fprintf(stderr, "readWithTimeout(sock=%d, buf='%s', bufSize=%d, timeout{tv_sec=%d, tv_usec=%d})\n",
sock, buf, bufSize, timeout->tv_sec, timeout->tv_usec);
FD_ZERO(&set);
FD_SET(sock, &set);
res = select(sock+1, &set, NULL, NULL, timeout);
if (res < 0) perror("ERROR waiting for data");
else if (res == 0) fprintf(stderr, "Timed out waiting for data\n");
else {
nBytes = read(sock, buf, bufSize);
if (nBytes < 0) {
perror("ERROR reading from socket");
nBytes = ERR_SOCK_READ;
}
else if (nBytes == 0) {
fprintf(stderr, "Remote end closed socket\n");
shutdown(sock, 2);
close(sock);
nBytes = ERR_SOCK_REMOTE_CLOSED;
}
}
return nBytes;
}
Server Source
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <fcntl.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#define TCP_PORT 5000
#define BUF_SIZE 512
int readCommand(int clientSockFd);
void myWrite (int fileDescriptor, const void *buf, size_t nbytes);
int main (void) {
socklen_t client_len;
int optval;
int flags;
struct sockaddr_in serv_addr, client_addr;
int serverSockFd;
int clientSockFd;
fd_set set;
struct timeval timeout;
int rv;
serverSockFd = socket(AF_INET, SOCK_STREAM, 0);
if(serverSockFd < 0) perror("ERROR opening socket");
bzero((char *) &serv_addr, sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = INADDR_ANY;
serv_addr.sin_port = htons(TCP_PORT);
if(bind(serverSockFd, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0) {
perror("Unable to bind TCP socket");
}
listen(serverSockFd, 5);
client_len = sizeof(client_addr);
flags = fcntl(serverSockFd, F_GETFL, 0);
if (flags < 0) perror("Unable to read TCP socket flags");
flags = flags|O_NONBLOCK;
fcntl(serverSockFd, F_SETFL, flags);
// Wait for client connections
while(1) {
clientSockFd = accept(serverSockFd, (struct sockaddr *) &client_addr, &client_len);
if(clientSockFd < 0) {
usleep(50000);
continue;
}
//After connected, inner loop to read and write multiple packages
while(1) {
FD_ZERO(&set);
FD_SET(clientSockFd, &set);
timeout.tv_sec = 15;
timeout.tv_usec = 0;
rv = select(clientSockFd+1, &set, NULL, NULL, &timeout);
if(rv == -1) {
perror("select");
continue;
}
else if(rv == 0) {
printf("TCP timeout, closing client connection.\n");
shutdown(clientSockFd, 2);
break;
}
if (!readCommand(clientSockFd)) break;
}
close(clientSockFd);
}
close(serverSockFd);
return 0;
}
int readCommand(int sock) {
int nBytes;
int len;
char inBuf[BUF_SIZE];
char outBuf[BUF_SIZE];
nBytes = read(sock, inBuf, BUF_SIZE);
if(nBytes < 0) perror("ERROR reading from TCP socket");
else if(nBytes == 0) {
printf("Client closed TCP socket\n");
shutdown(sock, 2);
return nBytes;
}
else {
// Acknowledge command
len = sprintf(outBuf, "Command received: %s", inBuf);
if (write(sock, outBuf, len+1) < 0) {
perror("ERROR writing to TCP socket");
}
// Send response data
if (!strncmp("show version", inBuf, 12)) strcpy(outBuf, "Beta");
else strcpy(outBuf, "Invalid command");
if (write(sock, outBuf, strnlen(outBuf, BUF_SIZE-1)+1) < 0) {
perror("ERROR writing to TCP socket");
}
}
return nBytes;
}
I just realized both the acknowledgement and the data were consumed in the first read() when running the client on localhost.
So I need to parse the result of the first read before attempting a second.

Epoll tcp server grinds to a halt when accepting connections

I'm trying to connect 10,000+ tcp clients to my tcp server below. After 1-5 seconds I'm able to get between 200 and 5000 clients connected before the code grinds to a halt and hangs without terminating. I cant find any further documentation on this and the gprof profiler isnt able to collect any data.
Server:
#include <unistd.h>
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <fcntl.h>
#include <sys/epoll.h>
#include <netdb.h>
#include <errno.h>
#include <iostream>
#ifndef MAXEVENTS
#define MAXEVENTS 64
#endif
#ifndef TX_BUF_SIZE
#define TX_BUF_SIZE (65535)
#endif
#ifndef RX_BUF_SIZE
#define RX_BUF_SIZE (65535)
#endif
char buf[RX_BUF_SIZE];
void user_recv_handler(int efd, int fd, char * buf, int len)
{
int s = -1;
struct epoll_event ev;
ev.data.fd = fd;
ev.events = EPOLLOUT | EPOLLET;
s = epoll_ctl(efd, EPOLL_CTL_MOD, fd, &ev);
//assert(s!=-1);
if(s==-1)
{
fprintf(stderr, "epoll out error.\n");
return;
}
}
struct addrinfo* tcpipv4_getaddrinfo(char* port)
{
struct addrinfo hints;
struct addrinfo *res;
int s;
bzero(&hints, sizeof(struct addrinfo));
hints.ai_family = AF_INET; // ipv4 addrs
hints.ai_socktype = SOCK_STREAM; // TCP
hints.ai_flags = AI_PASSIVE;
s = getaddrinfo(NULL, port, &hints, &res);
//assert(s==0);
if (s)
{
fprintf(stderr, "failed to getaddrinfo: %s\n", gai_strerror(s));
return NULL;
}
return res;
}
struct addrinfo* tcpipv6_getaddrinfo(char* port)
{
struct addrinfo hints;
struct addrinfo *res;
int s;
bzero(&hints, sizeof(struct addrinfo));
hints.ai_family = AF_INET6; // ipv4 addrs
hints.ai_socktype = SOCK_STREAM; // TCP
hints.ai_flags = AI_PASSIVE;
s = getaddrinfo(NULL, port, &hints, &res);
//assert(s==0);
if (s)
{
fprintf(stderr, "failed to getaddrinfo-ipv6: %s\n", gai_strerror(s));
return NULL;
}
return res;
}
int set_nonblock(int fd)
{
int flags = -1;
if(-1 == (flags = fcntl(fd, F_GETFL, 0)))
{
return -1;
}
flags |= O_NONBLOCK;
if( fcntl(fd, F_SETFL, flags) == -1 )
{
return -1;
}
return 0;
}
int tcpipv4_createfd_bind(struct addrinfo* rp)
{
int flags = -1;
int s;
// create socket
int sfd = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol);
//assert(sfd!=-1);
if (sfd == -1)
{
fprintf(stderr, "failed to create socket\n");
return -1;
}
// bind
s = bind(sfd, rp->ai_addr, rp->ai_addrlen);
//assert(s==0);
if(s!=0)
{
fprintf(stderr, "failed to bind socket %d\n", sfd);
return -1;
}
// nonblock
s = set_nonblock(sfd);
//assert(s != -1);
if (s == -1)
{
fprintf(stderr, "failed to set nonblocking socket %d\n", sfd);
return -1;
}
return sfd;
}
int writen(int fd, char * buf, size_t len)
{
char * cur = buf;
int n = -1;
while(len>0)
{
n = write(fd, cur, len);
if (n<=0)
{
if(errno == EINTR) continue;
else return -1;
}
len -= n;
cur += n;
}
return 0;
}
int readn(int fd, char* buf, size_t len)
{
char *cur = buf;
int n = -1;
while (len>0)
{
n = read(fd, cur, len);
if (n == -1)
{
if (errno == EINTR)
continue;
else break;
}
else if (n == 0)
break;
cur += n; len -= n;
}
return (int)(cur-buf);
}
void accept_handler(int efd, int listenfd)
{
struct epoll_event event;
int s;
while(1)
{
struct sockaddr in_addr;
socklen_t in_addrlen = sizeof(struct sockaddr);
int infd = -1;
char hbuf[NI_MAXHOST], sbuf[NI_MAXSERV];
infd = accept(listenfd, &in_addr, &in_addrlen);
//assert(infd != -1);
if(infd == -1)
{
if(errno == EAGAIN || errno == EWOULDBLOCK)
;
else
perror("failed to accept\n");
return;
}
s = getnameinfo(&in_addr, in_addrlen,
hbuf, sizeof(hbuf),
sbuf, sizeof(sbuf),
NI_NUMERICHOST | NI_NUMERICSERV);
//assert(s == 0);
if(s == 0)
{
printf("Accept fd %d host %s port %s\n", infd, hbuf, sbuf);
s = set_nonblock(infd);
//assert(s!=-1);
event.data.fd = infd;
event.events = EPOLLIN | EPOLLET;
s = epoll_ctl(efd, EPOLL_CTL_ADD, infd, &event);
//assert(s != -1);
return;
}
}
return;
}
void read_handler(int efd, int fd)
{
//do sonething with buf.
int s = -1;
s=readn(fd, buf, sizeof(buf));
buf[s] = 0;
//printf("recv %d bytes: %s", s, buf);
if(s < 0)
{
close(fd);
if(-1 == epoll_ctl(efd, EPOLL_CTL_DEL, fd, NULL) )
fprintf(stderr, "failed to del event of %d\n", fd);
printf("close conection on fd %d", fd);
}
else if(s > 0)
{
//std::cout << buf << std::endl;
//do sonething with buf.
user_recv_handler(efd, fd, buf, s);
}
}
void write_handler(int efd, int fd)
{
writen(fd, buf, strlen(buf));
if(-1 == epoll_ctl(efd, EPOLL_CTL_DEL, fd, NULL) )
fprintf(stderr, "failed to del event of %d\n", fd);
// close(fd);
}
int main(int argc, char ** argv)
{
char* port = NULL;
int listenfd = -1;
struct addrinfo* hostaddr=NULL;
struct addrinfo* rp = NULL;
struct epoll_event event;
struct epoll_event * events, *cur_ev;
int efd = -1;
int num_ev = -1;
int s;
port = argv[1];
// get server ipv4 address by getaddrinfo
(rp = hostaddr = tcpipv4_getaddrinfo(port));
// create and bind listening socket
for(; rp; rp = rp->ai_next)
{
(listenfd = tcpipv4_createfd_bind(rp));
if(-1 == listenfd)
continue;
}
freeaddrinfo(hostaddr);
//assert(listenfd!=-1);
if(listenfd==-1)
exit(EXIT_FAILURE);
//start listening
(s = listen(listenfd, SOMAXCONN));
//assert(s!=-1);
if(s == -1)
exit(EXIT_FAILURE);
// create epoll
efd = epoll_create(MAXEVENTS);
//assert(efd != -1);
if(efd == -1)
exit(EXIT_FAILURE);
event.data.fd = listenfd;
// epoll: read, ET
event.events = EPOLLIN | EPOLLET;
s = epoll_ctl(efd, EPOLL_CTL_ADD, listenfd, &event);
//assert(s!=-1);
if(s==-1)
exit(EXIT_FAILURE);
events = (struct epoll_event*)calloc(MAXEVENTS, sizeof(struct epoll_event));
// event loop;
while (1)
{
num_ev = epoll_wait(efd, events, MAXEVENTS, -1);
// for each active event:
while(num_ev--)
{
cur_ev = events+num_ev;
// close the fd if error (ERR) or hang up (HUP)
if(cur_ev->events & EPOLLERR ||
cur_ev->events & EPOLLHUP)
{
fprintf(stderr, "epoll get event error\n");
close(cur_ev->data.fd);
continue;
}
// one or more new connections (fd = listenfd)
else if(cur_ev->data.fd == listenfd)
{
accept_handler(efd, listenfd);
continue;
}
else if(cur_ev->events & EPOLLIN)
{
// since the registered event is EPOLLIN,
// here we have data on fd waiting for reading.
read_handler(efd, cur_ev->data.fd);
}
else if (cur_ev->events & EPOLLOUT)
{
write_handler(efd, cur_ev->data.fd);
}
}
}
free(events); events = NULL;
close(listenfd);
exit(EXIT_SUCCESS);
}
Client:
int connected_count=0;
int i=0;
struct timespec tstart={0,0}, tend={0,0};
clock_gettime(CLOCK_MONOTONIC, &tstart);
for(; i!=10000; i++)
{
int sockfd;
int portno = 4000;
ssize_t n;
struct sockaddr_in serveraddr;
struct hostent* server;
char hostname[] = "127.0.0.1";
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if(sockfd < 0)
{
printf("ERROR opening socket");
printf("error %d",errno);
test_function_killall(NULL);
return;
}
server = gethostbyname(hostname);
if(server == NULL)
{
fprintf(stderr,"ERROR, no such host as %s\n", hostname);
test_function_killall(NULL);
return;
}
bzero((char*)&serveraddr, sizeof(serveraddr));
serveraddr.sin_family = AF_INET;
bcopy((char*)server->h_addr, (char*)&serveraddr.sin_addr.s_addr, server->h_length);
serveraddr.sin_port = htons(portno);
if(connect(sockfd, (struct sockaddr*)&serveraddr, sizeof(serveraddr)) < 0)
{
printf("ERROR connecting");
test_function_killall(NULL);
return;
}
else
{
std::cout << "active connections " << connected_count++ << std::endl;
}
set_nonblock(sockfd);
}
if(connected_count==10000)
{
printf("complete");
}
Start with this:
Remove the EPOLLET flags from the listen socket registration. You
might want to remove it from the client connection sockets too.
Set your listen socket to non-blocking similar to how the client
connection sockets returned from accept are set.
There's all kinds of edge cases with the listen sockets. I'm not sure, but it appears you aren't fully draining the accept queue when epoll_ctl comes back to indicate that the listen socket has a connection ready. (Think: multiple incoming connections on one edge trigger). It's possible you are blocking on accept and/or stuck on epoll_wait.
Update:
Another thing you could be hitting are the system limits for the maximum number of files handles per process. Read up here.

Seeing two accept events on epoll

I'm playing around with epoll on Linux for the first time and see some strange behavior. Specificall, when I connect with a client to a socket, I see two events emitted by epoll_wait on the server side. When I call accept on the second attempt I get a "temporary unavailable" error.
Here's the simple client code:
#include <stdio.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <unistd.h>
const char* msg = "friendly ping";
int main(int argc, char** argv) {
if (argc != 2) {
fprintf(stderr, "Usage: %s <socket>\n", argv[0]);
exit(-1);
}
int sock = socket(AF_UNIX, SOCK_STREAM, 0);
if (sock < 0) {
perror("socket");
exit(-1);
}
struct sockaddr_un addr;
addr.sun_family = AF_UNIX;
strncpy(addr.sun_path, argv[1], sizeof(addr.sun_path) - 1);
if (connect(sock, (struct sockaddr*)&addr, sizeof(addr)) == -1) {
perror("Error connecting");
exit(-1);
}
write(sock, msg, strlen(msg));
close(sock);
return 0;
}
The server code is the following:
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/epoll.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <unistd.h>
const int kMaxEvents = 100;
const char *kSocketFile = "dummy_socket";
void MakeNonBlocking(int fd) {
int flags, s;
flags = fcntl (fd, F_GETFL, 0);
if (flags == -1) {
perror ("fcntl");
exit(-1);
}
flags |= O_NONBLOCK;
s = fcntl (fd, F_SETFL, flags);
if (s == -1) {
perror ("fcntl");
exit(-1);
}
}
void AcceptConnections(int sock, int epoll_fd) {
struct epoll_event event;
event.data.fd = sock;
event.events = EPOLLIN;
int insock = accept(sock, NULL, NULL);
if (insock < 0) {
perror("Error accepting connection");
exit(-1);
}
MakeNonBlocking(insock);
int s = epoll_ctl(epoll_fd, EPOLL_CTL_ADD, insock, &event);
if (s < 0) {
perror("Epoll error adding accepted connection");
exit(-1);
}
printf("Connection processed.\n");
}
int main(void) {
int sock, efd, n;
struct sockaddr_un addr;
struct epoll_event event;
struct epoll_event *events;
char buf[1024];
if ((sock = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) {
perror("Error creating socket.");
exit(-1);
}
addr.sun_family = AF_UNIX;
strncpy(addr.sun_path, kSocketFile, sizeof(addr.sun_path) - 1);
if (bind(sock, (struct sockaddr *)&addr, sizeof(addr)) == -1) {
perror("Error binding name to socket");
exit(-1);
}
if (listen(sock, SOMAXCONN) < 0) {
perror("Error listening on socket");
exit(-1);
}
MakeNonBlocking(sock);
if ((efd = epoll_create1(0)) < 0) {
perror("Epoll initialization error");
exit(-1);
}
event.data.fd = sock;
event.events = EPOLLIN;
if (epoll_ctl(efd, EPOLL_CTL_ADD, sock, &event) < 0) {
perror("Epoll error adding socket");
exit(-1);
}
events = (struct epoll_event*) calloc(kMaxEvents, sizeof(event));
if (!events) {
perror("Error allocating event buffers");
exit(-1);
}
while(1) {
printf("Calling epoll_wait\n");
if ((n = epoll_wait(efd, events, kMaxEvents, -1)) == -1) {
perror("epoll_wait failure");
exit(-1);
}
for (int i = 0; i < n; ++i) {
printf("Checking event for fd = %d\n", events[i].data.fd);
if (sock == events[i].data.fd) {
AcceptConnections(sock, efd);
continue;
}
int count = read(events[i].data.fd, buf, 100);
if (count == 0) {
close(events[i].data.fd);
}
write(1, buf, count);
}
}
free(events);
close(efd);
close(sock);
unlink(kSocketFile);
return 0;
}
When I run the server and connect to the client I get:
Calling epoll_wait
Checking event for fd = 3
Connection processed.
Calling epoll_wait
Checking event for fd = 3
Error accepting connection: Resource temporarily unavailable
In other words, I see two events on the listening socket. Any ideas?
To fix, change AcceptConnections to:
void AcceptConnections(int sock, int epoll_fd) {
struct epoll_event event;
event.events = EPOLLIN;
int insock = accept(sock, NULL, NULL);
if (insock < 0) {
perror("Error accepting connection");
exit(-1);
}
// This is the important change.
event.data.fd = insock;
MakeNonBlocking(insock);
int s = epoll_ctl(epoll_fd, EPOLL_CTL_ADD, insock, &event);
if (s < 0) {
perror("Epoll error adding accepted connection");
exit(-1);
}
printf("Connection processed.\n");
}
epoll is sometimes funny...
The issue is with the way you register the event in AcceptConnections.
epoll accepts two different fd values, one in event.data.fd (user opaque data value) and the other in the beginning of the epoll_ctl function call (the fd controlling the event).
The event.data.fd can be anything, and it's the actual data you read in your event loop...
... in your original code, you set it to the listening socket instead of the client socket.
So, when the client socket has data ready to be read, an event is raised with event.data.fd pointing at the listening socket instead of the client socket.
Since you don't clear the event (for the client socket), it's repeatedly raised with the data you set (the listening socket fd).
Good Luck!

C, Socket, pthread: read doesn't work on a new thread

I'm making a client-server program in C using threads.
I've got this problem: on the server, on thread #1 (number_one), function "read" works fine. But when I create another thread #2 (number_two), on this one something goes wrong. Parameters are passed in the right way (I think).
-->thread number_one
...
char message[256];
int new_connection=accept(master_sock,NULL,NULL);
pthread_t temp
if(pthread_create(&temp , NULL , number_two , (void*) &new_connection))
{
perror("pthread_create failed");
exit(-2);
}
else
{
puts("number_two created");
if(read(new_connection, message, 256) > 0)
printf("Message from client is %s", message);
}
if(pthread_detach(temp))
{
perror("detach failed");
exit(-3);
}
...
---> thread number_two
void *number_two(void *sock_desc)
{
int sock = *(int*)sock_desc;
int read_size;
char client_message[2000];
read_size=read(sock, client_message, 256);
client_message[read_size]='\0';
return 0;
}
In "number_one", read waits an input from the client, and then it sets correctly the buffer "message".
In "number_two", read does not wait the client and does not set the buffer "client_message".
Thank you.
Please try my code? it works, I think it is the same with your code.
#include <stdio.h>
#include <stdbool.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <time.h>
#include <pthread.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <net/if.h>
#include <netdb.h>
#define INVALID_SOCKET_FD (-1)
int create_tcp_server_socket(unsigned short port, bool bind_local, int backlog,
char *caller_name)
{
int socket_fd = INVALID_SOCKET_FD;
struct sockaddr_storage server_addr;
unsigned int yes = 1;
// just try ipv4
if (socket_fd < 0 && (socket_fd = socket(PF_INET, SOCK_STREAM, 0)) >= 0) {
struct sockaddr_in *s4 = (struct sockaddr_in *)&server_addr;
setsockopt(socket_fd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes));
memset(&server_addr, 0, sizeof(server_addr));
s4->sin_family = AF_INET;
s4->sin_port = htons(port);
if (bind_local)
s4->sin_addr.s_addr = htonl(INADDR_LOOPBACK);
else
s4->sin_addr.s_addr = htonl(INADDR_ANY);
if (bind(socket_fd, (struct sockaddr *)&server_addr,
sizeof(server_addr)) < 0) {
close(socket_fd);
printf("Server: Failed to bind ipv4 server socket.\n");
return INVALID_SOCKET_FD;
}
}
else if (socket_fd < 0) {
printf("Server: Failed to create server socket.\n");
return INVALID_SOCKET_FD;
}
if (listen(socket_fd, backlog) < 0) {
close(socket_fd);
printf("Server: Failed to set listen.\n");
return INVALID_SOCKET_FD;
}
return socket_fd;
}
pthread_t temp;
void *number_two(void *sock)
{
char buf[1024];
int fd = *(int *)sock;
int nread = read(fd, buf, 1024);
write(STDOUT_FILENO, buf, nread);
return NULL;
}
int main()
{
pid_t pid;
if ((pid = fork()) < 0) {
}
else if (pid > 0) { // parent, server
char buf[1024];
int fd = create_tcp_server_socket(8787, false, 10, "zz");
int new_fd = accept(fd, NULL, 0);
pthread_create(&temp, NULL, number_two, (void *)&new_fd);
}
else { // child, client
uint32_t ip;
struct hostent *hp = gethostbyname("localhost");
memcpy(&ip, hp->h_addr_list[0], hp->h_length);
struct sockaddr_in server_addr;
memset((char *)&server_addr, 0, sizeof(server_addr));
server_addr.sin_family = AF_INET;
server_addr.sin_addr.s_addr = ip;
server_addr.sin_port = htons(8787);
int fd = socket(AF_INET, SOCK_STREAM, 0);
connect(fd, (struct sockaddr *)&server_addr, sizeof(server_addr));
write(fd, "abcd", 4);
}
pause();
return 0;
}

recv() read() and send() without waiting

I am learning how to program a Server TCP socket wherein clients can connect to and wait for commands...
fd = open("/tmp/myFIFO", O_RDWR);
if(fd<0){
perror("open() error");
exit(1);
}
do {
while ((nbytes = read(fd, buffer, sizeof(buffer)-1)) > 0) {
buffer[nbytes] = '\0';
printf("%s\n", buffer);
}
err = recv(cFD, strbuf, sizeof(strbuf), 0);
if (err < 0) {
if (errno != EWOULDBLOCK) {
perror(" recv() failed");
state = TRUE;
}
break;
}
if (err == 0) {
printf(" Connection closed\n");
state = TRUE;
break;
}
dSize = err;
printf(" %d bytes received\n", dSize);
err = send(cFD, buffer, strlen(buffer), 0);
if (err < 0) {
perror(" send() failed");
state = TRUE;
break;
}
} while (TRUE);
I just get the part of the code where I'm having problem. I'm reading from a pipe. I'm using that to send messages to the client.. but my problem is with recv. it waits for data sent by client before it sends the data read from my pipe to the client. What i want to happen is everytime i send a data to my pipe it goes directly to the client without waiting for recv.. How can this be done?
Here's the full code:
#include <stdio.h>
#include <stdlib.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <sys/time.h>
#include <netinet/in.h>
#include <errno.h>
#include <string.h>
#include <sys/select.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <pthread.h>
#define TRUE 1
#define FALSE 0
typedef struct SERVER_FD{
int sPort;
int serverFD;
int smaxFD;
int newFD;
}sSD;
int cFD,
dSize,
err,
start = 1,
state,
DescRead,
DCSERVER = FALSE;
struct sockaddr_in addr, cli_addr;
unsigned long ip;
char strbuf[256];
socklen_t clilen;
fd_set fdin, fduse;
pid_t pid, sid;
int fd=-1;
int nbytes;
char buffer[256];
void process(int ServerFD, int Port, int sMax, int NewSFD);
void cleanUP(int i, int max);
void dlogs(unsigned long ip);
void daemonize();
main (int argc, char *argv[])
{
sSD link;
sSD *sCon;
sCon = &link;
sCon->sPort = 53234;
fd = open("/tmp/myFIFO", O_RDWR);
if(fd<0){
perror("open() error");
exit(1);
}
printf("Starting Server-G\n");
fcntl(fd, F_SETFL,
fcntl(fd, F_GETFL) | O_NONBLOCK);
sCon->serverFD = socket(AF_INET, SOCK_STREAM, 0);
if (sCon->serverFD != -1) {
err = setsockopt(sCon->serverFD, SOL_SOCKET, SO_REUSEADDR,(char *)&start, sizeof(start));
if (err != -1) {
err = ioctl(sCon->serverFD, FIONBIO, (char *)&start);
if (err != -1){
process(sCon->serverFD,sCon->sPort,sCon->smaxFD,sCon->newFD);
}
else{
perror("ioctl() failed");
close(sCon->serverFD);
exit(EXIT_FAILURE);
}
}
else{
perror("setsockopt() failed");
close(sCon->serverFD);
exit(EXIT_FAILURE);
}
}
else{
perror("FAILED CONNECTING TO SOCKET");
exit(EXIT_FAILURE);
}
}
void process(int ServerFD, int Port, int sMax, int NewSFD){
bzero((char *) &addr, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = 0;
addr.sin_port = htons(Port);
err = bind(ServerFD,(struct sockaddr *)&addr, sizeof(addr));
if (err < 0) {
perror("bind() failed");
close(ServerFD);
exit(EXIT_FAILURE);
}
daemonize();
err = listen(ServerFD, 32);
if (err < 0) {
perror("listen() failed");
close(ServerFD);
exit(EXIT_FAILURE);
}
clilen = sizeof(cli_addr);
FD_ZERO(&fdin);
sMax = ServerFD;
FD_SET(ServerFD, &fdin);
do {
fduse = fdin;
err = select(sMax + 1, &fduse, NULL, NULL, NULL);
if (err < 0) {
perror(" select() failed");
break;
}
DescRead = err;
for (cFD=0; cFD <= sMax && DescRead > 0; ++cFD) {
if (FD_ISSET(cFD, &fduse)) {
DescRead -= 1;
if (cFD == ServerFD) {
do {
NewSFD = accept(ServerFD,(struct sockaddr *) &cli_addr, &clilen);
if (NewSFD < 0) {
if (errno != EWOULDBLOCK) {
perror(" accept() failed");
DCSERVER = TRUE;
}
break;
}
ip = ntohl(cli_addr.sin_addr.s_addr);
printf(" Connection from %d.%d.%d.%d\n",
(int)(ip>>24)&0xff,
(int)(ip>>16)&0xff,
(int)(ip>>8)&0xff,
(int)(ip>>0)&0xff);
dlogs(ip);
FD_SET(NewSFD, &fdin);
if (NewSFD > sMax)
sMax = NewSFD;
} while (NewSFD != -1);
}
else {
state = FALSE;
do {
//PART WHERE I'm Having problems.
err = recv(cFD, strbuf, sizeof(strbuf), 0);
if (err < 0) {
if (errno != EWOULDBLOCK) {
perror(" recv() failed");
state = TRUE;
}
break;
}
if (err == 0) {
printf(" Connection closed\n");
state = TRUE;
break;
}
dSize = err;
printf(" %d bytes received\n", dSize);
while ((nbytes = read(fd, buffer, sizeof(buffer)-1)) > 0) {
buffer[nbytes] = '\0';
printf("%s\n", buffer);
}
err = send(cFD, buffer, strlen(buffer), 0);
if (err < 0) {
perror(" send() failed");
state = TRUE;
break;
}
} while (TRUE);
if (state) {
close(fd);
close(cFD);
FD_CLR(cFD, &fdin);
if (cFD == sMax) {
while (FD_ISSET(sMax, &fdin) == FALSE)
sMax -= 1;
}
}
}
}
}
} while (DCSERVER == FALSE);
cleanUP(cFD, sMax);
}
void cleanUP(int i, int max){
for (i=0; i <= max; ++i) {
if (FD_ISSET(i, &fdin))
close(i);
}
}
void dlogs(unsigned long ip){
FILE* pFile = fopen("/sockF.txt", "a+");
fprintf(pFile,"Connection from: %d.%d.%d.%d",
(int)(ip>>24)&0xff,
(int)(ip>>16)&0xff,
(int)(ip>>8)&0xff,
(int)(ip>>0)&0xff);
fclose(pFile);
}
void daemonize(){
pid = fork();
if(pid<0){
perror("fork() failed");
exit(EXIT_FAILURE);
}
if(pid>0){
exit(EXIT_SUCCESS);
}
umask(0);
sid = setsid();
if(sid<0){
perror("setsid() failed");
exit(EXIT_FAILURE);
}
if((chdir("/")) < 0){
perror("failed changing directory");
exit(EXIT_FAILURE);
}
}
Sample Output: I am using telnet and putty to test Server
From Telnet: IP: 192.168.5.53
Telnet 192.168.5.55 53234
./socks
Starting Server-G
Connection from: 192.168.5.53
Now When telnet is connected i use putty to send data to the pipe so the server will read it.
From Putty:
echo "TEST" > /tmp/myFIFO
the problem here is that whenever i send the data from putty writing to the pipe the server waits for telnet to send data before it outputs and send the data i've written to the pipe. How can i make both recv and read work at the same tym so when i write to my pipe it will output without waiting for recv?
Thanks
EDIT: I've also used thread to read the pipe but it still waits recv() before the server output what have been read to the pipe.
Use select or poll to wait for events on both of your file handles, eg. (using poll)
#include <poll.h>
//...
struct pollfd pfds[2];
int rc;
/* Wait for input on either one of the fds */
pfds[0].fd = fd;
pfds[0].events = POLLIN;
pfds[1].fd = cFD;
pfds[1].events = POLLIN;
do {
/* Wait forever for something to happen */
rc = poll(&pfds, 2, -1);
/* Error handling elided */
if (pfds[0].revents & POLLIN)
{
/* Read from fd, change pfds[1].events to (POLLIN | POLLOUT) so you know when you
can write without blocking. also clear pfds[0].events so we don't read until we
write */
pfds[0].events = 0;
pfds[1].events = POLLIN | POLLOUT;
}
if (pfds[1].revents & POLLIN)
{
/* Read from socket */
}
if (pfds[1].revents & POLLOUT)
{
/* write to socket, reset events flags */
pfds[0].events = POLLIN;
pfds[1].events = POLLIN;
}
} while (1)

Resources