/* $Id: ftp.c,v 10.1 92/10/06 23:06:45 ca Exp $ */ /* * MaRS Maryland Routing Simulator * Copyright (c) 1991 University of Maryland * All Rights Reserved. * * Permission to use, copy, modify, distribute, and sell this software and its * documentation for any purpose is hereby granted without fee, provided that * the above copyright notice appear in all copies and that both that * copyright notice and this permission notice appear in supporting * documentation, and that the name of U.M. not be used in advertising or * publicity pertaining to distribution of the software without specific, * written prior permission. U.M. makes no representations about the * suitability of this software for any purpose. It is provided "as is" * without express or implied warranty. * * U.M. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL U.M. * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * * Authors: Cengiz Alaettinoglu, Klaudia Dussa-Zieger, Ibrahim Matta * Systems Design and Analysis Group * Department of Computer Science * University of Maryland at College Park. */ /* * Application/Transport module with FTP traffic pattern * */ #include #include #include #include "sim.h" #include "q.h" #include "list.h" #include "component.h" #include "log.h" #include "comptypes.h" #include "packet.h" #include "eventdefs.h" #include "event.h" #include "ftp.h" #include "perf.h" #ifdef DEBUG extern Log debug_log; #endif static caddr_t instant_rate(); /* function to compute the instantaneous thruput */ static caddr_t ftp_source_create(), ftp_sink_create(), ftp_neighbor(), ftp_uneighbor(), ftp_source_start(), ftp_sink_start(), ftp_reset(), ftp_produce(), ftp_consume(), ftp_retransmit(), ftp_send(), ftp_receive(), ftp_mk_peer(), ftp_conn_on(), ftp_conn_down(); #define ticks_btw_conns(g) (random_no(0, \ (double)g->ftp_tr_delay->u.i, \ (double) 0.0,\ (unsigned) 1, \ (unsigned) 10000000) \ * 1000 / USECS_PER_TICK) #define car_length(g) (pval(g, ftp_car_length)->u.i) #define ticks_btw_packets(g) (pval(g, ftp_car_delay)->u.i / USECS_PER_TICK) static int train_length(g) register Ftpt *g; { int length; if (g->ftp_car_per_tr->u.i == -1) length = -1; else /* Geometrically distributed */ length = random_no(2, (double) pval(g, ftp_car_per_tr)->u.i, (double) 0.0, (unsigned) 1, (unsigned) pval(g, ftp_car_per_tr)->u.i * 3); return length; } caddr_t ftp_source_action(src, g, type, pkt, arg) Component *src; register Ftpt *g; int type; Packet *pkt; caddr_t arg; { caddr_t result = NULL; dbg_set_level(DBG_ERR); /* Just a big switch on type of event */ switch (type) { case EV_RESET: #ifdef DEBUG dbg_write(debug_log, DBG_INFO, (Component *)g, "reset"); #endif result = ftp_reset(g); break; case EV_CREATE: /* Minor sanity check first-- g should be NULL when initializing. */ #ifdef DEBUG if (g) dbg_write(debug_log, DBG_INFO, (Component *)NULL, "FTP Generator initialization called with non-null pointer."); #endif result = ftp_source_create((char *)arg); break; case EV_DEL: free(g->ftp_peer->u.p); comp_delete((Component *)g); result = (caddr_t)g; break; case EV_NEIGHBOR: result = ftp_neighbor(g, (Component *)arg); break; case EV_UNEIGHBOR: result = ftp_uneighbor(g, (Component *)arg); break; case EV_MK_PEER: result = ftp_mk_peer(g, (Component *)arg, FTP_SINK); break; case EV_START: result = ftp_source_start(g); break; case EV_STOP: result = (caddr_t) g; break; /********** The preceding were the commands. Following are the actual events that the application/transport module expects to receive. */ case EV_APTR_CONN_ON: result = ftp_conn_on((Ftpt *)src, g, (int)arg); break; case EV_APTR_PRODUCE: result = ftp_produce(g); break; case EV_APTR_CONSUME: result = ftp_consume(g, pkt); break; case EV_APTR_SEND: result = ftp_send(g); break; case EV_APTR_RECEIVE: result = ftp_receive(g, src, pkt); break; case EV_APTR_RETRANSMIT: result = ftp_retransmit(g, pkt); break; case EV_INSTANT_RATE: result = instant_rate(g); break; default: #ifdef DEBUG dbg_write(debug_log, DBG_ERR, (Component *)g, "got unexpected event of type %x", type); #endif break; } return(result); } /****************************************/ static caddr_t ftp_source_create(name) register char *name; { Ftpt *newg; /* Memory for the component structure. */ newg = (Ftpt *)sim_malloc(sizeof(Ftpt)); /* First things first-- copy name into the new structure. */ strncpy(newg->ftp_name, name, 40); /* have to create a neighbor list */ newg->ftp_neighbors = l_create(); newg->ftp_params = q_create(); newg->ftp_class = APTR_CLASS; newg->ftp_type = FTP_SOURCE; newg->ftp_action = ftp_source_action; newg->ftp_menu_up = FALSE; newg->source_socket.so_port = (Component *) newg; newg->source_socket.so_host = (Component *) NULL; newg->dest_socket.so_port = (Component *) NULL; newg->dest_socket.so_host = (Component *) NULL; /* Initialize the parameters */ (void)param_init((Component *)newg, "Name", (PFD)NULL, make_name_text, make_short_name_text, param_input_name, 0, DisplayMask | InputMask, 0.0); newg->ftp_peer = param_init((Component *)newg, "Peer", (PFD)NULL, make_str_text, make_short_str_text, (PFI)NULL, 0, DisplayMask, 0.0); pval(newg, ftp_peer)->u.p = sim_malloc(40); strcpy(newg->ftp_peer->u.p, "unknown"); newg->ftp_select = param_init((Component *)newg, "Not select(0), select(1) ", (PFD)NULL, make_int_text, make_short_int_text, param_input_int, 0, DisplayMask | ModifyMask, 0.0); newg->ftp_select->u.i = 0; newg->init_conn_on_off = param_init((Component *)newg, "Initial Connection status", (PFI)NULL, make_str_text, make_short_str_text, param_input_str, TIME_HISTORY, DisplayMask | ModifyMask, 0.0); newg->init_conn_on_off->u.p = (caddr_t) sim_malloc(40); strcpy(newg->init_conn_on_off->u.p, "Off"); newg->conn_on_off = param_init((Component *)newg, "Connection status", (PFI)NULL, make_str_text, make_short_str_text, param_input_str, TIME_HISTORY, DisplayMask | CanHaveLogMask, 0.0); pval(newg, conn_on_off)->u.p = "Off"; newg->ftp_tr_how_many = param_init((Component *)newg, "How many connections (-1 inf)", (PFD)NULL, make_int_text, make_short_int_text, param_input_int, 0, DisplayMask | ModifyMask, 0.0); newg->ftp_tr_how_many->u.i = -1; newg->ftp_car_per_tr = param_init((Component *)newg, "Ave packets per conn. (-1 inf)", (PFD)NULL, make_int_text, make_short_int_text, param_input_int, 0, DisplayMask | ModifyMask, 0.0); newg->ftp_car_per_tr->u.i = -1; newg->ftp_car_length = param_init((Component *)newg, "Ave Packet length (byte)", (PFD)NULL, make_int_text, make_short_int_text, param_input_int, 0, DisplayMask | ModifyMask, 0.0); newg->ftp_car_length->u.i = 512; newg->ftp_tr_delay = param_init((Component *)newg, "Ave delay btw conns (mSec)", (PFD)NULL, make_int_text, make_short_int_text, param_input_int, 0, DisplayMask | ModifyMask, 0.0); newg->ftp_tr_delay->u.i = 60000; newg->ftp_car_delay = param_init((Component *)newg, "Delay btw packets (uSec)", (PFD)NULL, make_int_text, make_short_int_text, param_input_int, 0, DisplayMask | ModifyMask, 0.0); newg->ftp_car_delay->u.i = 100000; newg->ftp_current_train = param_init((Component *)newg, "Current connection", int_calc, make_int_text, make_short_int_text, (PFI)NULL, TIME_HISTORY, DisplayMask | CanHaveMeterMask | CanHaveLogMask, 0.0); pval(newg, ftp_current_train)->u.i = 0; newg->ftp_car_how_many = param_init((Component *)newg, "No of packets in this conn.", (PFD)NULL, make_int_text, make_short_int_text, param_input_int, TIME_HISTORY, DisplayMask | CanHaveMeterMask | CanHaveLogMask, 0.0); pval(newg, ftp_car_how_many)->u.i = 0; newg->ftp_current_car = param_init((Component *)newg, "Current packet in this conn.", int_calc, make_int_text, make_short_int_text, (PFI)NULL, TIME_HISTORY, DisplayMask | CanHaveMeterMask | CanHaveLogMask, 0.0); pval(newg, ftp_current_car)->u.i = 0; newg->ftp_produce_ws = param_init((Component *)newg, "Max Produce w size (-1 inf)", (PFD)NULL, make_int_text, make_short_int_text, param_input_int, 0, DisplayMask | ModifyMask, 0.0); pval(newg, ftp_produce_ws)->u.i = 2; newg->ftp_send_ws = param_init((Component *)newg, "Max Send w size (-1 inf)", (PFD)NULL, make_int_text, make_short_int_text, param_input_int, 0, DisplayMask | ModifyMask, 0.0); pval(newg, ftp_send_ws)->u.i = 20; newg->ftp_packets_produced = param_init((Component *)newg, "Packets Produced", int_calc, make_int_text, make_short_int_text, (PFI)NULL, TIME_HISTORY, DisplayMask | CanHaveMeterMask | CanHaveLogMask, 0.0); pval(newg, ftp_packets_produced)->u.i = 0; newg->ftp_packets_sent = param_init((Component *)newg, "Packets Sent", int_calc, make_int_text, make_short_int_text, (PFI)NULL, TIME_HISTORY, DisplayMask | CanHaveMeterMask | CanHaveLogMask, 0.0); pval(newg, ftp_packets_sent)->u.i = 0; newg->ftp_packets_acked = param_init((Component *)newg, "Packets Acked", int_calc, make_int_text, make_short_int_text, (PFI)NULL, TIME_HISTORY, DisplayMask | CanHaveMeterMask | CanHaveLogMask, 0.0); pval(newg, ftp_packets_acked)->u.i = 0; newg->ftp_packets_recvd = param_init((Component *)newg, "Packets Received", int_calc, make_int_text, make_short_int_text, (PFI)NULL, TIME_HISTORY, DisplayMask | CanHaveMeterMask | CanHaveLogMask, 0.0); pval(newg, ftp_packets_recvd)->u.i = 0; newg->ftp_packets_retransmitted = param_init((Component *)newg, "Packets Retransmitted", int_calc, make_int_text, make_short_int_text, (PFI)NULL, TIME_HISTORY, DisplayMask | CanHaveMeterMask | CanHaveLogMask, 0.0); pval(newg, ftp_packets_retransmitted)->u.i = 0; newg->ftp_token_time = 0; newg->ftp_rtt = param_init((Component *)newg, "Round trip time est (usec)", int_calc, make_int_text, make_short_int_text, (PFI)NULL, TIME_HISTORY, DisplayMask | CanHaveMeterMask | CanHaveLogMask, 0.0); pval(newg, ftp_rtt)->u.i = 10000; /* The following parameters are used to compute the instantaneous sent and acked thruputs */ newg->sent_thruput = param_init((Component *)newg, "Inst. sent rate", double_calc, make_double_text, make_short_double_text, (PFI)NULL, TIME_HISTORY, DisplayMask | CanHaveMeterMask | CanHaveLogMask, 0.0); pval(newg, sent_thruput)->u.d = 0; newg->acked_thruput = param_init((Component *)newg, "Inst. acked rate", double_calc, make_double_text, make_short_double_text, (PFI)NULL, TIME_HISTORY, DisplayMask | CanHaveMeterMask | CanHaveLogMask, 0.0); pval(newg, acked_thruput)->u.d = 0; newg->retransmission_rate = param_init((Component *)newg, "Inst. retransmission rate", double_calc, make_double_text, make_short_double_text, (PFI)NULL, TIME_HISTORY, DisplayMask | CanHaveMeterMask | CanHaveLogMask, 0.0); pval(newg, retransmission_rate)->u.d = 0; /* Compute instantaneous delay */ newg->inst_delay = param_init((Component *)newg, "Inst delay in msecs", double_calc, make_double_text, make_short_double_text, (PFI)NULL, TIME_HISTORY, DisplayMask | CanHaveMeterMask | CanHaveLogMask, 0.0); pval(newg, inst_delay)->u.d = 0.0; newg->last_pkt_delay = 0; newg->data_acked = 0; newg->last_bytes_acked = 0; newg->ftp_bytes_sent = 0; newg->ftp_bytes_retransmitted = 0; #ifdef DEBUG dbg_write(debug_log, DBG_INFO, (Component *)newg, "ftp generator initialized"); #endif return((caddr_t)newg); } static caddr_t ftp_reset(g) Ftpt *g; { pval(g, ftp_packets_produced)->u.i = 0; pval(g, ftp_packets_sent)->u.i = 0; pval(g, ftp_packets_acked)->u.i = 0; pval(g, ftp_packets_recvd)->u.i = 0; pval(g, ftp_packets_retransmitted)->u.i= 0; pval(g, ftp_rtt)->u.i = 10000; pval(g, ftp_current_train)->u.i = 0; pval(g, ftp_current_car)->u.i = 0; pval(g, ftp_car_how_many)->u.i = 0; g->ftp_token_time = 0; g->last_pkt_delay = 0; g->data_acked = 0; g->last_bytes_acked = 0; g->conn_on_off->u.p = "Off"; g->sent_thruput->u.d = 0; g->last_bytes_acked = 0; g->acked_thruput->u.d = 0; g->inst_delay->u.d = 0; g->total_delay = 0; g->recent_pkts_acked = 0; g->retransmission_rate->u.d = 0; g->no_of_current_conns = 0; g->no_of_total_cars = 0; log_param((Component *)g, g->conn_on_off); log_param((Component *)g, g->sent_thruput); log_param((Component *)g, g->acked_thruput); log_param((Component *)g, g->inst_delay); log_param((Component *)g, g->retransmission_rate); log_param((Component *)g, g->ftp_packets_produced); log_param((Component *)g, g->ftp_packets_sent); log_param((Component *)g, g->ftp_packets_acked); log_param((Component *)g, g->ftp_packets_recvd); log_param((Component *)g, g->ftp_packets_retransmitted); log_param((Component *)g, g->ftp_rtt); log_param((Component *)g, g->ftp_current_train); log_param((Component *)g, g->ftp_current_car); log_param((Component *)g, g->ftp_car_how_many); g->total_prev_bytes_acked = 0; g->ftp_bytes_sent = 0; g->ftp_bytes_retransmitted = 0; g->produce_scheduled = 0; return((caddr_t)g); } /****************************************/ static caddr_t ftp_neighbor(g, c) register Ftpt *g; register Component *c; { caddr_t result; /* Put the passed neighbor into my neighbor list, but only if it is a legal neighbor (a node). Also can only have one neighbor. */ result = (caddr_t)add_neighbor((Component *)g, c, 1, 1, NODE_CLASS); if (result != (caddr_t)NULL) g->source_socket.so_host = c; return result; } static caddr_t ftp_mk_peer(g, c, peer_type) register Ftpt *g; register Component *c; int peer_type; { caddr_t result; /* Put the passed neighbor into my neighbor list, but only if it is a legal neighbor (a node). Also can only have one neighbor. */ result = (caddr_t) NULL; if (c->co_type == peer_type) if (((Ftpt *)c)->source_socket.so_host != (Component *) NULL) { g->dest_socket.so_host = ((Ftpt *)c)->source_socket.so_host; g->dest_socket.so_port = ((Ftpt *)c)->source_socket.so_port; strcpy(g->ftp_peer->u.p, ((Component *)((Ftpt *)c)->source_socket.so_host)->co_name); strcat(g->ftp_peer->u.p, "."); strcat(g->ftp_peer->u.p, c->co_name); log_param((Component *)g, g->ftp_peer); result = (caddr_t) g; } #ifdef DEBUG else dbg_write(debug_log, DBG_ERR, (Component *)g, "Source socket in destination not yet initialized"); else dbg_write(debug_log, DBG_ERR, (Component *)g, "Incompatible peer"); #endif return result; } /****************************************/ static caddr_t ftp_uneighbor(g, c) register Ftpt *g; register Component *c; { return((caddr_t)remove_neighbor((Component *)g, c)); } /*******************************************************/ static caddr_t instant_rate(g) /* Compute instantaneous thruputs of this source (in bytes per msec) */ register Ftpt *g; { g->sent_thruput->u.d = ((double)g->ftp_bytes_sent) * 1000.0 / (double)perf_update_dt_usecs; log_param((Component *)g, g->sent_thruput); g->ftp_bytes_sent = 0; g->acked_thruput->u.d = ((double)g->data_acked - (double)g->total_prev_bytes_acked) * 1000.0 / (double)perf_update_dt_usecs; log_param((Component *)g, g->acked_thruput); g->total_prev_bytes_acked = g->data_acked; g->retransmission_rate->u.d = ((double)g->ftp_bytes_retransmitted) * 1000.0 / (double)perf_update_dt_usecs; /* rate is number of bytes retransmitted per msecond */ log_param((Component *)g, g->retransmission_rate); g->ftp_bytes_retransmitted = 0; /* Update instantaneous delay for this connection */ g->inst_delay->u.d = (g->recent_pkts_acked) ? ((double)g->total_delay * (double)USECS_PER_TICK) / ((double)(1000.0) * (double)g->recent_pkts_acked) : 0.0; log_param((Component *)g, g->inst_delay); g->total_delay = 0; g->recent_pkts_acked = 0; /* Schedule next computation */ ev_enqueue(EV_INSTANT_RATE, (Component *)g, (Component *)g, ev_now() + perf_update_dt_usecs / USECS_PER_TICK, g->ftp_action, (Packet *)NULL, (caddr_t)NULL); return ((caddr_t)g); } static caddr_t ftp_source_start(g) register Ftpt *g; { Packet *pkt; Component *c; tick_t time; if (g->ftp_neighbors->l_len != 1) { #ifdef DEBUG dbg_write(debug_log, DBG_ERR, (Component *)g, "can't generate packets-- no neighbors."); #endif return((caddr_t)NULL); } if (g->dest_socket.so_host == (Component *)NULL) { #ifdef DEBUG dbg_write(debug_log, DBG_ERR, (Component *)g, "can't generate packets-- no peer."); #endif return((caddr_t)NULL); } /* Schedule first computation of instantaneous thruput */ ev_enqueue(EV_INSTANT_RATE, (Component *)g, (Component *)g, ev_now() + perf_update_dt_usecs/USECS_PER_TICK, g->ftp_action, (Packet *)NULL, (caddr_t)NULL); /* produce first packet */ if (strcmp(g->init_conn_on_off->u.p, "On") == 0) time = ev_now(); else time = ticks_btw_conns(g); ev_enqueue(EV_APTR_CONN_ON, (Component *)g, (Component *)g, time, g->ftp_action, (Packet *)NULL, (caddr_t)train_length(g)); /* send a token packet */ pkt = pk_alloc(); pkt->pk_length = TOKEN_PKT_SIZE; pkt->pk_type = TR_PACKET; pkt->tr_pk.tr_type = TR_TOKEN; pkt->tr_pk.response = 0; pkt->pk_source_socket.so_host = g->source_socket.so_host; pkt->pk_source_socket.so_port = g->source_socket.so_port; pkt->pk_dest_socket.so_host = g->dest_socket.so_host; pkt->pk_dest_socket.so_port = g->dest_socket.so_port; c = (Component *)(((Neighbor *)g->ftp_neighbors->l_head)->n_c); ev_enqueue(EV_NODE_PRODUCE, (Component *)g, c, ev_now(), c->co_action, pkt, (caddr_t)NULL); pm((Component *)g, FTP_SOURCE, NEW_COMPONENT); /* Something non-NULL to return */ return((caddr_t)g); } static caddr_t ftp_conn_on(source, g, no_of_pkts) /* Start a connection i.e. train, * the no of pkts are passed as a parameter instead of calculating it here, * useful with -play command line option */ register Ftpt *g, *source; int no_of_pkts; { /* if -play in effect, and this event is read from a file then the source is NULL, o/w just return */ if (play_flag && source) return (caddr_t) g; g->conn_on_off->u.p = "On"; log_param((Component *)g, g->conn_on_off); pm((Component *)g, FTP_SOURCE, CONN_UP, 0, 0, 0, g->ftp_select->u.i); g->ftp_car_how_many->u.i = no_of_pkts; if (g->no_of_current_conns) { /* did the previous conn ended ? */ #ifdef DEBUG if (g->no_of_current_conns > 1) printf("%s : %d conns overlapped %d total cars\n", g->ftp_name, g->no_of_current_conns, g->no_of_total_cars); #endif g->no_of_current_conns++; g->no_of_total_cars += g->ftp_car_how_many->u.i; } else { g->no_of_current_conns = 1; g->no_of_total_cars = g->ftp_car_how_many->u.i; g->conn_start_time = ev_now(); } g->ftp_current_train->u.i++; log_param((Component *) g, g->ftp_car_how_many); log_param((Component *) g, g->ftp_current_car); log_param((Component *) g, g->ftp_current_train); if (!g->produce_scheduled) { /* start producing, o/w we are already producing */ g->produce_scheduled = 1; ev_call(EV_APTR_PRODUCE, (Component *)g, (Component *)g, g->ftp_action, (caddr_t *)NULL, (caddr_t)NULL); } return (caddr_t) g; } static caddr_t ftp_conn_down(g) /* End the connection i.e. train */ register Ftpt *g; { g->conn_on_off->u.p = "Off"; log_param((Component *)g, g->conn_on_off); pm((Component *)g, FTP_SOURCE, CONN_DOWN, (int)(TICKS_TO_USECS(ev_now() - g->conn_start_time) / 1000), g->no_of_total_cars, g->no_of_current_conns, g->ftp_select->u.i); g->no_of_total_cars = 0; g->no_of_current_conns = 0; g->ftp_current_car->u.i= 0; log_param((Component *)g, g->ftp_current_car); } static caddr_t ftp_produce(g) /* Produce a packet */ register Ftpt *g; { /* is there a place in the produce window */ if (g->ftp_packets_produced->u.i - g->ftp_packets_sent->u.i < g->ftp_produce_ws->u.i || g->ftp_produce_ws->u.i == -1) { g->ftp_packets_produced->u.i ++; g->ftp_current_car->u.i++; log_param((Component *)g, g->ftp_packets_produced); log_param((Component *)g, g->ftp_current_car); ev_call(EV_APTR_SEND, (Component *)g, (Component *)g, g->ftp_action, (caddr_t *)NULL, (caddr_t)NULL); #ifdef DEBUG dbg_write(debug_log, DBG_INFO, (Component *)g, "Produced a packet"); #endif } if (g->ftp_current_car->u.i != g->no_of_total_cars) /* schedule an event for the next pkt */ ev_enqueue(EV_APTR_PRODUCE, (Component *)g, (Component *)g, ev_now() + ticks_btw_packets(g), (PFP)g->ftp_action, (Packet *)NULL, (caddr_t)NULL); else { g->produce_scheduled = 0; /* schedule an event for the next connection i.e. train */ if (g->ftp_current_train->u.i < g->ftp_tr_how_many->u.i || g->ftp_tr_how_many->u.i == -1) ev_enqueue(EV_APTR_CONN_ON, (Component *)g, (Component *)g, ev_now() + ticks_btw_conns(g), g->ftp_action, (Packet *)NULL, (caddr_t) train_length(g)); } return((caddr_t)g); } static caddr_t ftp_send(g) /* Send out a packet */ register Ftpt *g; { register Component *c; register Packet *pkt; if (g->ftp_packets_produced->u.i > g->ftp_packets_sent->u.i && (g->ftp_packets_sent->u.i - g->ftp_packets_acked->u.i < g->ftp_send_ws->u.i || g->ftp_send_ws->u.i == -1)) { g->ftp_packets_sent->u.i ++; log_param((Component *) g, g->ftp_packets_sent); pkt = pk_alloc(); pkt->pk_sent_time = ev_now(); pkt->pk_length = car_length(g) + 32; pkt->pk_type = TR_PACKET; pkt->tr_pk.tr_type = TR_DATA; pkt->tr_pk.response = 0; pkt->tr_pk.data_size= pkt->pk_length - 32; pkt->pk_source_socket.so_host = g->source_socket.so_host; pkt->pk_source_socket.so_port = g->source_socket.so_port; pkt->pk_dest_socket.so_host = g->dest_socket.so_host; pkt->pk_dest_socket.so_port = g->dest_socket.so_port; g->ftp_bytes_sent += pkt->tr_pk.data_size; c = (Component *)(((Neighbor *)g->ftp_neighbors->l_head)->n_c); ev_call(EV_NODE_PRODUCE, (Component *)g, c, c->co_action, pkt, (caddr_t)NULL); #ifdef DEBUG dbg_write(debug_log, DBG_INFO, (Component *)g, "sent a packet"); #endif } else if (g->ftp_current_car->u.i == g->no_of_total_cars && g->ftp_packets_produced->u.i == g->ftp_packets_sent->u.i && g->ftp_packets_sent->u.i == g->ftp_packets_acked->u.i && g->ftp_type == FTP_SOURCE) /* an ack is received for everything produced */ ftp_conn_down(g); return((caddr_t)g); } static caddr_t ftp_retransmit(g, pkt) /* receive a packet */ register Ftpt *g; Packet *pkt; { register unsigned int time_now, ticks; register Component *c; time_now = ev_now(); g->ftp_packets_retransmitted->u.i ++; log_param((Component *) g, g->ftp_packets_retransmitted); g->ftp_bytes_retransmitted += pkt->tr_pk.data_size; c = (Component *)(((Neighbor *)g->ftp_neighbors->l_head)->n_c); ticks = g->ftp_rtt->u.i * 2 / USECS_PER_TICK; if (pkt->tr_pk.tr_type == TR_TOKEN) { g->ftp_token_time = time_now + ticks; } ev_enqueue(EV_NODE_PRODUCE, (Component *)g, c, time_now + ticks, c->co_action, pkt, (caddr_t)NULL); #ifdef DEBUG dbg_write(debug_log, DBG_INFO, (Component *)g, "retransmitted a packet"); #endif pm((Component *)g, g->ftp_type, PKT_RETRANSMITTED, 0, 0, 0, g->ftp_select->u.i); return((caddr_t)g); } caddr_t ftp_sink_action(src, g, type, pkt, arg) Component *src; register Ftpt *g; int type; Packet *pkt; caddr_t arg; { caddr_t result = NULL; dbg_set_level(DBG_ERR); /* Just a big switch on type of event */ switch (type) { case EV_RESET: #ifdef DEBUG dbg_write(debug_log, DBG_INFO, (Component *)g, "reset"); #endif result = ftp_reset(g); break; case EV_CREATE: /* Minor sanity check first-- g should be NULL when initializing. */ #ifdef DEBUG if (g) dbg_write(debug_log, DBG_INFO, (Component *)NULL, "FTP Generator initialization called with non-null pointer."); #endif result = ftp_sink_create((char *)arg); break; case EV_DEL: free(g->ftp_peer->u.p); comp_delete((Component *)g); result = (caddr_t)g; break; case EV_NEIGHBOR: result = ftp_neighbor(g, (Component *)arg); break; case EV_UNEIGHBOR: result = ftp_uneighbor(g, (Component *)arg); break; case EV_MK_PEER: result = ftp_mk_peer(g, (Component *)arg, FTP_SOURCE); break; case EV_START: result = ftp_sink_start(g); break; case EV_STOP: result = (caddr_t) g; break; /********** The preceding were the commands. Following are the actual events that the application/transport module expects to receive. */ case EV_APTR_CONN_ON: result = ftp_conn_on((Ftpt *)src, g, arg); break; case EV_APTR_PRODUCE: result = ftp_produce(g); break; case EV_APTR_CONSUME: result = ftp_consume(g, pkt); break; case EV_APTR_SEND: result = ftp_send(g); break; case EV_APTR_RECEIVE: result = ftp_receive(g, src, pkt); break; case EV_APTR_RETRANSMIT: result = ftp_retransmit(g, pkt); break; default: #ifdef DEBUG dbg_write(debug_log, DBG_ERR, (Component *)g, "got unexpected event of type %x", type); #endif break; } return(result); } static caddr_t ftp_sink_create(name) register char *name; { Ftpt *newg; /* Memory for the component structure. */ newg = (Ftpt *)sim_malloc(sizeof(Ftpt)); /* First things first-- copy name into the new structure. */ strncpy(newg->ftp_name, name, 40); /* have to create a neighbor list */ newg->ftp_neighbors = l_create(); newg->ftp_params = q_create(); newg->ftp_class = APTR_CLASS; newg->ftp_type = FTP_SINK; newg->ftp_action = ftp_sink_action; newg->ftp_menu_up = FALSE; newg->source_socket.so_port = (Component *) newg; newg->source_socket.so_host = (Component *) NULL; newg->dest_socket.so_port = (Component *) NULL; newg->dest_socket.so_host = (Component *) NULL; /* Initialize the parameters */ (void)param_init((Component *)newg, "Name", (PFD)NULL, make_name_text, make_short_name_text, param_input_name, 0, DisplayMask | InputMask, 0.0); newg->ftp_peer = param_init((Component *)newg, "Peer", (PFD)NULL, make_str_text, make_short_str_text, (PFI)NULL, 0, DisplayMask, 0.0); pval(newg, ftp_peer)->u.p = sim_malloc(40); strcpy(newg->ftp_peer->u.p, "unknown"); newg->ftp_select = param_init((Component *)newg, "Not select(0), select(1) ", (PFD)NULL, make_int_text, make_short_int_text, param_input_int, 0, 0, 0.0); newg->ftp_select->u.i = 0; newg->conn_on_off = param_init((Component *)newg, "Connection status", (PFD)NULL, make_str_text, make_short_str_text, (PFI)NULL, TIME_HISTORY, 0, 0.0); pval(newg, conn_on_off)->u.p = "Off"; newg->ftp_tr_how_many = param_init((Component *)newg, "How many connections (-1 inf)", (PFD)NULL, make_int_text, make_short_int_text, param_input_int, 0, 0, 0.0); newg->ftp_tr_how_many->u.i = -1; newg->ftp_car_per_tr = param_init((Component *)newg, "Ave packets per conn. (-1 inf)", (PFD)NULL, make_int_text, make_short_int_text, param_input_int, 0, 0, 0.0); newg->ftp_car_per_tr->u.i = -1; newg->ftp_car_length = param_init((Component *)newg, "Ave Packet length", (PFD)NULL, make_int_text, make_short_int_text, param_input_int, 0, 0, 0.0); newg->ftp_car_length->u.i = 512; newg->ftp_tr_delay = param_init((Component *)newg, "Ave delay btw conns (mSec)", (PFD)NULL, make_int_text, make_short_int_text, param_input_int, 0, 0, 0.0); newg->ftp_tr_delay->u.i = 60000; newg->ftp_car_delay = param_init((Component *)newg, "Ave delay btw packets (uSec)", (PFD)NULL, make_int_text, make_short_int_text, param_input_int, 0, 0, 0.0); newg->ftp_car_delay->u.i = 100000; newg->ftp_current_train = param_init((Component *)newg, "Current connection", int_calc, make_int_text, make_short_int_text, (PFI)NULL, TIME_HISTORY, 0, 0.0); pval(newg, ftp_current_train)->u.i = 0; newg->ftp_car_how_many = param_init((Component *)newg, "No of packets in this conn.", (PFD)NULL, make_int_text, make_short_int_text, param_input_int, 0, 0, 0.0); pval(newg, ftp_car_how_many)->u.i = 0; newg->ftp_current_car = param_init((Component *)newg, "Current packet in this conn.", int_calc, make_int_text, make_short_int_text, (PFI)NULL, TIME_HISTORY, 0, 0.0); pval(newg, ftp_current_car)->u.i = 0; newg->ftp_produce_ws = param_init((Component *)newg, "Max Produce w size (-1 inf)", (PFD)NULL, make_int_text, make_short_int_text, param_input_int, 0, 0, 0.0); pval(newg, ftp_produce_ws)->u.i = 20; newg->ftp_send_ws = param_init((Component *)newg, "Max Send w size (-1 inf)", (PFD)NULL, make_int_text, make_short_int_text, param_input_int, 0, 0, 0.0); pval(newg, ftp_send_ws)->u.i = 50; newg->ftp_packets_produced = param_init((Component *)newg, "Packets Produced", int_calc, make_int_text, make_short_int_text, (PFI)NULL, TIME_HISTORY, 0, 0.0); pval(newg, ftp_packets_produced)->u.i = 0; newg->ftp_packets_sent = param_init((Component *)newg, "Packets Sent", int_calc, make_int_text, make_short_int_text, (PFI)NULL, TIME_HISTORY, 0, 0.0); pval(newg, ftp_packets_sent)->u.i = 0; newg->ftp_packets_acked = param_init((Component *)newg, "Packets Acked", int_calc, make_int_text, make_short_int_text, (PFI)NULL, TIME_HISTORY, 0, 0.0); pval(newg, ftp_packets_acked)->u.i = 0; newg->ftp_packets_recvd = param_init((Component *)newg, "Packets Received", int_calc, make_int_text, make_short_int_text, (PFI)NULL, TIME_HISTORY, DisplayMask | CanHaveMeterMask | CanHaveLogMask, 0.0); pval(newg, ftp_packets_recvd)->u.i = 0; newg->ftp_packets_retransmitted = param_init((Component *)newg, "Packets Retransmitted", int_calc, make_int_text, make_short_int_text, (PFI)NULL, TIME_HISTORY, DisplayMask | CanHaveMeterMask | CanHaveLogMask, 0.0); pval(newg, ftp_packets_retransmitted)->u.i = 0; newg->ftp_token_time = 0; newg->ftp_rtt = param_init((Component *)newg, "Round trip time est (usec)", int_calc, make_int_text, make_short_int_text, (PFI)NULL, TIME_HISTORY, 0, 0.0); pval(newg, ftp_rtt)->u.i = 10000; /* The following parameters are used to compute the instantaneous sent and acked thruputs */ newg->sent_thruput = param_init((Component *)newg, "Instantaneous sent throughput", double_calc, make_double_text, make_short_double_text, (PFI)NULL, TIME_HISTORY, 0, 0.0); pval(newg, sent_thruput)->u.d = 0; newg->acked_thruput = param_init((Component *)newg, "Instantaneous acked throughput", double_calc, make_double_text, make_short_double_text, (PFI)NULL, TIME_HISTORY, 0, 0.0); pval(newg, acked_thruput)->u.d = 0; newg->retransmission_rate = param_init((Component *)newg, "Instantaneous retransmission rate", double_calc, make_double_text, make_short_double_text, (PFI)NULL, TIME_HISTORY, 0, 0.0); pval(newg, retransmission_rate)->u.d = 0; /* Compute instantaneous delay */ newg->inst_delay = param_init((Component *)newg, "Inst delay in msecs", double_calc, make_double_text, make_short_double_text, (PFI)NULL, TIME_HISTORY, 0, 0.0); pval(newg, inst_delay)->u.d = 0.0; newg->last_pkt_delay = 0; newg->data_acked = 0; newg->last_bytes_acked = 0; #ifdef DEBUG dbg_write(debug_log, DBG_INFO, (Component *)newg, "ftp generator initialized"); #endif return((caddr_t)newg); } static caddr_t ftp_sink_start(g) register Ftpt *g; { if (g->ftp_neighbors->l_len != 1) { #ifdef DEBUG dbg_write(debug_log, DBG_ERR, (Component *)g, "can't receive packets-- no neighbors."); #endif return((caddr_t)NULL); } if (g->dest_socket.so_host == (Component *)NULL) { #ifdef DEBUG dbg_write(debug_log, DBG_ERR, (Component *)g, "can't generate packets-- no peer."); #endif return((caddr_t)NULL); } /* Something non-NULL to return */ pm((Component *)g, FTP_SINK, NEW_COMPONENT, 0, 0, 0, 0); return((caddr_t)g); } static caddr_t ftp_consume(g, pkt) /* consume a packet */ register Ftpt *g; Packet *pkt; { pk_free(pkt); return((caddr_t)g); } static caddr_t ftp_receive(g, c, pkt) /* receive a packet */ register Ftpt *g; register Component *c; register Packet *pkt; { register unsigned int time_now; unsigned int sentTime, DataSize; switch (pkt->tr_pk.tr_type) { case TR_DATA : sentTime = pkt->pk_sent_time; DataSize = pkt->tr_pk.data_size; g->ftp_packets_recvd->u.i ++; log_param((Component *) g, g->ftp_packets_recvd); ev_call(EV_APTR_CONSUME, (Component *)g, (Component *)g, g->ftp_action, pkt, (caddr_t)NULL); pkt = pk_alloc(); pkt->pk_sent_time = sentTime; pkt->pk_length = ACK_PKT_SIZE; pkt->pk_type = TR_PACKET; pkt->tr_pk.tr_type = TR_ACK; pkt->tr_pk.response = 0; pkt->tr_pk.data_size= DataSize; pkt->pk_source_socket.so_host = g->source_socket.so_host; pkt->pk_source_socket.so_port = g->source_socket.so_port; pkt->pk_dest_socket.so_host = g->dest_socket.so_host; pkt->pk_dest_socket.so_port = g->dest_socket.so_port; ev_call(EV_NODE_PRODUCE, (Component *)g, c, c->co_action, pkt, (caddr_t)NULL); #ifdef DEBUG dbg_write(debug_log, DBG_INFO, (Component *)g, "sent an ack"); #endif break; case TR_ACK : g->ftp_packets_acked->u.i ++; g->data_acked += pkt->tr_pk.data_size; g->last_bytes_acked = pkt->tr_pk.data_size; pm((Component *)g, FTP_SOURCE, ACK_RECEIVED, pkt->tr_pk.data_size, g->last_pkt_delay, 0, g->ftp_select->u.i); log_param((Component *) g, g->ftp_packets_acked); /* Compute the average delay of a packet for this connection (the time delay between entering the network and being acked )*/ g->last_pkt_delay = (ev_now() - pkt->pk_sent_time); g->total_delay += (ev_now() - pkt->pk_sent_time); g->recent_pkts_acked ++; pk_free(pkt); ev_call(EV_APTR_SEND, (Component *)g, (Component *)g, g->ftp_action, (Packet *)NULL, (caddr_t)NULL); break; case TR_TOKEN : time_now = ev_now(); /* calculate rtt in usecs, time_now and token time are in ticks */ g->ftp_rtt->u.i = ((time_now - g->ftp_token_time) * USECS_PER_TICK + g->ftp_rtt->u.i) / 2 ; log_param((Component *) g, g->ftp_rtt); g->ftp_token_time = time_now; /* dest is source, source is dest */ pkt->pk_source_socket.so_host = g->source_socket.so_host; pkt->pk_source_socket.so_port = g->source_socket.so_port; pkt->pk_dest_socket.so_host = g->dest_socket.so_host; pkt->pk_dest_socket.so_port = g->dest_socket.so_port; ev_call(EV_NODE_PRODUCE, (Component *)g, c, c->co_action, pkt, (caddr_t)NULL); break; default : break; } return((caddr_t)g); }