From 2c4a43756ff76f84dc151088153266c81efda213 Mon Sep 17 00:00:00 2001
From: Mihai-Valentin DUMITRU <mihai.dumitru2201@upb.ro>
Date: Sat, 24 Feb 2024 13:07:59 +0200
Subject: [PATCH] refactor the two link emulator labs

---
 common/Makefile                         |   8 +
 common/include/utils.h                  |  18 +
 common/link_emulator/.clang-format      | 560 ++++++++++++++++++++++++
 {lab3 => common}/link_emulator/Makefile |   4 +-
 common/link_emulator/lib.c              | 117 +++++
 common/link_emulator/lib.h              |  25 ++
 common/link_emulator/link.c             | 465 ++++++++++++++++++++
 {lab2 => common}/link_emulator/link.h   |   9 +-
 common/link_emulator/queue.c            |  66 +++
 common/link_emulator/queue.h            |  25 ++
 common/run_experiment.sh                |  24 +
 common/utils.c                          |  42 ++
 lab2/Makefile                           |  16 +-
 lab2/common.h                           |  11 +-
 lab2/link_emulator                      |   1 +
 lab2/link_emulator.err                  |   0
 lab2/link_emulator.out                  |   0
 lab2/link_emulator/Makefile             |  10 -
 lab2/link_emulator/lib.c                | 105 -----
 lab2/link_emulator/lib.h                |  23 -
 lab2/link_emulator/link.c               | 415 ------------------
 lab2/link_emulator/queue.c              |  61 ---
 lab2/link_emulator/queue.h              |  25 --
 lab2/recv                               | Bin 0 -> 23120 bytes
 lab2/recv.c                             |  17 +-
 lab2/run_experiment.sh                  |  24 +-
 lab2/send                               | Bin 0 -> 23072 bytes
 lab2/send.c                             |  12 +-
 lab3/Makefile                           |  16 +-
 lab3/link_emulator                      |   1 +
 lab3/link_emulator/lib.c                | 103 -----
 lab3/link_emulator/lib.h                |  19 -
 lab3/link_emulator/link.c               | 428 ------------------
 lab3/link_emulator/link.h               |  10 -
 lab3/link_emulator/queue.c              |  61 ---
 lab3/link_emulator/queue.h              |  25 --
 lab3/recv.c                             |  14 +-
 lab3/run_experiment.sh                  |  24 +-
 lab3/send.c                             |   1 +
 39 files changed, 1412 insertions(+), 1373 deletions(-)
 create mode 100644 common/Makefile
 create mode 100644 common/include/utils.h
 create mode 100644 common/link_emulator/.clang-format
 rename {lab3 => common}/link_emulator/Makefile (71%)
 create mode 100644 common/link_emulator/lib.c
 create mode 100644 common/link_emulator/lib.h
 create mode 100644 common/link_emulator/link.c
 rename {lab2 => common}/link_emulator/link.h (56%)
 create mode 100644 common/link_emulator/queue.c
 create mode 100644 common/link_emulator/queue.h
 create mode 100755 common/run_experiment.sh
 create mode 100644 common/utils.c
 create mode 120000 lab2/link_emulator
 create mode 100644 lab2/link_emulator.err
 create mode 100644 lab2/link_emulator.out
 delete mode 100644 lab2/link_emulator/Makefile
 delete mode 100644 lab2/link_emulator/lib.c
 delete mode 100644 lab2/link_emulator/lib.h
 delete mode 100644 lab2/link_emulator/link.c
 delete mode 100644 lab2/link_emulator/queue.c
 delete mode 100644 lab2/link_emulator/queue.h
 create mode 100755 lab2/recv
 mode change 100755 => 120000 lab2/run_experiment.sh
 create mode 100755 lab2/send
 create mode 120000 lab3/link_emulator
 delete mode 100644 lab3/link_emulator/lib.c
 delete mode 100644 lab3/link_emulator/lib.h
 delete mode 100644 lab3/link_emulator/link.c
 delete mode 100644 lab3/link_emulator/link.h
 delete mode 100644 lab3/link_emulator/queue.c
 delete mode 100644 lab3/link_emulator/queue.h
 mode change 100755 => 120000 lab3/run_experiment.sh

diff --git a/common/Makefile b/common/Makefile
new file mode 100644
index 0000000..fbedc82
--- /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 0000000..b276371
--- /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 0000000..fa95943
--- /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 bc25fa3..9503a5a 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 0000000..49181d2
--- /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 0000000..5d4fca6
--- /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 0000000..a714173
--- /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 92b64db..ab2a462 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 0000000..88d3196
--- /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 0000000..08c5a65
--- /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 0000000..f363f62
--- /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 0000000..7714e53
--- /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 7715dbc..20341b2 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 18344a6..94b55bd 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 0000000..ce372f4
--- /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 0000000..e69de29
diff --git a/lab2/link_emulator.out b/lab2/link_emulator.out
new file mode 100644
index 0000000..e69de29
diff --git a/lab2/link_emulator/Makefile b/lab2/link_emulator/Makefile
deleted file mode 100644
index b2105de..0000000
--- 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 1d9e87b..0000000
--- 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 b6f98b0..0000000
--- 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 a6c1c73..0000000
--- 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 daced7e..0000000
--- 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 9b6a45b..0000000
--- 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
GIT binary patch
literal 23120
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
M3W>HHg&dUq5A*^SzW@LL

literal 0
HcmV?d00001

diff --git a/lab2/recv.c b/lab2/recv.c
index 99dba5d..3e6d72d 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 fadeeb3..0000000
--- 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 0000000..a204cff
--- /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
GIT binary patch
literal 23072
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

literal 0
HcmV?d00001

diff --git a/lab2/send.c b/lab2/send.c
index 33fdd73..7e70a31 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 3640948..c1f3d41 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 0000000..ce372f4
--- /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 360ffbe..0000000
--- 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 5d8634c..0000000
--- 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 71b18ab..0000000
--- 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 92b64db..0000000
--- 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 daced7e..0000000
--- 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 9b6a45b..0000000
--- 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 0372ee4..84f3e99 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 7381313..0000000
--- 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 0000000..a204cff
--- /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 0c6e8d4..c9f4e5b 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
-- 
GitLab