[Tinyos-2-commits] CVS: tinyos-2.x/support/sdk/c/blip/libtcp Makefile, NONE, 1.1 circ.c, NONE, 1.1 circ.h, NONE, 1.1 tcplib.c, NONE, 1.1 tcplib.h, NONE, 1.1 test_circ.c, NONE, 1.1 test_server.c, NONE, 1.1
sdhsdh
sdhsdh at users.sourceforge.net
Mon Jan 19 16:28:18 PST 2009
- Previous message: [Tinyos-2-commits] CVS: tinyos-2.x/support/sdk/c/blip/lib6lowpan Makefile, NONE, 1.1 in_cksum.c, NONE, 1.1 ip_malloc.c, NONE, 1.1 lib6lowpan.c, NONE, 1.1 lib6lowpanFrag.c, NONE, 1.1 lib6lowpanIP.c, NONE, 1.1 printpacket.c, NONE, 1.1
- Next message: [Tinyos-2-commits] CVS: tinyos-2.x/support/sdk/c/sf serialsource.c, 1.4, 1.5
- Messages sorted by:
[ date ]
[ thread ]
[ subject ]
[ author ]
Update of /cvsroot/tinyos/tinyos-2.x/support/sdk/c/blip/libtcp
In directory ddv4jf1.ch3.sourceforge.com:/tmp/cvs-serv6583/support/sdk/c/blip/libtcp
Added Files:
Makefile circ.c circ.h tcplib.c tcplib.h test_circ.c
test_server.c
Log Message:
- initial commit of blip (berkeley low-power ip) stack
--- NEW FILE: Makefile ---
GCC=gcc
CFLAGS=-I../include -I../driver/ -DPC -g
all: test_client test_server
test_circ: test_circ.c circ.c
$(GCC) -o $@ $^
test_client: test_client.c tcplib.h tcplib.c circ.c
$(GCC) -o $@ $< tcplib.c circ.c ../driver/tun_dev.c ../lib6lowpan/ip_malloc.c ../lib6lowpan/in_cksum.c $(CFLAGS)
test_server: test_server.c tcplib.h tcplib.c circ.c
$(GCC) -o $@ $< tcplib.c circ.c ../driver/tun_dev.c ../lib6lowpan/ip_malloc.c ../lib6lowpan/in_cksum.c $(CFLAGS)
clean:
rm -rf test_server test_circ
--- NEW FILE: circ.c ---
#include <stdio.h>
#include <stdint.h>
// #include <assert.h>
#include <string.h>
#include "tcplib.h"
struct circ_buf {
uint8_t *map;
uint16_t map_len;
uint8_t *data_start;
uint8_t *data_head;
uint16_t data_len;
uint32_t head_seqno;
};
int circ_buf_init(void *data, int len, uint32_t seqno, int incl_map) {
struct circ_buf *b = (struct circ_buf *)data;
int bitmap_len = ((len - sizeof(struct circ_buf)) / 9);
// int data_len = bitmap_len * 8;
// printf("circ_buf_init: len: %i data_len: %i bitmap_len: %i\n", len, data_len, bitmap_len);
// assert(bitmap_len + data_len + sizeof(struct circ_buf) <= len);
if (len < sizeof(struct circ_buf))
return -1;
if (incl_map) {
b->map = (uint8_t *)(b + 1);
b->map_len = bitmap_len;
b->data_start = b->map + bitmap_len;
b->data_len= bitmap_len * 8;
memset(b->map, 0, bitmap_len * 9);
} else {
b->map = NULL;
b->map_len = 0;
b->data_start = (uint8_t *)(b + 1);
b->data_len = len - sizeof(struct circ_buf);
memset(b->data_start, 0, b->data_len);
}
b->data_head = b->data_start;
b->head_seqno = seqno;
// printf("circ_buf_init: buf: %p data_start: %p data_head: %p data_len: %i\n",
// b, b->data_start, b->data_head, b->data_len);
return 0;
}
#define BIT_SET(off,map) map[(off)/8] |= (1 << (7 - ((off) % 8)))
#define BIT_UNSET(off,map) map[(off)/8] &= ~(1 << (7 - ((off) % 8)))
#define BIT_ISSET(off, map) map[(off)/8] & 1 << (7 - (off) % 8)
static void bitmap_mark(struct circ_buf *b, uint8_t *data, int len) {
int offset = data - b->data_start;
if (b->map_len == 0) return;
while (len-- > 0) {
BIT_SET(offset, b->map);
offset = (offset + 1) % b->data_len;
}
}
/* return the sequence number of the first byte of data in the buffer;
this is what the stack can ACK. */
uint32_t circ_get_seqno(void *buf) {
struct circ_buf *b = (struct circ_buf *)buf;
return b->head_seqno;
}
void circ_set_seqno(void *buf, uint32_t seqno) {
struct circ_buf *b = (struct circ_buf *)buf;
b->head_seqno = seqno;
}
uint16_t circ_get_window(void *buf) {
struct circ_buf *b = (struct circ_buf *)buf;
return b->data_len;
}
/* read as many contiguous bytes from the head of the buffer as
* possible, and update the internal data structures to shorten the
* buffer
*
* buf: the circular buffer
* data: a pointer which will be updated with the location of the data
* return: the number of bytes available
*/
int circ_buf_read_head(void *buf, char **data) {
struct circ_buf *b = (struct circ_buf *)buf;
int off = b->data_head - b->data_start;
int rlen = 0;
*data = b->data_head;
while (BIT_ISSET(off, b->map) && off < b->data_len) {
BIT_UNSET(off, b->map);
rlen++;
b->head_seqno++;
b->data_head ++;
if (b->data_head == b->data_start + b->data_len)
b->data_head = b->data_start;
off++;
}
return rlen;
}
static void get_ptr_off_1(struct circ_buf *b, uint32_t sseqno, int len,
uint8_t **writeptr, int *w_len) {
uint8_t *endptr = b->data_start + b->data_len;
int offset;
*writeptr = NULL;
*w_len = 0;
/* write up to either the end of the buffer */
offset = sseqno - b->head_seqno;
if (b->data_head + offset < endptr) {
*w_len = len;
*writeptr = b->data_head + offset;
if (*writeptr + *w_len > endptr) {
*w_len = endptr - *writeptr;
}
}
}
int circ_shorten_head(void *buf, uint32_t seqno) {
struct circ_buf *b = (struct circ_buf *)buf;
int offset = seqno - b->head_seqno;
b->head_seqno = seqno;
b->data_head += offset;
while (b->data_head > b->data_start + b->data_len)
b->data_head -= b->data_len;
return 0;
}
int circ_buf_read(void *buf, uint32_t sseqno,
uint8_t *data, int len) {
struct circ_buf *b = (struct circ_buf *)buf;
uint8_t *readptr;
int r_len, rc = 0;
get_ptr_off_1(b, sseqno, len, &readptr, &r_len);
memcpy(data, readptr, r_len);
data += r_len;
rc += r_len;
if (r_len != len) {
readptr = b->data_start;
r_len = min(len - r_len, b->data_head - b->data_start);
memcpy(data, readptr, r_len);
rc += r_len;
}
return rc;
}
int circ_buf_write(void *buf, uint32_t sseqno,
uint8_t *data, int len) {
struct circ_buf *b = (struct circ_buf *)buf;
uint8_t *writeptr;
int w_len;
/* we can't write any bytes since we're trying to write too far
ahead */
// printf("circ_buf_write: sseqno: %i head_seqno: %i len: %i\n",
// sseqno, b->head_seqno, len);
if (sseqno > b->head_seqno + b->data_len)
return -1;
if (sseqno < b->head_seqno) {
/* old data, but already received */
if (sseqno < b->head_seqno - len) return -1;
/* a segment which overlaps with data we've already received */
data += (b->head_seqno - sseqno);
len -= (b->head_seqno - sseqno);
sseqno = b->head_seqno;
}
if (len == 0) return 0;
// printf("circ_buf_write: buf: %p data_start: %p data_head: %p data_len: %i\n",
// b, b->data_start, b->data_head, b->data_len);
get_ptr_off_1(b, sseqno, len, &writeptr, &w_len);
memcpy(writeptr, data, w_len);
data += w_len;
bitmap_mark(b, writeptr, w_len);
if (w_len != len) {
writeptr = b->data_start;
w_len = min(len - w_len, b->data_head - b->data_start);
memcpy(writeptr, data, w_len);
bitmap_mark(b, writeptr, w_len);
// printf("circ_buf_write (2): write: %p len: %i\n", writeptr, w_len);
}
return 0;
}
#ifdef PC
void circ_buf_dump(void *buf) {
struct circ_buf *b = (struct circ_buf *)buf;
int i;
/* printf("circ buf: %p\n\tmap: %p\n\tmap_len: %i\n\tdata_start: %p\n\t" */
/* "data_head: %p\n\tdata_len: %i\n\thead_seqno: %i\n", */
/* b, b->map, */
/* b->map_len, b->data_start, b->data_head, b->data_len, b->head_seqno); */
for (i = 1; i <= b->data_len; i++) {
if (BIT_ISSET(i-1, b->map))
putc('x',stdout);
else
putc('_',stdout);
if (i % 80 == 0 || i == b->data_len) {
putc('\n',stdout);
}
}
}
#endif
--- NEW FILE: circ.h ---
#ifndef __CIRC_H_
#define __CIRC_H_
#include <stdint.h>
int circ_buf_init(void *data, int len, uint32_t seqno, int inc_map);
int circ_buf_write(void *buf, uint32_t sseqno,
uint8_t *data, int len);
int circ_buf_read(void *buf, uint32_t sseqno,
uint8_t *data, int len);
int circ_shorten_head(void *buf, uint32_t seqno);
/* read from the head of the buffer, moving the data pointer forward */
int circ_buf_read_head(void *buf, char **data);
void circ_buf_dump(void *buf);
void circ_set_seqno(void *buf, uint32_t seqno);
#endif
--- NEW FILE: tcplib.c ---
/* A nonblocking library-based implementation of TCP
*
* There are some things like timers which need to be handled
* externally with callbacks.
*
*/
#include <stdio.h>
#include <string.h>
#include "ip_malloc.h"
#include "in_cksum.h"
#include "6lowpan.h"
#include "ip.h"
#include "tcplib.h"
#include "circ.h"
static struct tcplib_sock *conns = NULL;
#define ONE_SEGMENT(X) ((X)->mss)
uint16_t alloc_local_port() {
return 32012;
}
static inline void conn_add_once(struct tcplib_sock *sock) {
struct tcplib_sock *iter;
for (iter = conns; iter != NULL; iter = iter->next) {
if (iter == sock) break;
}
if (iter == NULL) {
sock->next = conns;
conns = sock;
}
}
static int isInaddrAny(struct in6_addr *addr) {
int i;
for (i = 0; i < 8; i++)
if (addr->s6_addr16[i] != 0) break;
if (i != 8) return 0;
return 1;
}
static struct tcplib_sock *conn_lookup(struct ip6_hdr *iph,
struct tcp_hdr *tcph) {
struct tcplib_sock *iter;
printfUART("looking up conns...\n");
for (iter = conns; iter != NULL; iter = iter->next) {
printf("conn lport: %i\n", ntohs(iter->l_ep.sin6_port));
if (((memcmp(iph->ip6_dst.s6_addr, iter->l_ep.sin6_addr.s6_addr, 16) == 0) ||
isInaddrAny(&iter->l_ep.sin6_addr)) &&
tcph->dstport == iter->l_ep.sin6_port &&
(iter->r_ep.sin6_port == 0 ||
(memcmp(&iph->ip6_src, &iter->r_ep.sin6_addr, 16) == 0 &&
tcph->srcport == iter->r_ep.sin6_port)))
return iter;
}
return NULL;
}
static int conn_checkport(uint16_t port) {
struct tcplib_sock *iter;
for (iter = conns; iter != NULL; iter = iter->next) {
if (iter->l_ep.sin6_port == port)
return -1;
}
return 0;
}
struct tcp_hdr *find_tcp_hdr(struct split_ip_msg *msg) {
if (msg->hdr.nxt_hdr == IANA_TCP) {
return (struct tcp_hdr *)((msg->headers == NULL) ? msg->data :
msg->headers->hdr.data);
}
}
static struct split_ip_msg *get_ipmsg(int plen) {
struct split_ip_msg *msg =
(struct split_ip_msg *)ip_malloc(sizeof(struct split_ip_msg) + sizeof(struct tcp_hdr) + plen);
if (msg == NULL) return NULL;
memset(msg, 0, sizeof(struct split_ip_msg) + sizeof(struct tcp_hdr));
msg->hdr.nxt_hdr = IANA_TCP;
msg->hdr.plen = htons(sizeof(struct tcp_hdr) + plen);
msg->headers = NULL;
msg->data = (void *)(msg + 1);
msg->data_len = sizeof(struct tcp_hdr) + plen;
return msg;
}
static void __tcplib_send(struct tcplib_sock *sock,
struct split_ip_msg *msg) {
struct tcp_hdr *tcph = find_tcp_hdr(msg);
memcpy(&msg->hdr.ip6_dst, &sock->r_ep.sin6_addr, 16);
sock->flags &= ~TCP_ACKPENDING;
// sock->ackno = ntohl(tcph->ackno);
tcph->srcport = sock->l_ep.sin6_port;
tcph->dstport = sock->r_ep.sin6_port;
tcph->offset = sizeof(struct tcp_hdr) * 4;
tcph->window = htons(circ_get_window(sock->rx_buf));
tcph->chksum = 0;
tcph->urgent = 0;
tcplib_send_out(msg, tcph);
}
static void tcplib_send_ack(struct tcplib_sock *sock, int fin_seqno, uint8_t flags) {
struct split_ip_msg *msg = get_ipmsg(0);
if (msg != NULL) {
struct tcp_hdr *tcp_rep = (struct tcp_hdr *)(msg + 1);
tcp_rep->flags = flags;
tcp_rep->seqno = htonl(sock->seqno);
tcp_rep->ackno = htonl(circ_get_seqno(sock->rx_buf) +
(fin_seqno ? 1 : 0));
__tcplib_send(sock, msg);
ip_free(msg);
}
}
static void tcplib_send_rst(struct ip6_hdr *iph, struct tcp_hdr *tcph) {
struct split_ip_msg *msg = get_ipmsg(0);
if (msg != NULL) {
struct tcp_hdr *tcp_rep = (struct tcp_hdr *)(msg + 1);
memcpy(&msg->hdr.ip6_dst, &iph->ip6_src, 16);
tcp_rep->flags = TCP_FLAG_RST;
tcp_rep->ackno = tcph->seqno + 1;
tcp_rep->seqno = tcph->ackno;;
tcp_rep->srcport = tcph->dstport;
tcp_rep->dstport = tcph->srcport;
tcp_rep->offset = sizeof(struct tcp_hdr) * 4;
tcp_rep->window = 0;
tcp_rep->chksum = 0;
tcp_rep->urgent = 0;
tcplib_send_out(msg, tcp_rep);
ip_free(msg);
}
}
/* send all the data in the tx buffer, starting at sseqno */
static int tcplib_output(struct tcplib_sock *sock, uint32_t sseqno) {
// the output size is the minimum of the advertised window and the
// conjestion window. of course, if we have less data we send even
// less.
int seg_size = min(sock->seqno - sseqno, sock->r_wind);
seg_size = min(seg_size, sock->cwnd);
while (seg_size > 0 && sock->seqno > sseqno) {
// printf("sending seg_size: %i\n", seg_size);
struct split_ip_msg *msg = get_ipmsg(seg_size);
struct tcp_hdr *tcph;
uint8_t *data;
if (msg == NULL) return -1;
tcph = (struct tcp_hdr *)(msg + 1);
data = (uint8_t *)(tcph + 1);
tcph->flags = TCP_FLAG_ACK;
tcph->seqno = htonl(sseqno);
tcph->ackno = htonl(circ_get_seqno(sock->rx_buf));
circ_buf_read(sock->tx_buf, sseqno, data, seg_size);
__tcplib_send(sock, msg);
ip_free(msg);
sseqno += seg_size;
seg_size = min(sock->seqno - sseqno, sock->mss);
}
return 0;
}
int tcplib_init_sock(struct tcplib_sock *sock) {
memset(sock, 0, sizeof(struct tcplib_sock) - sizeof(struct tcplib_sock *));
sock->mss = 100;
sock->cwnd = ONE_SEGMENT(sock);
sock->ssthresh = 0xffff;
conn_add_once(sock);
return 0;
}
/* called when a new segment arrives. */
/* deliver as much data to the app as possible, and update the ack
* number of the socket to reflect how much was delivered
*/
static void add_data(struct tcplib_sock *sock, struct tcp_hdr *tcph, int len) {
char *ptr;
int payload_len;
ptr = ((uint8_t *)tcph) + (tcph->offset / 4);
payload_len = len - (tcph->offset / 4);
// TODO : SDH : optimize out the extra copy for in-sequence data
circ_buf_write(sock->rx_buf, ntohl(tcph->seqno),
ptr, payload_len);
// now try to deliver any data ahead of the ack pointer that's in
// the buffer
/* if we wrapped around the buffer, we'll actually recieve twice. */
while ((payload_len = circ_buf_read_head(sock->rx_buf, &ptr)) > 0) {
sock->ops.recvfrom(sock, ptr, payload_len);
}
}
static void reset_ssthresh(struct tcplib_sock *conn) {
uint16_t new_ssthresh = min(conn->cwnd, conn->r_wind) / 2;
if (new_ssthresh < 2 * ONE_SEGMENT(conn))
new_ssthresh = 2 * ONE_SEGMENT(conn);
conn->ssthresh = new_ssthresh;
}
int tcplib_process(struct ip6_hdr *iph, void *payload) {
int rc = 0;
struct tcp_hdr *tcph;
struct tcplib_sock *this_conn;
// uint8_t *ptr;
int payload_len;
int len = ntohs(iph->plen) + sizeof(struct ip6_hdr);;
tcph = (struct tcp_hdr *)payload;
// printf("tcplib_process\n");
/* malformed ip packet? could happen I supppose... */
/* if (len < sizeof(struct ip6_hdr) || */
/* len != ntohs(iph->plen) + sizeof(struct ip6_hdr)) { */
/* fprintf(stderr, "tcplib_process: warn: length mismatch\n"); */
/* return -1; */
/* } */
/* if there's no local */
this_conn = conn_lookup(iph, tcph);
if (this_conn != NULL) {
if (tcph->flags & TCP_FLAG_RST) {
/* Really hose this connection if we get a RST packet.
* still TODO: RST generation for unbound ports */
printf("connection reset by peer\n");
if (this_conn->ops.closed)
this_conn->ops.close_done(this_conn);
tcplib_init_sock(this_conn);
return 0;
}
// always get window updates from new segments
// TODO : this should be after we detect out-of-sequence ACK
// numbers!
this_conn->r_wind = ntohs(tcph->window);
switch (this_conn->state) {
case TCP_LAST_ACK:
if (tcph->flags & TCP_FLAG_ACK &&
ntohl(tcph->ackno) == this_conn->seqno + 1) {
// printf("closing connection\n");
this_conn->state = TCP_CLOSED;
this_conn->ops.close_done(this_conn);
break;
}
case TCP_SYN_SENT:
if (tcph->flags & (TCP_FLAG_SYN | TCP_FLAG_ACK)) {
// got a syn-ack
// send the ACK
this_conn->state = TCP_ESTABLISHED;
circ_set_seqno(this_conn->rx_buf, ntohl(tcph->seqno) + 1);
// skip the LISTEN processing
// this will also generate an ACK
goto ESTABLISHED;
} else if (this_conn->flags & TCP_FLAG_SYN) {
// otherwise the state machine says we're in a simultaneous open, so continue doen
this_conn->state = TCP_SYN_RCVD;
} else {
printf("sending RST on bad data in state SYN_SENT\n");
tcplib_send_rst(iph, tcph);
break;
}
case TCP_SYN_RCVD:
case TCP_LISTEN:
/* not connected. */
if (tcph->flags & TCP_FLAG_SYN) {
struct tcplib_sock *new_sock;
if (this_conn->state == TCP_LISTEN) {
memcpy(&this_conn->r_ep.sin6_addr, &iph->ip6_src, 16);
this_conn->r_ep.sin6_port = tcph->srcport;
new_sock = tcplib_accept(this_conn, &this_conn->r_ep);
if (new_sock != this_conn) {
memset(this_conn->r_ep.sin6_addr.s6_addr, 0, 16);
this_conn->r_ep.sin6_port = 0;
if (new_sock != NULL) {
memcpy(&new_sock->r_ep.sin6_addr, &iph->ip6_src, 16);
new_sock->r_ep.sin6_port = tcph->srcport;
conn_add_once(new_sock);
}
}
if (new_sock == NULL) {
tcplib_send_rst(iph, tcph);
break;
}
memcpy(&new_sock->l_ep.sin6_addr, &iph->ip6_dst, 16);
new_sock->l_ep.sin6_port = tcph->dstport;
circ_buf_init(new_sock->rx_buf, new_sock->rx_buf_len,
ntohl(tcph->seqno) + 1, 1);
circ_buf_init(new_sock->tx_buf, new_sock->tx_buf_len,
0xcafebabe + 1, 0);
} else {
/* recieved a SYN retransmission. */
new_sock = this_conn;
}
if (new_sock != NULL) {
new_sock->seqno = 0xcafebabe + 1;
new_sock->state = TCP_SYN_RCVD;
tcplib_send_ack(new_sock, 0, TCP_FLAG_ACK | TCP_FLAG_SYN);
new_sock->seqno++;
} else {
memset(&this_conn->r_ep, 0, sizeof(struct sockaddr_in6));
}
} else if (this_conn->state == TCP_LISTEN) {
printf("sending RST on out-of-sequence data\n");
tcplib_send_rst(iph, tcph);
break;
}
/* this is SYN_RECVd */
if (tcph->flags & TCP_FLAG_ACK) {
// printf("recv ack, in state TCP_SYN_RCVD\n");
this_conn->state = TCP_ESTABLISHED;
}
/* fall through to handle any data. */
case TCP_CLOSE_WAIT:
case TCP_ESTABLISHED:
ESTABLISHED:
// ptr = ((uint8_t *)(iph + 1)) + (tcph->offset / 4);
payload_len = len - sizeof(struct ip6_hdr) - (tcph->offset / 4);
// printf("recv data len: %i\n", payload_len);
/* ack any data in this packet */
if (this_conn->state == TCP_ESTABLISHED) {
if (payload_len > 0)
this_conn->flags ++;
// receive side sequence check and add data
// printf("seqno: %i ackno: %i\n", ntohl(tcph->seqno), ntohl(tcph->ackno));
// send side recieve sequence check and congestion window updates.
if (ntohl(tcph->ackno) > circ_get_seqno(this_conn->tx_buf)) {
// new data is being ACKed
// or we haven't sent anything new
if (this_conn->cwnd <= this_conn->ssthresh) {
// in slow start; increase the cwnd by one segment
this_conn->cwnd += ONE_SEGMENT(this_conn);
// printf("in slow start\n");
} else {
// in congestion avoidance
this_conn->cwnd += (ONE_SEGMENT(this_conn) * ONE_SEGMENT(this_conn)) / this_conn->cwnd;
// printf("in congestion avoidence\n");
}
// printf("ACK new data: cwnd: %i ssthresh: %i\n", this_conn->cwnd, this_conn->ssthresh);
// reset the duplicate ack counter
UNSET_ACK_COUNT(this_conn->flags);
// truncates the ack buffer
circ_shorten_head(this_conn->tx_buf, ntohl(tcph->ackno));
// printf("ack_count: %i\n", GET_ACK_COUNT(this_conn->flags));
} else if (this_conn->seqno > circ_get_seqno(this_conn->tx_buf)) {
// this is a duplicate ACK
// - increase the counter of the number of duplicate ACKs
// - if we get to three duplicate ACK's, start resending at
// the ACK number because this probably means we lost a segment
INCR_ACK_COUNT(this_conn->flags);
// printf("ack_count: %i\n", GET_ACK_COUNT(this_conn->flags));
// printf("dup ack count: %i\n", GET_ACK_COUNT(this_conn->flags));
// a "dup ack count" of 2 is really 3 total acks because we start with zero
if (GET_ACK_COUNT(this_conn->flags) == 2) {
UNSET_ACK_COUNT(this_conn->flags);
printf("detected multiple duplicate ACKs-- doing fast retransmit [%u, %u]\n",
circ_get_seqno(this_conn->tx_buf),
this_conn->seqno);
// this is our detection of a "duplicate ack" event.
// we are going to reset ssthresh and retransmit the data.
reset_ssthresh(this_conn);
tcplib_output(this_conn, circ_get_seqno(this_conn->tx_buf));
this_conn->timer.retx = 6;
}
} else if (ntohl(tcph->seqno) != circ_get_seqno(this_conn->rx_buf)) {
printf("==> received out-of-sequence data!\n");
tcplib_send_ack(this_conn, 0, TCP_FLAG_ACK);
}
add_data(this_conn, tcph, len - sizeof(struct ip6_hdr));
// printf("tx seqno: %i ackno: %i\n", circ_get_seqno(this_conn->tx_buf),
// ntohl(tcph->ackno));
// reset the retransmission timer
if (this_conn->timer.retx == 0)
this_conn->timer.retx = 6;
}
if ((payload_len > 0 && (this_conn->flags & TCP_ACKPENDING) >= 2)
|| tcph->flags & TCP_FLAG_FIN) {
///|| ntohl(tcph->seqno) != circ_get_seqno(this_conn->rx_buf)) {
tcplib_send_ack(this_conn, (payload_len == 0 && tcph->flags & TCP_FLAG_FIN), TCP_FLAG_ACK);
/* only close the connection if we've gotten all the data */
if (this_conn->state == TCP_ESTABLISHED
&& tcph->flags & TCP_FLAG_FIN
&& ntohl(tcph->seqno) == circ_get_seqno(this_conn->rx_buf)) {
this_conn->state = TCP_CLOSE_WAIT;
this_conn->ops.closed(this_conn);
}
}
break;
case TCP_CLOSED:
default:
rc = -1;
// printf("sending RST\n");
// tcplib_send_ack(this_conn, 0, TCP_FLAG_ACK | TCP_FLAG_RST);
}
} else {
/* this_conn was NULL */
/* TODO : SDH : send ICMP error */
}
return rc;
}
/* bind the socket to a local address */
int tcplib_bind(struct tcplib_sock *sock,
struct sockaddr_in6 *addr) {
/* not using an already-bound port */
/* TODO : SDH : check local address */
if (conn_checkport(addr->sin6_port))
return -1;
memcpy(&sock->l_ep, addr, sizeof(struct sockaddr_in6));
/* passive open */
sock->state = TCP_LISTEN;
}
/* connect the socket to a remote endpoint */
int tcplib_connect(struct tcplib_sock *sock,
struct sockaddr_in6 *serv_addr) {
if (sock->rx_buf == NULL || sock->tx_buf == NULL)
return -1;
switch (sock->state) {
case TCP_CLOSED:
// passive open; need to set up the local endpoint.
memset(&sock->l_ep, 0, sizeof(struct sockaddr_in6));
sock->l_ep.sin6_port = htons(alloc_local_port());
break;
case TCP_LISTEN:
// we got here by calling bind, so we're cool.
break;
default:
return -1;
}
circ_buf_init(sock->rx_buf, sock->rx_buf_len,
0, 1);
circ_buf_init(sock->tx_buf, sock->tx_buf_len,
0xcafebabe + 1, 0);
sock->seqno = 0xcafebabe;
memcpy(&sock->r_ep, serv_addr, sizeof(struct sockaddr_in6));
tcplib_send_ack(sock, 0, TCP_FLAG_SYN);
sock->state = TCP_SYN_SENT;
sock->seqno++;
return 0;
}
int tcplib_send(struct tcplib_sock *sock, void *data, int len) {
/* have enough tx buffer left? */
if (sock->state != TCP_ESTABLISHED)
return -1;
if (sock->seqno - circ_get_seqno(sock->tx_buf) + len > circ_get_window(sock->tx_buf))
return -1;
circ_buf_write(sock->tx_buf, sock->seqno, data, len);
sock->seqno += len;
// printf("tcplib_output from send\n");
tcplib_output(sock, sock->seqno - len);
// 3 seconds
if (sock->timer.retx == 0)
sock->timer.retx = 6;
return 0;
}
void tcplib_retx_expire(struct tcplib_sock *sock) {
// printf("retransmission timer expired!\n");
if (sock->state == TCP_ESTABLISHED &&
circ_get_seqno(sock->tx_buf) != sock->seqno) {
printf("retransmitting [%u, %u]\n", circ_get_seqno(sock->tx_buf),
sock->seqno);
reset_ssthresh(sock);
// restart slow start
sock->cwnd = ONE_SEGMENT(sock);
// printf("tcplib_output from timer\n");
tcplib_output(sock, circ_get_seqno(sock->tx_buf));
sock->timer.retx = 6;
} else if (sock->state == TCP_LAST_ACK) {
// printf("resending FIN\n");
tcplib_send_ack(sock, 1, TCP_FLAG_ACK | TCP_FLAG_FIN);
sock->timer.retx = 6;
}
}
int tcplib_close(struct tcplib_sock *sock) {
int rc = -1;
switch (sock->state) {
/* passive close */
case TCP_CLOSE_WAIT:
tcplib_send_ack(sock, 1, TCP_FLAG_ACK | TCP_FLAG_FIN);
sock->timer.retx = 6;
sock->state = TCP_LAST_ACK;
break;
/* active close */
case TCP_ESTABLISHED:
// kick off the close
break;
case TCP_SYN_SENT:
sock->state = TCP_CLOSED;
break;
default:
/* this is meaningless in other states */
rc = -1;
}
return rc;
}
int tcplib_timer_process() {
struct tcplib_sock *iter;
for (iter = conns; iter != NULL; iter = iter->next) {
if (iter->timer.retx > 0 && (--iter->timer.retx) == 0)
tcplib_retx_expire(iter);
if (iter->flags & TCP_ACKPENDING) {
// printf("sending delayed ACK\n");
tcplib_send_ack(iter, 0, TCP_FLAG_ACK);
}
}
return 0;
}
--- NEW FILE: tcplib.h ---
#ifndef TCPLIB_H_
#define TCPLIB_H_
// #include <netinet/in.h>
#include "ip.h"
#define min(X,Y) (((X) > (Y)) ? (Y) : (X))
#ifndef PC
#define printf(X, args ...) dbg("stdout", X, ## args)
#define fprintf(X, Y, args ...) dbg("fprintf", Y, ## args)
#endif
typedef enum {
TCP_CLOSED = 0,
TCP_LISTEN,
TCP_SYN_RCVD,
TCP_SYN_SENT,
TCP_ESTABLISHED,
TCP_CLOSE_WAIT,
TCP_LAST_ACK,
TCP_FIN_WAIT_1,
TCP_FIN_WAIT_2,
TCP_CLOSING,
TCP_TIME_WAIT,
} tcplib_sock_state_t;
enum {
TCP_ACKPENDING = 0x3,
TCP_DUPACKS = 0x3c,
TCP_DUPACKS_OFF = 2,
};
#define GET_ACK_COUNT(X) (((X) & TCP_DUPACKS) >> TCP_DUPACKS_OFF)
#define UNSET_ACK_COUNT(X) ((X) &= ~TCP_DUPACKS)
#define INCR_ACK_COUNT(X) ((X) += 1 << TCP_DUPACKS_OFF)
#define ACK_COUNT_IS_3(X) (((X) & TCP_DUPACKS) == TCP_DUPACKS)
struct tcplib_sock {
uint8_t flags;
/* local and remote endpoints */
struct sockaddr_in6 l_ep;
struct sockaddr_in6 r_ep;
/* current connection state */
tcplib_sock_state_t state;
/* a buffer allocated for data on this connection */
void *rx_buf;
uint16_t rx_buf_len;
void *tx_buf;
uint16_t tx_buf_len;
/* max segment size, or default if
we didn't bother to pull it out
of the options field */
uint16_t mss;
/* the window the other end is
reporting */
uint16_t r_wind;
uint16_t cwnd;
uint16_t ssthresh;
// the current next sequence number for ourgoing data.
// the ack number is stored in the receive buffer.
uint32_t seqno;
// uint32_t ackno;
struct {
int8_t retx;
} timer;
/* callbacks for this connection */
struct {
/* a previous connection request has finished */
void (*connect_done)(struct tcplib_sock *sock, int error);
/* a callback to signal new data is ready */
void (*recvfrom)(struct tcplib_sock *sock, void *data, int len);
/* the connection was closed by the other party */
void (*closed)(struct tcplib_sock *sock);
/* you called close(); we've finished closing the socket. */
void (*close_done)(struct tcplib_sock *sock);
} ops;
/* this needs to be at the end so
we can call init() on a socket
without blowing away the linked
list */
struct tcplib_sock *next;
};
/* EVENTS
* ------------------------------------------------------------
*
* calls generated by tcplib that must be dealt with elsewhere in the
* program.
*/
/* called when a new connection request is recieved on a socket which
* is LISTENing.
*
*
* return 0 if it wants to accept the connection and allocated a
* buffer for it; -1 otherwise.
*/
struct tcplib_sock *tcplib_accept(struct tcplib_sock *conn,
struct sockaddr_in6 *from);
/* a call-out point for tcplib to send a message */
void tcplib_send_out(struct split_ip_msg *msg, struct tcp_hdr *tcph);
/* upcall for new data; may be dispatched all the way out to a
* handler.
*
* Returns: 0 on success,
* -1 otherwise. The error may be safely ignored.
*/
int tcplib_process(struct ip6_hdr *ip_packet, void *payload);
/*
* should be called every 500ms to increment all the tcp timers
*/
int tcplib_timer_process();
/* Just fill in the fields of the socket.
*
* If you perform a send on a socket in this state, an ephemeral port
* will be allocated to it.
*
* This must be called once on any socket that might be sent on, or
* might have bind() called.
*/
int tcplib_init_sock(struct tcplib_sock *sock);
/* bind the socket to a local address */
int tcplib_bind(struct tcplib_sock *sock,
struct sockaddr_in6 *addr);
/* connect the socket to a remote endpoint */
int tcplib_connect(struct tcplib_sock *sock,
struct sockaddr_in6 *serv_addr);
/* send data on an open socket.
*
* returns: 0 on success
* other errors
* - no local buffer is available,
*
*/
int tcplib_send(struct tcplib_sock *sock,
void *data, int len);
int tcplib_close(struct tcplib_sock *sock);
#endif
--- NEW FILE: test_circ.c ---
#include <stdio.h>
#include "circ.h"
void do_head_read(void *buf) {
char *read_data;
int i, data_len;
data_len = circ_buf_read_head(buf, (void **)&read_data);
printf("buf_read_head: %i\n", data_len);
for (i = 0; i < data_len; i++)
putc(((char *)read_data)[i], stdout);
putc('\n', stdout);
}
void do_read(void *buf, uint32_t sseqno) {
char data[20];
int data_len, i;
data_len = circ_buf_read(buf, sseqno, data, 20);
printf("buf_read: %i\n", data_len);
for (i = 0; i < data_len; i++)
putc(((char *)data)[i], stdout);
putc('\n', stdout);
}
int main(int argc, char **argv) {
char buf[200];
char data[20], readbuf[30];
int i = 20, data_len;
char *read_data;
if (circ_buf_init(buf, 200, 0, 1) < 0)
printf("cir_buf_init: error\n");
for (i=0;i<20;i++)
data[i] = 'a' + i;
if (circ_buf_write(buf, 0, data, 20) < 0)
printf("circ_buf_write: error\n");
if (circ_buf_write(buf, 10, data, 20) < 0)
printf("circ_buf_write: error\n");
if (circ_buf_write(buf, 50, data, 20) < 0)
printf("circ_buf_write: error\n");
circ_buf_dump(buf);
do_head_read(buf);
circ_buf_dump(buf);
if (circ_buf_write(buf, 30, data, 20) < 0)
printf("circ_buf_write: error\n");
circ_buf_dump(buf);
if (circ_buf_write(buf, 70, data, 20) < 0)
printf("circ_buf_write: error\n");
circ_buf_dump(buf);
do_read(buf, 50);
/* do_head_read(buf); */
/* circ_buf_dump(buf); */
/* if (circ_buf_write(buf, 90, data, 20) < 0) */
/* printf("circ_buf_write: error\n"); */
/* if (circ_buf_write(buf, 110, data, 20) < 0) */
/* printf("circ_buf_write: error\n"); */
/* if (circ_buf_write(buf, 130, data, 20) < 0) */
/* printf("circ_buf_write: error\n"); */
/* circ_buf_dump(buf); */
/* do_head_read(buf); */
/* do_head_read(buf); */
/* circ_buf_dump(buf); */
}
--- NEW FILE: test_server.c ---
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <stdio.h>
#include <sys/select.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <linux/if.h>
#include <signal.h>
#include <string.h>
#include "ip.h"
#include "tcplib.h"
#include "tun_dev.h"
#include "ip_malloc.h"
#define BUFSZ 1024
#define LOSS_RATE_RECPR 100
int sock = 0;
uint8_t iface_addr[16] = {0x20, 0x01, 0x00, 0x00, 0xde, 0xad, 0xbe, 0xef,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01};
struct sockaddr_in6 laddr;
void printBuf(uint8_t *buf, uint16_t len) {
int i;
// print("len: %i: ", len);
for (i = 1; i <= len; i++) {
printf(" 0x%02x", buf[i-1]);
// if (i % 16 == 0) printf("\n");
}
printf("\n");
}
void print_split_msg(struct split_ip_msg *msg) {
int i;
printf("src_addr: ");
for (i = 0; i < 16; i++) printf("0x%x ", msg->hdr.src_addr[i]);
printf("\ndst_addr: ");
for (i = 0; i < 16; i++) printf("0x%x ", msg->hdr.dst_addr[i]);
printf("\nplen: %i hlim: %i\n", ntohs(msg->hdr.plen), msg->hdr.hlim);
printBuf(msg->data, msg->data_len);
}
void rx(struct tcplib_sock *sock, void *data, int len) {
// printBuf(data, len);
if (tcplib_send(sock, data, len) < 0)
printf("tcplib_send: fail\n");
}
void cl(struct tcplib_sock *sock) {
printf("remote conn closed\n");
tcplib_close(sock);
}
void cd(struct tcplib_sock *sock) {
printf("local close done\n");
free(sock->rx_buf);
free(sock->tx_buf);
tcplib_init_sock(sock);
/* printf("rebinding...\n"); */
}
/* called when a new connection request is received: not
*
* return: a tcplib_struc, with the ops table filled in and send and
* receive buffers allocated.
*/
struct tcplib_sock *tcplib_accept(struct tcplib_sock *conn,
struct sockaddr_in6 *from) {
printf("tcplib_accept\n");
conn->rx_buf = malloc(BUFSZ);
conn->rx_buf_len = BUFSZ;
conn->tx_buf = malloc(BUFSZ);
conn->tx_buf_len = BUFSZ;
conn->ops.recvfrom = rx;
conn->ops.closed = cl;
conn->ops.close_done = cd;
return conn;
}
void tcplib_send_out(struct split_ip_msg *msg, struct tcp_hdr *tcph) {
uint8_t buf[8192];
if (sock <= 0) return;
memcpy(msg->hdr.src_addr, iface_addr, 16);
msg->hdr.src_addr[15] = 2;
msg->hdr.hlim = 64;
memset(msg->hdr.vlfc, 0, 4);
msg->hdr.vlfc[0] = 6 << 4;
tcph->chksum = msg_cksum(msg, IANA_TCP);
// print_split_msg(msg);
if (rand() % LOSS_RATE_RECPR == 0) {
printf("dropping packet on write\n");
} else {
tun_write(sock, msg);
}
}
/* practice accepting connections and transfering data */
int main(int argg, char **argv) {
char buf[8192], dev[IFNAMSIZ];
uint8_t *payload;
int len, i, flags;
ip_malloc_init();
payload = buf + sizeof(struct tun_pi);
dev[0] = 0;
if ((sock = tun_open(dev)) < 0)
exit(1);
if (tun_setup(dev, iface_addr) < 0)
exit(1);
/* tun_setup turns on non-blocking IO. Turn it off. */
flags = fcntl(sock, F_GETFL);
flags &= ~O_NONBLOCK;
fcntl(sock,F_SETFL, flags);
struct tcplib_sock srv_sock;
tcplib_init_sock(&srv_sock);
memcpy(laddr.sin6_addr.s6_addr, iface_addr, 16);
laddr.sin6_addr.s6_addr[15] = 2;
laddr.sin6_port = htons(atoi(argv[1]));
tcplib_bind(&srv_sock, &laddr);
fd_set fds;
struct timeval timeout;
FD_ZERO(&fds);
FD_SET(sock, &fds);
timeout.tv_sec = 0;
timeout.tv_usec = 500000;
while (select(sock + 1, &fds, NULL, NULL, &timeout) >= 0) {
if (FD_ISSET(sock, &fds)) {
if ((len = read(sock, buf, 8192)) <= 0) break;
struct ip6_hdr *iph = (struct ip6_hdr *)payload;
if (iph->nxt_hdr == IANA_TCP) {
if (rand() % LOSS_RATE_RECPR == 0) {
printf("dropping packet on rx\n");
} else {
if (tcplib_process(payload, len - sizeof(struct tun_pi)))
printf("TCPLIB_PROCESS: ERROR!\n");
}
}
} else {
timeout.tv_sec = 0;
timeout.tv_usec = 500000;
tcplib_timer_process();
}
if (srv_sock.state == TCP_CLOSED) {
tcplib_bind(&srv_sock, &laddr);
}
FD_ZERO(&fds);
FD_SET(sock, &fds);
}
tun_close(sock, dev);
}
- Previous message: [Tinyos-2-commits] CVS: tinyos-2.x/support/sdk/c/blip/lib6lowpan Makefile, NONE, 1.1 in_cksum.c, NONE, 1.1 ip_malloc.c, NONE, 1.1 lib6lowpan.c, NONE, 1.1 lib6lowpanFrag.c, NONE, 1.1 lib6lowpanIP.c, NONE, 1.1 printpacket.c, NONE, 1.1
- Next message: [Tinyos-2-commits] CVS: tinyos-2.x/support/sdk/c/sf serialsource.c, 1.4, 1.5
- Messages sorted by:
[ date ]
[ thread ]
[ subject ]
[ author ]
More information about the Tinyos-2-commits
mailing list