]> rtime.felk.cvut.cz Git - pes-rpp/rpp-lwip.git/blob - test/unit/tcp/tcp_helper.c
bccc69dde0f2bee5811b3b1c9ebdc94cecc4444f
[pes-rpp/rpp-lwip.git] / test / unit / tcp / tcp_helper.c
1 #include "tcp_helper.h"
2
3 #include "lwip/tcp_impl.h"
4 #include "lwip/stats.h"
5 #include "lwip/pbuf.h"
6 #include "lwip/inet_chksum.h"
7
8 #if !LWIP_STATS || !TCP_STATS || !MEMP_STATS
9 #error "This tests needs TCP- and MEMP-statistics enabled"
10 #endif
11
12 /** Remove all pcbs on the given list. */
13 static void
14 tcp_remove(struct tcp_pcb* pcb_list)
15 {
16   struct tcp_pcb *pcb = pcb_list;
17   struct tcp_pcb *pcb2;
18
19   while(pcb != NULL) {
20     pcb2 = pcb;
21     pcb = pcb->next;
22     tcp_abort(pcb2);
23   }
24 }
25
26 /** Remove all pcbs on listen-, active- and time-wait-list (bound- isn't exported). */
27 void
28 tcp_remove_all(void)
29 {
30   tcp_remove(tcp_listen_pcbs.pcbs);
31   tcp_remove(tcp_active_pcbs);
32   tcp_remove(tcp_tw_pcbs);
33   fail_unless(lwip_stats.memp[MEMP_TCP_PCB].used == 0);
34   fail_unless(lwip_stats.memp[MEMP_TCP_PCB_LISTEN].used == 0);
35   fail_unless(lwip_stats.memp[MEMP_TCP_SEG].used == 0);
36   fail_unless(lwip_stats.memp[MEMP_PBUF_POOL].used == 0);
37 }
38
39 /** Create a TCP segment usable for passing to tcp_input
40  * - IP-addresses, ports, seqno and ackno are taken from pcb
41  * - seqno and ackno can be altered with an offset
42  */
43 struct pbuf*
44 tcp_create_rx_segment(struct tcp_pcb* pcb, void* data, size_t data_len, u32_t seqno_offset,
45                       u32_t ackno_offset, u8_t headerflags)
46 {
47   return tcp_create_segment(&pcb->remote_ip, &pcb->local_ip, pcb->remote_port, pcb->local_port,
48     data, data_len, pcb->rcv_nxt + seqno_offset, pcb->snd_nxt + ackno_offset, headerflags);
49 }
50
51 /** Create a TCP segment usable for passing to tcp_input */
52 struct pbuf*
53 tcp_create_segment(ip_addr_t* src_ip, ip_addr_t* dst_ip,
54                    u16_t src_port, u16_t dst_port, void* data, size_t data_len,
55                    u32_t seqno, u32_t ackno, u8_t headerflags)
56 {
57   struct pbuf* p;
58   struct ip_hdr* iphdr;
59   struct tcp_hdr* tcphdr;
60   u16_t pbuf_len = (u16_t)(sizeof(struct ip_hdr) + sizeof(struct tcp_hdr) + data_len);
61
62   p = pbuf_alloc(PBUF_RAW, pbuf_len, PBUF_POOL);
63   EXPECT_RETNULL(p != NULL);
64   EXPECT_RETNULL(p->next == NULL);
65
66   memset(p->payload, 0, p->len);
67
68   iphdr = p->payload;
69   /* fill IP header */
70   iphdr->dest.addr = dst_ip->addr;
71   iphdr->src.addr = src_ip->addr;
72   IPH_VHLTOS_SET(iphdr, 4, IP_HLEN / 4, 0);
73   IPH_LEN_SET(iphdr, htons(p->tot_len));
74   IPH_CHKSUM_SET(iphdr, inet_chksum(iphdr, IP_HLEN));
75
76   pbuf_header(p, -(s16_t)sizeof(struct ip_hdr));
77
78   tcphdr = p->payload;
79   tcphdr->src   = htons(src_port);
80   tcphdr->dest  = htons(dst_port);
81   tcphdr->seqno = htonl(seqno);
82   tcphdr->ackno = htonl(ackno);
83   TCPH_HDRLEN_SET(tcphdr, sizeof(struct tcp_hdr)/4);
84   TCPH_FLAGS_SET(tcphdr, headerflags);
85   tcphdr->wnd   = htons(TCP_WND);
86
87   /* copy data */
88   memcpy((char*)tcphdr + sizeof(struct tcp_hdr), data, data_len);
89
90   /* calculate checksum */
91   tcphdr->chksum = inet_chksum_pseudo(p, &(iphdr->src), &(iphdr->dest),
92           IP_PROTO_TCP, p->tot_len);
93
94   pbuf_header(p, sizeof(struct ip_hdr));
95
96   return p;
97 }
98
99 /** Safely bring a tcp_pcb into the requested state */
100 void
101 tcp_set_state(struct tcp_pcb* pcb, enum tcp_state state, ip_addr_t* local_ip,
102                    ip_addr_t* remote_ip, u16_t local_port, u16_t remote_port)
103 {
104   /* @todo: are these all states? */
105   /* @todo: remove from previous list */
106   pcb->state = state;
107   if (state == ESTABLISHED) {
108     TCP_REG(&tcp_active_pcbs, pcb);
109     pcb->local_ip.addr = local_ip->addr;
110     pcb->local_port = local_port;
111     pcb->remote_ip.addr = remote_ip->addr;
112     pcb->remote_port = remote_port;
113   } else if(state == LISTEN) {
114     TCP_REG(&tcp_listen_pcbs.pcbs, pcb);
115     pcb->local_ip.addr = local_ip->addr;
116     pcb->local_port = local_port;
117   } else if(state == TIME_WAIT) {
118     TCP_REG(&tcp_tw_pcbs, pcb);
119     pcb->local_ip.addr = local_ip->addr;
120     pcb->local_port = local_port;
121     pcb->remote_ip.addr = remote_ip->addr;
122     pcb->remote_port = remote_port;
123   } else {
124     fail();
125   }
126 }
127
128 void
129 test_tcp_counters_err(void* arg, err_t err)
130 {
131   struct test_tcp_counters* counters = arg;
132   EXPECT_RET(arg != NULL);
133   counters->err_calls++;
134   counters->last_err = err;
135 }
136
137 static void
138 test_tcp_counters_check_rxdata(struct test_tcp_counters* counters, struct pbuf* p)
139 {
140   struct pbuf* q;
141   u32_t i, received;
142   if(counters->expected_data == NULL) {
143     /* no data to compare */
144     return;
145   }
146   EXPECT_RET(counters->recved_bytes + p->tot_len <= counters->expected_data_len);
147   received = counters->recved_bytes;
148   for(q = p; q != NULL; q = q->next) {
149     char *data = q->payload;
150     for(i = 0; i < q->len; i++) {
151       EXPECT_RET(data[i] == counters->expected_data[received]);
152       received++;
153     }
154   }
155   EXPECT(received == counters->recved_bytes + p->tot_len);
156 }
157
158 err_t
159 test_tcp_counters_recv(void* arg, struct tcp_pcb* pcb, struct pbuf* p, err_t err)
160 {
161   struct test_tcp_counters* counters = arg;
162   EXPECT_RETX(arg != NULL, ERR_OK);
163   EXPECT_RETX(pcb != NULL, ERR_OK);
164   EXPECT_RETX(err == ERR_OK, ERR_OK);
165
166   if (p != NULL) {
167     if (counters->close_calls == 0) {
168       counters->recv_calls++;
169       test_tcp_counters_check_rxdata(counters, p);
170       counters->recved_bytes += p->tot_len;
171     } else {
172       counters->recv_calls_after_close++;
173       counters->recved_bytes_after_close += p->tot_len;
174     }
175     pbuf_free(p);
176   } else {
177     counters->close_calls++;
178   }
179   EXPECT(counters->recv_calls_after_close == 0 && counters->recved_bytes_after_close == 0);
180   return ERR_OK;
181 }
182
183 /** Allocate a pcb and set up the test_tcp_counters_* callbacks */
184 struct tcp_pcb*
185 test_tcp_new_counters_pcb(struct test_tcp_counters* counters)
186 {
187   struct tcp_pcb* pcb = tcp_new();
188   if (pcb != NULL) {
189     /* set up args and callbacks */
190     tcp_arg(pcb, counters);
191     tcp_recv(pcb, test_tcp_counters_recv);
192     tcp_err(pcb, test_tcp_counters_err);
193   }
194   return pcb;
195 }