2013-04-28 19:11:44 +02:00
|
|
|
/*
|
|
|
|
* 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 "kore.h"
|
|
|
|
|
2013-07-15 10:13:36 +02:00
|
|
|
struct kore_pool nb_pool;
|
|
|
|
|
|
|
|
void
|
|
|
|
net_init(void)
|
|
|
|
{
|
|
|
|
kore_pool_init(&nb_pool, "nb_pool", sizeof(struct netbuf), 1000);
|
|
|
|
}
|
|
|
|
|
2013-05-02 14:47:02 +02:00
|
|
|
void
|
2013-05-02 00:28:49 +02:00
|
|
|
net_send_queue(struct connection *c, u_int8_t *data, size_t len, int flags,
|
2013-05-01 13:43:47 +02:00
|
|
|
struct netbuf **out, int (*cb)(struct netbuf *))
|
2013-04-28 19:11:44 +02:00
|
|
|
{
|
|
|
|
struct netbuf *nb;
|
|
|
|
|
2013-07-15 10:13:36 +02:00
|
|
|
nb = kore_pool_get(&nb_pool);
|
2013-04-28 19:11:44 +02:00
|
|
|
nb->cb = cb;
|
|
|
|
nb->len = len;
|
|
|
|
nb->owner = c;
|
|
|
|
nb->offset = 0;
|
2013-05-02 00:28:49 +02:00
|
|
|
nb->flags = flags;
|
2013-04-28 23:42:13 +02:00
|
|
|
nb->type = NETBUF_SEND;
|
2013-05-01 13:43:47 +02:00
|
|
|
|
|
|
|
if (len > 0) {
|
2013-07-13 21:08:55 +02:00
|
|
|
nb->buf = kore_malloc(nb->len);
|
2013-05-01 13:43:47 +02:00
|
|
|
memcpy(nb->buf, data, nb->len);
|
|
|
|
} else {
|
|
|
|
nb->buf = NULL;
|
|
|
|
}
|
2013-04-28 19:11:44 +02:00
|
|
|
|
|
|
|
TAILQ_INSERT_TAIL(&(c->send_queue), nb, list);
|
2013-05-01 13:43:47 +02:00
|
|
|
if (out != NULL)
|
|
|
|
*out = nb;
|
2013-04-28 19:11:44 +02:00
|
|
|
}
|
|
|
|
|
2013-05-02 14:47:02 +02:00
|
|
|
void
|
2013-05-02 00:28:49 +02:00
|
|
|
net_recv_queue(struct connection *c, size_t len, int flags,
|
2013-05-01 13:43:47 +02:00
|
|
|
struct netbuf **out, int (*cb)(struct netbuf *))
|
2013-04-28 19:11:44 +02:00
|
|
|
{
|
|
|
|
struct netbuf *nb;
|
|
|
|
|
2013-07-15 10:13:36 +02:00
|
|
|
nb = kore_pool_get(&nb_pool);
|
2013-04-28 19:11:44 +02:00
|
|
|
nb->cb = cb;
|
|
|
|
nb->len = len;
|
|
|
|
nb->owner = c;
|
|
|
|
nb->offset = 0;
|
2013-05-02 00:28:49 +02:00
|
|
|
nb->flags = flags;
|
2013-04-28 23:42:13 +02:00
|
|
|
nb->type = NETBUF_RECV;
|
2013-07-13 21:08:55 +02:00
|
|
|
nb->buf = kore_malloc(nb->len);
|
2013-04-28 19:11:44 +02:00
|
|
|
|
|
|
|
TAILQ_INSERT_TAIL(&(c->recv_queue), nb, list);
|
2013-05-01 13:43:47 +02:00
|
|
|
if (out != NULL)
|
|
|
|
*out = nb;
|
2013-04-28 23:42:13 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
net_recv_expand(struct connection *c, struct netbuf *nb, size_t len,
|
|
|
|
int (*cb)(struct netbuf *))
|
|
|
|
{
|
|
|
|
if (nb->type != NETBUF_RECV) {
|
2013-06-04 16:30:53 +02:00
|
|
|
kore_debug("net_recv_expand(): wrong netbuf type");
|
2013-04-28 23:42:13 +02:00
|
|
|
return (KORE_RESULT_ERROR);
|
|
|
|
}
|
|
|
|
|
|
|
|
nb->cb = cb;
|
|
|
|
nb->len += len;
|
2013-07-13 21:08:55 +02:00
|
|
|
nb->buf = kore_realloc(nb->buf, nb->len);
|
2013-07-12 15:49:49 +02:00
|
|
|
|
|
|
|
TAILQ_REMOVE(&(c->recv_queue), nb, list);
|
2013-04-28 23:42:13 +02:00
|
|
|
TAILQ_INSERT_HEAD(&(c->recv_queue), nb, list);
|
|
|
|
|
2013-05-02 09:10:35 +02:00
|
|
|
return (KORE_RESULT_OK);
|
2013-04-28 19:11:44 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
net_send(struct connection *c)
|
|
|
|
{
|
|
|
|
int r;
|
|
|
|
struct netbuf *nb;
|
|
|
|
|
2013-06-27 00:22:48 +02:00
|
|
|
while (!TAILQ_EMPTY(&(c->send_queue))) {
|
|
|
|
nb = TAILQ_FIRST(&(c->send_queue));
|
2013-10-15 11:09:33 +02:00
|
|
|
if (nb->len != 0) {
|
|
|
|
r = SSL_write(c->ssl,
|
|
|
|
(nb->buf + nb->offset), (nb->len - nb->offset));
|
|
|
|
|
|
|
|
kore_debug("net_send(%ld/%ld bytes), progress with %d",
|
|
|
|
nb->offset, nb->len, r);
|
|
|
|
|
|
|
|
if (r <= 0) {
|
|
|
|
r = SSL_get_error(c->ssl, r);
|
|
|
|
switch (r) {
|
|
|
|
case SSL_ERROR_WANT_READ:
|
|
|
|
case SSL_ERROR_WANT_WRITE:
|
|
|
|
c->flags &= ~CONN_WRITE_POSSIBLE;
|
|
|
|
return (KORE_RESULT_OK);
|
|
|
|
default:
|
|
|
|
kore_debug("SSL_write(): %s",
|
|
|
|
ssl_errno_s);
|
|
|
|
return (KORE_RESULT_ERROR);
|
|
|
|
}
|
2013-06-27 00:22:48 +02:00
|
|
|
}
|
2013-10-15 11:09:33 +02:00
|
|
|
|
|
|
|
nb->offset += (size_t)r;
|
2013-06-27 00:22:48 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if (nb->offset == nb->len) {
|
2013-05-02 00:28:49 +02:00
|
|
|
TAILQ_REMOVE(&(c->send_queue), nb, list);
|
2013-04-28 19:11:44 +02:00
|
|
|
|
2013-06-27 00:22:48 +02:00
|
|
|
if (nb->cb != NULL)
|
|
|
|
r = nb->cb(nb);
|
|
|
|
else
|
|
|
|
r = KORE_RESULT_OK;
|
2013-04-28 19:11:44 +02:00
|
|
|
|
2013-06-27 00:22:48 +02:00
|
|
|
if (nb->offset == nb->len) {
|
|
|
|
if (nb->buf != NULL)
|
2013-06-27 08:43:07 +02:00
|
|
|
kore_mem_free(nb->buf);
|
2013-07-15 10:13:36 +02:00
|
|
|
kore_pool_put(&nb_pool, nb);
|
2013-06-27 00:22:48 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if (r != KORE_RESULT_OK)
|
|
|
|
return (r);
|
2013-05-02 00:28:49 +02:00
|
|
|
}
|
2013-04-28 19:11:44 +02:00
|
|
|
}
|
|
|
|
|
2013-06-27 00:22:48 +02:00
|
|
|
return (KORE_RESULT_OK);
|
2013-04-28 19:11:44 +02:00
|
|
|
}
|
|
|
|
|
2013-05-01 13:43:47 +02:00
|
|
|
int
|
|
|
|
net_send_flush(struct connection *c)
|
|
|
|
{
|
2013-06-04 16:30:53 +02:00
|
|
|
kore_debug("net_send_flush(%p)", c);
|
2013-05-02 09:10:35 +02:00
|
|
|
|
2013-05-01 13:43:47 +02:00
|
|
|
while (!TAILQ_EMPTY(&(c->send_queue)) &&
|
|
|
|
(c->flags & CONN_WRITE_POSSIBLE)) {
|
|
|
|
if (!net_send(c))
|
|
|
|
return (KORE_RESULT_ERROR);
|
|
|
|
}
|
|
|
|
|
|
|
|
return (KORE_RESULT_OK);
|
|
|
|
}
|
|
|
|
|
2013-04-28 19:11:44 +02:00
|
|
|
int
|
|
|
|
net_recv(struct connection *c)
|
|
|
|
{
|
|
|
|
int r;
|
|
|
|
struct netbuf *nb;
|
|
|
|
|
2013-06-27 00:22:48 +02:00
|
|
|
while (!TAILQ_EMPTY(&(c->recv_queue))) {
|
|
|
|
nb = TAILQ_FIRST(&(c->recv_queue));
|
2013-04-28 19:11:44 +02:00
|
|
|
if (nb->cb == NULL) {
|
2013-06-04 16:30:53 +02:00
|
|
|
kore_debug("kore_read_client(): nb->cb == NULL");
|
2013-04-28 19:11:44 +02:00
|
|
|
return (KORE_RESULT_ERROR);
|
|
|
|
}
|
|
|
|
|
2013-06-27 00:22:48 +02:00
|
|
|
r = SSL_read(c->ssl,
|
|
|
|
(nb->buf + nb->offset), (nb->len - nb->offset));
|
|
|
|
|
|
|
|
kore_debug("net_recv(%ld/%ld bytes), progress with %d",
|
|
|
|
nb->offset, nb->len, r);
|
|
|
|
|
|
|
|
if (r <= 0) {
|
|
|
|
r = SSL_get_error(c->ssl, r);
|
|
|
|
switch (r) {
|
|
|
|
case SSL_ERROR_WANT_READ:
|
|
|
|
c->flags &= ~CONN_READ_POSSIBLE;
|
2013-06-27 08:43:07 +02:00
|
|
|
if (nb->flags & NETBUF_CALL_CB_ALWAYS &&
|
|
|
|
nb-> offset > 0)
|
2013-06-27 00:22:48 +02:00
|
|
|
goto handle;
|
|
|
|
return (KORE_RESULT_OK);
|
|
|
|
case SSL_ERROR_WANT_WRITE:
|
|
|
|
c->flags &= ~CONN_READ_POSSIBLE;
|
|
|
|
return (KORE_RESULT_OK);
|
|
|
|
default:
|
|
|
|
kore_debug("SSL_read(): %s", ssl_errno_s);
|
|
|
|
return (KORE_RESULT_ERROR);
|
|
|
|
}
|
|
|
|
}
|
2013-05-02 14:47:02 +02:00
|
|
|
|
2013-06-27 00:22:48 +02:00
|
|
|
nb->offset += (size_t)r;
|
|
|
|
if (nb->offset == nb->len) {
|
|
|
|
handle:
|
|
|
|
r = nb->cb(nb);
|
|
|
|
if (nb->offset == nb->len ||
|
|
|
|
(nb->flags & NETBUF_FORCE_REMOVE)) {
|
|
|
|
TAILQ_REMOVE(&(c->recv_queue), nb, list);
|
|
|
|
|
2013-07-10 13:39:35 +02:00
|
|
|
kore_mem_free(nb->buf);
|
2013-07-15 10:13:36 +02:00
|
|
|
kore_pool_put(&nb_pool, nb);
|
2013-05-02 14:47:02 +02:00
|
|
|
}
|
2013-06-27 00:22:48 +02:00
|
|
|
|
|
|
|
if (r != KORE_RESULT_OK)
|
|
|
|
return (r);
|
2013-04-28 23:42:13 +02:00
|
|
|
}
|
2013-04-28 19:11:44 +02:00
|
|
|
}
|
|
|
|
|
2013-06-27 00:22:48 +02:00
|
|
|
return (KORE_RESULT_OK);
|
2013-04-28 19:11:44 +02:00
|
|
|
}
|
2013-05-01 00:35:33 +02:00
|
|
|
|
2013-05-01 13:43:47 +02:00
|
|
|
int
|
|
|
|
net_recv_flush(struct connection *c)
|
|
|
|
{
|
2013-06-04 16:30:53 +02:00
|
|
|
kore_debug("net_recv_flush(%p)", c);
|
2013-05-02 09:10:35 +02:00
|
|
|
|
2013-05-01 13:43:47 +02:00
|
|
|
while (!TAILQ_EMPTY(&(c->recv_queue)) &&
|
|
|
|
(c->flags & CONN_READ_POSSIBLE)) {
|
|
|
|
if (!net_recv(c))
|
|
|
|
return (KORE_RESULT_ERROR);
|
|
|
|
}
|
|
|
|
|
|
|
|
return (KORE_RESULT_OK);
|
|
|
|
}
|
|
|
|
|
2013-05-01 00:35:33 +02:00
|
|
|
u_int16_t
|
|
|
|
net_read16(u_int8_t *b)
|
|
|
|
{
|
|
|
|
u_int16_t r;
|
|
|
|
|
|
|
|
r = *(u_int16_t *)b;
|
|
|
|
return (ntohs(r));
|
|
|
|
}
|
|
|
|
|
|
|
|
u_int32_t
|
|
|
|
net_read32(u_int8_t *b)
|
|
|
|
{
|
|
|
|
u_int32_t r;
|
|
|
|
|
|
|
|
r = *(u_int32_t *)b;
|
|
|
|
return (ntohl(r));
|
|
|
|
}
|
2013-05-01 08:09:04 +02:00
|
|
|
|
|
|
|
void
|
|
|
|
net_write16(u_int8_t *p, u_int16_t n)
|
|
|
|
{
|
2013-05-01 12:23:21 +02:00
|
|
|
u_int16_t r;
|
|
|
|
|
|
|
|
r = htons(n);
|
|
|
|
memcpy(p, &r, sizeof(r));
|
2013-05-01 08:09:04 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
net_write32(u_int8_t *p, u_int32_t n)
|
|
|
|
{
|
2013-05-01 12:23:21 +02:00
|
|
|
u_int32_t r;
|
|
|
|
|
|
|
|
r = htonl(n);
|
|
|
|
memcpy(p, &r, sizeof(r));
|
2013-05-01 08:09:04 +02:00
|
|
|
}
|