#include "utcp_priv.h"
+#ifndef EBADMSG
+#define EBADMSG 104
+#endif
+
+#ifndef SHUT_RDWR
+#define SHUT_RDWR 2
+#endif
+
+#ifdef poll
+#undef poll
+#endif
+
+#ifndef timersub
+#define timersub(a, b, r) do {\
+ (r)->tv_sec = (a)->tv_sec - (b)->tv_sec;\
+ (r)->tv_usec = (a)->tv_usec - (b)->tv_usec;\
+ if((r)->tv_usec < 0)\
+ (r)->tv_sec--, (r)->tv_usec += 1000000;\
+} while (0)
+#endif
+
#ifdef UTCP_DEBUG
#include <stdarg.h>
return NULL;
c->recv = recv;
+ c->priv = priv;
struct hdr hdr;
struct {
struct hdr hdr;
- char data[c->utcp->mtu];
- } pkt;
+ char data[];
+ } *pkt;
- pkt.hdr.src = c->src;
- pkt.hdr.dst = c->dst;
- pkt.hdr.ack = c->rcv.nxt;
- pkt.hdr.wnd = c->snd.wnd;
- pkt.hdr.ctl = ACK;
- pkt.hdr.aux = 0;
+ pkt = malloc(sizeof pkt->hdr + c->utcp->mtu);
+ if(!pkt->data)
+ return;
+
+ pkt->hdr.src = c->src;
+ pkt->hdr.dst = c->dst;
+ pkt->hdr.ack = c->rcv.nxt;
+ pkt->hdr.wnd = c->snd.wnd;
+ pkt->hdr.ctl = ACK;
+ pkt->hdr.aux = 0;
do {
uint32_t seglen = left > c->utcp->mtu ? c->utcp->mtu : left;
- pkt.hdr.seq = c->snd.nxt;
+ pkt->hdr.seq = c->snd.nxt;
- memcpy(pkt.data, data, seglen);
+ memcpy(pkt->data, data, seglen);
c->snd.nxt += seglen;
data += seglen;
case FIN_WAIT_1:
case CLOSING:
seglen--;
- pkt.hdr.ctl |= FIN;
+ pkt->hdr.ctl |= FIN;
break;
default:
break;
}
}
- print_packet(c->utcp, "send", &pkt, sizeof pkt.hdr + seglen);
- c->utcp->send(c->utcp, &pkt, sizeof pkt.hdr + seglen);
+ print_packet(c->utcp, "send", pkt, sizeof pkt->hdr + seglen);
+ c->utcp->send(c->utcp, pkt, sizeof pkt->hdr + seglen);
} while(left);
+
+ free(pkt);
}
ssize_t utcp_send(struct utcp_connection *c, const void *data, size_t len) {
struct {
struct hdr hdr;
- char data[c->utcp->mtu];
- } pkt;
+ char data[];
+ } *pkt;
- pkt.hdr.src = c->src;
- pkt.hdr.dst = c->dst;
+ pkt = malloc(sizeof pkt->hdr + c->utcp->mtu);
+ if(!pkt)
+ return;
+
+ pkt->hdr.src = c->src;
+ pkt->hdr.dst = c->dst;
switch(c->state) {
case LISTEN:
break;
case SYN_SENT:
- pkt.hdr.seq = c->snd.iss;
- pkt.hdr.ack = 0;
- pkt.hdr.wnd = c->rcv.wnd;
- pkt.hdr.ctl = SYN;
- print_packet(c->utcp, "rtrx", &pkt, sizeof pkt.hdr);
- utcp->send(utcp, &pkt, sizeof pkt.hdr);
+ pkt->hdr.seq = c->snd.iss;
+ pkt->hdr.ack = 0;
+ pkt->hdr.wnd = c->rcv.wnd;
+ pkt->hdr.ctl = SYN;
+ print_packet(c->utcp, "rtrx", pkt, sizeof pkt->hdr);
+ utcp->send(utcp, pkt, sizeof pkt->hdr);
break;
case SYN_RECEIVED:
- pkt.hdr.seq = c->snd.nxt;
- pkt.hdr.ack = c->rcv.nxt;
- pkt.hdr.ctl = SYN | ACK;
- print_packet(c->utcp, "rtrx", &pkt, sizeof pkt.hdr);
- utcp->send(utcp, &pkt, sizeof pkt.hdr);
+ pkt->hdr.seq = c->snd.nxt;
+ pkt->hdr.ack = c->rcv.nxt;
+ pkt->hdr.ctl = SYN | ACK;
+ print_packet(c->utcp, "rtrx", pkt, sizeof pkt->hdr);
+ utcp->send(utcp, pkt, sizeof pkt->hdr);
break;
case ESTABLISHED:
case FIN_WAIT_1:
- pkt.hdr.seq = c->snd.una;
- pkt.hdr.ack = c->rcv.nxt;
- pkt.hdr.ctl = ACK;
+ pkt->hdr.seq = c->snd.una;
+ pkt->hdr.ack = c->rcv.nxt;
+ pkt->hdr.ctl = ACK;
uint32_t len = seqdiff(c->snd.nxt, c->snd.una);
if(c->state == FIN_WAIT_1)
len--;
len = utcp->mtu;
else {
if(c->state == FIN_WAIT_1)
- pkt.hdr.ctl |= FIN;
+ pkt->hdr.ctl |= FIN;
}
- memcpy(pkt.data, c->sndbuf, len);
- print_packet(c->utcp, "rtrx", &pkt, sizeof pkt.hdr + len);
- utcp->send(utcp, &pkt, sizeof pkt.hdr + len);
+ memcpy(pkt->data, c->sndbuf, len);
+ print_packet(c->utcp, "rtrx", pkt, sizeof pkt->hdr + len);
+ utcp->send(utcp, pkt, sizeof pkt->hdr + len);
break;
default:
// TODO: implement
abort();
}
+
+ free(pkt);
}
/* Handle timeouts.
retransmit(c);
}
+ if(c->poll && c->sndbufsize < c->maxsndbufsize / 2)
+ c->poll(c, c->maxsndbufsize - c->sndbufsize);
+
if(timerisset(&c->conn_timeout) && timercmp(&c->conn_timeout, &next, <))
next = c->conn_timeout;
return c->maxsndbufsize;
}
+size_t utcp_get_sndbuf_free(struct utcp_connection *c) {
+ return c->maxsndbufsize - c->sndbufsize;
+}
+
void utcp_set_sndbuf(struct utcp_connection *c, size_t size) {
c->maxsndbufsize = size;
if(c->maxsndbufsize != size)
size_t utcp_get_outq(struct utcp_connection *c) {
return seqdiff(c->snd.nxt, c->snd.una);
}
+
+void utcp_set_recv_cb(struct utcp_connection *c, utcp_recv_t recv) {
+ c->recv = recv;
+}
+
+void utcp_set_poll_cb(struct utcp_connection *c, utcp_poll_t poll) {
+ c->poll = poll;
+}