diff --git a/common/Makefile b/common/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..fbedc829a6cccf227edfff2ee111397a416060fc --- /dev/null +++ b/common/Makefile @@ -0,0 +1,8 @@ +CFLAGS= -Wall -Werror -Wno-error=unused-variable + +all: utils.o + +clean: + -rm -f *.o + +.PHONY: all clean diff --git a/common/include/utils.h b/common/include/utils.h new file mode 100644 index 0000000000000000000000000000000000000000..b276371e8e40bda5531547e1b3361fce8cd70426 --- /dev/null +++ b/common/include/utils.h @@ -0,0 +1,18 @@ +#ifndef UTILS_H +#define UTILS_H + +#include <stdio.h> +#include <stdlib.h> + +void hex_dump(const void * addr, size_t size); + +#define DIE(condition, message, ...) \ +do { \ + if ((condition)) { \ + fprintf(stderr, "[(%s:%d)]: " # message "\n", __FILE__, __LINE__, ##__VA_ARGS__); \ + perror(""); \ + exit(1); \ + } \ +} while (0) + +#endif /* UTILS_H */ diff --git a/common/link_emulator/.clang-format b/common/link_emulator/.clang-format new file mode 100644 index 0000000000000000000000000000000000000000..fa959436bcfd0fdc41d69e15496289bc998a07e6 --- /dev/null +++ b/common/link_emulator/.clang-format @@ -0,0 +1,560 @@ +# SPDX-License-Identifier: GPL-2.0 +# +# clang-format configuration file. Intended for clang-format >= 4. +# +# For more information, see: +# +# Documentation/process/clang-format.rst +# https://clang.llvm.org/docs/ClangFormat.html +# https://clang.llvm.org/docs/ClangFormatStyleOptions.html +# +--- +AccessModifierOffset: -4 +AlignAfterOpenBracket: Align +AlignConsecutiveAssignments: false +AlignConsecutiveDeclarations: false +#AlignEscapedNewlines: Left # Unknown to clang-format-4.0 +AlignOperands: true +AlignTrailingComments: false +AllowAllParametersOfDeclarationOnNextLine: false +AllowShortBlocksOnASingleLine: false +AllowShortCaseLabelsOnASingleLine: false +AllowShortFunctionsOnASingleLine: None +AllowShortIfStatementsOnASingleLine: false +AllowShortLoopsOnASingleLine: false +AlwaysBreakAfterDefinitionReturnType: None +AlwaysBreakAfterReturnType: None +AlwaysBreakBeforeMultilineStrings: false +AlwaysBreakTemplateDeclarations: false +BinPackArguments: true +BinPackParameters: true +BraceWrapping: + AfterClass: false + AfterControlStatement: false + AfterEnum: false + AfterFunction: true + AfterNamespace: true + AfterObjCDeclaration: false + AfterStruct: false + AfterUnion: false + #AfterExternBlock: false # Unknown to clang-format-5.0 + BeforeCatch: false + BeforeElse: false + IndentBraces: false + #SplitEmptyFunction: true # Unknown to clang-format-4.0 + #SplitEmptyRecord: true # Unknown to clang-format-4.0 + #SplitEmptyNamespace: true # Unknown to clang-format-4.0 +BreakBeforeBinaryOperators: None +BreakBeforeBraces: Custom +#BreakBeforeInheritanceComma: false # Unknown to clang-format-4.0 +BreakBeforeTernaryOperators: false +BreakConstructorInitializersBeforeComma: false +#BreakConstructorInitializers: BeforeComma # Unknown to clang-format-4.0 +BreakAfterJavaFieldAnnotations: false +BreakStringLiterals: false +ColumnLimit: 80 +CommentPragmas: '^ IWYU pragma:' +#CompactNamespaces: false # Unknown to clang-format-4.0 +ConstructorInitializerAllOnOneLineOrOnePerLine: false +ConstructorInitializerIndentWidth: 8 +ContinuationIndentWidth: 8 +Cpp11BracedListStyle: false +DerivePointerAlignment: false +DisableFormat: false +ExperimentalAutoDetectBinPacking: false +#FixNamespaceComments: false # Unknown to clang-format-4.0 + +# Taken from: +# git grep -h '^#define [^[:space:]]*for_each[^[:space:]]*(' include/ \ +# | sed "s,^#define \([^[:space:]]*for_each[^[:space:]]*\)(.*$, - '\1'," \ +# | sort | uniq +ForEachMacros: + - 'apei_estatus_for_each_section' + - 'ata_for_each_dev' + - 'ata_for_each_link' + - '__ata_qc_for_each' + - 'ata_qc_for_each' + - 'ata_qc_for_each_raw' + - 'ata_qc_for_each_with_internal' + - 'ax25_for_each' + - 'ax25_uid_for_each' + - '__bio_for_each_bvec' + - 'bio_for_each_bvec' + - 'bio_for_each_bvec_all' + - 'bio_for_each_integrity_vec' + - '__bio_for_each_segment' + - 'bio_for_each_segment' + - 'bio_for_each_segment_all' + - 'bio_list_for_each' + - 'bip_for_each_vec' + - 'bitmap_for_each_clear_region' + - 'bitmap_for_each_set_region' + - 'blkg_for_each_descendant_post' + - 'blkg_for_each_descendant_pre' + - 'blk_queue_for_each_rl' + - 'bond_for_each_slave' + - 'bond_for_each_slave_rcu' + - 'bpf_for_each_spilled_reg' + - 'btree_for_each_safe128' + - 'btree_for_each_safe32' + - 'btree_for_each_safe64' + - 'btree_for_each_safel' + - 'card_for_each_dev' + - 'cgroup_taskset_for_each' + - 'cgroup_taskset_for_each_leader' + - 'cpufreq_for_each_entry' + - 'cpufreq_for_each_entry_idx' + - 'cpufreq_for_each_valid_entry' + - 'cpufreq_for_each_valid_entry_idx' + - 'css_for_each_child' + - 'css_for_each_descendant_post' + - 'css_for_each_descendant_pre' + - 'device_for_each_child_node' + - 'displayid_iter_for_each' + - 'dma_fence_chain_for_each' + - 'do_for_each_ftrace_op' + - 'drm_atomic_crtc_for_each_plane' + - 'drm_atomic_crtc_state_for_each_plane' + - 'drm_atomic_crtc_state_for_each_plane_state' + - 'drm_atomic_for_each_plane_damage' + - 'drm_client_for_each_connector_iter' + - 'drm_client_for_each_modeset' + - 'drm_connector_for_each_possible_encoder' + - 'drm_for_each_bridge_in_chain' + - 'drm_for_each_connector_iter' + - 'drm_for_each_crtc' + - 'drm_for_each_crtc_reverse' + - 'drm_for_each_encoder' + - 'drm_for_each_encoder_mask' + - 'drm_for_each_fb' + - 'drm_for_each_legacy_plane' + - 'drm_for_each_plane' + - 'drm_for_each_plane_mask' + - 'drm_for_each_privobj' + - 'drm_mm_for_each_hole' + - 'drm_mm_for_each_node' + - 'drm_mm_for_each_node_in_range' + - 'drm_mm_for_each_node_safe' + - 'flow_action_for_each' + - 'for_each_acpi_dev_match' + - 'for_each_active_dev_scope' + - 'for_each_active_drhd_unit' + - 'for_each_active_iommu' + - 'for_each_aggr_pgid' + - 'for_each_available_child_of_node' + - 'for_each_bio' + - 'for_each_board_func_rsrc' + - 'for_each_bvec' + - 'for_each_card_auxs' + - 'for_each_card_auxs_safe' + - 'for_each_card_components' + - 'for_each_card_dapms' + - 'for_each_card_pre_auxs' + - 'for_each_card_prelinks' + - 'for_each_card_rtds' + - 'for_each_card_rtds_safe' + - 'for_each_card_widgets' + - 'for_each_card_widgets_safe' + - 'for_each_cgroup_storage_type' + - 'for_each_child_of_node' + - 'for_each_clear_bit' + - 'for_each_clear_bit_from' + - 'for_each_cmsghdr' + - 'for_each_compatible_node' + - 'for_each_component_dais' + - 'for_each_component_dais_safe' + - 'for_each_comp_order' + - 'for_each_console' + - 'for_each_cpu' + - 'for_each_cpu_and' + - 'for_each_cpu_not' + - 'for_each_cpu_wrap' + - 'for_each_dapm_widgets' + - 'for_each_dev_addr' + - 'for_each_dev_scope' + - 'for_each_dma_cap_mask' + - 'for_each_dpcm_be' + - 'for_each_dpcm_be_rollback' + - 'for_each_dpcm_be_safe' + - 'for_each_dpcm_fe' + - 'for_each_drhd_unit' + - 'for_each_dss_dev' + - 'for_each_dtpm_table' + - 'for_each_efi_memory_desc' + - 'for_each_efi_memory_desc_in_map' + - 'for_each_element' + - 'for_each_element_extid' + - 'for_each_element_id' + - 'for_each_endpoint_of_node' + - 'for_each_evictable_lru' + - 'for_each_fib6_node_rt_rcu' + - 'for_each_fib6_walker_rt' + - 'for_each_free_mem_pfn_range_in_zone' + - 'for_each_free_mem_pfn_range_in_zone_from' + - 'for_each_free_mem_range' + - 'for_each_free_mem_range_reverse' + - 'for_each_func_rsrc' + - 'for_each_hstate' + - 'for_each_if' + - 'for_each_iommu' + - 'for_each_ip_tunnel_rcu' + - 'for_each_irq_nr' + - 'for_each_link_codecs' + - 'for_each_link_cpus' + - 'for_each_link_platforms' + - 'for_each_lru' + - 'for_each_matching_node' + - 'for_each_matching_node_and_match' + - 'for_each_member' + - 'for_each_memcg_cache_index' + - 'for_each_mem_pfn_range' + - '__for_each_mem_range' + - 'for_each_mem_range' + - '__for_each_mem_range_rev' + - 'for_each_mem_range_rev' + - 'for_each_mem_region' + - 'for_each_migratetype_order' + - 'for_each_msi_entry' + - 'for_each_msi_entry_safe' + - 'for_each_net' + - 'for_each_net_continue_reverse' + - 'for_each_netdev' + - 'for_each_netdev_continue' + - 'for_each_netdev_continue_rcu' + - 'for_each_netdev_continue_reverse' + - 'for_each_netdev_feature' + - 'for_each_netdev_in_bond_rcu' + - 'for_each_netdev_rcu' + - 'for_each_netdev_reverse' + - 'for_each_netdev_safe' + - 'for_each_net_rcu' + - 'for_each_new_connector_in_state' + - 'for_each_new_crtc_in_state' + - 'for_each_new_mst_mgr_in_state' + - 'for_each_new_plane_in_state' + - 'for_each_new_private_obj_in_state' + - 'for_each_node' + - 'for_each_node_by_name' + - 'for_each_node_by_type' + - 'for_each_node_mask' + - 'for_each_node_state' + - 'for_each_node_with_cpus' + - 'for_each_node_with_property' + - 'for_each_nonreserved_multicast_dest_pgid' + - 'for_each_of_allnodes' + - 'for_each_of_allnodes_from' + - 'for_each_of_cpu_node' + - 'for_each_of_pci_range' + - 'for_each_old_connector_in_state' + - 'for_each_old_crtc_in_state' + - 'for_each_old_mst_mgr_in_state' + - 'for_each_oldnew_connector_in_state' + - 'for_each_oldnew_crtc_in_state' + - 'for_each_oldnew_mst_mgr_in_state' + - 'for_each_oldnew_plane_in_state' + - 'for_each_oldnew_plane_in_state_reverse' + - 'for_each_oldnew_private_obj_in_state' + - 'for_each_old_plane_in_state' + - 'for_each_old_private_obj_in_state' + - 'for_each_online_cpu' + - 'for_each_online_node' + - 'for_each_online_pgdat' + - 'for_each_pci_bridge' + - 'for_each_pci_dev' + - 'for_each_pci_msi_entry' + - 'for_each_pcm_streams' + - 'for_each_physmem_range' + - 'for_each_populated_zone' + - 'for_each_possible_cpu' + - 'for_each_present_cpu' + - 'for_each_prime_number' + - 'for_each_prime_number_from' + - 'for_each_process' + - 'for_each_process_thread' + - 'for_each_prop_codec_conf' + - 'for_each_prop_dai_codec' + - 'for_each_prop_dai_cpu' + - 'for_each_prop_dlc_codecs' + - 'for_each_prop_dlc_cpus' + - 'for_each_prop_dlc_platforms' + - 'for_each_property_of_node' + - 'for_each_registered_fb' + - 'for_each_requested_gpio' + - 'for_each_requested_gpio_in_range' + - 'for_each_reserved_mem_range' + - 'for_each_reserved_mem_region' + - 'for_each_rtd_codec_dais' + - 'for_each_rtd_components' + - 'for_each_rtd_cpu_dais' + - 'for_each_rtd_dais' + - 'for_each_set_bit' + - 'for_each_set_bit_from' + - 'for_each_set_clump8' + - 'for_each_sg' + - 'for_each_sg_dma_page' + - 'for_each_sg_page' + - 'for_each_sgtable_dma_page' + - 'for_each_sgtable_dma_sg' + - 'for_each_sgtable_page' + - 'for_each_sgtable_sg' + - 'for_each_sibling_event' + - 'for_each_subelement' + - 'for_each_subelement_extid' + - 'for_each_subelement_id' + - '__for_each_thread' + - 'for_each_thread' + - 'for_each_unicast_dest_pgid' + - 'for_each_vsi' + - 'for_each_wakeup_source' + - 'for_each_zone' + - 'for_each_zone_zonelist' + - 'for_each_zone_zonelist_nodemask' + - 'fwnode_for_each_available_child_node' + - 'fwnode_for_each_child_node' + - 'fwnode_graph_for_each_endpoint' + - 'gadget_for_each_ep' + - 'genradix_for_each' + - 'genradix_for_each_from' + - 'hash_for_each' + - 'hash_for_each_possible' + - 'hash_for_each_possible_rcu' + - 'hash_for_each_possible_rcu_notrace' + - 'hash_for_each_possible_safe' + - 'hash_for_each_rcu' + - 'hash_for_each_safe' + - 'hctx_for_each_ctx' + - 'hlist_bl_for_each_entry' + - 'hlist_bl_for_each_entry_rcu' + - 'hlist_bl_for_each_entry_safe' + - 'hlist_for_each' + - 'hlist_for_each_entry' + - 'hlist_for_each_entry_continue' + - 'hlist_for_each_entry_continue_rcu' + - 'hlist_for_each_entry_continue_rcu_bh' + - 'hlist_for_each_entry_from' + - 'hlist_for_each_entry_from_rcu' + - 'hlist_for_each_entry_rcu' + - 'hlist_for_each_entry_rcu_bh' + - 'hlist_for_each_entry_rcu_notrace' + - 'hlist_for_each_entry_safe' + - 'hlist_for_each_entry_srcu' + - '__hlist_for_each_rcu' + - 'hlist_for_each_safe' + - 'hlist_nulls_for_each_entry' + - 'hlist_nulls_for_each_entry_from' + - 'hlist_nulls_for_each_entry_rcu' + - 'hlist_nulls_for_each_entry_safe' + - 'i3c_bus_for_each_i2cdev' + - 'i3c_bus_for_each_i3cdev' + - 'ide_host_for_each_port' + - 'ide_port_for_each_dev' + - 'ide_port_for_each_present_dev' + - 'idr_for_each_entry' + - 'idr_for_each_entry_continue' + - 'idr_for_each_entry_continue_ul' + - 'idr_for_each_entry_ul' + - 'in_dev_for_each_ifa_rcu' + - 'in_dev_for_each_ifa_rtnl' + - 'inet_bind_bucket_for_each' + - 'inet_lhash2_for_each_icsk_rcu' + - 'key_for_each' + - 'key_for_each_safe' + - 'klp_for_each_func' + - 'klp_for_each_func_safe' + - 'klp_for_each_func_static' + - 'klp_for_each_object' + - 'klp_for_each_object_safe' + - 'klp_for_each_object_static' + - 'kunit_suite_for_each_test_case' + - 'kvm_for_each_memslot' + - 'kvm_for_each_vcpu' + - 'list_for_each' + - 'list_for_each_codec' + - 'list_for_each_codec_safe' + - 'list_for_each_continue' + - 'list_for_each_entry' + - 'list_for_each_entry_continue' + - 'list_for_each_entry_continue_rcu' + - 'list_for_each_entry_continue_reverse' + - 'list_for_each_entry_from' + - 'list_for_each_entry_from_rcu' + - 'list_for_each_entry_from_reverse' + - 'list_for_each_entry_lockless' + - 'list_for_each_entry_rcu' + - 'list_for_each_entry_reverse' + - 'list_for_each_entry_safe' + - 'list_for_each_entry_safe_continue' + - 'list_for_each_entry_safe_from' + - 'list_for_each_entry_safe_reverse' + - 'list_for_each_entry_srcu' + - 'list_for_each_prev' + - 'list_for_each_prev_safe' + - 'list_for_each_safe' + - 'llist_for_each' + - 'llist_for_each_entry' + - 'llist_for_each_entry_safe' + - 'llist_for_each_safe' + - 'mci_for_each_dimm' + - 'media_device_for_each_entity' + - 'media_device_for_each_intf' + - 'media_device_for_each_link' + - 'media_device_for_each_pad' + - 'nanddev_io_for_each_page' + - 'netdev_for_each_lower_dev' + - 'netdev_for_each_lower_private' + - 'netdev_for_each_lower_private_rcu' + - 'netdev_for_each_mc_addr' + - 'netdev_for_each_uc_addr' + - 'netdev_for_each_upper_dev_rcu' + - 'netdev_hw_addr_list_for_each' + - 'nft_rule_for_each_expr' + - 'nla_for_each_attr' + - 'nla_for_each_nested' + - 'nlmsg_for_each_attr' + - 'nlmsg_for_each_msg' + - 'nr_neigh_for_each' + - 'nr_neigh_for_each_safe' + - 'nr_node_for_each' + - 'nr_node_for_each_safe' + - 'of_for_each_phandle' + - 'of_property_for_each_string' + - 'of_property_for_each_u32' + - 'pci_bus_for_each_resource' + - 'pcl_for_each_chunk' + - 'pcl_for_each_segment' + - 'pcm_for_each_format' + - 'ping_portaddr_for_each_entry' + - 'plist_for_each' + - 'plist_for_each_continue' + - 'plist_for_each_entry' + - 'plist_for_each_entry_continue' + - 'plist_for_each_entry_safe' + - 'plist_for_each_safe' + - 'pnp_for_each_card' + - 'pnp_for_each_dev' + - 'protocol_for_each_card' + - 'protocol_for_each_dev' + - 'queue_for_each_hw_ctx' + - 'radix_tree_for_each_slot' + - 'radix_tree_for_each_tagged' + - 'rb_for_each' + - 'rbtree_postorder_for_each_entry_safe' + - 'rdma_for_each_block' + - 'rdma_for_each_port' + - 'rdma_umem_for_each_dma_block' + - 'resource_list_for_each_entry' + - 'resource_list_for_each_entry_safe' + - 'rhl_for_each_entry_rcu' + - 'rhl_for_each_rcu' + - 'rht_for_each' + - 'rht_for_each_entry' + - 'rht_for_each_entry_from' + - 'rht_for_each_entry_rcu' + - 'rht_for_each_entry_rcu_from' + - 'rht_for_each_entry_safe' + - 'rht_for_each_from' + - 'rht_for_each_rcu' + - 'rht_for_each_rcu_from' + - '__rq_for_each_bio' + - 'rq_for_each_bvec' + - 'rq_for_each_segment' + - 'scsi_for_each_prot_sg' + - 'scsi_for_each_sg' + - 'sctp_for_each_hentry' + - 'sctp_skb_for_each' + - 'shdma_for_each_chan' + - '__shost_for_each_device' + - 'shost_for_each_device' + - 'sk_for_each' + - 'sk_for_each_bound' + - 'sk_for_each_entry_offset_rcu' + - 'sk_for_each_from' + - 'sk_for_each_rcu' + - 'sk_for_each_safe' + - 'sk_nulls_for_each' + - 'sk_nulls_for_each_from' + - 'sk_nulls_for_each_rcu' + - 'snd_array_for_each' + - 'snd_pcm_group_for_each_entry' + - 'snd_soc_dapm_widget_for_each_path' + - 'snd_soc_dapm_widget_for_each_path_safe' + - 'snd_soc_dapm_widget_for_each_sink_path' + - 'snd_soc_dapm_widget_for_each_source_path' + - 'tb_property_for_each' + - 'tcf_exts_for_each_action' + - 'udp_portaddr_for_each_entry' + - 'udp_portaddr_for_each_entry_rcu' + - 'usb_hub_for_each_child' + - 'v4l2_device_for_each_subdev' + - 'v4l2_m2m_for_each_dst_buf' + - 'v4l2_m2m_for_each_dst_buf_safe' + - 'v4l2_m2m_for_each_src_buf' + - 'v4l2_m2m_for_each_src_buf_safe' + - 'virtio_device_for_each_vq' + - 'while_for_each_ftrace_op' + - 'xa_for_each' + - 'xa_for_each_marked' + - 'xa_for_each_range' + - 'xa_for_each_start' + - 'xas_for_each' + - 'xas_for_each_conflict' + - 'xas_for_each_marked' + - 'xbc_array_for_each_value' + - 'xbc_for_each_key_value' + - 'xbc_node_for_each_array_value' + - 'xbc_node_for_each_child' + - 'xbc_node_for_each_key_value' + - 'zorro_for_each_dev' + +#IncludeBlocks: Preserve # Unknown to clang-format-5.0 +IncludeCategories: + - Regex: '.*' + Priority: 1 +IncludeIsMainRegex: '(Test)?$' +IndentCaseLabels: false +#IndentPPDirectives: None # Unknown to clang-format-5.0 +IndentWidth: 8 +IndentWrappedFunctionNames: false +JavaScriptQuotes: Leave +JavaScriptWrapImports: true +KeepEmptyLinesAtTheStartOfBlocks: false +MacroBlockBegin: '' +MacroBlockEnd: '' +MaxEmptyLinesToKeep: 1 +NamespaceIndentation: None +#ObjCBinPackProtocolList: Auto # Unknown to clang-format-5.0 +ObjCBlockIndentWidth: 8 +ObjCSpaceAfterProperty: true +ObjCSpaceBeforeProtocolList: true + +# Taken from git's rules +#PenaltyBreakAssignment: 10 # Unknown to clang-format-4.0 +PenaltyBreakBeforeFirstCallParameter: 30 +PenaltyBreakComment: 10 +PenaltyBreakFirstLessLess: 0 +PenaltyBreakString: 10 +PenaltyExcessCharacter: 100 +PenaltyReturnTypeOnItsOwnLine: 60 + +PointerAlignment: Right +ReflowComments: false +SortIncludes: false +#SortUsingDeclarations: false # Unknown to clang-format-4.0 +SpaceAfterCStyleCast: false +SpaceAfterTemplateKeyword: true +SpaceBeforeAssignmentOperators: true +#SpaceBeforeCtorInitializerColon: true # Unknown to clang-format-5.0 +#SpaceBeforeInheritanceColon: true # Unknown to clang-format-5.0 +SpaceBeforeParens: ControlStatements +#SpaceBeforeRangeBasedForLoopColon: true # Unknown to clang-format-5.0 +SpaceInEmptyParentheses: false +SpacesBeforeTrailingComments: 1 +SpacesInAngles: false +SpacesInContainerLiterals: false +SpacesInCStyleCastParentheses: false +SpacesInParentheses: false +SpacesInSquareBrackets: false +Standard: Cpp03 +TabWidth: 8 +UseTab: Always +... diff --git a/lab3/link_emulator/Makefile b/common/link_emulator/Makefile similarity index 71% rename from lab3/link_emulator/Makefile rename to common/link_emulator/Makefile index bc25fa35e005fafff429c72f9eb99c93d90f89be..9503a5ae8f4d15dd9d86512620d88096178702c2 100644 --- a/lab3/link_emulator/Makefile +++ b/common/link_emulator/Makefile @@ -3,8 +3,8 @@ all: link lib.o link: link.o queue.o gcc -g link.o queue.o -o link -pthread -.c.o: - gcc -Wall -g -c $? -pthread +.c.o: + gcc -Wall -g -c $? -pthread -I../ clean: rm -f *.o link diff --git a/common/link_emulator/lib.c b/common/link_emulator/lib.c new file mode 100644 index 0000000000000000000000000000000000000000..49181d2b1f5e1ac8c990d947d1999e1dd2e17f89 --- /dev/null +++ b/common/link_emulator/lib.c @@ -0,0 +1,117 @@ +#include "lib.h" +#include "include/utils.h" +#include <arpa/inet.h> +#include <poll.h> +#include <netinet/in.h> +#include <stdio.h> +#include <stdlib.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <unistd.h> +#include <string.h> + +struct sockaddr_in addr_local, addr_remote; +int s; +struct pollfd fds[1]; + +void set_local_port(int port) +{ + memset((char *) &addr_local, 0, sizeof(addr_local)); + addr_local.sin_family = AF_INET; + addr_local.sin_port = htons(port); + addr_local.sin_addr.s_addr = htonl(INADDR_ANY); +} + +void set_remote(char* ip, int port) +{ + memset((char *) &addr_remote, 0, sizeof(addr_remote)); + addr_remote.sin_family = AF_INET; + addr_remote.sin_port = htons(port); + int res = inet_aton(ip, &addr_remote.sin_addr); + DIE(res == 0, "inet_aton failed\n"); +} + +void init(char* remote, int REMOTE_PORT) +{ + s=socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); + DIE(s == -1, "Error creating socket"); + + set_local_port(0); + set_remote(remote, REMOTE_PORT); + + int res = bind(s, (struct sockaddr*)&addr_local, sizeof(addr_local)); + DIE(res == -1, "Failed to bind"); + + fds[0].fd = s; + fds[0].events = POLLIN; + + msg m; + send_message(&m); +} + +int send_message(const msg *m) +{ + return sendto(s, m, sizeof(msg), 0,(struct sockaddr*) &addr_remote, + sizeof(addr_remote)); +} + +int link_send(void *buf, int len) +{ + msg m; + + memcpy(m.payload, buf, len); + m.len = len; + + return send_message(&m); +} + +int recv_message(msg *ret) +{ + return recvfrom(s, ret, sizeof(msg), 0, NULL, NULL); +} + +int link_recv(void *buf, int len) +{ + msg m; + recv_message(&m); + int r = m.len < len ? m.len : len; + memcpy(buf, m.payload, r); + return r; +} + +//timeout in millis +int recv_message_timeout(msg *m, int timeout) +{ + int ret = poll(fds, 1, timeout); + + if (ret > 0) { + if (fds[0].revents & POLLIN) + return recv_message(m); + } + + return -1; +} + +int link_recv_timeout(void *buf, int len, int timeout) +{ + msg m; + recv_message_timeout(&m, timeout); + int r = m.len < len ? m.len : len; + memcpy(buf, m.payload, r); + return r; +} + +int send_byte(uint8_t byte) { + printf("Sending byte %1$c (0x%1$02x)\n", byte); + return link_send(&byte, sizeof(byte)); +} + +uint8_t recv_byte() { + int ret; + uint8_t byte; + ret = link_recv_timeout(&byte, sizeof(byte), 100000); + if (ret < 0) + byte = rand() % 128; + + return byte; +} diff --git a/common/link_emulator/lib.h b/common/link_emulator/lib.h new file mode 100644 index 0000000000000000000000000000000000000000..5d4fca6411757a891aab2683f7bebc98e7f20124 --- /dev/null +++ b/common/link_emulator/lib.h @@ -0,0 +1,25 @@ +#ifndef _LIB_H_ +#define _LIB_H_ + +#include <stddef.h> +#include <stdint.h> + +#define MAX_LEN 1400 + +typedef struct { + int len; + char payload[MAX_LEN]; +} msg; + +void init(char* remote, int remote_port); +void set_local_port(int port); +void set_remote(char* ip, int port); +int send_message(const msg *t); +int recv_message(msg* r); +int recv_message_timeout(msg *m, int timeout); +int link_send(void *buf, int len); +int link_recv(void *buf, int len); +int send_byte(uint8_t b); +uint8_t recv_byte(void); + +#endif /* _LIB_H_ */ diff --git a/common/link_emulator/link.c b/common/link_emulator/link.c new file mode 100644 index 0000000000000000000000000000000000000000..a71417341912f00affd33a4d9ab782a045a1dd4c --- /dev/null +++ b/common/link_emulator/link.c @@ -0,0 +1,465 @@ +#include <arpa/inet.h> +#include <assert.h> +#include <netinet/in.h> +#include <pthread.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/socket.h> +#include <sys/time.h> +#include <sys/types.h> +#include <unistd.h> +//#include <asm/param.h> +#include "link.h" +#include "queue.h" +#include "include/utils.h" + +#define DEBUG 0 + +int BUFFER_SIZE = 1000; + +int serialization_delay = 1000; +int delay = 1000; +int loss = 0; +int corrupt = 0; +int corrupt2 = 0; +int reorder = 0; + +#define CHANNEL_BUSY 1 +#define CHANNEL_IDLE 0 + +#define LOCAL_PORT1 10000 +#define LOCAL_PORT2 10001 + +pthread_mutex_t buffer_lock = PTHREAD_MUTEX_INITIALIZER; +pthread_cond_t buffer_cond = PTHREAD_COND_INITIALIZER; +queue *buffer; + +struct sockaddr_in local_addr1, remote_addr1; +struct sockaddr_in local_addr2, remote_addr2; + +int s1, s2; +socklen_t sz; + +// 1 if a message was received on this link +int link_up1 = 0; +int link_up2 = 0; + +void init_sockets() +{ + /*LOCAL ADDRESSES*/ + + memset((char *)&local_addr1, 0, sizeof(local_addr1)); + local_addr1.sin_family = AF_INET; + local_addr1.sin_port = htons(LOCAL_PORT1); + local_addr1.sin_addr.s_addr = htonl(INADDR_ANY); + + memset((char *)&local_addr2, 0, sizeof(local_addr2)); + local_addr2.sin_family = AF_INET; + local_addr2.sin_port = htons(LOCAL_PORT2); + local_addr2.sin_addr.s_addr = htonl(INADDR_ANY); + + s1 = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); + DIE(s1 == -1, "Error creating socket"); + + // now bind + int res = bind(s1, (struct sockaddr *)&local_addr1, sizeof(local_addr1)); + DIE(res == -1, "Failed to bind s1"); + + s2 = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); + DIE(s2 == -1, "Error creating socket 2"); + + res = bind(s2, (struct sockaddr *)&local_addr2, sizeof(local_addr2)); + DIE(res == -1, "Failed to bind s2"); +} + +int send_message1(const msg *m) +{ + if (!link_up1) { + printf("Trying to send a message but remote peer is not connected on my " + "port %d\n", + LOCAL_PORT1); + } + return sendto(s1, m, sizeof(msg), 0, (struct sockaddr *)&remote_addr1, + sizeof(remote_addr1)); +} + +msg *receive_message1() +{ + msg *ret; + +a: + ret = (msg *)malloc(sizeof(msg)); + DIE(!ret, "malloc"); + + if (!link_up1) { + sz = sizeof(remote_addr1); + if (recvfrom(s1, ret, sizeof(msg), 0, + (struct sockaddr *)&remote_addr1, &sz) == -1) { + free(ret); + return NULL; + } + + link_up1 = 1; + +#if DEBUG + printf("Link 1 is up, remote addr is %s port %d\n", + inet_ntoa(remote_addr1.sin_addr), + ntohs(remote_addr1.sin_port)); +#endif + + free(ret); + goto a; + } else if (recvfrom(s1, ret, sizeof(msg), 0, NULL, NULL) == -1) { + free(ret); + return NULL; + } + return ret; +} + +int send_message2(const msg *m) +{ + if (!link_up2) { + printf("Trying to send a message but remote peer is not connected on my " + "port %d\n", + LOCAL_PORT2); + } + return sendto(s2, m, sizeof(msg), 0, (struct sockaddr *)&remote_addr2, + sizeof(remote_addr2)); +} + +msg *receive_message2() +{ + msg *ret; + +a: + ret = (msg *)malloc(sizeof(msg)); + DIE(!ret, "malloc"); + + if (!link_up2) { + sz = sizeof(remote_addr2); + if (recvfrom(s2, ret, sizeof(msg), 0, + (struct sockaddr *)&remote_addr2, &sz) == -1) { + free(ret); + return NULL; + } + link_up2 = 1; + +#if DEBUG + printf("Link 2 is up, remote addr is %s port %d\n", + inet_ntoa(remote_addr2.sin_addr), + ntohs(remote_addr2.sin_port)); +#endif + + free(ret); + goto a; + } else if (recvfrom(s2, ret, sizeof(msg), 0, NULL, NULL) == -1) { + free(ret); + return NULL; + } + + return ret; +} + +unsigned long long now() +{ + struct timeval b; + gettimeofday(&b, NULL); + return (unsigned long long)b.tv_sec * 1000000 + b.tv_usec; +} + +void *link_scheduler(void *argument) +{ + msg_in_flight *mif; + queue *in_flight = create_queue(); + long long idle_time = 0; + long long crt_time, wait_time_idle, wait_time_send; + int stuff; + + while (1) { + crt_time = now(); + +#if DEBUG + printf("In flight size %d at %lld\n", in_flight->size, + crt_time); +#endif + + while (in_flight->size > 0) { + msg_in_flight *last = + (msg_in_flight *)in_flight->last->crt; + if (crt_time < last->finish_time) { + break; + } + + // else send first packet on the wire + mif = (msg_in_flight *)dequeue(in_flight); + DIE(!mif, "Error in deque: expecting non null msg!"); + if (send_message2(mif->m) <= 0) + perror("SNDMSG2"); + +#if DEBUG + printf("Sending message\n"); +#endif + + free(mif->m); + free(mif); + mif = NULL; + } + + pthread_mutex_lock(&buffer_lock); + stuff = buffer->size > 0; + pthread_mutex_unlock(&buffer_lock); + +#if DEBUG + printf("Stuff is %d\n", stuff); +#endif + + wait_time_send = wait_time_idle = 0; + + // crt_time = now(); + + // now see if we can put stuff in flight + if (stuff && crt_time >= idle_time) { + idle_time = crt_time + serialization_delay; + + mif = (msg_in_flight *)malloc(sizeof(msg_in_flight)); + assert(mif); + + pthread_mutex_lock(&buffer_lock); + + if (rand() % 100 < reorder && buffer->size > 1) { + msg *m = (msg *)dequeue(buffer); + enqueue(buffer,m); + } + + mif->m = (msg *)dequeue(buffer); + pthread_mutex_unlock(&buffer_lock); + + assert(mif->m); + mif->finish_time = + crt_time + serialization_delay + delay; + + // send message here from buffer to link + enqueue(in_flight, mif); + +#if DEBUG + printf("Enquing message\n"); +#endif + } + wait_time_idle = idle_time - crt_time; + + if (in_flight->size > 0) { + msg_in_flight *last = + (msg_in_flight *)in_flight->last->crt; + wait_time_send = last->finish_time - crt_time; + } + + if (wait_time_idle > 0 || wait_time_send > 0) { + long long wait_time = 0; + if (wait_time_idle > 0) + wait_time = wait_time_idle; + if (wait_time_send > 0 && wait_time_send < wait_time) + wait_time = wait_time_send; + + // printf("Sleeping %lld\n", wait_time); + usleep(wait_time); + } else { + pthread_mutex_lock(&buffer_lock); + assert(!buffer->size); +#if DEBUG + printf("Waiting on cond\n"); +#endif + pthread_cond_wait(&buffer_cond, &buffer_lock); + pthread_mutex_unlock(&buffer_lock); + } + } + + return NULL; +} + +void *run_forwarding(void *param) +{ + msg *m; + + while (1) { + int overflow; + m = receive_message1(); + DIE(m == NULL, "Read error"); + + // check queue space + pthread_mutex_lock(&buffer_lock); + overflow = buffer->size >= BUFFER_SIZE; + pthread_mutex_unlock(&buffer_lock); + + if (overflow || (rand() % 100) < loss) { + // just drop message + free(m); + printf("Dropped packet\n"); + } else { + if (rand() % 100 < corrupt) { + // flip a random bit in a randomly chosen byte + // of the payload + int random_byte = rand() % m->len; + int random_bit = rand(); + m->payload[random_byte] ^= 1 + << (random_bit % 8); + + if (rand() % 100 < corrupt2) { + // flip a second bit in the same byte + int random_bit2; + do { + random_bit2 = rand(); + } while (random_bit2 == random_bit); + m->payload[random_byte] ^= + 1 << (random_bit2 % 8); + } + // printf("Enqueue 1."); + pthread_mutex_lock(&buffer_lock); + enqueue(buffer, m); + pthread_cond_signal(&buffer_cond); + pthread_mutex_unlock(&buffer_lock); + // printf("Done!\n"); + } + } + } +} + +void *run_reverse_forwarding(void *param) +{ + msg *m; + + while (1) { + m = receive_message2(); + DIE(m == NULL, "Read error"); + + send_message1(m); + free(m); + } +} + +#define SPEED 1 +#define DELAY 2 +#define LOSS 3 +#define CORRUPT 4 +#define CORRUPT2 5 +#define REORDER 6 + +int split_param(char *p, int *type, double *value) +{ + char c[100]; + int crt = 0, t = 1; + + for (; *p != 0; p++) { + if (t && *p == '=') { + t = 0; + c[crt] = 0; + crt = 0; + + if (!strcasecmp(c, "speed")) + *type = SPEED; + else if (!strcasecmp(c, "delay")) + *type = DELAY; + else if (!strcasecmp(c, "loss")) + *type = LOSS; + else if (!strcasecmp(c, "corrupt")) + *type = CORRUPT; + else if (!strcasecmp(c, "corrupt2")) + *type = CORRUPT2; + else if (!strcasecmp(c, "reorder")) + *type = REORDER; + else { + printf("Unknown parameter %s\n", c); + return -1; + } + } else + c[crt++] = *p; + } + *value = atof(c); + return 0; +} + +int guess_hz() +{ + long long a, b, diff = 0; + int i; + + for (i = 0; i < 100; i++) { + a = now(); + // 0.1ms + usleep(100); + b = now(); + diff += (b - a); + } + + int error = (int)(diff / i - 100); + printf("Average error 100 was %d\n", error); + + diff = 0; + for (i = 0; i < 100; i++) { + a = now(); + // 0.1ms + usleep(1000); + b = now(); + diff += (b - a); + } + + error = (int)(diff / i - 1000); + printf("Average error 1000 was %d\n", error); + return error; +} + +int main(int argc, char **argv) +{ + pthread_t link_thread, fw_thread; + int i; + for (i = 1; i < argc; i++) { + int type; + double value; + if (split_param(argv[i], &type, &value) < 0) { + printf("Usage %s speed=[speed in mb/s] delay=[delay in ms] " + "loss=[percent of packets] corrupt=[percent of packets]\n", + argv[0]); + return -1; + } + + switch (type) { + case SPEED: + printf("Setting speed to %f Mb/s\n", value); + serialization_delay = 2 * 11200 / value; + break; + case DELAY: + printf("Setting delay %f to ms\n", value); + delay = value * 1000; + break; + case LOSS: + printf("Setting loss rate to %f%%\n", value); + loss = value; + break; + case CORRUPT: + printf("Setting corruption rate to %f%%\n", value); + corrupt = value; + break; + case CORRUPT2: + printf("Setting double corruption to %f%%\n", value); + corrupt2 = value; + break; + case REORDER: + printf("Setting reorder rate to %f%%\n", value); + reorder = value; + break; + } + } + +#if DEBUG + guess_hz(); +#endif + + init_sockets(); + srand(time(NULL)); + buffer = create_queue(); + assert(!pthread_create(&link_thread, NULL, link_scheduler, NULL)); + assert(!pthread_create(&fw_thread, NULL, run_forwarding, NULL)); + + run_reverse_forwarding(NULL); + return 0; +} diff --git a/lab2/link_emulator/link.h b/common/link_emulator/link.h similarity index 56% rename from lab2/link_emulator/link.h rename to common/link_emulator/link.h index 92b64db0b579489f735064e9be2428ef1e984846..ab2a462c1e719d60c78968bb4a58395a23ebb0d5 100644 --- a/lab2/link_emulator/link.h +++ b/common/link_emulator/link.h @@ -1,10 +1,11 @@ -#ifndef LINK -#define LINK +#ifndef _LINK_H_ +#define _LINK_H_ + #include "lib.h" typedef struct { - msg* m; + msg *m; unsigned long long finish_time; } msg_in_flight; -#endif +#endif /* _LINK_H_ */ diff --git a/common/link_emulator/queue.c b/common/link_emulator/queue.c new file mode 100644 index 0000000000000000000000000000000000000000..88d3196c88e6971c8c2fd4035d8cc743cf09a8b9 --- /dev/null +++ b/common/link_emulator/queue.c @@ -0,0 +1,66 @@ +#include <assert.h> +#include <stdio.h> +#include <stdlib.h> +#include "queue.h" +#include "include/utils.h" + +void enqueue(queue * q, void *m) +{ + if (q->first == NULL) { + assert(q->last == NULL); + + q->first = (queue_entry *) malloc(sizeof(queue_entry)); + DIE(!q->first, "malloc"); + q->last = q->first; + } else { + queue_entry *t = (queue_entry *) malloc(sizeof(queue_entry)); + DIE(!t, "malloc"); + q->first->prev = t; + q->first = t; + } + + q->first->prev = NULL; + q->first->crt = m; + + q->size++; +} + +void *dequeue(queue * q) +{ + queue_entry *t; + void *m; + + if (q->first == NULL) { + assert(q->size == 0); + return NULL; + } else if (q->first == q->last) { + t = q->last; + assert(q->first->prev == NULL); + + q->first = q->last = NULL; + } else { + t = q->last; + q->last = q->last->prev; + } + + m = t->crt; + free(t); + q->size--; + + return m; +} + +queue *create_queue() +{ + queue *q = (queue *) malloc(sizeof(queue)); + DIE(!q, "malloc"); + q->first = NULL; + q->last = NULL; + q->size = 0; + return q; +} + +void destroy_queue(queue * q) +{ + assert(0); +} diff --git a/common/link_emulator/queue.h b/common/link_emulator/queue.h new file mode 100644 index 0000000000000000000000000000000000000000..08c5a65d242cea51c96a8998d3cb3db923a68f9c --- /dev/null +++ b/common/link_emulator/queue.h @@ -0,0 +1,25 @@ +#ifndef _QUEUE_H_ +#define _QUEUE_H_ + +#include "lib.h" + +struct q { + void* crt; + struct q *prev; +}; + +typedef struct q queue_entry; + +typedef struct { + int size; + queue_entry *first; + queue_entry *last; +} queue; + +void enqueue(queue *q,void *m); +void *dequeue(queue *q); + +queue *create_queue(); +void destroy_queue(queue *q); + +#endif /* _QUEUE_H_ */ diff --git a/common/run_experiment.sh b/common/run_experiment.sh new file mode 100755 index 0000000000000000000000000000000000000000..f363f62065d61990b2c2738fc29e14a8079d3a31 --- /dev/null +++ b/common/run_experiment.sh @@ -0,0 +1,24 @@ +#!/bin/bash + +SPEED=1 +DELAY=1 +LOSS=0 +# Adjust the corruption +CORRUPT=0 + +# Second bit corruption rate +CORRUPT2=0 + +{ + pkill -9 link + pkill -9 recv + pkill -9 send +} &> /dev/null + +./link_emulator/link speed=$SPEED delay=$DELAY loss=$LOSS corrupt=$CORRUPT \ + corrupt2=$CORRUPT2 > link_emulator.out 2> link_emulator.err & +sleep 1 +./recv & +sleep 1 + +./send diff --git a/common/utils.c b/common/utils.c new file mode 100644 index 0000000000000000000000000000000000000000..7714e53e08ea0781af5c155e6c0212e64b071289 --- /dev/null +++ b/common/utils.c @@ -0,0 +1,42 @@ +#include "include/utils.h" + +#include <stdio.h> +#include <stdlib.h> + +#define HEX_LINESIZE 16 + +void hex_dump(const void * addr, size_t size) +{ + int i; + unsigned char buff[HEX_LINESIZE+1]; + const unsigned char * pc = (const unsigned char *)addr; + + // Process every byte in the data. + for (i = 0; i < size; i++) { + // Multiple of HEX_LINESIZE means new or first line (with line offset). + if ((i % HEX_LINESIZE) == 0) { + // Only print previous-line ASCII buffer for lines beyond first. + if (i != 0) printf(" %s\n", buff); + printf(" %04x ", i); + } + + // Now the hex code for the specific character. + printf(" %02x", pc[i]); + + // And buffer a printable ASCII character for later. + if ((pc[i] < 0x20) || (pc[i] > 0x7e)) // isprint() may be better. + buff[i % HEX_LINESIZE] = '.'; + else + buff[i % HEX_LINESIZE] = pc[i]; + buff[(i % HEX_LINESIZE) + 1] = '\0'; + } + + // Pad out last line if not exactly HEX_LINESIZE characters. + while ((i % HEX_LINESIZE) != 0) { + printf(" "); + i++; + } + + // And print the final ASCII buffer. + printf(" %s\n", buff); +} diff --git a/lab2/Makefile b/lab2/Makefile index 7715dbc98d5b0351751df9a9e7bf12a799b8f81b..20341b2820b4a502de5d921230cc02118b24095f 100644 --- a/lab2/Makefile +++ b/lab2/Makefile @@ -1,19 +1,19 @@ -CFLAGS= -Wall -Werror -Wno-error=unused-variable +CFLAGS= -Wall -Werror -Wno-error=unused-variable -I../common/ all: send recv +../common/utils.o: + $(MAKE) -C ../common + link_emulator/lib.o: $(MAKE) -C link_emulator -send: send.o link_emulator/lib.o - gcc $(CFLAGS) -g send.o link_emulator/lib.o -o send - -recv: recv.o link_emulator/lib.o - gcc $(CFLAGS) -g recv.o link_emulator/lib.o -o recv +send: send.o link_emulator/lib.o ../common/utils.o -.c.o: - gcc $(CFLAGS) -g -c $? +recv: recv.o link_emulator/lib.o ../common/utils.o clean: $(MAKE) -C link_emulator clean -rm -f *.o send recv + +.PHONY: all clean diff --git a/lab2/common.h b/lab2/common.h index 18344a61becf9d773a778bdd0f6d572f1b5c0b68..94b55bdd1aa83d2f630b3b47fdbcd84549fd0fc5 100644 --- a/lab2/common.h +++ b/lab2/common.h @@ -5,14 +5,9 @@ /* Atributul este folosit pentru a anunta compilatorul sa nu alinieze structura */ /* DELIM | DATE | DELIM */ struct __attribute__((packed)) Frame { - char frame_delim_start[2]; /* DEL STX */ + char frame_delim_start[2]; /* DLE STX */ + /* TODO 2: Add source and destination */ char payload[30]; /* Datele pe care vrem sa le transmitem */ - char frame_delim_end[2]; /* DEL ETX */ + char frame_delim_end[2]; /* DLE ETX */ }; - -/* Sends one character to the other end via the Physical layer */ -int send_byte(char c); -/* Receives one character from the other end, if nothing is sent by the other end, returns a random character */ -char recv_byte(); - diff --git a/lab2/link_emulator b/lab2/link_emulator new file mode 120000 index 0000000000000000000000000000000000000000..ce372f42c8092972e2e4b833e566b786f3d73cc8 --- /dev/null +++ b/lab2/link_emulator @@ -0,0 +1 @@ +../common/link_emulator \ No newline at end of file diff --git a/lab2/link_emulator.err b/lab2/link_emulator.err new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/lab2/link_emulator.out b/lab2/link_emulator.out new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/lab2/link_emulator/Makefile b/lab2/link_emulator/Makefile deleted file mode 100644 index b2105de964c0cbc2b4c5832d70801110670a8740..0000000000000000000000000000000000000000 --- a/lab2/link_emulator/Makefile +++ /dev/null @@ -1,10 +0,0 @@ -all: link lib.o - -link: link.o queue.o - gcc -g link.o queue.o -o link -lpthread - -.c.o: - gcc -Wall -g -c $? -lpthread - -clean: - -rm *.o link diff --git a/lab2/link_emulator/lib.c b/lab2/link_emulator/lib.c deleted file mode 100644 index 1d9e87bc877c6dba8926f4a5175293e894586fe2..0000000000000000000000000000000000000000 --- a/lab2/link_emulator/lib.c +++ /dev/null @@ -1,105 +0,0 @@ -#include "lib.h" -#include <arpa/inet.h> -#include <poll.h> -//#include <stropts.h> -#include <netinet/in.h> -#include <stdio.h> -#include <stdlib.h> -#include <sys/types.h> -#include <sys/socket.h> -#include <unistd.h> -#include <string.h> - -struct sockaddr_in addr_local, addr_remote; -int s; -struct pollfd fds[1]; - -void set_local_port(int port) -{ - memset((char *) &addr_local, 0, sizeof(addr_local)); - addr_local.sin_family = AF_INET; - addr_local.sin_port = htons(port); - addr_local.sin_addr.s_addr = htonl(INADDR_ANY); -} - -void set_remote(char* ip, int port){ - memset((char *) &addr_remote, 0, sizeof(addr_remote)); - addr_remote.sin_family = AF_INET; - addr_remote.sin_port = htons(port); - if (inet_aton(ip, &addr_remote.sin_addr)==0) { - perror("inet_aton failed\n"); - exit(1); - } -} - -void init(char* remote, int REMOTE_PORT){ - if ((s=socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP))==-1){ - perror("Error creating socket"); - exit(1); - } - - set_local_port(0); - set_remote(remote,REMOTE_PORT); - - if (bind(s, (struct sockaddr*)&addr_local, sizeof(addr_local))==-1){ - perror("Failed to bind"); - exit(1); - } - - fds[0].fd = s; - fds[0].events = POLLIN; - - msg m; - send_message(&m); -} - -int send_message(const msg* m){ - return sendto(s, m, sizeof(msg), 0,(struct sockaddr*) &addr_remote, sizeof(addr_remote)); -} - -/*msg* receive_message(){ - msg* ret = (msg*)malloc(sizeof(msg)); - if (recvfrom(s, ret, sizeof(msg), 0, NULL, NULL)==-1){ - free(ret); - return NULL; - } - return ret; - }*/ - -int recv_message(msg* ret){ - return recvfrom(s, ret, sizeof(msg), 0, NULL, NULL); -} - -int send_byte(char c) { - msg m; - m.len = 1; - m.payload[0] = c; - printf("Sending byte %c \n", m.payload[0]); - return send_message(&m); -} - -char recv_byte() { - msg m; - int ret; - usleep(100000); - ret = recvfrom(s, &m, sizeof(msg), MSG_DONTWAIT, NULL, NULL); - if (ret < 0) { - char c = rand() % 128; - return c; - - } else { - return m.payload[0]; - } -} - -//timeout in millis -/*msg* receive_message_timeout(int timeout){ - int ret = poll(fds,1,timeout); - - if (ret>0){ - if (fds[0].revents & POLLIN) - return receive_message(); - } - - return NULL; - }*/ diff --git a/lab2/link_emulator/lib.h b/lab2/link_emulator/lib.h deleted file mode 100644 index b6f98b040fda0d8ee49efc3ea2faf949c2067d40..0000000000000000000000000000000000000000 --- a/lab2/link_emulator/lib.h +++ /dev/null @@ -1,23 +0,0 @@ -#ifndef LIB -#define LIB - -#define MAX_LEN 1400 - -typedef struct { - // int type; - int len; - char payload[MAX_LEN]; -} msg; - -void init(char* remote,int remote_port); -void set_local_port(int port); -void set_remote(char* ip, int port); -int send_message(const msg* m); -int recv_message(msg* r); -int send_byte(char c); -char recv_byte(); - -//msg* receive_message_timeout(int timeout); - -#endif - diff --git a/lab2/link_emulator/link.c b/lab2/link_emulator/link.c deleted file mode 100644 index a6c1c73fa63dddae6b861c8e7e78648eb67a4634..0000000000000000000000000000000000000000 --- a/lab2/link_emulator/link.c +++ /dev/null @@ -1,415 +0,0 @@ -#include <pthread.h> -#include <stdio.h> -#include <stdlib.h> -#include <assert.h> -#include <sys/time.h> -#include <arpa/inet.h> -#include <netinet/in.h> -#include <stdio.h> -#include <stdlib.h> -#include <sys/types.h> -#include <sys/socket.h> -#include <unistd.h> -#include <string.h> -//#include <asm/param.h> -#include "queue.h" -#include "link.h" - -#define DEBUG 0 - -int BUFFER_SIZE=1000; - -int serialization_delay = 1000; -int delay = 1000; -int loss = 0; -int corrupt = 0; - -#define CHANNEL_BUSY 1 -#define CHANNEL_IDLE 0 - -#define LOCAL_PORT1 10000 -#define LOCAL_PORT2 10001 - -pthread_mutex_t buffer_lock = PTHREAD_MUTEX_INITIALIZER; -pthread_cond_t buffer_cond = PTHREAD_COND_INITIALIZER; -queue* buffer; - -struct sockaddr_in local_addr1, remote_addr1; -struct sockaddr_in local_addr2, remote_addr2; - -int s1,s2; -socklen_t sz; - -//1 if a message was received on this link -int link_up1 = 0; -int link_up2 = 0; - -void init_sockets() -{ - /*LOCAL ADDRESSES*/ - - memset((char *) &local_addr1, 0, sizeof(local_addr1)); - local_addr1.sin_family = AF_INET; - local_addr1.sin_port = htons(LOCAL_PORT1); - local_addr1.sin_addr.s_addr = htonl(INADDR_ANY); - - memset((char *) &local_addr2, 0, sizeof(local_addr2)); - local_addr2.sin_family = AF_INET; - local_addr2.sin_port = htons(LOCAL_PORT2); - local_addr2.sin_addr.s_addr = htonl(INADDR_ANY); - - if ((s1=socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP))==-1){ - perror("Error creating socket"); - exit(1); - } - - //now bind - if (bind(s1, (struct sockaddr*)&local_addr1, sizeof(local_addr1))==-1){ - perror("Failed to bind s1"); - exit(1); - } - - if ((s2=socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP))==-1){ - perror("Error creating socket 2"); - exit(1); - } - - if (bind(s2, (struct sockaddr*)&local_addr2, sizeof(local_addr2))==-1){ - perror("Failed to bind s2"); - exit(1); - } -} - -int send_message1(const msg* m){ - if (!link_up1){ - printf("Trying to send a message but remote peer is not connected on my port %d\n",LOCAL_PORT1); - } - return sendto(s1, m, sizeof(msg), 0,(struct sockaddr*) &remote_addr1, sizeof(remote_addr1)); -} - -msg* receive_message1(){ - msg* ret; - - a: - ret = (msg*)malloc(sizeof(msg)); - - if (!link_up1){ - sz = sizeof(remote_addr1); - if (recvfrom(s1, ret, sizeof(msg), 0, (struct sockaddr*)&remote_addr1, &sz)==-1){ - free(ret); - return NULL; - } - - link_up1 = 1; - -#if DEBUG - printf("Link 1 is up, remote addr is %s port %d\n",inet_ntoa(remote_addr1.sin_addr),ntohs(remote_addr1.sin_port)); -#endif - - free(ret); - goto a; - } - else if (recvfrom(s1, ret, sizeof(msg), 0, NULL,NULL)==-1){ - free(ret); - return NULL; - } - return ret; -} - -int send_message2(const msg* m){ - if (!link_up2){ - printf("Trying to send a message but remote peer is not connected on my port %d\n",LOCAL_PORT2); - } - return sendto(s2, m, sizeof(msg), 0,(struct sockaddr*) &remote_addr2, sizeof(remote_addr2)); -} - -msg* receive_message2(){ - msg* ret; - - a: - ret = (msg*)malloc(sizeof(msg)); - if (!link_up2){ - sz = sizeof(remote_addr2); - if (recvfrom(s2, ret, sizeof(msg), 0, (struct sockaddr*)&remote_addr2, &sz)==-1){ - free(ret); - return NULL; - } - link_up2 = 1; - -#if DEBUG - printf("Link 2 is up, remote addr is %s port %d\n",inet_ntoa(remote_addr2.sin_addr),ntohs(remote_addr2.sin_port)); -#endif - - free(ret); - goto a; - } - else - if (recvfrom(s2, ret, sizeof(msg), 0, NULL, NULL)==-1){ - free(ret); - return NULL; - } - - return ret; -} - -unsigned long long now(){ - struct timeval b; - gettimeofday(&b,NULL); - return (unsigned long long)b.tv_sec*1000000+b.tv_usec; -} - -void* link_scheduler(void *argument) -{ - msg_in_flight* mif; - queue* in_flight = create_queue(); - long long idle_time = 0; - long long crt_time,wait_time_idle,wait_time_send; - int stuff; - - while (1){ - crt_time = now(); - -#if DEBUG - printf("In flight size %d at %lld\n",in_flight->size, crt_time); -#endif - - while (in_flight->size>0){ - msg_in_flight* last = (msg_in_flight*)in_flight->last->crt; - if (crt_time<last->finish_time){ - break; - } - - //else send first packet on the wire - mif = (msg_in_flight*)dequeue(in_flight); - if (!mif){ - printf("Error in deque: expecting non null msg!\n"); - exit(1); - } - if (send_message2(mif->m)<=0) - perror("SNDMSG2"); - -#if DEBUG - printf("Sending message\n"); -#endif - - free(mif->m); - free(mif); - mif = NULL; - } - - pthread_mutex_lock( &buffer_lock ); - stuff = buffer->size>0; - pthread_mutex_unlock( &buffer_lock ); - -#if DEBUG - printf("Stuff is %d\n",stuff); -#endif - - wait_time_send = wait_time_idle = 0; - - //crt_time = now(); - - //now see if we can put stuff in flight - if (stuff && crt_time>=idle_time){ - idle_time = crt_time + serialization_delay; - - mif = (msg_in_flight*)malloc(sizeof(msg_in_flight)); - assert(mif); - - pthread_mutex_lock( &buffer_lock ); - mif->m = (msg*)dequeue(buffer); - pthread_mutex_unlock( &buffer_lock ); - - assert(mif->m); - mif->finish_time = crt_time + serialization_delay + delay; - - //send message here from buffer to link - enqueue(in_flight,mif); - -#if DEBUG - printf("Enquing message\n"); -#endif - } - wait_time_idle = idle_time - crt_time; - - if (in_flight->size>0){ - msg_in_flight* last = (msg_in_flight*)in_flight->last->crt; - wait_time_send = last->finish_time-crt_time; - } - - if (wait_time_idle>0 || wait_time_send>0){ - long long wait_time = 0; - if (wait_time_idle>0) wait_time = wait_time_idle; - if (wait_time_send>0&&wait_time_send<wait_time) - wait_time = wait_time_send; - - //printf("Sleeping %lld\n", wait_time); - usleep(wait_time); - } - else { - pthread_mutex_lock( &buffer_lock ); - assert(!buffer->size); -#if DEBUG - printf("Waiting on cond\n"); -#endif - pthread_cond_wait(&buffer_cond,&buffer_lock); - pthread_mutex_unlock( &buffer_lock ); - } - } - - return NULL; -} - -void* run_forwarding(void* param){ - msg *m; - - while (1){ - int overflow; - m = receive_message1(); - if (m==NULL){ - perror("Read error"); - exit(1); - } - - //check queue space - pthread_mutex_lock( &buffer_lock ); - overflow = buffer->size>=BUFFER_SIZE; - pthread_mutex_unlock( &buffer_lock ); - - if (overflow || (rand()%100)<loss) { - //just drop message - free(m); - printf("Dropped packet\n"); - } - else { - if (rand()%100 < corrupt){ - m->payload[rand()%m->len] = rand()%128; - } - //printf("Enqueue 1."); - pthread_mutex_lock( &buffer_lock ); - enqueue(buffer,m); - pthread_cond_signal(&buffer_cond); - pthread_mutex_unlock(&buffer_lock); - //printf("Done!\n"); - } - } -} - -void* run_reverse_forwarding(void* param){ - msg *m; - - while (1){ - m = receive_message2(); - if (m==NULL){ - perror("Read error"); - exit(1); - } - - send_message1(m); - free(m); - } -} - -#define SPEED 1 -#define DELAY 2 -#define LOSS 3 -#define CORRUPT 4 - -int split_param(char* p,int * type, double* value){ - char c[100]; - int crt = 0, t=1; - - for (;*p!=0;p++){ - if (t && *p=='='){ - t = 0; - c[crt] = 0; - crt = 0; - - if (!strcasecmp(c,"speed")) - *type = SPEED; - else if (!strcasecmp(c,"delay")) - *type = DELAY; - else if (!strcasecmp(c,"loss")) - *type = LOSS; - else if (!strcasecmp(c,"corrupt")) - *type = CORRUPT; - else { - printf ("Unknown parameter %s\n",c); - return -1; - } - } - else c[crt++] = *p; - } - *value = atof(c); - return 0; -} - -int guess_hz(){ - long long a,b,diff = 0; - int i; - - for (i=0;i<100;i++){ - a = now(); - //0.1ms - usleep(100); - b = now(); - diff += (b-a); - } - - int error = (int)(diff/i-100); - printf("Average error 100 was %d\n",error); - - diff = 0; - for (i=0;i<100;i++){ - a = now(); - //0.1ms - usleep(1000); - b = now(); - diff += (b-a); - } - - error = (int)(diff/i-1000); - printf("Average error 1000 was %d\n",error); - return error; -} - -int main(int argc, char** argv){ - pthread_t link_thread, fw_thread; - int i; - for (i=1;i<argc;i++){ - int type; - double value; - if (split_param(argv[i],&type,&value)<0){ - printf("Usage %s speed=[speed in mb/s] delay=[delay in ms] loss=[percent of packets] corrupt=[percent of packets]\n",argv[0]); - return -1; - } - - switch(type){ - case SPEED: - printf("Setting speed to %f Mb/s\n",value); - serialization_delay = 2*11200/value;break; - case DELAY: - printf("Setting delay %f to ms\n",value); - delay = value*1000; break; - case LOSS: - printf("Setting loss rate to %f%%\n",value); - loss = value; break; - case CORRUPT: - printf("Setting corruption rate to %f%%\n",value); - corrupt = value; break; - } - } - -#if DEBUG - guess_hz(); -#endif - - init_sockets(); - srand(time(NULL)); - buffer = create_queue(); - assert(!pthread_create(&link_thread, NULL, link_scheduler, NULL)); - assert(!pthread_create(&fw_thread, NULL, run_forwarding, NULL)); - - run_reverse_forwarding(NULL); - return 0; -} diff --git a/lab2/link_emulator/queue.c b/lab2/link_emulator/queue.c deleted file mode 100644 index daced7e77ff0a452492049c5164c98a38b9c9fe6..0000000000000000000000000000000000000000 --- a/lab2/link_emulator/queue.c +++ /dev/null @@ -1,61 +0,0 @@ -#include <assert.h> -#include <stdio.h> -#include <stdlib.h> -#include "queue.h" - -void enqueue(queue* q,void* m){ - if (q->first==NULL){ - assert(q->last==NULL); - - q->first = (queue_entry*)malloc(sizeof(queue_entry)); - q->last = q->first; - } - else { - queue_entry * t = (queue_entry*)malloc(sizeof(queue_entry)); - q->first->prev = t; - q->first = t; - } - - q->first->prev = NULL; - q->first->crt = m; - - q->size++; -} - -void* dequeue(queue* q){ - queue_entry * t; - void* m; - - if (q->first==NULL){ - assert(q->size==0); - return NULL; - } - else if (q->first==q->last){ - t = q->last; - assert(q->first->prev==NULL); - - q->first = q->last = NULL; - } - else { - t = q->last; - q->last = q->last->prev; - } - - m = t->crt; - free(t); - q->size--; - - return m; -} - -queue* create_queue(){ - queue* q = (queue*)malloc(sizeof(queue)); - q->first = NULL; - q->last = NULL; - q->size = 0; - return q; -} - -void destroy_queue(queue* q){ - assert(0); -} diff --git a/lab2/link_emulator/queue.h b/lab2/link_emulator/queue.h deleted file mode 100644 index 9b6a45b0b5a77a3875e8523a52ad61bd48a69c5d..0000000000000000000000000000000000000000 --- a/lab2/link_emulator/queue.h +++ /dev/null @@ -1,25 +0,0 @@ -#ifndef QUEUE -#define QUEUE -#include "lib.h" - - -struct q { - void* crt; - struct q* prev; -}; - -typedef struct q queue_entry; - -typedef struct { - int size; - queue_entry* first; - queue_entry* last; -} queue; - -void enqueue(queue* q,void* m); -void* dequeue(queue* q); - -queue* create_queue(); -void destroy_queue(queue* q); - -#endif diff --git a/lab2/recv b/lab2/recv new file mode 100755 index 0000000000000000000000000000000000000000..ec239882d193b863ef0f6be1622bfcd711d80f54 Binary files /dev/null and b/lab2/recv differ diff --git a/lab2/recv.c b/lab2/recv.c index 99dba5d27133051a8898435ceef64bb876e95dfc..3e6d72d6da2f7223ea8e616d2a54b039c27af001 100644 --- a/lab2/recv.c +++ b/lab2/recv.c @@ -4,14 +4,20 @@ #include <unistd.h> #include <fcntl.h> #include "link_emulator/lib.h" - -/* Do not touch these two */ +#include "include/utils.h" + +/** + * You can change these to communicate with another colleague. + * There are several factors that could stop this from working over the + * internet, but if you're on the same network it should work. + * Just fill in their IP here and make sure that you use the same port. + */ #define HOST "127.0.0.1" #define PORT 10001 #include "common.h" -/* Our unqiue layer 2 ID */ +/* Our unique layer 2 ID */ static int ID = 123131; /* Function which our protocol implementation will provide to the upper layer. */ @@ -32,10 +38,11 @@ int recv_frame(char *buf, int size) } int main(int argc,char** argv){ - /* Do not touch this */ + /* Don't modify this */ init(HOST,PORT); - + // TODO remove these recives, whih are hardcoded to receive a "Hello" + // message, and replace them with code that can receive any message. char c; /* Wait for the start of a frame */ diff --git a/lab2/run_experiment.sh b/lab2/run_experiment.sh deleted file mode 100755 index fadeeb3a1182ae5cde6a7b5f4161b98039fcd7f2..0000000000000000000000000000000000000000 --- a/lab2/run_experiment.sh +++ /dev/null @@ -1,23 +0,0 @@ -#!/bin/bash - -SPEED=1 -DELAY=1 -LOSS=0 -CORRUPT=0 - -{ - killall link - killall recv - killall send -} &> /dev/null - -./link_emulator/link speed=$SPEED delay=$DELAY loss=$LOSS corrupt=$CORRUPT &> /dev/null & -sleep 1 -./recv & -sleep 1 - -./send - -#sleep 2 -#echo "Finished transfer, checking files" -#diff tema.txt recv_tema.txt diff --git a/lab2/run_experiment.sh b/lab2/run_experiment.sh new file mode 120000 index 0000000000000000000000000000000000000000..a204cff38ba9a5a5601351d3569f0c0bd8d05fde --- /dev/null +++ b/lab2/run_experiment.sh @@ -0,0 +1 @@ +../common/run_experiment.sh \ No newline at end of file diff --git a/lab2/send b/lab2/send new file mode 100755 index 0000000000000000000000000000000000000000..4599f0679206ff30a524decc8981d7142fcac658 Binary files /dev/null and b/lab2/send differ diff --git a/lab2/send.c b/lab2/send.c index 33fdd738409cf61c86049f8458720b23ddcd8c26..7e70a31960580501367f020bb8f9bf8eded35f11 100644 --- a/lab2/send.c +++ b/lab2/send.c @@ -6,8 +6,14 @@ #include <sys/types.h> #include <sys/stat.h> #include "link_emulator/lib.h" - -/* We don't touch this */ +#include "include/utils.h" + +/** + * You can change these to communicate with another colleague. + * There are several factors that could stop this from working over the + * internet, but if you're on the same network it should work. + * Just fill in their IP here and make sure that you use the same port. + */ #define HOST "127.0.0.1" #define PORT 10000 @@ -38,6 +44,8 @@ int main(int argc,char** argv){ // Don't touch this init(HOST,PORT); + // TODO remove these sends, whih are hardcoded to send a "Hello" + // message, and replace them with code that can send any message. /* Send Hello */ send_byte(DLE); send_byte(STX); diff --git a/lab3/Makefile b/lab3/Makefile index 364094868399f95f307bd0a48dc41add8a096111..c1f3d41dfe30c45bec5f6cccff1304307362eab1 100644 --- a/lab3/Makefile +++ b/lab3/Makefile @@ -1,21 +1,21 @@ -CFLAGS= -Wall -Werror -Wno-error=unused-variable +CFLAGS= -Wall -Werror -Wno-error=unused-variable -I../common/ all: send recv +../common/utils.o: + $(MAKE) -C ../common + link_emulator/lib.o: $(MAKE) -C link_emulator -send: send.o link_emulator/lib.o common.o - gcc $(CFLAGS) -g send.o link_emulator/lib.o common.o -o send +send: send.o link_emulator/lib.o common.o ../common/utils.o -recv: recv.o link_emulator/lib.o common.o - gcc $(CFLAGS) -g recv.o link_emulator/lib.o common.o -o recv +recv: recv.o link_emulator/lib.o common.o ../common/utils.o common.o: common.c common.h -.c.o: - gcc $(CFLAGS) -g -c $? - clean: $(MAKE) -C link_emulator clean -rm -f *.o send recv common.h.gch + +.PHONY: all clean diff --git a/lab3/link_emulator b/lab3/link_emulator new file mode 120000 index 0000000000000000000000000000000000000000..ce372f42c8092972e2e4b833e566b786f3d73cc8 --- /dev/null +++ b/lab3/link_emulator @@ -0,0 +1 @@ +../common/link_emulator \ No newline at end of file diff --git a/lab3/link_emulator/lib.c b/lab3/link_emulator/lib.c deleted file mode 100644 index 360ffbea389616bc83970414866f8c353fa02abe..0000000000000000000000000000000000000000 --- a/lab3/link_emulator/lib.c +++ /dev/null @@ -1,103 +0,0 @@ -#include "lib.h" -#include <arpa/inet.h> -#include <poll.h> -//#include <stropts.h> -#include <netinet/in.h> -#include <stdio.h> -#include <stdlib.h> -#include <sys/types.h> -#include <sys/socket.h> -#include <unistd.h> -#include <string.h> - -struct sockaddr_in addr_local, addr_remote; -int s; -struct pollfd fds[1]; - -static int send_message(const msg* m); - -void set_local_port(int port) -{ - memset((char *) &addr_local, 0, sizeof(addr_local)); - addr_local.sin_family = AF_INET; - addr_local.sin_port = htons(port); - addr_local.sin_addr.s_addr = htonl(INADDR_ANY); -} - -void set_remote(char* ip, int port){ - memset((char *) &addr_remote, 0, sizeof(addr_remote)); - addr_remote.sin_family = AF_INET; - addr_remote.sin_port = htons(port); - if (inet_aton(ip, &addr_remote.sin_addr)==0) { - perror("inet_aton failed\n"); - exit(1); - } -} - -void init(char* remote, int REMOTE_PORT){ - if ((s=socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP))==-1){ - perror("Error creating socket"); - exit(1); - } - - set_local_port(0); - set_remote(remote,REMOTE_PORT); - - if (bind(s, (struct sockaddr*)&addr_local, sizeof(addr_local))==-1){ - perror("Failed to bind"); - exit(1); - } - - fds[0].fd = s; - fds[0].events = POLLIN; - - msg m; - send_message(&m); -} - -int send_message(const msg* m){ - return sendto(s, m, sizeof(msg), 0,(struct sockaddr*) &addr_remote, sizeof(addr_remote)); -} - -void link_send(void *buf, int len) { - msg m; - - memcpy(m.payload, buf, len); - m.len = len; - - send_message(&m); -} - -/*msg* receive_message(){ - msg* ret = (msg*)malloc(sizeof(msg)); - if (recvfrom(s, ret, sizeof(msg), 0, NULL, NULL)==-1){ - free(ret); - return NULL; - } - return ret; - }*/ - -int recv_message(msg* ret){ - return recvfrom(s, ret, sizeof(msg), 0, NULL, NULL); -} - - -int link_recv(void *buf, int len) { - msg m; - recv_message(&m); - int r = m.len < len ? m.len : len; - memcpy(buf, m.payload, r); - return r; -} - -//timeout in millis -/*msg* receive_message_timeout(int timeout){ - int ret = poll(fds,1,timeout); - - if (ret>0){ - if (fds[0].revents & POLLIN) - return receive_message(); - } - - return NULL; - }*/ diff --git a/lab3/link_emulator/lib.h b/lab3/link_emulator/lib.h deleted file mode 100644 index 5d8634c71f4ba58558423b65bd89e4d9f0b19f76..0000000000000000000000000000000000000000 --- a/lab3/link_emulator/lib.h +++ /dev/null @@ -1,19 +0,0 @@ -#ifndef LIB -#define LIB - -#include <stddef.h> - -#define MAX_LEN 1500 - -typedef struct { - int len; - char payload[MAX_LEN]; -} msg; - -void init(char* remote,int remote_port); -void set_local_port(int port); -void set_remote(char* ip, int port); -int link_recv(void *buf, int len); -void link_send(void *buf, int len); - -#endif diff --git a/lab3/link_emulator/link.c b/lab3/link_emulator/link.c deleted file mode 100644 index 71b18ab3bbec1c6c2af24cf21656e414e3f01ef0..0000000000000000000000000000000000000000 --- a/lab3/link_emulator/link.c +++ /dev/null @@ -1,428 +0,0 @@ -#include <pthread.h> -#include <stdio.h> -#include <stdlib.h> -#include <assert.h> -#include <sys/time.h> -#include <arpa/inet.h> -#include <netinet/in.h> -#include <stdio.h> -#include <stdlib.h> -#include <sys/types.h> -#include <sys/socket.h> -#include <unistd.h> -#include <string.h> -//#include <asm/param.h> -#include "queue.h" -#include "link.h" - -#define DEBUG 0 - -int BUFFER_SIZE=1000; - -int serialization_delay = 1000; -int delay = 1000; -int loss = 0; -int corrupt = 0; -int corrupt2 = 0; - -#define CHANNEL_BUSY 1 -#define CHANNEL_IDLE 0 - -#define LOCAL_PORT1 10000 -#define LOCAL_PORT2 10001 - -pthread_mutex_t buffer_lock = PTHREAD_MUTEX_INITIALIZER; -pthread_cond_t buffer_cond = PTHREAD_COND_INITIALIZER; -queue* buffer; - -struct sockaddr_in local_addr1, remote_addr1; -struct sockaddr_in local_addr2, remote_addr2; - -int s1,s2; -socklen_t sz; - -//1 if a message was received on this link -int link_up1 = 0; -int link_up2 = 0; - -void init_sockets() -{ - /*LOCAL ADDRESSES*/ - - memset((char *) &local_addr1, 0, sizeof(local_addr1)); - local_addr1.sin_family = AF_INET; - local_addr1.sin_port = htons(LOCAL_PORT1); - local_addr1.sin_addr.s_addr = htonl(INADDR_ANY); - - memset((char *) &local_addr2, 0, sizeof(local_addr2)); - local_addr2.sin_family = AF_INET; - local_addr2.sin_port = htons(LOCAL_PORT2); - local_addr2.sin_addr.s_addr = htonl(INADDR_ANY); - - if ((s1=socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP))==-1){ - perror("Error creating socket"); - exit(1); - } - - //now bind - if (bind(s1, (struct sockaddr*)&local_addr1, sizeof(local_addr1))==-1){ - perror("Failed to bind s1"); - exit(1); - } - - if ((s2=socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP))==-1){ - perror("Error creating socket 2"); - exit(1); - } - - if (bind(s2, (struct sockaddr*)&local_addr2, sizeof(local_addr2))==-1){ - perror("Failed to bind s2"); - exit(1); - } -} - -int send_message1(const msg* m){ - if (!link_up1){ - printf("Trying to send a message but remote peer is not connected on my port %d\n",LOCAL_PORT1); - } - return sendto(s1, m, sizeof(msg), 0,(struct sockaddr*) &remote_addr1, sizeof(remote_addr1)); -} - -msg* receive_message1(){ - msg* ret; - - a: - ret = (msg*)malloc(sizeof(msg)); - - if (!link_up1){ - sz = sizeof(remote_addr1); - if (recvfrom(s1, ret, sizeof(msg), 0, (struct sockaddr*)&remote_addr1, &sz)==-1){ - free(ret); - return NULL; - } - - link_up1 = 1; - -#if DEBUG - printf("Link 1 is up, remote addr is %s port %d\n",inet_ntoa(remote_addr1.sin_addr),ntohs(remote_addr1.sin_port)); -#endif - - free(ret); - goto a; - } - else if (recvfrom(s1, ret, sizeof(msg), 0, NULL,NULL)==-1){ - free(ret); - return NULL; - } - return ret; -} - -int send_message2(const msg* m){ - if (!link_up2){ - printf("Trying to send a message but remote peer is not connected on my port %d\n",LOCAL_PORT2); - } - return sendto(s2, m, sizeof(msg), 0,(struct sockaddr*) &remote_addr2, sizeof(remote_addr2)); -} - -msg* receive_message2(){ - msg* ret; - - a: - ret = (msg*)malloc(sizeof(msg)); - if (!link_up2){ - sz = sizeof(remote_addr2); - if (recvfrom(s2, ret, sizeof(msg), 0, (struct sockaddr*)&remote_addr2, &sz)==-1){ - free(ret); - return NULL; - } - link_up2 = 1; - -#if DEBUG - printf("Link 2 is up, remote addr is %s port %d\n",inet_ntoa(remote_addr2.sin_addr),ntohs(remote_addr2.sin_port)); -#endif - - free(ret); - goto a; - } - else - if (recvfrom(s2, ret, sizeof(msg), 0, NULL, NULL)==-1){ - free(ret); - return NULL; - } - - return ret; -} - -unsigned long long now(){ - struct timeval b; - gettimeofday(&b,NULL); - return (unsigned long long)b.tv_sec*1000000+b.tv_usec; -} - -void* link_scheduler(void *argument) -{ - msg_in_flight* mif; - queue* in_flight = create_queue(); - long long idle_time = 0; - long long crt_time,wait_time_idle,wait_time_send; - int stuff; - - while (1){ - crt_time = now(); - -#if DEBUG - printf("In flight size %d at %lld\n",in_flight->size, crt_time); -#endif - - while (in_flight->size>0){ - msg_in_flight* last = (msg_in_flight*)in_flight->last->crt; - if (crt_time<last->finish_time){ - break; - } - - //else send first packet on the wire - mif = (msg_in_flight*)dequeue(in_flight); - if (!mif){ - printf("Error in deque: expecting non null msg!\n"); - exit(1); - } - if (send_message2(mif->m)<=0) - perror("SNDMSG2"); - -#if DEBUG - printf("Sending message\n"); -#endif - - free(mif->m); - free(mif); - mif = NULL; - } - - pthread_mutex_lock( &buffer_lock ); - stuff = buffer->size>0; - pthread_mutex_unlock( &buffer_lock ); - -#if DEBUG - printf("Stuff is %d\n",stuff); -#endif - - wait_time_send = wait_time_idle = 0; - - //crt_time = now(); - - //now see if we can put stuff in flight - if (stuff && crt_time>=idle_time){ - idle_time = crt_time + serialization_delay; - - mif = (msg_in_flight*)malloc(sizeof(msg_in_flight)); - assert(mif); - - pthread_mutex_lock( &buffer_lock ); - mif->m = (msg*)dequeue(buffer); - pthread_mutex_unlock( &buffer_lock ); - - assert(mif->m); - mif->finish_time = crt_time + serialization_delay + delay; - - //send message here from buffer to link - enqueue(in_flight,mif); - -#if DEBUG - printf("Enquing message\n"); -#endif - } - wait_time_idle = idle_time - crt_time; - - if (in_flight->size>0){ - msg_in_flight* last = (msg_in_flight*)in_flight->last->crt; - wait_time_send = last->finish_time-crt_time; - } - - if (wait_time_idle>0 || wait_time_send>0){ - long long wait_time = 0; - if (wait_time_idle>0) wait_time = wait_time_idle; - if (wait_time_send>0&&wait_time_send<wait_time) - wait_time = wait_time_send; - - //printf("Sleeping %lld\n", wait_time); - usleep(wait_time); - } - else { - pthread_mutex_lock( &buffer_lock ); - assert(!buffer->size); -#if DEBUG - printf("Waiting on cond\n"); -#endif - pthread_cond_wait(&buffer_cond,&buffer_lock); - pthread_mutex_unlock( &buffer_lock ); - } - } - - return NULL; -} - -void* run_forwarding(void* param){ - msg *m; - - while (1){ - int overflow; - m = receive_message1(); - if (m==NULL){ - perror("Read error"); - exit(1); - } - - //check queue space - pthread_mutex_lock( &buffer_lock ); - overflow = buffer->size>=BUFFER_SIZE; - pthread_mutex_unlock( &buffer_lock ); - - if (overflow || (rand()%100)<loss) { - //just drop message - free(m); - printf("Dropped packet\n"); - } - else { - if (rand()%100 < corrupt){ - //flip a random bit in a randomly chosen byte of the payload - int random_byte = rand() % m->len; - int random_bit = rand(); - m->payload[random_byte] ^= 1 << (random_bit % 8); - if (corrupt2) - m->payload[random_byte] ^= 1 << (random_bit % 8); - } - //printf("Enqueue 1."); - pthread_mutex_lock( &buffer_lock ); - enqueue(buffer,m); - pthread_cond_signal(&buffer_cond); - pthread_mutex_unlock(&buffer_lock); - //printf("Done!\n"); - } - } -} - -void* run_reverse_forwarding(void* param){ - msg *m; - - while (1){ - m = receive_message2(); - if (m==NULL){ - perror("Read error"); - exit(1); - } - - send_message1(m); - free(m); - } -} - -#define SPEED 1 -#define DELAY 2 -#define LOSS 3 -#define CORRUPT 4 -#define CORRUPT2 5 - -int split_param(char* p,int * type, double* value){ - char c[100]; - int crt = 0, t=1; - - for (;*p!=0;p++){ - if (t && *p=='='){ - t = 0; - c[crt] = 0; - crt = 0; - - if (!strcasecmp(c,"speed")) - *type = SPEED; - else if (!strcasecmp(c,"delay")) - *type = DELAY; - else if (!strcasecmp(c,"loss")) - *type = LOSS; - else if (!strcasecmp(c,"corrupt")) - *type = CORRUPT; - else if (!strcasecmp(c,"corrupt2")) - *type = CORRUPT2; - else { - printf ("Unknown parameter %s\n",c); - return -1; - } - } - else c[crt++] = *p; - } - *value = atof(c); - return 0; -} - -int guess_hz(){ - long long a,b,diff = 0; - int i; - - for (i=0;i<100;i++){ - a = now(); - //0.1ms - usleep(100); - b = now(); - diff += (b-a); - } - - int error = (int)(diff/i-100); - printf("Average error 100 was %d\n",error); - - diff = 0; - for (i=0;i<100;i++){ - a = now(); - //0.1ms - usleep(1000); - b = now(); - diff += (b-a); - } - - error = (int)(diff/i-1000); - printf("Average error 1000 was %d\n",error); - return error; -} - -int main(int argc, char** argv){ - pthread_t link_thread, fw_thread; - int i; - for (i=1;i<argc;i++){ - int type; - double value; - if (split_param(argv[i],&type,&value)<0){ - printf("Usage %s speed=[speed in mb/s] delay=[delay in ms] loss=[percent of packets] corrupt=[percent of packets]\n",argv[0]); - return -1; - } - - switch(type){ - case SPEED: - printf("Setting speed to %f Mb/s\n",value); - serialization_delay = 2*11200/value;break; - case DELAY: - printf("Setting delay %f to ms\n",value); - delay = value*1000; break; - case LOSS: - printf("Setting loss rate to %f%%\n",value); - loss = value; break; - case CORRUPT: - printf("Setting corruption rate to %f%%\n",value); - corrupt = value; break; - - case CORRUPT2: - printf("Setting double corruption to %f\n", value); - corrupt2 = value; break; - } - } - -#if DEBUG - guess_hz(); -#endif - - init_sockets(); - srand(time(NULL)); - buffer = create_queue(); - assert(!pthread_create(&link_thread, NULL, link_scheduler, NULL)); - assert(!pthread_create(&fw_thread, NULL, run_forwarding, NULL)); - - run_reverse_forwarding(NULL); - return 0; -} diff --git a/lab3/link_emulator/link.h b/lab3/link_emulator/link.h deleted file mode 100644 index 92b64db0b579489f735064e9be2428ef1e984846..0000000000000000000000000000000000000000 --- a/lab3/link_emulator/link.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef LINK -#define LINK -#include "lib.h" - -typedef struct { - msg* m; - unsigned long long finish_time; -} msg_in_flight; - -#endif diff --git a/lab3/link_emulator/queue.c b/lab3/link_emulator/queue.c deleted file mode 100644 index daced7e77ff0a452492049c5164c98a38b9c9fe6..0000000000000000000000000000000000000000 --- a/lab3/link_emulator/queue.c +++ /dev/null @@ -1,61 +0,0 @@ -#include <assert.h> -#include <stdio.h> -#include <stdlib.h> -#include "queue.h" - -void enqueue(queue* q,void* m){ - if (q->first==NULL){ - assert(q->last==NULL); - - q->first = (queue_entry*)malloc(sizeof(queue_entry)); - q->last = q->first; - } - else { - queue_entry * t = (queue_entry*)malloc(sizeof(queue_entry)); - q->first->prev = t; - q->first = t; - } - - q->first->prev = NULL; - q->first->crt = m; - - q->size++; -} - -void* dequeue(queue* q){ - queue_entry * t; - void* m; - - if (q->first==NULL){ - assert(q->size==0); - return NULL; - } - else if (q->first==q->last){ - t = q->last; - assert(q->first->prev==NULL); - - q->first = q->last = NULL; - } - else { - t = q->last; - q->last = q->last->prev; - } - - m = t->crt; - free(t); - q->size--; - - return m; -} - -queue* create_queue(){ - queue* q = (queue*)malloc(sizeof(queue)); - q->first = NULL; - q->last = NULL; - q->size = 0; - return q; -} - -void destroy_queue(queue* q){ - assert(0); -} diff --git a/lab3/link_emulator/queue.h b/lab3/link_emulator/queue.h deleted file mode 100644 index 9b6a45b0b5a77a3875e8523a52ad61bd48a69c5d..0000000000000000000000000000000000000000 --- a/lab3/link_emulator/queue.h +++ /dev/null @@ -1,25 +0,0 @@ -#ifndef QUEUE -#define QUEUE -#include "lib.h" - - -struct q { - void* crt; - struct q* prev; -}; - -typedef struct q queue_entry; - -typedef struct { - int size; - queue_entry* first; - queue_entry* last; -} queue; - -void enqueue(queue* q,void* m); -void* dequeue(queue* q); - -queue* create_queue(); -void destroy_queue(queue* q); - -#endif diff --git a/lab3/recv.c b/lab3/recv.c index 0372ee45ca230947628dee115ce8f1b4eb29aece..84f3e99bfe2aa8d2f7399955da3d1cbb810a49d9 100644 --- a/lab3/recv.c +++ b/lab3/recv.c @@ -6,7 +6,14 @@ #include <arpa/inet.h> #include "common.h" #include "link_emulator/lib.h" - +#include "include/utils.h" + +/** + * You can change these to communicate with another colleague. + * There are several factors that could stop this from working over the + * internet, but if you're on the same network it should work. + * Just fill in their IP here and make sure that you use the same port. + */ #define HOST "127.0.0.1" #define PORT 10001 @@ -19,10 +26,7 @@ int main(int argc,char** argv) { /* Receive the frame from the link */ int len = link_recv(&t, sizeof(struct l3_msg)); - if (len < 0){ - perror("Receive message"); - return -1; - } + DIE(len < 0, "Receive message"); /* We have to convert it to host order */ uint32_t recv_sum = ntohl(t.hdr.sum); diff --git a/lab3/run_experiment.sh b/lab3/run_experiment.sh deleted file mode 100755 index 73813130efa7cd0bc0449473ba287de6c007ad3a..0000000000000000000000000000000000000000 --- a/lab3/run_experiment.sh +++ /dev/null @@ -1,23 +0,0 @@ -#!/bin/bash - -SPEED=1 -DELAY=1 -LOSS=0 -# Adjust the corruption -CORRUPT=80 - -# Second bit corruption rate -CORRUPT2=0 - -{ - pkill -9 link - pkill -9 recv - pkill -9 send -} &> /dev/null - -./link_emulator/link speed=$SPEED delay=$DELAY loss=$LOSS corrupt=$CORRUPT corrupt2=$CORRUPT2 & -sleep 1 -./recv & -sleep 1 - -./send diff --git a/lab3/run_experiment.sh b/lab3/run_experiment.sh new file mode 120000 index 0000000000000000000000000000000000000000..a204cff38ba9a5a5601351d3569f0c0bd8d05fde --- /dev/null +++ b/lab3/run_experiment.sh @@ -0,0 +1 @@ +../common/run_experiment.sh \ No newline at end of file diff --git a/lab3/send.c b/lab3/send.c index 0c6e8d463a2aacbaef6150243938e64c53da2c13..c9f4e5b203d9838cf1b06a7e09ff81187bded35a 100644 --- a/lab3/send.c +++ b/lab3/send.c @@ -8,6 +8,7 @@ #include "common.h" #include "link_emulator/lib.h" #include <arpa/inet.h> +#include "include/utils.h" #define HOST "127.0.0.1" #define PORT 10000