/******************************************/ /* network.c 0.2.5 (1999-Dec-19-Sun) */ /* Adam M. Costello */ /******************************************/ /* An example implementation of the interfaces of */ /* network.h 0.2.x and network_config.h 0.2.x. */ /* This is ANSI C code. */ #include #include #include #include #include "deliver_packet.h" #include "network.h" #include "network_config.h" #include "random.h" #include "timer.h" #include "warnf.h" struct network_path { struct network_path *next; struct network_address source, destination; struct network_path_parameters parameters; int max_payload_length_returned; /* boolean */ }; static struct network_path *paths = 0; /* linked list of paths */ static struct network_path_parameters default_path_parameters = { 556, 0.0, 0.0, 0.0, 0.01, 0.0, 0.0, }; static struct network_bottleneck_parameters bottleneck_parameters = { 1.0, 0.0, 0.0 }; static struct network_statistics statistics = { 0, 0 }; static unsigned long stored_packets = 0, stored_payload_bytes = 0; static struct network_path *find_path( const struct network_address *source, const struct network_address *destination ) /* Returns a pointer to the specified path, or 0 if not found. */ { struct network_path *path; size_t length; for (path = paths; path; path = path->next) { length = source->length; if (length != path->source.length) continue; if (memcmp(source->address, path->source.address, length) != 0) continue; length = destination->length; if (length != path->destination.length) continue; if (memcmp(destination->address, path->destination.address, length) != 0) continue; break; } return path; } void network_path_config( struct network_address source, struct network_address destination, struct network_path_parameters parameters) { struct network_path *path; path = find_path(&source, &destination); if (!path) { path = malloc(sizeof (struct network_path)); if (!path) failf(out_of_memory); path->next = paths; paths = path; path->source = source; path->destination = destination; path->max_payload_length_returned = 0; } if (path->max_payload_length_returned && path->parameters.max_payload_length != parameters.max_payload_length) { if (0) warnf("The promise of network.h not to change" " network_max_payload_length is broken!\n"); /* This warning was just annoying. */ } if (parameters.max_payload_length < 320) { warnf("The promise of network.h that network_max_payload_length() >= 320" " is broken!\n"); } path->parameters = parameters; } void network_bottleneck_config( struct network_bottleneck_parameters parameters ) { bottleneck_parameters = parameters; } static timer_handler deliver; static void deliver(double now, void *who, void *what) { struct network_packet *p = what; stored_payload_bytes -= p->payload_length; --stored_packets; deliver_packet(*p); free((void *) p->payload); free(p); } void network_send_packet(struct network_packet packet) { size_t length = packet.payload_length; struct network_packet *p; struct network_path *path; const struct network_path_parameters *parameters; unsigned char *payload; double now = timer_now(), delay; ++statistics.packets_sent; path = find_path(&packet.source, &packet.destination); parameters = path ? &path->parameters : &default_path_parameters; /* Drop the packet: */ if (length > parameters->max_payload_length) { ++statistics.packets_dropped; return; } if (parameters->drop_probability > 0.0) { if (random_uniform01() < parameters->drop_probability) { ++statistics.packets_dropped; return; } } if (bottleneck_parameters.budget > 0.0) { double packet_cost = bottleneck_parameters.packet_cost; double payload_byte_cost = bottleneck_parameters.payload_byte_cost; packet_cost *= stored_packets + 1; payload_byte_cost *= stored_payload_bytes + length; if (packet_cost + payload_byte_cost > bottleneck_parameters.budget) { ++statistics.packets_dropped; return; } } /* Duplicate the packet: */ if (parameters->duplicate_probability > 0.0) { if (random_uniform01() < parameters->duplicate_probability) { network_send_packet(packet); } } /* Make a local copy of the packet: */ p = malloc(sizeof (struct network_packet)); if (!p) failf(out_of_memory); *p = packet; payload = malloc(length); if (!payload) failf(out_of_memory); memcpy(payload, packet.payload, length); p->payload = payload; /* Corrupt the packet: */ if (parameters->bit_error_rate > 0.0 && length > 0) { double packet_error_rate = 1.0 - pow(1.0 - parameters->bit_error_rate, length * 8); while (random_uniform01() < packet_error_rate) { payload[random_discrete_uniform(0, length - 1)] ^= (1 << random_discrete_uniform(0,7)); } } /* Delay the packet: */ delay = parameters->delay_constant + parameters->delay_per_bit * length * 8 + random_uniform(0.0, 1, parameters->delay_random_max, 1); timer_set(deliver, now + delay, 0, p); /* Bookkeeping: */ ++stored_packets; stored_payload_bytes += packet.payload_length; } size_t network_max_payload_length( struct network_address source, struct network_address destination ) { struct network_path *path; path = find_path(&source, &destination); if (!path) return default_path_parameters.max_payload_length; path->max_payload_length_returned = 1; return path->parameters.max_payload_length; } struct network_statistics network_statistics(void) { return statistics; }