WolfPack

In this assignment you will work with a fictional network protocol called WolfPack. It is based loosely on the IPv4 packet format, which you should review quickly to get a feel of what a real network packet format looks like.
WolfPack network packets contain 4 fields with information about the sending and receiving computers, 4 other fields that tell the network important information and options about the communication, and a data payload. We will assume that big endian ordering is used, which is not what our target computer architecture uses (Intel, Apple M1/M2). Therefore, when reading and writing packets, we will need to convert to/from big endian and little endian.

A WolfPack header itself consists of 24 bytes divided into 8 fields: Bit #:
Source Address
Destination Address
Dest. Port
Fragment Offset
Total Length
Payload (at most 224 – 24 bytes)
1. Source Address: 40-bit WolfPack network address of transmitting host
2. Destination Address: 40-bit WolfPack network address of receiving host
3. Source Port: 8-bit WolfPack network port of transmitting host
4. Destination Port: 8-bit WolfPack network port of receiving host
5. Fragment Offset: 24-bit byte offset of payload in original data
6. Flags: 16-bit field specifying encryption scheme and other special options/flags
7. Total Length: 24-bit total length of the packet in bytes, including the header and
8. Checksum: 32-bit checksum computed as the sum of all the fields of the packet
(except for the Checksum field itself) modulo (232-1). This is not the same sum obtained by adding all the bytes of the header. (Again, this is a fictional network protocol. This checksum calculation will accept corrupted payloads!)
For instance, consider a packet with the following fields, given in hexadecimal, and a payload containing the ASCII characters ABCDE.
1. 0000003039 2. 000001093b 3. 20
5. 000000 6. 1000
7. 00001d 8. 000149f1 9. ABCDE
This packet would be stored as follows:

Complete the functions specified below in the file wolfpack.c provided in the template repository.
Part 1: Print the Fields and Payload of a WolfPack Network Packet
void print_packet_sf(const unsigned char packet[])
Given a valid WolfPacket network packet in the argument packet, the print_packet function prints the fields in the order shown below this paragraph, ending each line with
a newline. It prints all 8 fields in hexadecimal and prepends zeros as needed to print a number of digits equal to 2 * the length of the field in bytes. For example, the Source Address field is 5 bytes, so the output for that field must contain exactly 2*5=10 hexadecimal digits The function may not print blank lines, extra spaces or extra newlines, labels, or any other output. You may not use the ntohl() function or similar built-in functions to perform any endianness conversions for you. For the payload, treat its bytes as 8-bit ASCII characters and simply display the payload as a string, followed by a newline. Note: the specification of the packet format does not require the payload to be a string, meaning that there is no guarantee of a null-terminator being present at the end of the payload.
1. SourceAddress
2. DestinationAddress
3. Source Port
4. Destination Port
5. Fragment Offset
7. Total Length
8. Checksum
Sample output below. The payload is the 5 characters ¡°ABCDE¡± (no null-terminator):

0000003039
000001093b
Part 2: Compute a Packet¡¯s Checksum
unsigned int checksum_sf(const unsigned char packet[])
Given a WolfPacket network packet in the argument packet that is valid and complete except for its Checksum field, compute and return the packet¡¯s checksum. Do not modify the packet.
Example packet:
0000003039
000001093b
¡û random garbage stored in Checksum field; ignore it
Returned value (shown here in hex): 149f1
Part 3: Reconstruct a Message Sent as a Series of Packets
Complete the reconstruct_sf function, which takes an array of WolfPack network packets, extracts the payloads, and writes the original transmitted data into the message argument. The function ignores (i.e., skips over) any packets with invalid checksums (i.e., the checksum field in the packet does not match the checksum value computed by the checksum_sf function). You may not assume that the message buffer is large enough to store the reconstructed data. Rather, store up to message_len-1 bytes, leaving one byte available for the null-terminator in message.
Github
Do not modify any of the bytes of message except to write the payloads and null-terminator into it. The Fragment Offset field in each packet tells you where in message to start writing the payload. For instance, if the Fragment Offset of a packet is 0x028, then you should start writing its payload at index 0x028 of message. In a real network protocol, packets may be received out of order. It is necessary to always read the Fragment Offset. The function returns the number of full or partial payloads it was able to write into message. For instance, suppose that the function has enough room to write the first four payloads of the message and part of the fifth, but the second and third packets are corrupted (i.e., they have invalid checksums). In this case the function would return 3 because it was able to write all or part of 3 payloads. Note that it would write as much of the fifth payload as it could before running out of memory.
unsigned int reconstruct_sf(unsigned char *packets[],
unsigned int packets_len, char *message,
unsigned int message_len);
¡ñ packets is an array of character arrays representing packets, i.e., packets[0] is a pointer to the first character array, packets[1] is a pointer to the second character array, etc.
¡ñ packets_len is the number of character arrays pointed to by packets
¡ñ message is an uninitialized region of memory where the reconstructed message
must be written
¡ñ message_len is the size of message in bytes
Writing the Null-terminator
When reconstructing the message, write the null-terminator immediately following the rightmost valid packet you were able to write, regardless of whether you wrote all or some of the payload.
Example #1: No special cases
Suppose message starts with the following contents:

