You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

178 lines
3.9 KiB

#include <sys/socket.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <arpa/inet.h>
#include <errno.h>
#include <ev.h>
#include <fcntl.h>
#include <langinfo.h>
#include <locale.h>
#include <netdb.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <pthread.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <strings.h>
#include <time.h>
#include <unistd.h>
#define PORT 1090
#define REPLY "HTTP/1.1 200 OK\n\nhello"
// every watcher type has its own typedef'd struct
// with the name ev_TYPE
ev_io stdin_watcher;
ev_timer timeout_watcher;
struct server_ctx {
ev_io io;
int fd;
struct sockaddr sock;
};
struct client_ctx {
ev_io io;
int fd;
};
int setnonblocking(int fd) {
int flags;
if (-1 ==(flags = fcntl(fd, F_GETFL, 0)))
flags = 0;
return fcntl(fd, F_SETFL, flags | O_NONBLOCK);
}
int create_and_bind(char *port) {
struct addrinfo hints;
struct addrinfo *result, *rp;
int s, listen_sock;
memset(&hints, 0, sizeof(struct addrinfo));
hints.ai_family = AF_UNSPEC; /* Return IPv4 and IPv6 choices */
hints.ai_socktype = SOCK_STREAM; /* We want a TCP socket */
hints.ai_flags = AI_PASSIVE; /* All interfaces */
s = getaddrinfo("0.0.0.0", port, &hints, &result);
if (s != 0) {
fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(s));
return -1;
}
for (rp = result; rp != NULL; rp = rp->ai_next) {
listen_sock = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol);
int opt = 1;
setsockopt(listen_sock, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
if (listen_sock == -1)
continue;
s = bind(listen_sock, rp->ai_addr, rp->ai_addrlen);
if (s == 0) {
/* We managed to bind successfully! */
break;
}
close(listen_sock);
}
if (rp == NULL) {
fprintf(stderr, "Could not bind\n");
return -1;
}
freeaddrinfo(result);
return listen_sock;
}
static void
write_cb (EV_P_ ev_io *w, int revents)
{
struct client_ctx *client = (struct client_ctx *)w;
ev_io_stop(EV_A_ &client->io);
close(client->fd);
free(client);
}
static void
read_cb (EV_P_ ev_io *w, int revents)
{
struct client_ctx *client = (struct client_ctx *)w;
char buf[4096];
int n = recv(client->fd, buf, 4096, 0);
if (n == 0) {
ev_io_stop(EV_A_ &client->io);
close(client->fd);
free(client);
return;
} else if (n < 0) {
perror("recv");
return;
}
//write(1, buf, n);
send(client->fd, REPLY, sizeof(REPLY), 0);
ev_io_stop(EV_A_ &client->io);
ev_io_init(&client->io, write_cb, client->fd, EV_WRITE);
ev_io_start(EV_A_ &client->io);
}
static struct client_ctx* client_new(int fd) {
struct client_ctx* client;
client = malloc(sizeof(struct client_ctx));
client->fd = fd;
//client->server = server;
setnonblocking(client->fd);
ev_io_init(&client->io, read_cb, client->fd, EV_READ);
return client;
}
// all watcher callbacks have a similar signature
// this callback is called when data is readable on stdin
static void
server_cb (EV_P_ ev_io *w, int revents)
{
// puts ("clients connected");
struct server_ctx *server = (struct server_ctx *)w;
int connectfd;
while (1) {
connectfd = accept(server->fd, NULL, NULL);
if (connectfd == -1) {
perror("accept");
break;
}
struct client_ctx *client = client_new(connectfd);
ev_io_start(EV_A_ &client->io);
break;
}
}
int
main (void)
{
int listenfd, connectfd;
listenfd = create_and_bind("1090");
if (listen(listenfd, SOMAXCONN) == -1) {
perror("listen() error.");
return 1;
}
setnonblocking(listenfd);
struct server_ctx listen_ctx;
listen_ctx.fd = listenfd;
// use the default event loop unless you have special needs
struct ev_loop *loop = EV_DEFAULT;
// initialise an io watcher, then start it
// this one will watch for stdin to become readable
ev_io_init (&listen_ctx.io, server_cb, listenfd, EV_READ);
ev_io_start (loop, &listen_ctx.io);
// now wait for events to arrive
ev_run (loop, 0);
// break was called, so exit
return 0;
}