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, Haldeneggsteig 4, 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/udp.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//called whenever a new datagram for that pcb arrived
22static void udp_recv_handler_bm(void *arg, struct udp_pcb *pcb,
23        struct pbuf *p, struct ip_addr *addr, u16_t port)
24{
25    // Send the data to benchmarking code for furthur analysis
26    handle_data_arrived(p->payload, p->len);
27
28    //send the echo
29    struct ip_addr destaddr = *addr;
30    udp_sendto(pcb, p, &destaddr, port);
31    pbuf_free(p);
32}
33
34int udp_server_bm_init(uint16_t bind_port)
35{
36    err_t r;
37
38    //create a new UDP PCB
39    struct udp_pcb *pcb = udp_new(); //UDP connection data
40    if (pcb == NULL) {
41        return ERR_MEM;
42    }
43
44    //bind it to every IP of every interface and define a specific port to
45    //bind to
46    r = udp_bind(pcb, IP_ADDR_ANY, bind_port);
47    if(r != ERR_OK) {
48        udp_remove(pcb);
49        return(r);
50    }
51
52    //install a callback for received datagrams
53    udp_recv(pcb, udp_recv_handler_bm, 0);
54    printf("installed receive callback for server.\n");
55    printf("udp_server_bm_init (): bound.\n");
56    return (0);
57} // end function: udp_server_bm_init
58
59// *********************************************************************
60
61// ***************************************************************
62// udp client code
63// ***************************************************************
64
65// A client pcb
66static struct udp_pcb *client_pcb = NULL;
67
68// single pbuf that will be used by client to send over and over again.
69static struct pbuf *udp_pbuf_cl = NULL;
70
71static void *payload_ptr = NULL;
72static size_t udp_msg_size = 0;
73
74//called whenever a new datagram for that pcb arrived
75static void udp_recv_handler_bm_client(void *arg, struct udp_pcb *pcb,
76        struct pbuf *p, struct ip_addr *addr, u16_t port)
77{
78    // Send the data to benchmarking code for furthur analysis
79    handle_data_arrived(p->payload, p->len);
80    pbuf_free(p);
81}
82
83// initialize udp connection for the client
84int udp_client_bm_init(char *ip_addr_str,  uint16_t server_port)
85{
86    err_t r;
87
88    // Preparing IP address for use
89    assert(ip_addr_str != NULL);
90    struct in_addr addr;
91    if (inet_aton(ip_addr_str, &addr) == 0) {
92        printf("Invalid IP addr: %s\n", ip_addr_str);
93        USER_PANIC("Invalid IP address %s", ip_addr_str);
94        return -1;
95    }
96    struct ip_addr server_addr;
97    server_addr.addr = addr.s_addr;
98
99    // Prepare udp_pcb
100    client_pcb = udp_new();
101    if (client_pcb == NULL) {
102        USER_PANIC("udp_new failed");
103        return -1;
104    }
105
106    // Connecting to given IP address, port no.
107    //don't use htons() on port no. (don't know why...)
108    r = udp_connect(client_pcb, &server_addr, server_port);
109    if(r != ERR_OK) {
110        USER_PANIC("udp_connect failed");
111        return(r);
112    }
113
114    udp_recv(client_pcb, udp_recv_handler_bm_client, 0);
115
116    // Connection established!
117    printf("udp benchmark client started\n");
118    handle_connection_opened();
119    return (0);
120} // end function: udp_client_bm_init
121
122
123void *prepare_udp_buffer(size_t payload_size)
124{
125
126//    udp_pbuf_cl = pbuf_alloc(PBUF_TRANSPORT, payload_size, PBUF_POOL);
127    udp_pbuf_cl = pbuf_alloc(PBUF_TRANSPORT, payload_size, PBUF_RAM);
128    if (udp_pbuf_cl == NULL){
129        USER_PANIC("pbuf_alloc failed in prepare_udb_buffer");
130        return NULL;
131    }
132    assert(udp_pbuf_cl != NULL);
133    assert(udp_pbuf_cl->payload != NULL);
134    assert(udp_pbuf_cl->len == payload_size);
135    payload_ptr = udp_pbuf_cl->payload;
136    udp_msg_size = payload_size;
137    return udp_pbuf_cl->payload;
138}
139
140// send single message over udp connection
141int send_udp_message_client(void)
142{
143    err_t err;
144
145    // resetting the values as they will be changed by
146    // pbuf_header function
147    udp_pbuf_cl->len = udp_msg_size;
148    udp_pbuf_cl->tot_len = udp_msg_size;
149    udp_pbuf_cl->payload = payload_ptr;
150
151    err = udp_send(client_pcb, udp_pbuf_cl);
152    if (err_is_fail(err)) {
153        USER_PANIC_ERR(err, "udp_send failed");
154        return -1;
155    }
156    return 0;
157} // end function: send_message_client
158