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