1/*
2 * Copyright (c) 2007-12 ETH Zurich.
3 * All rights reserved.
4 *
5 * This file is distributed under the terms in the attached LICENSE file.
6 * If you do not find this file, copies can be found by writing to:
7 * ETH Zurich D-INFK, Universitaetstrasse 6, CH-8092 Zurich. Attn: Systems Group.
8 */
9
10#include <barrelfish/barrelfish.h>
11#include <stdio.h>
12#include <assert.h>
13#include <lwip/netif.h>
14#include <lwip/tcp.h>
15#include <lwip/ip_addr.h>
16#include <netif/bfeth.h>
17#include <trace/trace.h>
18#include <arpa/inet.h>
19#include "tcp_server_bm.h"
20
21
22static void tcp_server_bm_close(struct tcp_pcb *tpcb)
23{
24    tcp_arg(tpcb, NULL);
25    tcp_close(tpcb);
26}
27
28
29static void tcp_server_bm_err(void *arg, err_t err)
30{
31    printf("tcp_server_bm_err! %p %d\n", arg, err);
32}
33
34
35static err_t tcp_server_bm_recv(void *arg, struct tcp_pcb *tpcb, struct pbuf *p,
36                              err_t err)
37{
38    int r;
39    if (p == NULL) {
40        // close the connection
41        tcp_server_bm_close(tpcb);
42        printf("Error in tcp_server_bm_recv");
43        return ERR_OK;
44    }
45
46    /* don't send an immediate ack here, do it later with the data */
47    // FIXME: send ack immediately!
48    tpcb->flags |= TF_ACK_DELAY;
49    assert(p->next == 0);
50
51    // Send the data to benchmarking code for furthur analysis
52    handle_data_arrived(p->payload, p->len);
53
54    //XXX: can we do that without needing to copy it??
55    r = tcp_write(tpcb, p->payload, p->len, TCP_WRITE_FLAG_COPY);
56    assert(r == ERR_OK);
57
58    // make sure data gets sent immediately
59    r = tcp_output(tpcb);
60    assert(r == ERR_OK);
61
62    tcp_recved(tpcb, p->len);
63
64    //now we can advertise a bigger window
65    pbuf_free(p);
66
67    return ERR_OK;
68}
69
70static err_t tcp_server_bm_sent(void *arg, struct tcp_pcb *tpcb, u16_t length)
71{
72    return ERR_OK;
73}
74
75static err_t tcp_server_bm_accept(void *arg, struct tcp_pcb *tpcb, err_t err)
76{
77    assert(err == ERR_OK);
78    tcp_recv(tpcb, tcp_server_bm_recv);
79    tcp_sent(tpcb, tcp_server_bm_sent);
80    tcp_err(tpcb, tcp_server_bm_err);
81
82    tcp_arg(tpcb, 0);
83
84    return ERR_OK;
85}
86
87int tcp_server_bm_init(uint16_t bind_port)
88{
89    err_t r;
90
91    //don't use htons() (don't know why...)
92
93    struct tcp_pcb *pcb = tcp_new();
94    if (pcb == NULL) {
95        return ERR_MEM;
96    }
97
98    r = tcp_bind(pcb, IP_ADDR_ANY, bind_port);
99    if(r != ERR_OK) {
100        return(r);
101    }
102
103    struct tcp_pcb *pcb2 = tcp_listen(pcb);
104    assert(pcb2 != NULL);
105    tcp_accept(pcb2, tcp_server_bm_accept);
106
107    printf("TCP tcp_server_bm_init(): bound.\n");
108    printf("TCP installed receive callback.\n");
109    printf("TCP benchmark server started\n");
110    return (0);
111}
112
113// ***************************************************************
114// tcp client code
115// ***************************************************************
116
117
118static void close_connection(struct tcp_pcb *pcb)
119{
120    printf("closing(pcb: %p)\n", pcb);
121    tcp_close(pcb);
122    tcp_arg(pcb, NULL);
123    tcp_sent(pcb, NULL);
124    tcp_recv(pcb, NULL);
125    printf("connection closed:\n");
126}
127
128
129static err_t tcp_is_sent_client(void *arg, struct tcp_pcb *pcb, u16_t len)
130{
131//  assert(pcb != NULL);
132//  printf("sent %u bytes.\n", len);
133    return ERR_OK;
134}
135
136static void tcp_is_err_client(void *arg, err_t err)
137{
138    printf("tcp is err: %d\n", (int)err);
139}
140
141static err_t tcp_is_poll_client(void *arg, struct tcp_pcb *pcb)
142{
143    printf("tcp is poll\n");
144    return ERR_OK;
145}
146
147
148static err_t tcp_is_recv_client(void *arg, struct tcp_pcb *pcb,
149        struct pbuf *pb, err_t err)
150{
151    assert(err == ERR_OK);
152    assert(pcb != NULL);
153
154    if (pb == NULL) {
155        printf("finished receiving data\n");
156        close_connection(pcb);
157    }
158
159    // pointer to the payload
160    char *payload = (char *)pb->payload;
161    handle_data_arrived(payload, pb->tot_len);
162
163    // Inform TCP that we have taken the data.
164    tcp_recved(pcb, pb->tot_len);
165
166    // Free the packet buffer
167    pbuf_free(pb);
168
169    return ERR_OK;
170} // end function: tcp_is_recv_client
171
172
173static err_t tcp_is_connected_client(void *arg, struct tcp_pcb *pcb, err_t err)
174{
175
176    if (err != ERR_OK) {
177        fprintf(stderr, "tcp connection failed\n");
178        close_connection(pcb);
179        return err;
180    }
181
182    tcp_sent(pcb, tcp_is_sent_client);
183    tcp_recv(pcb, tcp_is_recv_client);
184    tcp_err( pcb, tcp_is_err_client);
185    tcp_poll(pcb, tcp_is_poll_client, 10);
186
187    printf("tcp client connected\n");
188    handle_connection_opened();
189
190    return ERR_OK;
191}
192
193static struct tcp_pcb *client_pcb = NULL;
194
195// initialize tcp connection for the client
196int tcp_client_bm_init(char *ip_addr_str,  uint16_t server_port)
197{
198    err_t r;
199
200    // Preparing IP address for use
201    assert(ip_addr_str != NULL);
202    struct in_addr addr;
203    if (inet_aton(ip_addr_str, &addr) == 0) {
204        printf("Invalid IP addr: %s\n", ip_addr_str);
205        USER_PANIC("Invalid IP address %s", ip_addr_str);
206        return -1;
207    }
208    struct ip_addr ip;
209    ip.addr = addr.s_addr;
210
211    // Prepare tcp_pcb
212    client_pcb = tcp_new();
213    if (client_pcb == NULL) {
214        USER_PANIC("tcp_new failed");
215        return -1;
216    }
217
218    //don't use htons() on port no. (don't know why...)
219    r = tcp_connect(client_pcb, &ip, server_port, tcp_is_connected_client);
220    if(r != ERR_OK) {
221        USER_PANIC("tcp_connect failed");
222        return(r);
223    }
224
225    // Connection established!
226    printf("TCP benchmark client started\n");
227    return (0);
228} // end function: tcp_client_bm_init
229
230
231// send single message over TCP connection
232int send_message_client(void *msg, size_t len)
233{
234    err_t err;
235
236//    printf("send_message(pcb: %p, msg: %p, len: %d)\n",
237//           pcb, msg, (int)len);
238
239    if (len > 0) {
240        assert(tcp_sndbuf(client_pcb) >= len);
241
242        err = tcp_write(client_pcb, msg, len, TCP_WRITE_FLAG_COPY);
243        if (err != ERR_OK) {
244            USER_PANIC_ERR(err, "tcp_write failed in send_message");
245            return -1;
246        }
247    }
248
249    // FIXME: Do I need this?
250    err = tcp_output(client_pcb);
251    if (err != ERR_OK) {
252        USER_PANIC_ERR(err, "tcp_write failed in send_message");
253        return -1;
254    }
255
256    // printf("done send_message()\n");
257
258    return 0;
259} // end function: send_message_client
260