summaryrefslogtreecommitdiff
path: root/lib/base.c
diff options
context:
space:
mode:
authorLinus Nordberg <linus@nordu.net>2010-09-13 17:27:40 +0200
committerLinus Nordberg <linus@nordu.net>2010-09-13 17:27:40 +0200
commit23dfea91ef5e921da0b09d91004436a7d8715c42 (patch)
tree3ef5ba7681bbe664efb51064f29adc5cec2778b7 /lib/base.c
parent8455dc9801730e599510c92cdb3e05da351aa7a5 (diff)
First stab at a working blocking example.
Diffstat (limited to 'lib/base.c')
-rw-r--r--lib/base.c161
1 files changed, 142 insertions, 19 deletions
diff --git a/lib/base.c b/lib/base.c
index 38086c0..2427bae 100644
--- a/lib/base.c
+++ b/lib/base.c
@@ -1,12 +1,16 @@
#include <sys/socket.h>
#include <errno.h>
#include <stdlib.h>
+#include <string.h>
+//#include <unistd.h>
+#include <stdint.h>
+#include "../tlv11.h" /* FIXME: .. */
#include "libradsec-base.h"
static int
-do_connect(int type,
- const struct sockaddr *addr,
- socklen_t addrlen)
+_do_connect(int type,
+ const struct sockaddr *addr,
+ socklen_t addrlen)
{
int s;
@@ -19,6 +23,56 @@ do_connect(int type,
return s;
}
+static struct list *
+_list_new(const struct rs_config *ctx)
+{
+ struct list *list = rs_malloc(ctx, sizeof(struct list));
+ if (list)
+ memset(list, 0, sizeof(struct list));
+ return list;
+}
+
+static int
+_list_push(const struct rs_config *ctx, /* FIXME: code duplicate, list.c */
+ struct list *list,
+ void *data)
+{
+ struct list_node *node;
+
+ node = rs_malloc(ctx, sizeof(struct list_node));
+ if (!node)
+ return 0;
+
+ node->next = NULL;
+ node->data = data;
+
+ if (list->first)
+ list->last->next = node;
+ else
+ list->first = node;
+ list->last = node;
+
+ list->count++;
+ return 1;
+}
+
+static void
+_list_destroy(const struct rs_config *ctx, /* FIXME: code dup */
+ struct list *list)
+{
+ struct list_node *node, *next;
+
+ if (list) {
+ for (node = list->first; node; node = next) {
+ rs_free(ctx, node->data);
+ next = node->next;
+ rs_free(ctx, node);
+ }
+ free(list);
+ }
+}
+
+/* ------------------------------------------------------- */
int
rs_connect(const struct rs_config *conf,
const struct sockaddr *addr,
@@ -27,9 +81,9 @@ rs_connect(const struct rs_config *conf,
switch (conf->conn_type)
{
case RS_CONN_TYPE_UDP:
- return do_connect(SOCK_DGRAM, addr, addrlen);
+ return _do_connect(SOCK_DGRAM, addr, addrlen);
case RS_CONN_TYPE_TCP:
- return do_connect(SOCK_STREAM, addr, addrlen);
+ return _do_connect(SOCK_STREAM, addr, addrlen);
/* fall thru */
case RS_CONN_TYPE_TLS:
/* fall thru */
@@ -66,38 +120,83 @@ rs_packet_new(const struct rs_config *ctx,
const uint8_t buf[RS_HEADER_LEN],
size_t *count)
{
- struct rs_packet *p =
- (ctx->alloc_scheme.malloc ? ctx->alloc_scheme.malloc : malloc)(20);
+ struct rs_packet *p = rs_malloc(ctx, sizeof(struct rs_packet));
if (p) {
- p->code = buf[0];
- p->id = buf[1];
- if (count)
- *count = 256 * buf[2] + buf[3];
+ p->attrs = _list_new(ctx);
+ if (p->attrs) {
+ p->code = buf[0];
+ p->id = buf[1];
+ if (count)
+ *count = (buf[2] << 8) + buf[3];
+ }
+ else
+ rs_packet_free(ctx, &p);
}
return p;
}
struct rs_packet *
rs_packet_parse(const struct rs_config *ctx,
- struct rs_packet *packet,
+ struct rs_packet **packet,
const uint8_t *buf,
size_t buflen)
{
+ struct rs_packet *p = *packet;
+ struct tlv *tlv;
+ size_t i;
+ uint8_t atype, alen;
+
if (buflen < 16) {
- rs_packet_free(ctx, packet);
errno = EPROTO;
+ rs_packet_free(ctx, &p);
return NULL;
}
- memcpy(packet->auth, buf, 16);
- /* TODO: copy attributes starting at buf[16]. */
- return packet;
+
+ i = 16;
+ while (i + 2 < buflen) {
+ atype = buf[i++];
+ alen = buf[i++];
+ if (alen < 2) {
+#if DEBUG
+ fprintf(stderr,
+ "%s: DEBUG: attribute (type %d, len %d) has an invalid length\n",
+ __func__, atype, alen);
+#endif
+ errno = EPROTO;
+ rs_packet_free(ctx, &p);
+ return NULL;
+ }
+ alen -= 2;
+ if (alen + i >= buflen) {
+#if DEBUG
+ fprintf(stderr,
+ "%s: DEBUG: attribute (type %d, len %d) wouldn't fit packet\n",
+ __func__, atype, alen);
+#endif
+ errno = EPROTO;
+ rs_packet_free(ctx, &p);
+ return NULL;
+ }
+ tlv = maketlv(atype, alen, (void *) (buf + i));
+ if (tlv)
+ _list_push(ctx, p->attrs, tlv);
+ else {
+ errno = ENOMEM;
+ rs_packet_free(ctx, &p);
+ }
+ i += alen;
+ }
+ memcpy(p->auth, buf, 16);
+ return p;
}
void
rs_packet_free(const struct rs_config *ctx,
- struct rs_packet *packet)
+ struct rs_packet **packet)
{
- (ctx->alloc_scheme.free ? ctx->alloc_scheme.free : free)(packet);
+ _list_destroy(ctx, (*packet)->attrs);
+ rs_free(ctx, *packet);
+ *packet = NULL;
}
ssize_t
@@ -105,7 +204,31 @@ rs_packet_serialize(const struct rs_packet *packet,
uint8_t *buf,
size_t buflen)
{
- fixme;
+ struct list_node *ln;
+ size_t pktlen;
+ ssize_t i;
+
+ for (ln = list_first(packet->attrs), pktlen = 20; ln; ln = list_next(ln))
+ pktlen += ((struct rs_attribute *)(ln->data))->length;
+ if (pktlen > buflen)
+ return -(pktlen - buflen);
+
+ buf[0] = packet->code;
+ buf[1] = packet->id;
+ buf[2] = (pktlen & 0xff00) >> 8;
+ buf[3] = pktlen & 0xff;
+
+ memcpy(buf + 4, packet->auth, 16);
+
+ for (ln = list_first(packet->attrs), i = 20; ln; ln = list_next(ln)) {
+ struct rs_attribute *a = (struct rs_attribute *)(ln->data);
+ buf[i++] = a->type;
+ buf[i++] = a->length;
+ memcpy(buf + i, a->value, a->length - 2);
+ i += a->length - 2;
+ }
+
+ return i;
}
/* Local Variables: */