├── .circleci
└── config.yml
├── .gitignore
├── .gitmodules
├── FileBroadcaster.sln
├── LICENSE
├── Makefile
├── README.md
├── src
├── Config.hpp
├── FileBroadcaster.vcxproj
├── FileBroadcaster.vcxproj.filters
├── FileBroadcaster.vcxproj.user
├── Main.cpp
├── Receiver.cpp
├── Sender.cpp
└── Utils.hpp
└── tests
├── Tests.cpp
├── packages.config
└── tests.vcxproj
/.circleci/config.yml:
--------------------------------------------------------------------------------
1 | version: 2
2 | jobs:
3 | gtest:
4 | working_directory: ~/root
5 | docker:
6 | - image: gcc:latest
7 | steps:
8 | - run:
9 | name: Downloading dependencies
10 | command: |
11 | apt-get update
12 | apt-get install -y cmake
13 | apt-get install -y libgtest-dev
14 | - run:
15 | name: Installing dependencies
16 | working_directory: /usr/src/gtest/
17 | command: |
18 | cmake CMakeLists.txt
19 | make
20 | cp /usr/src/gtest/*.a /usr/lib
21 | - checkout
22 | - run:
23 | name: "Pull Submodules"
24 | command: |
25 | git submodule init
26 | git submodule update --recursive --remote
27 | - run:
28 | name: Building tests
29 | command: make gtests
30 | - run:
31 | name: Running tests
32 | command: ./GTests --gtest_filter=*
33 | workflows:
34 | version: 2
35 | build_and_test:
36 | jobs:
37 | - gtest:
38 | filters:
39 | branches:
40 | only:
41 | - master
42 | - develop
43 | - tests
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Prerequisites
2 | *.d
3 |
4 | # Compiled Object files
5 | *.slo
6 | *.lo
7 | *.o
8 | *.obj
9 |
10 | # Precompiled Headers
11 | *.gch
12 | *.pch
13 |
14 | # Compiled Dynamic libraries
15 | *.so
16 | *.dylib
17 | *.dll
18 |
19 | # Fortran module files
20 | *.mod
21 | *.smod
22 |
23 | # Compiled Static libraries
24 | *.lai
25 | *.la
26 | *.a
27 | *.lib
28 |
29 | # Executables
30 | *.exe
31 | *.out
32 | *.app
33 |
34 | #Visual studio dirs
35 | .vs/
36 | x64/
37 | x86/
38 | Debug/
39 | Release/
40 | packages/
--------------------------------------------------------------------------------
/.gitmodules:
--------------------------------------------------------------------------------
1 | [submodule "lib/cxxopts"]
2 | path = lib/cxxopts
3 | url = https://github.com/jarro2783/cxxopts
4 |
--------------------------------------------------------------------------------
/FileBroadcaster.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio 15
4 | VisualStudioVersion = 15.0.27703.2047
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "FileBroadcaster", "src\FileBroadcaster.vcxproj", "{CB24E1BF-BA1E-405A-809C-7EA285F3AF1E}"
7 | EndProject
8 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "tests", "tests\tests.vcxproj", "{6E714D4E-EAB6-43B3-AD29-FB75743CA1BD}"
9 | EndProject
10 | Global
11 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
12 | Debug|x64 = Debug|x64
13 | Debug|x86 = Debug|x86
14 | Release|x64 = Release|x64
15 | Release|x86 = Release|x86
16 | EndGlobalSection
17 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
18 | {CB24E1BF-BA1E-405A-809C-7EA285F3AF1E}.Debug|x64.ActiveCfg = Debug|x64
19 | {CB24E1BF-BA1E-405A-809C-7EA285F3AF1E}.Debug|x64.Build.0 = Debug|x64
20 | {CB24E1BF-BA1E-405A-809C-7EA285F3AF1E}.Debug|x86.ActiveCfg = Debug|Win32
21 | {CB24E1BF-BA1E-405A-809C-7EA285F3AF1E}.Debug|x86.Build.0 = Debug|Win32
22 | {CB24E1BF-BA1E-405A-809C-7EA285F3AF1E}.Release|x64.ActiveCfg = Release|x64
23 | {CB24E1BF-BA1E-405A-809C-7EA285F3AF1E}.Release|x64.Build.0 = Release|x64
24 | {CB24E1BF-BA1E-405A-809C-7EA285F3AF1E}.Release|x86.ActiveCfg = Release|Win32
25 | {CB24E1BF-BA1E-405A-809C-7EA285F3AF1E}.Release|x86.Build.0 = Release|Win32
26 | {6E714D4E-EAB6-43B3-AD29-FB75743CA1BD}.Debug|x64.ActiveCfg = Debug|x64
27 | {6E714D4E-EAB6-43B3-AD29-FB75743CA1BD}.Debug|x64.Build.0 = Debug|x64
28 | {6E714D4E-EAB6-43B3-AD29-FB75743CA1BD}.Debug|x86.ActiveCfg = Debug|Win32
29 | {6E714D4E-EAB6-43B3-AD29-FB75743CA1BD}.Debug|x86.Build.0 = Debug|Win32
30 | {6E714D4E-EAB6-43B3-AD29-FB75743CA1BD}.Release|x64.ActiveCfg = Release|x64
31 | {6E714D4E-EAB6-43B3-AD29-FB75743CA1BD}.Release|x64.Build.0 = Release|x64
32 | {6E714D4E-EAB6-43B3-AD29-FB75743CA1BD}.Release|x86.ActiveCfg = Release|Win32
33 | {6E714D4E-EAB6-43B3-AD29-FB75743CA1BD}.Release|x86.Build.0 = Release|Win32
34 | EndGlobalSection
35 | GlobalSection(SolutionProperties) = preSolution
36 | HideSolutionNode = FALSE
37 | EndGlobalSection
38 | GlobalSection(ExtensibilityGlobals) = postSolution
39 | SolutionGuid = {08B5E1AD-5683-4253-9091-883D76F7F554}
40 | EndGlobalSection
41 | EndGlobal
42 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2019 Alex
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/Makefile:
--------------------------------------------------------------------------------
1 | program:
2 | g++ src/Main.cpp \
3 | -std=c++14 -pthread \
4 | -Ilib/cxxopts/include \
5 | -o FileBroadcaster
6 |
7 | gtests:
8 | g++ tests/Tests.cpp \
9 | -std=c++14 -pthread \
10 | -Ilib/cxxopts/include \
11 | -lgtest \
12 | -o GTests
13 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # File-Broadcaster
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 | UDP File sender and receiver
17 | Can use broadcast address to send file on all computers in LAN
18 |
19 | ## Features
20 |
21 | - Send file to one or all computers in LAN
22 | - Reliability of data transmission
23 | - Server timeout detection
24 | - Change MTU
25 |
26 | ## Overview
27 |
28 | - [Requirements](#requirements)
29 | - [Download](#download)
30 | - [Installation](#installation)
31 | - [Script Parameters](#script-parameters)
32 | - [Packets Specification](#packets-specification)
33 | - [Script Specification](#script-specification)
34 |
35 | ## Download
36 | Clone the [source repository](http://github.com/gistrec/File-Broadcaster) from Github.
37 | * On the command line, enter:
38 | ````
39 | git clone https://github.com/gistrec/File-Broadcaster.git
40 | git submodule init
41 | git submodule update --recursive --remote
42 | ````
43 |
44 | * You can probably use [Github for Windows](http://windows.github.com/) or [Github for Mac](http://mac.github.com/) instead of the command line, however these aren't tested/supported and we only use the command line for development. Use [this link](https://git-scm.com/downloads) to download the command line version.
45 |
46 |
47 | ## Requirements
48 | * Windows:
49 | * Visual Studio 2015 or 2017
50 | * Linux:
51 | * g++
52 | * pthread
53 | * arpa
54 |
55 |
56 |
57 | ## Installation
58 | * Windows
59 | * Open FileBroadcaster.sln via Visual Studio
60 | * Build project
61 | * Linux
62 | * Open a terminal/console/command prompt, change to the directory where you cloned project, and type:
63 | ````
64 | make all
65 | ````
66 |
67 | ## Script Parameters
68 | | Parameter | Default | Description |
69 | | ------ | -------- | -------- |
70 | | p, port | 33333 | Sender and receiver port |
71 | | f, filename| `none` | Transmitted and received file |
72 | | t, type | receiver | receiver or sender |
73 | | ttl | 15 | Seconds to wait cliend requests or sender responses |
74 | | mtu | 1500 | MTU packet size |
75 | | broadcast | 255.255.255.255 | Broadcast address. Can use to unicast. |
76 |
77 | ## Packets Specification
78 | Packets structure
79 | 
80 |
81 | ## Script Specification
82 | 1. Sender send `NEW_PACKET` packet to broadcast (or unicast) address
83 | 2. Sender send all parts of file via `TRANSFER` packet
84 | 3. If any pacckets were lost, receiver ask them sending `RESEND` packet to broadcast (or unicast) address
85 | 4. Sender wait `RESEND` packets or wait TTL and turns off
86 | 5. Receiver ask all lost parts, until the whole file is no downloaded or wait TTL and turns off
87 |
--------------------------------------------------------------------------------
/src/Config.hpp:
--------------------------------------------------------------------------------
1 | #ifndef FILEBROADCASTER_CONFIG_H
2 | #define FILEBROADCASTER_CONFIG_H
3 |
4 | #include "Utils.hpp"
5 |
6 |
7 | std::string fileName; // File Name to transfer or receive
8 |
9 | int mtu; // Max packet size to send and receive
10 |
11 | int ttl; // Current wait time for new packages before shutting down
12 | int ttl_max; // Maximum wait time for new packages before shutting down
13 |
14 | SOCKET _socket;
15 |
16 | SOCKADDR_IN server_address = { 0 };
17 | SOCKADDR_IN client_address = { 0 };
18 | SOCKADDR_IN broadcast_address = { 0 };
19 |
20 | addr_len server_address_length = sizeof(server_address);
21 | addr_len client_address_length = sizeof(client_address);
22 |
23 | size_t file_length; // File size in bytes
24 | char* file = nullptr; // Pointer to file in RAM
25 | char* buffer = nullptr; // Pointer to buffer
26 |
27 | #endif //FILEBROADCASTER_CONFIG_H
28 |
--------------------------------------------------------------------------------
/src/FileBroadcaster.vcxproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Debug
6 | Win32
7 |
8 |
9 | Release
10 | Win32
11 |
12 |
13 | Debug
14 | x64
15 |
16 |
17 | Release
18 | x64
19 |
20 |
21 |
22 | 15.0
23 | {CB24E1BF-BA1E-405A-809C-7EA285F3AF1E}
24 | FileBroadcaster
25 | 10.0.17763.0
26 |
27 |
28 |
29 | Application
30 | true
31 | v141
32 | MultiByte
33 |
34 |
35 | Application
36 | false
37 | v141
38 | true
39 | MultiByte
40 |
41 |
42 | Application
43 | true
44 | v141
45 | MultiByte
46 |
47 |
48 | Application
49 | false
50 | v141
51 | true
52 | MultiByte
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 | Level3
76 | Disabled
77 | true
78 | true
79 |
80 |
81 |
82 |
83 | Level3
84 | Disabled
85 | true
86 | true
87 | _MBCS;%(PreprocessorDefinitions);
88 | $(SolutionDir)/lib/cxxopts/include/
89 |
90 |
91 |
92 |
93 | Level3
94 | MaxSpeed
95 | true
96 | true
97 | true
98 | true
99 |
100 |
101 | true
102 | true
103 |
104 |
105 |
106 |
107 | Level3
108 | MaxSpeed
109 | true
110 | true
111 | true
112 | true
113 | _MBCS;%(PreprocessorDefinitions);
114 | $(SolutionDir)/lib/cxxopts/include/
115 |
116 |
117 | true
118 | true
119 |
120 |
121 |
122 |
123 |
124 |
125 |
126 |
127 |
128 |
129 |
130 |
131 |
132 |
133 |
--------------------------------------------------------------------------------
/src/FileBroadcaster.vcxproj.filters:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/src/FileBroadcaster.vcxproj.user:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/src/Main.cpp:
--------------------------------------------------------------------------------
1 | #include "cxxopts.hpp"
2 |
3 | #include "Receiver.cpp"
4 | #include "Sender.cpp"
5 | #include "Config.hpp"
6 |
7 |
8 | int main(int argc, char* argv[]) {
9 | // Parsing input parameters from the CLI
10 | cxxopts::Options options("File-Broadcaster", "UDB Broadcast file transfer");
11 |
12 | options
13 | .positional_help("[optional args]")
14 | .show_positional_help();
15 |
16 | options.add_options()
17 | ("f,file", "File name", cxxopts::value()->default_value("file.out"))
18 | ("t,type", "Receiver or sender", cxxopts::value()->default_value("sender"))
19 | ("broadcast", "Broadcast address", cxxopts::value()->default_value("yes"))
20 | ("p,port", "Port", cxxopts::value()->default_value("33333"))
21 | ("mtu", "MTU packet", cxxopts::value()->default_value("1500"))
22 | ("ttl", "Time to live", cxxopts::value()->default_value("15"));
23 |
24 | auto result = options.parse(argc, argv);
25 |
26 | #if defined(_WIN32) || defined(_WIN64) //
27 | WORD socketVer; // Initializing the use
28 | WSADATA wsaData; // of the Winsock DLL
29 | socketVer = MAKEWORD(2, 2); // by this process.
30 | WSAStartup(socketVer, &wsaData); //
31 | #endif //
32 |
33 | mtu = result["mtu"].as(); //
34 | ttl = result["ttl"].as(); // Initializing some variable
35 | ttl_max = result["ttl"].as(); //
36 | fileName = result["file"].as(); //
37 |
38 |
39 | _socket = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP); //
40 | if (_socket < 0) { // Create socket with
41 | std::cout << "Error: Can't create socket" << std::endl; // datagram-based protocol
42 | exit(1); //
43 | } else { //
44 | std::cout << "Ok: Socket created" << std::endl; //
45 | } //
46 |
47 | client_address.sin_family = AF_INET; //
48 | client_address.sin_port = htons(result["port"].as()); // Creating local address
49 | client_address.sin_addr.s_addr = INADDR_ANY; //
50 |
51 | memcpy(&server_address, &client_address, sizeof(server_address)); // Server address == Client address
52 |
53 | broadcast_address.sin_family = AF_INET; // Creating broadcast
54 | broadcast_address.sin_port = htons(result["port"].as()); // address
55 |
56 | if (result["broadcast"].as() == "yes") { //
57 | #if defined(_WIN32) || defined(_WIN64) // Getting access to
58 | char broadcastEnable = '1'; // the broadcast address
59 | #else //
60 | int broadcastEnable = 1; //
61 | #endif //
62 | //
63 | if (setsockopt(_socket, SOL_SOCKET, SO_BROADCAST, //
64 | &broadcastEnable, sizeof(broadcastEnable)) != 0) { //
65 | std::cout << "Ok: Got access to broadcast" << std::endl; //
66 | } else { //
67 | std::cerr << "Error: Cant't get access to broadcast" << std::endl; //
68 | exit(1); //
69 | } // If parameter "broadcast" is "yes", then
70 | broadcast_address.sin_addr.s_addr = INADDR_BROADCAST; // change server address
71 | } else { // to broadcast
72 | broadcast_address.sin_addr.s_addr = // Else change server address
73 | inet_addr(result["broadcast"].as().c_str()); // to address in parameter
74 | } //
75 |
76 | if (bind(_socket, (sockaddr *)&client_address, sizeof(client_address)) == 0) {//
77 | std::cout << "Ok: Socket binded" << std::endl; //
78 | } else { // Bind socket to
79 | std::cerr << "Error: Can't bind socket" << std::endl; // client address
80 | exit(1); //
81 | } //
82 |
83 | #if defined(_WIN32) || defined(_WIN64) //
84 | int tv = 1 * 1000; // user timeout in milliseconds [ms] //
85 | setsockopt(_socket, SOL_SOCKET, SO_RCVTIMEO, (char*)&tv, sizeof(tv)); // Set socket
86 | #else // receive timeout
87 | struct timeval tv; // to 1 sec
88 | tv.tv_sec = 1; //
89 | tv.tv_usec = 0; //
90 | setsockopt(_socket, SOL_SOCKET, SO_RCVTIMEO, (const char*)&tv, sizeof(tv)); //
91 | #endif
92 |
93 | // Run receiver or sender
94 | if (result["type"].as() == "receiver") { //
95 | Receiver::run(result); //
96 | } else if (result["type"].as() == "sender") { // Run receiver or sender
97 | Sender::run(result); // application
98 | } else { //
99 | std::cerr << "Error: Type not found" << std::endl; //
100 | }
101 |
102 | return 0;
103 | }
104 |
--------------------------------------------------------------------------------
/src/Receiver.cpp:
--------------------------------------------------------------------------------
1 | #include "Utils.hpp"
2 | #include "Config.hpp"
3 |
4 |
5 | namespace Receiver {
6 |
7 | /**
8 | * List of received parts
9 | */
10 | std::set parts;
11 |
12 | /**
13 | * Get empty parts
14 | */
15 | std::vector getEmptyParts() {
16 | std::vector result;
17 | // For each parts
18 | for (int i = 0; i < int((float)file_length / (float)mtu + 0.5); i++) {
19 | if (parts.find(i) == parts.end()) result.push_back(i);
20 | }
21 | return result;
22 | }
23 |
24 | /**
25 | * Runs when "FINISH" packet is received
26 | * Gets empty parts and requests them from the server
27 | */
28 | void checkParts() {
29 | char buffer[100];
30 |
31 | std::vector emptyParts = getEmptyParts();
32 |
33 | while (ttl && emptyParts.size() > 0) {
34 | for (auto index : emptyParts) {
35 | snprintf(buffer, 7, "RESEND"); //
36 | Utils::writeBytesFromNumber(buffer + 6, index, 4); // Create request packet
37 | sendto(_socket, buffer, 10, 0, (sockaddr*) &broadcast_address,//
38 | sizeof(broadcast_address)); //
39 |
40 | std::cout << "Request part of file with index " << index << std::endl;
41 | }
42 | emptyParts = getEmptyParts();
43 | }
44 |
45 | std::ofstream output(fileName, std::ofstream::binary); //
46 | output.write(file, file_length); // Save file
47 |
48 | std::cout << "File successfully received" << std::endl;
49 |
50 | delete[] file;
51 | exit(0);
52 | }
53 |
54 |
55 | void run(cxxopts::ParseResult &options) {
56 | bool finish = false; // Sender finish transfering
57 |
58 | char* buffer = new char[2 * mtu];
59 |
60 | while (auto length = recvfrom(_socket, buffer, 2 * mtu, 0, (sockaddr*) &server_address, &server_address_length)) {
61 | // Sender is no longer available
62 | if (ttl <= 0) return;
63 |
64 | // If Sender finish transfering check missing parts every 1 sec
65 | if (finish) checkParts();
66 |
67 | if (length <= 0) continue; // If no more packets in buffer
68 |
69 | ttl = ttl_max; // Update ttl
70 |
71 | if (strncmp(buffer, "NEW_PACKET", 10) == 0) {
72 | file_length = Utils::getNumberFromBytes(buffer + 10, 4); // Read section "file length"
73 |
74 | file = new char[file_length];
75 | memset(file, 0, file_length);
76 |
77 | std::cout << "Receive information about new file size: " << file_length << std::endl;
78 | std::cout << "Number of parts: " << int((float)file_length / (float)mtu + 0.5) << std::endl;
79 | } else if (strncmp(buffer, "TRANSFER", 8) == 0) {
80 | int part = Utils::getNumberFromBytes(buffer + 8, 4); // Read section "index"
81 | int size = Utils::getNumberFromBytes(buffer + 12, 4); // Read section "size"
82 | parts.insert(part);
83 | std::cout << "Receive " << part << " part with size " << size << std::endl;
84 |
85 | memcpy(file + part * options["mtu"].as(), buffer + 16, size);
86 | } else if (strncmp(buffer, "FINISH", 6) == 0) {
87 | // If receiver didn't receive a finish message
88 | if (!finish) {
89 | std::cout << "Server finished transferring" << std::endl;
90 | finish = true;
91 | }
92 | }
93 | }
94 | delete[] buffer;
95 | }
96 |
97 | } //namespace Receiver
--------------------------------------------------------------------------------
/src/Sender.cpp:
--------------------------------------------------------------------------------
1 | #include "Utils.hpp"
2 | #include "Config.hpp"
3 |
4 |
5 | namespace Sender {
6 |
7 | /**
8 | * Since server may receive many requests for sending some part
9 | * It is necessary to limit the sending of the same parts for a while
10 | * This container contains part number and time when the part was sended
11 | */
12 | std::map sent_part;
13 |
14 | void sendPart(int part_index) {
15 | int packet_length = file_length - part_index * mtu; // Get packet length
16 | if (packet_length > mtu) packet_length = mtu; //
17 |
18 | snprintf(buffer, 9, "TRANSFER");
19 | Utils::writeBytesFromNumber(buffer + 8, (size_t)part_index, 4); // Write section "number"
20 | Utils::writeBytesFromNumber(buffer + 12, (size_t)packet_length, 4); // Write section "length"
21 | memcpy(buffer + 16, (void *)(intptr_t)(file + part_index * mtu), packet_length); // Write section "data"
22 |
23 | // Sending part to the broadcast address
24 | sendto(_socket, buffer, packet_length + 16, 0, (struct sockaddr*) &broadcast_address, sizeof(broadcast_address));
25 | std::cout << "Part " << part_index << " with size " << packet_length << " was send" << std::endl;
26 | }
27 |
28 | void run(cxxopts::ParseResult &options) {
29 | buffer = new char[2 * mtu];
30 |
31 | std::ifstream input(fileName, std::ios::binary); //
32 | if (!input.is_open()) { // Opening the file
33 | std::cout << "Error: Can't open file " << fileName << std::endl; //
34 | exit(-1); //
35 | } //
36 |
37 | // Thk Windows.h, where define max(). It so horrible... //
38 | input.ignore((std::numeric_limits::max)()); //
39 | file_length = (int) input.gcount(); // Getting file length
40 | input.seekg(0, input.beg); // And writing file to RAM
41 | //
42 | file = new (std::nothrow) char[file_length + 1]; //
43 | if (!file) { //
44 | std::cout << "Error: Can't allocate " << file_length << " bytes" << std::endl;
45 | exit(-1);
46 | }
47 | input.read(file, file_length);
48 |
49 | std::cout << "Ok: File successfully copied to RAM" << std::endl;
50 |
51 | snprintf(buffer, 11, "NEW_PACKET"); //
52 | Utils::writeBytesFromNumber(buffer + 10, file_length, 4); // Sending information
53 | sendto(_socket, buffer, 14, 0, (sockaddr*) &broadcast_address, // about size of new file
54 | sizeof(broadcast_address)); //
55 |
56 | std::cout << "Ok: Send information about new file with size " << file_length << std::endl;
57 |
58 | int part_index = 0;
59 |
60 | while (part_index * mtu < file_length) { //
61 | sent_part.insert({ part_index, 0 }); //
62 | //
63 | sendPart(part_index); // Send parts
64 | // every 20ms
65 | part_index++; //
66 | std::this_thread::sleep_for(20ms); //
67 | } //
68 |
69 | snprintf(buffer, 7, "FINISH"); // Sending file transfer
70 | sendto(_socket, buffer, 6, 0, (sockaddr*) &broadcast_address, // completion information
71 | sizeof(broadcast_address)); //
72 | std::cout << "Ok: File transfer complete" << std::endl; //
73 |
74 | long lastFinishSendTime = 0; // Last time, when sender sended file transfer completion information
75 |
76 | while (ttl) {
77 | auto result = recvfrom(_socket, (char *)buffer, 100, 0, (struct sockaddr*) &broadcast_address, &client_address_length);
78 |
79 | // sending file completion information every second
80 | if (result <= 0) {
81 | ttl--;
82 | snprintf(buffer, 7, "FINISH");
83 | sendto(_socket, buffer, 6, 0, (struct sockaddr*) &broadcast_address, sizeof(broadcast_address));
84 | continue;
85 | }
86 |
87 | if (strncmp(buffer, "RESEND", 6) == 0) {
88 | int part = Utils::getNumberFromBytes(buffer + 6, 4);
89 |
90 | auto now = std::chrono::system_clock::now();
91 | auto now_ms = std::chrono::time_point_cast(now);
92 | auto epoch = now_ms.time_since_epoch();
93 | auto value = std::chrono::duration_cast(epoch);
94 | long duration = value.count(); // Unix time in second
95 |
96 | ttl = ttl_max;
97 |
98 | if (duration - sent_part[part] >= 1) {
99 | sent_part[part] = duration;
100 | std::cout << "Client requested part of file with index " << part << std::endl;
101 | sendPart(part);
102 | }
103 |
104 | // sending file completion information every second
105 | if (duration - lastFinishSendTime >= 1) {
106 | lastFinishSendTime = duration;
107 | snprintf(buffer, 7, "FINISH");
108 | sendto(_socket, buffer, 6, 0, (struct sockaddr*) &broadcast_address, sizeof(broadcast_address));
109 | }
110 | }
111 |
112 | }
113 | std::cout << "Ok: Process no longer be working" << std::endl;
114 | }
115 |
116 |
117 | } //namespace Sender
118 |
--------------------------------------------------------------------------------
/src/Utils.hpp:
--------------------------------------------------------------------------------
1 | #ifndef FILEBROADCASTER_UTILS_H
2 | #define FILEBROADCASTER_UTILS_H
3 |
4 | #if defined(_WIN32) || defined(_WIN64)
5 | #define _WINSOCK_DEPRECATED_NO_WARNINGS
6 | #define addr_len int //
7 | #include // Windows
8 | #include // socket
9 | #pragma comment(lib, "Ws2_32.lib") //
10 | #else
11 | #define SOCKET int //
12 | #define SOCKADDR_IN sockaddr_in //
13 | #define addr_len socklen_t // Linux socket
14 | #include //
15 | #endif
16 |
17 | #include
18 | #include
19 | #include
20 | #include // memcpy
21 | #include
22 |
23 | #include