1/**
2 * \file
3 * \brief Echo server
4 */
5
6/*
7 * Copyright (c) 2007-12 ETH Zurich.
8 * All rights reserved.
9 *
10 * This file is distributed under the terms in the attached LICENSE file.
11 * If you do not find this file, copies can be found by writing to:
12 * ETH Zurich D-INFK, Haldeneggsteig 4, CH-8092 Zurich. Attn: Systems Group.
13 */
14
15#include <barrelfish/barrelfish.h>
16#include <stdio.h>
17#include <assert.h>
18#include <lwip/netif.h>
19#include <lwip/dhcp.h>
20#include <netif/etharp.h>
21#include <lwip/init.h>
22#include <lwip/tcp.h>
23#include <netif/bfeth.h>
24#include <trace/trace.h>
25#include <trace_definitions/trace_defs.h>
26#include "echoserver.h"
27
28
29extern void idc_print_statistics(void);
30extern void idc_print_cardinfo(void);
31
32extern uint64_t minbase, maxbase;
33
34#if TRACE_ONLY_SUB_NNET
35static size_t n64b = 0;
36#endif
37
38static void echo_server_close(struct tcp_pcb *tpcb)
39{
40    tcp_arg(tpcb, NULL);
41    tcp_close(tpcb);
42}
43
44
45static void echo_server_err(void *arg, err_t err)
46{
47    printf("echo_server_err! %p %d\n", arg, err);
48}
49
50
51static err_t echo_server_recv(void *arg, struct tcp_pcb *tpcb, struct pbuf *p,
52                              err_t err)
53{
54    int r;
55    if (p == NULL) {
56        // close the connection
57        echo_server_close(tpcb);
58        return ERR_OK;
59    }
60
61#if TRACE_ONLY_SUB_NNET
62    trace_event(TRACE_SUBSYS_NNET, TRACE_EVENT_NNET_RXAPPRCV,
63                0);
64#endif // TRACE_ONLY_SUB_NNET
65
66    /* don't send an immediate ack here, do it later with the data */
67    tpcb->flags |= TF_ACK_DELAY;
68    assert(p->next == 0);
69
70    /*if ((p->tot_len > 2) && (p->tot_len < 200)) {
71        if (strncmp(p->payload, "stat", 4) == 0) {
72            idc_print_statistics();
73        }
74        if (strncmp(p->payload, "cardinfo", 8) == 0) {
75            idc_print_cardinfo();
76        }
77        if (strncmp(p->payload, "lwipinfo", 8) == 0) {
78            printf("echoserver's memory affinity: [0x%lx, 0x%lx]\n",
79                minbase, maxbase);
80        }
81    }*/
82
83#if TRACE_ONLY_SUB_NNET
84    if (p->tot_len == 64) {
85        n64b++;
86        if (n64b == 5) {
87            trace_control(TRACE_EVENT(TRACE_SUBSYS_NNET,
88                                      TRACE_EVENT_NNET_START, 0),
89                          TRACE_EVENT(TRACE_SUBSYS_NNET,
90                                      TRACE_EVENT_NNET_STOP, 0), 0);
91            trace_event(TRACE_SUBSYS_NNET, TRACE_EVENT_NNET_START, 0);
92        } else if (n64b == 8) {
93            trace_event(TRACE_SUBSYS_NNET, TRACE_EVENT_NNET_STOP, 0);
94            char* trbuf = malloc(4096*4096);
95            size_t length = trace_dump(trbuf, 4096*4096, NULL);
96            printf("%s\n", trbuf);
97            printf("length of buffer %zu\n", length);
98            free(trbuf);
99        }
100    }
101
102
103    trace_event(TRACE_SUBSYS_NNET, TRACE_EVENT_NNET_TXAPPSNT, 0);
104#endif
105
106
107    //XXX: can we do that without needing to copy it??
108    r = tcp_write(tpcb, p->payload, p->len, TCP_WRITE_FLAG_COPY);
109    assert(r == ERR_OK);
110
111#if TRACE_ONLY_SUB_NNET
112    trace_event(TRACE_SUBSYS_NNET, TRACE_EVENT_NNET_TX_TCP_WRITE, 0);
113#endif
114
115    // make sure data gets sent immediately
116    r = tcp_output(tpcb);
117    assert(r == ERR_OK);
118
119#if TRACE_ONLY_SUB_NNET
120    trace_event(TRACE_SUBSYS_NNET, TRACE_EVENT_NNET_TX_TCP_OUTPUT, 0);
121#endif
122
123    tcp_recved(tpcb, p->len);
124#if TRACE_ONLY_SUB_NNET
125    trace_event(TRACE_SUBSYS_NNET, TRACE_EVENT_NNET_TX_TCP_RECV, 0);
126#endif
127
128
129    //now we can advertise a bigger window
130    pbuf_free(p);
131#if TRACE_ONLY_SUB_NNET
132    trace_event(TRACE_SUBSYS_NNET, TRACE_EVENT_NNET_TX_TCP_FREE, 0);
133#endif
134
135
136    return ERR_OK;
137}
138
139static err_t echo_server_sent(void *arg, struct tcp_pcb *tpcb, u16_t length)
140{
141    return ERR_OK;
142}
143
144static err_t echo_server_accept(void *arg, struct tcp_pcb *tpcb, err_t err)
145{
146    assert(err == ERR_OK);
147    tcp_recv(tpcb, echo_server_recv);
148    tcp_sent(tpcb, echo_server_sent);
149    tcp_err(tpcb, echo_server_err);
150
151    tcp_arg(tpcb, 0);
152
153    return ERR_OK;
154}
155
156int tcp_echo_server_init(void)
157{
158    err_t r;
159
160    uint16_t bind_port = 7; //don't use htons() (don't know why...)
161
162
163    struct tcp_pcb *pcb = tcp_new();
164    if (pcb == NULL) {
165        return ERR_MEM;
166    }
167
168    r = tcp_bind(pcb, IP_ADDR_ANY, bind_port);
169    if(r != ERR_OK) {
170        return(r);
171    }
172
173    struct tcp_pcb *pcb2 = tcp_listen(pcb);
174    assert(pcb2 != NULL);
175    tcp_accept(pcb2, echo_server_accept);
176
177
178    printf("TCP echo_server_init(): bound.\n");
179    printf("TCP installed receive callback.\n");
180    return (0);
181}
182