We read 3 packets containing 6, 6 and 3 characters in the payloads. So we write the following characters, where a letter indicates a character read from a valid packet:

Then we write the null-terminator immediately following the rightmost character we wrote:

Example #2: Corrupted packets
Suppose message starts with the following contents:

We read 4 packets from packets, but the first and last are corrupted. Assume every packet contains payloads of exactly 5 characters. So we write the following characters, where a letter indicates a character read from a valid packet:

Then we write the null-terminator immediately following the rightmost character we wrote:

Example #3: Destination buffer too short
Suppose message starts with the following contents:

We read 3 packets containing 6, 6 and 3 characters in the payloads. The message we want to save is AAAAAABBBBBBCCC\0, but we won¡¯t have enough room. So we write the following characters, where a letter indicates a character read from a valid packet:
AAAAAABBB@ <-- had to save room for the null-terminator Then we write the null-terminator immediately following the rightmost character we wrote: AAAAAABBB\0 Code Help
Example #4: All packets are invalid
In this case, do not make ANY changes to message[] because you wrote zero payloads into message[].
See the provided unit tests for further examples. Part 4: Packetize a Message
Complete the packetize_sf function, which takes a null-terminated string in the argument message and packetizes it, i.e., it divides the message into payloads, which it
then attaches to new packets created by the function. The function is responsible for allocating memory as needed (via malloc) to create each WolfPack packet. The null-terminator is not stored in any payloads.
unsigned int packetize_sf(const char *message,
unsigned char *packets[], unsigned int packets_len,
unsigned int max_payload, unsigned long src_addr,
unsigned long dest_addr, unsigned short flags)
¡ñ message is the null-terminated string to packetize.
¡ñ packets is an array of (likely invalid) char * pointers. The function must create
each packet and store them sequentially in this array so that packets[0] points
to the first packet, packets[1] points to the second packet, etc.
¡ñ packets_len is simply the number of elements (invalid pointers initially) in the
packets array.
¡ñ max_payload is the maximum payload size of any packet created and
referenced by packets.
¡ñ src_addr and dest_addr are the source and destination addresses,
respectively, to be stored in each packet created.
¡ñ flags is the value to be stored in the Flags field of each packet.
Assign 3210 as the source port and 6410 as the destination port in each packet.
When creating packets, maximize the size of each payload, subject to the max_payload constraint. For example, suppose the message to packetize is 32 bytes long. The function should store 10 bytes in the payload of each of the first 3 packets, and the remaining 2 bytes in the payload of the last packet. The function must also assign correct values to the Fragment Offset, Total Length and Checksum fields.
程序代写 CS代考 加微信: cstutorcs
As an example of how to use malloc to create a packet, suppose num_bytes stores the number of bytes you need to allocate for a particular packet and that you want to store that packet at index i of the packets array. You would write the following line of code:
packets[i] = malloc(num_bytes);
Then you would write code to set values for all the bytes in the header of the packet and fill in the payload. (These would be the bytes packets[i][0], packets[i][1], …, packets[i][num_bytes-1])
If packets is not long enough to accommodate all the packets needed to packetize the message, fill it with as many packets as possible. Return the number of packets created by the function.
See the provided unit tests for examples.