Thursday, November 25, 2010
Linux sockets example
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <unistd.h>
#include <errno.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <sys/epoll.h>
#define EPOLL_ARRAY_SIZE 64
void sprint_buffer(const char *buffer, int size)
{
int i;
for (i = 0; i < size; i++)
{
if (isprint(buffer[i]))
printf("%c", buffer[i]);
else
printf("\\0x%02X", buffer[i]);
}
}
int main(int argc, char *argv[])
{
int sd, efd, clientsd, fd;
struct sockaddr_in bindaddr, peeraddr;
socklen_t salen = sizeof(peeraddr);
int pollsize = 1;
struct epoll_event ev;
struct epoll_event epoll_events[EPOLL_ARRAY_SIZE];
uint32_t events;
unsigned short port = 20000;
int i, rval, on = 1;
ssize_t rc;
char buffer[1024];
efd = epoll_create(pollsize);
if (efd < 0)
{
printf("Could not create the epoll fd: %m");
return 1;
}
sd = socket(AF_INET, SOCK_STREAM, 0);
if (sd < 0)
{
printf("Could not create new socket: %m\n");
return 2;
}
printf("New socket created with sd %d\n", sd);
if (fcntl(sd, F_SETFL, O_NONBLOCK))
{
printf("Could not make the socket non-blocking: %m\n");
close(sd);
return 3;
}
if (setsockopt(sd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)))
{
printf("Could not set socket %d option for reusability: %m\n", sd);
close(sd);
return 4;
}
bindaddr.sin_addr.s_addr = htonl(INADDR_ANY);
bindaddr.sin_family= AF_INET;
bindaddr.sin_port = htons(port);
if (bind(sd, (struct sockaddr *) &bindaddr, sizeof(struct sockaddr_in)) < 0)
{
printf("Could not bind socket %d to address 'INADDR_ANY' and port %u: %m", sd, port);
close(sd);
return 5;
}
else
{
printf("Bound socket %d to address 'INADDR_ANY' and port %u\n", sd, port);
}
if (listen(sd, SOMAXCONN))
{
printf("Could not start listening on server socket %d: %m\n", sd);
goto cleanup;
}
else
{
printf("Server socket %d started listening to address 'INADDR_ANY' and port %u\n", sd, port);
}
ev.events = EPOLLIN;
ev.data.u64 = 0LL;
ev.data.fd = sd;
if (epoll_ctl(efd, EPOLL_CTL_ADD, sd, &ev) < 0)
{
printf("Couldn't add server socket %d to epoll set: %m\n", sd);
goto cleanup;
}
for (;;)
{
printf("Starting epoll_wait on %d fds\n", pollsize);
while ((rval = epoll_wait(efd, epoll_events, EPOLL_ARRAY_SIZE, -1)) < 0)
{
if ((rval < 0) && (errno != EINTR))
{
printf("EPoll on %d fds failed: %m\n", pollsize);
goto cleanup;
}
}
for (i = 0; i < rval; i++)
{
events = epoll_events[i].events;
fd = epoll_events[i].data.fd;
if (events & EPOLLERR)
{
if (fd == sd)
{
printf("EPoll on %d fds failed: %m\n", pollsize);
goto cleanup;
} else
{
printf("Closing socket with sd %d\n", fd);
shutdown(fd, SHUT_RDWR);
close(fd);
continue;
}
}
if (events & EPOLLHUP)
{
if (fd == sd)
{
printf("EPoll on %d fds failed: %m\n", pollsize);
goto cleanup;
} else
{
printf("Closing socket with sd %d\n", fd);
shutdown(fd, SHUT_RDWR);
close(fd);
continue;
}
}
if (events & EPOLLRDHUP)
{
if (fd == sd)
{
printf("EPoll on %d fds failed: %m\n", pollsize);
goto cleanup;
} else
{
printf("Closing socket with sd %d\n", fd);
shutdown(fd, SHUT_RDWR);
close(fd);
continue;
}
}
if (events & EPOLLOUT)
{
if (fd != sd)
{
rc = snprintf(buffer, sizeof(buffer), "Hello socket %d from server socket %d!\n", fd, sd);
while ((rc = send(fd, buffer, rc, 0)) < 0)
{
if ((fd < 0) && (errno != EINTR))
{
printf("Send to socket %d failed: %m\n", fd);
pollsize--;
shutdown(fd, SHUT_RDWR);
close(fd);
continue;
}
}
if (rc == 0)
{
printf("Closing socket with sd %d\n", fd);
pollsize--;
shutdown(fd, SHUT_RDWR);
close(fd);
continue;
} else if (rc > 0)
{
printf("Sent '");
sprint_buffer(buffer, rc);
printf("' to socket with sd %d\n", fd);
ev.events = EPOLLIN;
ev.data.u64 = 0LL;
ev.data.fd = fd;
if (epoll_ctl(efd, EPOLL_CTL_MOD, fd, &ev) < 0)
{
printf("Couldn't modify client socket %d in epoll set: %m\n", fd);
goto cleanup;
}
}
}
}
if (events & EPOLLIN)
{
if (fd == sd)
{
while ((clientsd = accept(sd, (struct sockaddr *) &peeraddr, &salen)) < 0)
{
if ((clientsd < 0) && (errno != EINTR))
{
printf("Accept on socket %d failed: %m\n", sd);
goto cleanup;
}
}
if (inet_ntop(AF_INET, &peeraddr.sin_addr.s_addr, buffer, sizeof(buffer)) != NULL)
{
printf("Accepted connection from %s:%u, assigned new sd %d\n", buffer, ntohs(peeraddr.sin_port), clientsd);
} else
{
printf("Failed to convert address from binary to text form: %m\n");
}
ev.events = EPOLLIN;
ev.data.u64 = 0LL;
ev.data.fd = clientsd;
if (epoll_ctl(efd, EPOLL_CTL_ADD, clientsd, &ev) < 0)
{
printf("Couldn't add client socket %d to epoll set: %m\n", clientsd);
goto cleanup;
}
pollsize++;
} else
{
while ((rc = recv(fd, buffer, sizeof(buffer), 0)) < 0)
{
if ((fd < 0) && (errno != EINTR))
{
printf("Receive from socket %d failed: %m\n", fd);
pollsize--;
shutdown(fd, SHUT_RDWR);
close(fd);
continue;
}
}
if (rc == 0)
{
printf("Closing socket with sd %d\n", fd);
pollsize--;
shutdown(fd, SHUT_RDWR);
close(fd);
continue;
} else if (rc > 0)
{
printf("Received '");
sprint_buffer(buffer, rc);
printf("' from socket with sd %d\n", fd);
ev.events = EPOLLIN | EPOLLOUT;
ev.data.u64 = 0LL;
ev.data.fd = fd;
if (epoll_ctl(efd, EPOLL_CTL_MOD, fd, &ev) < 0)
{
printf("Couldn't modify client socket %d in epoll set: %m\n", fd);
goto cleanup;
}
}
}
}
}
}
cleanup:
shutdown(sd, SHUT_RDWR);
close(sd);
return 0;
}
Wednesday, November 24, 2010
Hello World
I will post mostly technical, programming related stuff, that at some point later I could use as reference.
Subscribe to:
Posts (Atom)