begin with the ability to read control frames. something feels fishy with epoll() and its triggering of events. I probably got it wrong.

This commit is contained in:
Joris Vink 2013-04-28 19:11:44 +02:00
parent 7a6be8ff2e
commit 23c0ec67c6
7 changed files with 408 additions and 17 deletions

View File

@ -3,7 +3,7 @@
CC=gcc
BIN=kore
S_SRC= src/kore.c src/utils.c
S_SRC= src/kore.c src/net.c src/spdy.c src/utils.c
S_OBJS= $(S_SRC:.c=.o)
CFLAGS+=-I/usr/local/ssl/include

View File

@ -28,9 +28,9 @@
#define KORE_SSL_PROTO_STRING "\x06spdy/3\x08http/1.1"
struct netbuf {
u_int8_t *data;
u_int8_t *buf;
u_int32_t offset;
u_int32_t length;
u_int32_t len;
void *owner;
int (*cb)(struct netbuf *);
@ -58,6 +58,8 @@ struct connection {
void *owner;
SSL *ssl;
struct spdy_frame spdy_cur_frame;
TAILQ_HEAD(, netbuf) send_queue;
TAILQ_HEAD(, netbuf) recv_queue;
};
@ -70,4 +72,13 @@ char *kore_strdup(const char *);
void fatal(const char *, ...);
void kore_log_internal(char *, int, const char *, ...);
int net_recv(struct connection *);
int net_send(struct connection *);
void net_recv_queue(struct connection *, size_t,
int (*cb)(struct netbuf *));
void net_send_queue(struct connection *, u_int8_t *, size_t,
int (*cb)(struct netbuf *));
int spdy_frame_recv(struct netbuf *);
#endif /* !__H_KORE_H */

47
includes/spdy.h Normal file
View File

@ -0,0 +1,47 @@
/*
* Copyright (c) 2013 Joris Vink <joris@coders.se>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#ifndef __H_SPDY_H
#define __H_SPDY_H
struct spdy_frame {
u_int32_t frame_1;
u_int32_t frame_2;
};
struct spdy_ctrl_frame {
int type:16;
int version:15;
int control_bit:1;
int length:24;
int flags:8;
};
struct spdy_data_frame {
int stream_id:31;
int control_bit:1;
int length:24;
int flags:8;
};
#define SPDY_CONTROL_FRAME(x) ((x->frame_1 & (1 << 31)))
#define SPDY_FRAME_SIZE 8
/* control frames. */
#define SPDY_CTRL_FRAME_SYN_STREAM 1
#define SPDY_CTRL_FRAME_SETTINGS 4
#endif /* !__H_SPDY_H */

View File

@ -33,6 +33,7 @@
#include <string.h>
#include <unistd.h>
#include "spdy.h"
#include "kore.h"
#define EPOLL_EVENTS 500
@ -44,6 +45,7 @@ static int kore_socket_nonblock(int);
static int kore_server_sslstart(void);
static void kore_event(int, int, void *);
static int kore_server_accept(struct listener *);
static void kore_server_disconnect(struct connection *);
static int kore_connection_handle(struct connection *, int);
static int kore_server_bind(struct listener *, const char *, int);
static int kore_ssl_npn_cb(SSL *, const u_char **, unsigned int *, void *);
@ -70,10 +72,12 @@ main(int argc, char *argv[])
kore_event(server.fd, EPOLLIN, &server);
events = kore_calloc(EPOLL_EVENTS, sizeof(struct epoll_event));
for (;;) {
kore_log("main(): epoll_wait()");
n = epoll_wait(efd, events, EPOLL_EVENTS, -1);
if (n == -1)
fatal("epoll_wait(): %s", errno_s);
kore_log("main(): %d sockets available", n);
for (i = 0; i < n; i++) {
fd = (int *)events[i].data.ptr;
@ -83,6 +87,7 @@ main(int argc, char *argv[])
fatal("error on server socket");
c = (struct connection *)events[i].data.ptr;
kore_server_disconnect(c);
continue;
}
@ -92,7 +97,7 @@ main(int argc, char *argv[])
c = (struct connection *)events[i].data.ptr;
if (!kore_connection_handle(c,
events[i].events))
/* Disconnect. */;
kore_server_disconnect(c);
}
}
}
@ -104,6 +109,8 @@ main(int argc, char *argv[])
static int
kore_server_sslstart(void)
{
kore_log("kore_server_sslstart()");
SSL_library_init();
SSL_load_error_strings();
ssl_ctx = SSL_CTX_new(SSLv23_server_method());
@ -135,6 +142,8 @@ kore_server_sslstart(void)
static int
kore_server_bind(struct listener *l, const char *ip, int port)
{
kore_log("kore_server_bind(%p, %s, %d)", l, ip, port);
if ((l->fd = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
kore_log("socket(): %s", errno_s);
return (KORE_RESULT_ERROR);
@ -171,6 +180,8 @@ kore_server_accept(struct listener *l)
socklen_t len;
struct connection *c;
kore_log("kore_server_accept(%p)", l);
len = sizeof(struct sockaddr_in);
c = (struct connection *)kore_malloc(sizeof(*c));
if ((c->fd = accept(l->fd, (struct sockaddr *)&(c->sin), &len)) == -1) {
@ -198,6 +209,35 @@ kore_server_accept(struct listener *l)
return (KORE_RESULT_OK);
}
static void
kore_server_disconnect(struct connection *c)
{
struct netbuf *nb, *next;
kore_log("kore_server_disconnect(%p)", c);
close(c->fd);
if (c->ssl != NULL)
SSL_free(c->ssl);
for (nb = TAILQ_FIRST(&(c->send_queue)); nb != NULL; nb = next) {
next = TAILQ_NEXT(nb, list);
TAILQ_REMOVE(&(c->send_queue), nb, list);
free(nb->buf);
free(nb);
}
for (nb = TAILQ_FIRST(&(c->recv_queue)); nb != NULL; nb = next) {
next = TAILQ_NEXT(nb, list);
TAILQ_REMOVE(&(c->recv_queue), nb, list);
free(nb->buf);
free(nb);
}
kore_log("disconnect connection from %s", inet_ntoa(c->sin.sin_addr));
free(c);
}
static int
kore_connection_handle(struct connection *c, int flags)
{
@ -205,6 +245,8 @@ kore_connection_handle(struct connection *c, int flags)
u_int32_t len;
const u_char *data;
kore_log("kore_connection_handle(%p, %d)", c, flags);
switch (c->state) {
case CONN_STATE_SSL_SHAKE:
if (c->ssl == NULL) {
@ -222,7 +264,10 @@ kore_connection_handle(struct connection *c, int flags)
r = SSL_get_error(c->ssl, r);
switch (r) {
case SSL_ERROR_WANT_READ:
kore_log("ssl_want_read on handshake");
return (KORE_RESULT_OK);
case SSL_ERROR_WANT_WRITE:
kore_log("ssl_want_write on handshake");
return (KORE_RESULT_OK);
default:
kore_log("SSL_accept(): %s", ssl_errno_s);
@ -241,6 +286,7 @@ kore_connection_handle(struct connection *c, int flags)
if (!memcmp(data, "spdy/3", 6))
kore_log("using SPDY/3");
c->proto = CONN_PROTO_SPDY;
net_recv_queue(c, SPDY_FRAME_SIZE, spdy_frame_recv);
} else {
kore_log("using HTTP/1.1");
c->proto = CONN_PROTO_HTTP;
@ -249,7 +295,12 @@ kore_connection_handle(struct connection *c, int flags)
c->state = CONN_STATE_ESTABLISHED;
break;
case CONN_STATE_ESTABLISHED:
kore_log("got bytes on established");
if (flags & EPOLLIN) {
if (!net_recv(c))
return (KORE_RESULT_ERROR);
} else {
kore_log("got unhandled client event");
}
break;
default:
kore_log("unknown state on %d (%d)", c->fd, c->state);
@ -264,6 +315,8 @@ kore_socket_nonblock(int fd)
{
int flags;
kore_log("kore_socket_nonblock(%d)", fd);
if ((flags = fcntl(fd, F_GETFL, 0)) == -1) {
kore_log("fcntl(): F_GETFL %s", errno_s);
return (KORE_RESULT_ERROR);
@ -278,24 +331,32 @@ kore_socket_nonblock(int fd)
return (KORE_RESULT_OK);
}
static void
kore_event(int fd, int flags, void *udata)
{
struct epoll_event evt;
evt.events = flags;
evt.data.ptr = udata;
if (epoll_ctl(efd, EPOLL_CTL_ADD, fd, &evt) == -1)
fatal("epoll_ctl(): %s", errno_s);
}
static int
kore_ssl_npn_cb(SSL *ssl, const u_char **data, unsigned int *len, void *arg)
{
kore_log("npn callback: sending protocols");
kore_log("kore_ssl_npn_cb(): sending protocols");
*data = (const unsigned char *)KORE_SSL_PROTO_STRING;
*len = strlen(KORE_SSL_PROTO_STRING);
return (SSL_TLSEXT_ERR_OK);
}
static void
kore_event(int fd, int flags, void *udata)
{
struct epoll_event evt;
kore_log("kore_event(%d, %d, %p)", fd, flags, udata);
evt.events = flags;
evt.data.ptr = udata;
if (epoll_ctl(efd, EPOLL_CTL_ADD, fd, &evt) == -1) {
if (errno == EEXIST) {
if (epoll_ctl(efd, EPOLL_CTL_MOD, fd, &evt) == -1)
fatal("epoll_ctl() MOD: %s", errno_s);
} else {
fatal("epoll_ctl() ADD: %s", errno_s);
}
}
}

171
src/net.c Normal file
View File

@ -0,0 +1,171 @@
/*
* Copyright (c) 2013 Joris Vink <joris@coders.se>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <sys/param.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/queue.h>
#include <sys/epoll.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <openssl/err.h>
#include <openssl/ssl.h>
#include <errno.h>
#include <fcntl.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "spdy.h"
#include "kore.h"
void
net_send_queue(struct connection *c, u_int8_t *data, size_t len,
int (*cb)(struct netbuf *))
{
struct netbuf *nb;
kore_log("net_send_queue(%p, %p, %d, %p)", c, data, len, cb);
nb = (struct netbuf *)kore_malloc(sizeof(*nb));
nb->cb = cb;
nb->len = len;
nb->owner = c;
nb->offset = 0;
nb->buf = (u_int8_t *)kore_malloc(nb->len);
memcpy(nb->buf, data, nb->len);
TAILQ_INSERT_TAIL(&(c->send_queue), nb, list);
net_send(c);
}
void
net_recv_queue(struct connection *c, size_t len, int (*cb)(struct netbuf *))
{
struct netbuf *nb;
kore_log("net_recv_queue(%p, %d, %p)", c, len, cb);
nb = (struct netbuf *)kore_malloc(sizeof(*nb));
nb->cb = cb;
nb->len = len;
nb->owner = c;
nb->offset = 0;
nb->buf = (u_int8_t *)kore_malloc(nb->len);
TAILQ_INSERT_TAIL(&(c->recv_queue), nb, list);
net_recv(c);
}
int
net_send(struct connection *c)
{
int r;
struct netbuf *nb;
kore_log("net_send(%p)", c);
if (TAILQ_EMPTY(&(c->send_queue)))
return (KORE_RESULT_OK);
nb = TAILQ_FIRST(&(c->send_queue));
r = SSL_write(c->ssl, (nb->buf + nb->offset), (nb->len - nb->offset));
kore_log("SSL_write(): %d bytes", r);
if (r <= 0) {
r = SSL_get_error(c->ssl, r);
switch (r) {
case SSL_ERROR_WANT_READ:
kore_log("ssl_want_read on net_send()");
return (KORE_RESULT_OK);
case SSL_ERROR_WANT_WRITE:
kore_log("ssl_want_write on net_send()");
return (KORE_RESULT_OK);
default:
kore_log("SSL_write(): %s", ssl_errno_s);
return (KORE_RESULT_ERROR);
}
}
nb->offset += (size_t)r;
if (nb->offset == nb->len) {
TAILQ_REMOVE(&(c->send_queue), nb, list);
if (nb->cb != NULL)
r = nb->cb(nb);
else
r = KORE_RESULT_OK;
free(nb->buf);
free(nb);
} else {
r = KORE_RESULT_OK;
}
return (r);
}
int
net_recv(struct connection *c)
{
int r;
struct netbuf *nb;
kore_log("net_recv(%p)", c);
if (TAILQ_EMPTY(&(c->recv_queue)))
return (KORE_RESULT_ERROR);
nb = TAILQ_FIRST(&(c->recv_queue));
kore_log("nb is %p (%d/%d bytes)", nb, nb->offset, nb->len);
r = SSL_read(c->ssl, (nb->buf + nb->offset), (nb->len - nb->offset));
kore_log("SSL_read(): %d bytes", r);
if (r <= 0) {
r = SSL_get_error(c->ssl, r);
switch (r) {
case SSL_ERROR_WANT_READ:
kore_log("ssl_want_read on net_recv()");
return (KORE_RESULT_OK);
case SSL_ERROR_WANT_WRITE:
kore_log("ssl_want_write on net_recv()");
return (KORE_RESULT_OK);
default:
kore_log("SSL_read(): %s", ssl_errno_s);
return (KORE_RESULT_ERROR);
}
}
nb->offset += (size_t)r;
kore_log("read %d out of %d bytes", nb->offset, nb->len);
if (nb->offset == nb->len) {
if (nb->cb == NULL) {
kore_log("kore_read_client(): nb->cb == NULL");
return (KORE_RESULT_ERROR);
}
TAILQ_REMOVE(&(c->recv_queue), nb, list);
r = nb->cb(nb);
free(nb->buf);
free(nb);
} else {
r = KORE_RESULT_OK;
}
return (r);
}

100
src/spdy.c Normal file
View File

@ -0,0 +1,100 @@
/*
* Copyright (c) 2013 Joris Vink <joris@coders.se>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <sys/param.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/queue.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <openssl/err.h>
#include <openssl/ssl.h>
#include <errno.h>
#include <fcntl.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "spdy.h"
#include "kore.h"
static int spdy_ctrl_frame_syn_stream(struct netbuf *);
static int spdy_ctrl_frame_settings(struct netbuf *);
int
spdy_frame_recv(struct netbuf *nb)
{
struct spdy_ctrl_frame *ctrl;
int (*cb)(struct netbuf *);
struct connection *c = (struct connection *)nb->owner;
struct spdy_frame *frame = (struct spdy_frame *)nb->buf;
frame->frame_1 = ntohl(frame->frame_1);
frame->frame_2 = ntohl(frame->frame_2);
c->spdy_cur_frame = *frame;
if (SPDY_CONTROL_FRAME(frame)) {
kore_log("received control frame");
ctrl = (struct spdy_ctrl_frame *)frame;
kore_log("type is %d", ctrl->type);
kore_log("version is %d", ctrl->version);
kore_log("length is %d", ctrl->length);
switch (ctrl->type) {
case SPDY_CTRL_FRAME_SYN_STREAM:
cb = spdy_ctrl_frame_syn_stream;
break;
case SPDY_CTRL_FRAME_SETTINGS:
cb = spdy_ctrl_frame_settings;
break;
default:
cb = NULL;
break;
}
if (cb != NULL) {
net_recv_queue(c, ctrl->length, cb);
} else {
kore_log("no callback for type %d", ctrl->type);
}
} else {
kore_log("received data frame");
}
return (KORE_RESULT_OK);
}
static int
spdy_ctrl_frame_syn_stream(struct netbuf *nb)
{
kore_log("-- SPDY_SYN_STREAM");
return (KORE_RESULT_OK);
}
static int
spdy_ctrl_frame_settings(struct netbuf *nb)
{
struct connection *c = (struct connection *)nb->owner;
kore_log("-- SPDY_SETTINGS");
net_recv_queue(c, SPDY_FRAME_SIZE, spdy_frame_recv);
return (KORE_RESULT_OK);
}

View File

@ -32,6 +32,7 @@
#include <stdlib.h>
#include <string.h>
#include "spdy.h"
#include "kore.h"
void *