A3
This commit is contained in:
29
A3/src/Makefile
Normal file
29
A3/src/Makefile
Normal file
@ -0,0 +1,29 @@
|
||||
GCC=gcc -O3 -g -Wall -Wextra -pedantic -std=gnu11
|
||||
LD_FLAGS= -lpthread
|
||||
|
||||
all: peer name_server cascade
|
||||
|
||||
rebuild: clean all
|
||||
|
||||
csapp.o: csapp.c csapp.h
|
||||
$(GCC) -c $< -o $@
|
||||
|
||||
common.o: common.c common.h
|
||||
$(GCC) -c $< -o $@
|
||||
|
||||
cascade: cascade.c cascade.h common.o csapp.o sha256.o
|
||||
$(GCC) $< *.o -o $@ $(LD_FLAGS)
|
||||
|
||||
name_server: name_server.c name_server.h common.o csapp.o
|
||||
$(CC) $(CFLAGS) $< *.o -o $@ $(LD_FLAGS)
|
||||
|
||||
sha256.o : sha256.c sha256.h
|
||||
$(CC) $(CFLAGS) -c $< -o $@
|
||||
|
||||
zip: ../src.zip
|
||||
|
||||
../src.zip: clean
|
||||
cd .. && zip -r src.zip src/Makefile src/*.c src/*.h src/tests/*
|
||||
|
||||
clean:
|
||||
rm -rf *.o peer name_server cascade sha256 vgcore*
|
450
A3/src/cascade.c
Normal file
450
A3/src/cascade.c
Normal file
@ -0,0 +1,450 @@
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <netdb.h>
|
||||
#include <sys/socket.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <endian.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "./cascade.h"
|
||||
#include "./sha256.h"
|
||||
|
||||
char tracker_ip[IP_LEN];
|
||||
char tracker_port[PORT_LEN];
|
||||
char my_ip[IP_LEN];
|
||||
char my_port[PORT_LEN];
|
||||
|
||||
struct csc_file *casc_file;
|
||||
csc_block_t** queue;
|
||||
csc_peer_t* peers;
|
||||
|
||||
void free_resources()
|
||||
{
|
||||
free(queue);
|
||||
free(peers);
|
||||
csc_free_file(casc_file);
|
||||
}
|
||||
|
||||
unsigned char* get_file_sha(const char* sourcefile, csc_file_t* res, char* hash, int size)
|
||||
{
|
||||
int n;
|
||||
int casc_file_size;
|
||||
|
||||
FILE* fp = fopen(sourcefile, "rb");
|
||||
if (fp == 0)
|
||||
{
|
||||
printf("Failed to open source: %s\n", sourcefile);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
fseek(fp, 0L, SEEK_END);
|
||||
casc_file_size = ftell(fp);
|
||||
fseek(fp, 0L, SEEK_SET);
|
||||
|
||||
char buffer[casc_file_size];
|
||||
fread(buffer, casc_file_size, 1, fp);
|
||||
fclose(fp);
|
||||
|
||||
SHA256_CTX shactx;
|
||||
unsigned char shabuffer[size];
|
||||
sha256_init(&shactx);
|
||||
sha256_update(&shactx, buffer, casc_file_size);
|
||||
sha256_final(&shactx, &shabuffer);
|
||||
|
||||
for (int i=0; i<size; i++)
|
||||
{
|
||||
hash[i] = shabuffer[i];
|
||||
}
|
||||
}
|
||||
|
||||
void download_only_peer(char *cascade_file)
|
||||
{
|
||||
printf("Managing download only for: %s\n", cascade_file);
|
||||
if (access(cascade_file, F_OK ) != 0 )
|
||||
{
|
||||
fprintf(stderr, ">> File %s does not exist\n", cascade_file);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
char output_file[strlen(cascade_file)];
|
||||
memcpy(output_file, cascade_file, strlen(cascade_file));
|
||||
char* r = strstr(cascade_file, "cascade");
|
||||
int cutoff = r - cascade_file ;
|
||||
output_file[cutoff-1] = '\0';
|
||||
printf("Downloading to: %s\n", output_file);
|
||||
|
||||
casc_file = csc_parse_file(cascade_file, output_file);
|
||||
|
||||
/*
|
||||
TODO Create a list of missing blocks
|
||||
*/
|
||||
|
||||
/*
|
||||
TODO Compute the hash of the cascade file
|
||||
HINT: Do not implement hashing from scratch. Use the provided 'get_file_sha' function
|
||||
*/
|
||||
|
||||
int peercount = 0;
|
||||
while (peercount == 0)
|
||||
{
|
||||
peercount = get_peers_list(&peers, hash_buf, tracker_ip, tracker_port);
|
||||
if (peercount == 0)
|
||||
{
|
||||
printf("No peers were found. Will try again in %d seconds\n", PEER_REQUEST_DELAY);
|
||||
fflush(stdout);
|
||||
sleep(PEER_REQUEST_DELAY);
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("Found %d peer(s)\n", peercount);
|
||||
}
|
||||
}
|
||||
|
||||
csc_peer_t peer = (peers[0]);
|
||||
// Get a good peer if one is available
|
||||
for (int i=0; i<peercount; i++)
|
||||
{
|
||||
if (peers[i].good)
|
||||
{
|
||||
peer = peers[i];
|
||||
}
|
||||
}
|
||||
|
||||
for (int i=0; i<uncomp_count; i++)
|
||||
{
|
||||
get_block(queue[i], peer, hash_buf, output_file);
|
||||
}
|
||||
|
||||
free_resources();
|
||||
}
|
||||
|
||||
int count_occurences(char string[], char c)
|
||||
{
|
||||
int i=0;
|
||||
int count=0;
|
||||
for(i=0; i<strlen(string); i++)
|
||||
{
|
||||
if(string[i] == c)
|
||||
{
|
||||
count++;
|
||||
}
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
// Adapted from: https://stackoverflow.com/a/35452093/
|
||||
uint8_t* hex_to_bytes(const char* string) {
|
||||
|
||||
if(string == NULL)
|
||||
return NULL;
|
||||
|
||||
size_t slength = strlen(string);
|
||||
if((slength % 2) != 0) // must be even
|
||||
return NULL;
|
||||
|
||||
size_t dlength = slength / 2;
|
||||
|
||||
uint8_t* data = malloc(dlength);
|
||||
memset(data, 0, dlength);
|
||||
|
||||
size_t index = 0;
|
||||
while (index < slength) {
|
||||
char c = string[index];
|
||||
int value = 0;
|
||||
if(c >= '0' && c <= '9')
|
||||
value = (c - '0');
|
||||
else if (c >= 'A' && c <= 'F')
|
||||
value = (10 + (c - 'A'));
|
||||
else if (c >= 'a' && c <= 'f')
|
||||
value = (10 + (c - 'a'));
|
||||
else {
|
||||
free(data);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
data[(index/2)] += value << (((index + 1) % 2) * 4);
|
||||
|
||||
index++;
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
/*
|
||||
* Parses a cascade file, given the sourcepath input and destination, which may or may not exist.
|
||||
* Returns a pointer to a datastructure describing the file, or NULL if the file could not be parsed
|
||||
*/
|
||||
csc_file_t* csc_parse_file(const char* sourcefile, const char* destination)
|
||||
{
|
||||
FILE* fp = fopen(sourcefile, "rb");
|
||||
if (fp == 0)
|
||||
{
|
||||
printf("Failed to open source: %s\n", sourcefile);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const int FILE_HEADER_SIZE = 8+8+8+8+32;
|
||||
|
||||
char header[FILE_HEADER_SIZE];
|
||||
if (fread(header, 1, FILE_HEADER_SIZE, fp) != FILE_HEADER_SIZE)
|
||||
{
|
||||
printf("Failed to read magic 8 bytes header from file\n");
|
||||
fclose(fp);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (memcmp(header, "CASCADE1", 8) != 0)
|
||||
{
|
||||
printf("File does not contain magic 8 bytes in header\n");
|
||||
fclose(fp);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
csc_file_t* casc_file_data = (csc_file_t*)malloc(sizeof(csc_file_t));
|
||||
|
||||
/*
|
||||
TODO Parse the cascade file and store the data in an appropriate data structure
|
||||
|
||||
HINT Use the definition of the 'csc_file' struct in cascade.h, as well as the
|
||||
assignment handout for guidance on what each attribute is and where it is stored
|
||||
in the files header/body.
|
||||
*/
|
||||
|
||||
fclose(fp);
|
||||
|
||||
fp = fopen(destination, "a+w");
|
||||
if (fp == NULL)
|
||||
{
|
||||
printf("Failed to open destination file %s\n", destination);
|
||||
csc_free_file(casc_file_data);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void* buffer = malloc(casc_file_data->blocksize);
|
||||
if (buffer == NULL)
|
||||
{
|
||||
printf("No block buffer asigned: %d\n", casc_file_data->blocksize);
|
||||
csc_free_file(casc_file_data);
|
||||
fclose(fp);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
SHA256_CTX shactx;
|
||||
for(unsigned long long i = 0; i < casc_file_data->blockcount; i++)
|
||||
{
|
||||
char shabuffer[SHA256_HASH_SIZE];
|
||||
unsigned long long size = casc_file_data->blocks[i].length;
|
||||
if (fread(buffer, size, 1, fp) != 1)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
sha256_init(&shactx);
|
||||
sha256_update(&shactx, buffer, size);
|
||||
sha256_final(&shactx, &shabuffer);
|
||||
|
||||
/*
|
||||
TODO Compare the hashes taken from the Cascade file with those of the local data
|
||||
file and keep a record of any missing blocks
|
||||
|
||||
HINT The code above takes a hash of each block of data in the local file in turn
|
||||
and stores it in the 'shabuffer' variable. You can compare then compare 'shabuffer'
|
||||
directly to the hashes of each block you have hopefully already assigned as part
|
||||
of the 'casc_file_data' struct
|
||||
*/
|
||||
}
|
||||
fclose(fp);
|
||||
|
||||
return casc_file_data;
|
||||
}
|
||||
|
||||
/*
|
||||
* Releases the memory allocated by a file datastructure
|
||||
*/
|
||||
void csc_free_file(csc_file_t* file)
|
||||
{
|
||||
free(file->blocks);
|
||||
file->blocks = NULL;
|
||||
free(file);
|
||||
}
|
||||
|
||||
size_t readbytes(int sock, void* buffer, size_t count)
|
||||
{
|
||||
size_t remaining = count;
|
||||
while(remaining > 0)
|
||||
{
|
||||
size_t read = recv(sock, buffer, remaining, NULL);
|
||||
if (read == 0)
|
||||
return 0;
|
||||
buffer += read;
|
||||
remaining -= read;
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
void get_block(csc_block_t* block, csc_peer_t peer, unsigned char* hash, char* output_file)
|
||||
{
|
||||
printf("Attempting to get block %d from %s:%s for %s\n", block->index, peer.ip, peer.port, output_file);
|
||||
|
||||
rio_t rio;
|
||||
char rio_buf[MAX_LINE];
|
||||
int peer_socket;
|
||||
|
||||
/*
|
||||
TODO Request a block from a peer
|
||||
*/
|
||||
|
||||
FILE* fp = fopen(output_file, "rb+");
|
||||
if (fp == 0)
|
||||
{
|
||||
printf("Failed to open destination: %s\n", output_file);
|
||||
Close(peer_socket);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
TODO Write the block into the data file
|
||||
*/
|
||||
|
||||
printf("Got block %d. Wrote from %d to %d\n", block->index, block->offset, block->offset+write_count-1);
|
||||
Close(peer_socket);
|
||||
fclose(fp);
|
||||
}
|
||||
|
||||
int get_peers_list(csc_peer_t** peers, unsigned char* hash, char* tracker_ip, char* tracker_port, char* my_ip, char* my_port)
|
||||
{
|
||||
rio_t rio;
|
||||
char rio_buf[MAX_LINE];
|
||||
int tracker_socket;
|
||||
|
||||
/*
|
||||
TODO Setup a connection to the tracker
|
||||
*/
|
||||
|
||||
struct RequestHeader request_header;
|
||||
strncpy(request_header.protocol, "CASC", 4);
|
||||
request_header.version = htonl(1);
|
||||
request_header.command = htonl(1);
|
||||
request_header.length = htonl(BODY_SIZE);
|
||||
memcpy(rio_buf, &request_header, HEADER_SIZE);
|
||||
|
||||
/*
|
||||
TODO Complete the peer list request and
|
||||
HINT The header has been provided above as a guide
|
||||
*/
|
||||
|
||||
Rio_writen(tracker_socket, rio_buf, MESSAGE_SIZE);
|
||||
|
||||
Rio_readnb(&rio, rio_buf, MAXLINE);
|
||||
|
||||
char reply_header[REPLY_HEADER_SIZE];
|
||||
memcpy(reply_header, rio_buf, REPLY_HEADER_SIZE);
|
||||
|
||||
uint32_t msglen = ntohl(*(uint32_t*)&reply_header[1]);
|
||||
if (msglen == 0)
|
||||
{
|
||||
Close(tracker_socket);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (reply_header[0] != 0)
|
||||
{
|
||||
char* error_buf = malloc(msglen + 1);
|
||||
if (error_buf == NULL)
|
||||
{
|
||||
printf("Tracker error %d and out-of-memory reading error\n", reply_header[0]);
|
||||
Close(tracker_socket);
|
||||
return NULL;
|
||||
}
|
||||
memset(error_buf, 0, msglen + 1);
|
||||
memcpy(reply_header, error_buf, msglen);
|
||||
printf("Tracker gave error: %d - %s\n", reply_header[0], error_buf);
|
||||
free(error_buf);
|
||||
Close(tracker_socket);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (msglen % 12 != 0)
|
||||
{
|
||||
printf("LIST response from tracker was length %llu but should be evenly divisible by 12\n", msglen);
|
||||
Close(tracker_socket);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
TODO Parse the body of the response to get a list of peers
|
||||
|
||||
HINT Some of the later provided code expects the peers to be stored in the ''peers' variable, which
|
||||
is an array of 'csc_peer's, as defined in cascade.h
|
||||
*/
|
||||
|
||||
Close(tracker_socket);
|
||||
return peercount;
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
if (argc != MAIN_ARGNUM + 1)
|
||||
{
|
||||
fprintf(stderr, "Usage: %s <cascade file(s)> <tracker server ip> <tracker server port> <peer ip> <peer port>.\n", argv[0]);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
else if (!is_valid_ip(argv[2]))
|
||||
{
|
||||
fprintf(stderr, ">> Invalid tracker IP: %s\n", argv[2]);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
else if (!is_valid_port(argv[3]))
|
||||
{
|
||||
fprintf(stderr, ">> Invalid tracker port: %s\n", argv[3]);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
else if (!is_valid_ip(argv[4]))
|
||||
{
|
||||
fprintf(stderr, ">> Invalid peer IP: %s\n", argv[4]);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
else if (!is_valid_port(argv[5]))
|
||||
{
|
||||
fprintf(stderr, ">> Invalid peer port: %s\n", argv[5]);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
snprintf(tracker_ip, IP_LEN, argv[2]);
|
||||
snprintf(tracker_port, PORT_LEN, argv[3]);
|
||||
snprintf(my_ip, IP_LEN, argv[4]);
|
||||
snprintf(my_port, PORT_LEN, argv[5]);
|
||||
|
||||
char cas_str[strlen(argv[1])];
|
||||
snprintf(cas_str, strlen(argv[1])+1, argv[1]);
|
||||
char delim[] = ":";
|
||||
|
||||
int casc_count = count_occurences(argv[1], ':') + 1;
|
||||
char *cascade_files[casc_count];
|
||||
|
||||
char *ptr = strtok(cas_str, delim);
|
||||
int i = 0;
|
||||
|
||||
while (ptr != NULL)
|
||||
{
|
||||
if (strstr(ptr, ".cascade") != NULL)
|
||||
{
|
||||
cascade_files[i++] = ptr;
|
||||
ptr = strtok(NULL, delim);
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("Abort on %s\n", ptr);
|
||||
fprintf(stderr, ">> Invalid cascade file: %s\n", ptr);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
for (int j=0; j<casc_count; j++)
|
||||
{
|
||||
download_only_peer(cascade_files[j]);
|
||||
}
|
||||
|
||||
exit(EXIT_SUCCESS);
|
||||
}
|
115
A3/src/cascade.h
Normal file
115
A3/src/cascade.h
Normal file
@ -0,0 +1,115 @@
|
||||
|
||||
#pragma once
|
||||
#include "common.h"
|
||||
|
||||
#ifndef CASCADE_H
|
||||
#define CASCADE_H
|
||||
#define MAIN_ARGNUM 5 // number of command line arguments to main().
|
||||
#define BODY_SIZE 38
|
||||
#define HEADER_SIZE 16
|
||||
#define MESSAGE_SIZE 54
|
||||
#define REPLY_HEADER_SIZE 5
|
||||
#define PEER_REQUEST_DELAY 10
|
||||
#define PEER_REQUEST_HEADER_SIZE 64
|
||||
#define PEER_RESPONSE_HEADER_SIZE 9
|
||||
#define MAX_LINE 128
|
||||
|
||||
|
||||
struct RequestHeader
|
||||
{
|
||||
char protocol[4];
|
||||
unsigned int version;
|
||||
unsigned int command;
|
||||
unsigned int length;
|
||||
};
|
||||
|
||||
struct RequestBody
|
||||
{
|
||||
char hash[32];
|
||||
struct in_addr ip;
|
||||
unsigned short port;
|
||||
};
|
||||
|
||||
struct ClientRequest
|
||||
{
|
||||
char protocol[8];
|
||||
char reserved[12];
|
||||
uint64_t block_num;
|
||||
char hash[32];
|
||||
};
|
||||
|
||||
struct ClientResponseHeader
|
||||
{
|
||||
char error[1];
|
||||
uint64_t length;
|
||||
};
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
typedef struct csc_hashdata { uint8_t x[32]; } csc_hashdata_t;
|
||||
|
||||
typedef struct csc_ipport {
|
||||
uint32_t ip;
|
||||
uint16_t port;
|
||||
} csc_ipport_t;
|
||||
|
||||
typedef struct csc_block {
|
||||
uint64_t index; // The index of this block in the data file
|
||||
uint64_t offset; // Number of bytes the start of this block is offset from the start of the file
|
||||
uint64_t length; // Number of bytes within this block
|
||||
uint8_t completed; // Flag of if this block is present in local file system or not
|
||||
csc_hashdata_t hash; // Hash of this blocks bytes
|
||||
} csc_block_t;
|
||||
|
||||
typedef struct csc_file {
|
||||
uint64_t targetsize; // Size of completed data file
|
||||
uint64_t blocksize; // Size of individual blocks data is divided into
|
||||
csc_hashdata_t targethash; // Hash of complete data file
|
||||
uint64_t trailblocksize; // Size of last block. Will differ from standard block size if data does not evenly divide amoungst blocks
|
||||
uint64_t blockcount; // Number of blocks data is divided into
|
||||
csc_block_t* blocks; // Pointer to array of all blocks
|
||||
} csc_file_t;
|
||||
|
||||
typedef struct csc_peer {
|
||||
char ip[16]; // IP of a peer
|
||||
char port[8]; // Port of a peer
|
||||
uint32_t lastseen; // Timestamp of last time Tracker saw this Peer
|
||||
uint8_t good; // Flag for if this is 'Good' peer. e.g. Always provides valid responses according to protocol
|
||||
} csc_peer_t;
|
||||
|
||||
typedef struct csc_server {
|
||||
} csc_server_t;
|
||||
|
||||
/*
|
||||
* Parses a hex-string and returns the bytes corresponding to the value
|
||||
*/
|
||||
uint8_t* hex_to_bytes(const char* string);
|
||||
|
||||
/*
|
||||
* Parses a cascade file, given the sourcepath input and destination, which may or may not exist.
|
||||
* Returns a pointer to a datastructure describing the file, or NULL if the file could not be parsed
|
||||
*/
|
||||
csc_file_t* csc_parse_file(const char* sourcefile, const char* destination);
|
||||
|
||||
/*
|
||||
* Releases the memory allocated by a file datastructure
|
||||
*/
|
||||
void csc_free_file(csc_file_t* sourcefile);
|
||||
|
||||
/*
|
||||
* Attempts to get a list of peers from the tracker.
|
||||
* The peers should contain a pre-allocated set of memory that can hold at least peercount elements.
|
||||
* If the function is successful, the return code is zero and the value of peercount has been updated to contain the number of peers.
|
||||
* If the function fails, the return code is non-zero
|
||||
*/
|
||||
int csc_get_peers(csc_ipport_t tracker, csc_hashdata_t cascadehash, csc_ipport_t localaddress, uint8_t subscribe, uint32_t* peercount, csc_peer_t* peers);
|
||||
|
||||
/*
|
||||
* Downloads a block of data from a client.
|
||||
* The supplied buffer should be at least large enough to contain blocklength-bytes.
|
||||
* If the function is successful, the return code is zero, and the buffer contains data of the size requested by blocklength.
|
||||
* If the function fails, the return code is non-zero, and will reflect the peer statuscode (if given).
|
||||
*/
|
||||
int csc_download_block(csc_ipport_t client, csc_hashdata_t cascadehash, uint64_t blockno, uint64_t blocklength, void* buffer);
|
||||
|
||||
#endif
|
97
A3/src/common.c
Normal file
97
A3/src/common.c
Normal file
@ -0,0 +1,97 @@
|
||||
#include "common.h"
|
||||
|
||||
/*
|
||||
* below two utility functions are for parsing user input.
|
||||
* YOU ONLY NEED A WORKING UNDERSTANDING OF parse_command,
|
||||
* and how it stores parsed arguments (see common.h).
|
||||
*/
|
||||
command_t parse_command(char *user_input,
|
||||
args_t args) {
|
||||
|
||||
for (int i = 0; i < MAX_USER_ARGNUM; i++)
|
||||
args[i] = NULL;
|
||||
|
||||
char *saveptr;
|
||||
char *command_str = strtok_r(user_input, " \n", &saveptr);
|
||||
if (command_str == NULL) return ERROR;
|
||||
|
||||
if (string_equal(command_str, "/msg")) { // if command_str is /msg, recipient username
|
||||
args[0] = strtok_r(NULL, " \n", &saveptr); // and actual message will be stored in
|
||||
args[1] = strtok_r(NULL, "\n\x0", &saveptr); // first two arguments, respectively.
|
||||
|
||||
if (args[0] == NULL || args[1] == NULL) return ERROR;
|
||||
else return MSG;
|
||||
}
|
||||
|
||||
unsigned int num_args = extract_args(saveptr, args); // args now contains arguments to command_str.
|
||||
|
||||
return string_equal(command_str, "/login") && num_args == 4 ? LOGIN
|
||||
: string_equal(command_str, "/lookup") && num_args <= 1 ? LOOKUP
|
||||
: string_equal(command_str, "/show") && num_args <= 1 ? SHOW
|
||||
: string_equal(command_str, "/logout") && num_args == 0 ? LOGOUT
|
||||
: string_equal(command_str, "/exit") && num_args == 0 ? EXIT
|
||||
: ERROR;
|
||||
}
|
||||
|
||||
/*
|
||||
* auxiliary function used by parse_command.
|
||||
*/
|
||||
inline size_t extract_args(char *input,
|
||||
args_t args) {
|
||||
|
||||
char *saveptr;
|
||||
size_t num_args = 0;
|
||||
while ((input = strtok_r(input, " \n\x0", &saveptr)) != NULL) { // and still tokens left to extract
|
||||
|
||||
num_args++;
|
||||
if (num_args > MAX_USER_ARGNUM)
|
||||
break;
|
||||
|
||||
args[num_args-1] = input;
|
||||
input = NULL; // strtok needs to be called with a null pointer to keep searching.
|
||||
}
|
||||
return num_args;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* returns 1 if ip_string is a valid IP address; else 0
|
||||
*/
|
||||
int is_valid_ip(char *ip_string) {
|
||||
int ip[4];
|
||||
int num_parsed = sscanf(ip_string, "%d.%d.%d.%d", ip+0, ip+1, ip+2, ip+3);
|
||||
printf("ip_string: a%sa\n", ip_string);
|
||||
|
||||
if (num_parsed < 0) {
|
||||
fprintf(stderr, "sscanf() error: %s\n", strerror(errno));
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
else if (num_parsed != 4)
|
||||
return string_equal(ip_string, "localhost");
|
||||
|
||||
for (int i = 0; i < 4; i++)
|
||||
if (ip[i] > 255 || ip[i] < 0)
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* returns 1 if port_string is a valid port number; else 0
|
||||
*/
|
||||
int is_valid_port(char *port_string) {
|
||||
int port;
|
||||
int num_parsed = sscanf(port_string, "%d", &port);
|
||||
|
||||
if (num_parsed < 0) {
|
||||
fprintf(stderr, "sscanf() error: %s\n", strerror(errno));
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
else if (num_parsed != 1 || port < 0 || port > 65535)
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
67
A3/src/common.h
Normal file
67
A3/src/common.h
Normal file
@ -0,0 +1,67 @@
|
||||
#pragma once
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
#include "csapp.h"
|
||||
|
||||
/*
|
||||
* add macros and function declarations which should be
|
||||
* common between the name server and peer programs in this file.
|
||||
*/
|
||||
|
||||
#define USERNAME_LEN 32 // max length of a valid username.
|
||||
#define MAX_LINE 128 // max length of a line of user input.
|
||||
#define MAX_USER_ARGNUM 4 // max number of arguments to peer commands.
|
||||
|
||||
#define IP_LEN 16
|
||||
#define PORT_LEN 8
|
||||
|
||||
/* slightly less awkward string equality check */
|
||||
#define string_equal(x, y) (strncmp((x), (y), strlen(y)) == 0)
|
||||
|
||||
/* enum type used to represent client commands */
|
||||
typedef enum command_t {
|
||||
LOGIN,
|
||||
LOGOUT,
|
||||
EXIT,
|
||||
LOOKUP,
|
||||
MSG,
|
||||
SHOW,
|
||||
ERROR
|
||||
} command_t;
|
||||
|
||||
/* string array type of size MAX_USER_ARGNUM used to hold arguments to a command */
|
||||
typedef char *args_t[MAX_USER_ARGNUM];
|
||||
|
||||
|
||||
/*
|
||||
* given "input", a newline- or NULL-terminated line of
|
||||
* user input containing command, followed by 0 or more
|
||||
* space-separated arguments, and "args", an args_t array:
|
||||
* - parses command and stores arguments sequentially in args.
|
||||
* - returns a command_t code representing the command.
|
||||
* - on an invalid number of arguments, ERROR is returned.
|
||||
*
|
||||
* example: if command is "/login anders topsecret 130.225.245.178 1337", then
|
||||
* args is the array ["anders", "topsecret", "130.225.245.178", "1337"],
|
||||
* and the function returns LOGIN.
|
||||
* (if command is a /msg, then recipient username and actual message stored in args[0..1]).
|
||||
*/
|
||||
command_t parse_command(char *input,
|
||||
args_t args);
|
||||
|
||||
/*
|
||||
* extract arguments from a line of user input and store in args.
|
||||
*/
|
||||
size_t extract_args(char *input,
|
||||
args_t args);
|
||||
|
||||
|
||||
/*
|
||||
* naive validity checks of IP addresses and port numbers given as strings,
|
||||
* eg. at command line. both return zero on invalid IP/port, else non-zero.
|
||||
*/
|
||||
int is_valid_ip(char *ip_string);
|
||||
int is_valid_port(char *port_string);
|
1076
A3/src/csapp.c
Normal file
1076
A3/src/csapp.c
Normal file
File diff suppressed because it is too large
Load Diff
199
A3/src/csapp.h
Normal file
199
A3/src/csapp.h
Normal file
@ -0,0 +1,199 @@
|
||||
/*
|
||||
* csapp.h - prototypes and definitions for the CS:APP3e book
|
||||
*/
|
||||
/* $begin csapp.h */
|
||||
#ifndef __CSAPP_H__
|
||||
#define __CSAPP_H__
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdarg.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
#include <setjmp.h>
|
||||
#include <signal.h>
|
||||
#include <dirent.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/wait.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/mman.h>
|
||||
#include <errno.h>
|
||||
#include <math.h>
|
||||
#include <pthread.h>
|
||||
#include <semaphore.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netdb.h>
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
|
||||
/* Default file permissions are DEF_MODE & ~DEF_UMASK */
|
||||
/* $begin createmasks */
|
||||
#define DEF_MODE S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH
|
||||
#define DEF_UMASK S_IWGRP|S_IWOTH
|
||||
/* $end createmasks */
|
||||
|
||||
/* Simplifies calls to bind(), connect(), and accept() */
|
||||
/* $begin sockaddrdef */
|
||||
typedef struct sockaddr SA;
|
||||
/* $end sockaddrdef */
|
||||
|
||||
/* Persistent state for the robust I/O (Rio) package */
|
||||
/* $begin rio_t */
|
||||
#define RIO_BUFSIZE 8192
|
||||
typedef struct {
|
||||
int rio_fd; /* Descriptor for this internal buf */
|
||||
int rio_cnt; /* Unread bytes in internal buf */
|
||||
char *rio_bufptr; /* Next unread byte in internal buf */
|
||||
char rio_buf[RIO_BUFSIZE]; /* Internal buffer */
|
||||
} rio_t;
|
||||
/* $end rio_t */
|
||||
|
||||
/* External variables */
|
||||
extern int h_errno; /* Defined by BIND for DNS errors */
|
||||
extern char **environ; /* Defined by libc */
|
||||
|
||||
/* Misc constants */
|
||||
#define MAXLINE 8192 /* Max text line length */
|
||||
#define MAXBUF 8192 /* Max I/O buffer size */
|
||||
#define LISTENQ 1024 /* Second argument to listen() */
|
||||
|
||||
/* Our own error-handling functions */
|
||||
void unix_error(char *msg);
|
||||
void posix_error(int code, char *msg);
|
||||
void dns_error(char *msg);
|
||||
void gai_error(int code, char *msg);
|
||||
void app_error(char *msg);
|
||||
|
||||
/* Process control wrappers */
|
||||
pid_t Fork(void);
|
||||
void Execve(const char *filename, char *const argv[], char *const envp[]);
|
||||
pid_t Wait(int *status);
|
||||
pid_t Waitpid(pid_t pid, int *iptr, int options);
|
||||
void Kill(pid_t pid, int signum);
|
||||
unsigned int Sleep(unsigned int secs);
|
||||
void Pause(void);
|
||||
unsigned int Alarm(unsigned int seconds);
|
||||
void Setpgid(pid_t pid, pid_t pgid);
|
||||
pid_t Getpgrp();
|
||||
|
||||
/* Signal wrappers */
|
||||
typedef void handler_t(int);
|
||||
handler_t *Signal(int signum, handler_t *handler);
|
||||
void Sigprocmask(int how, const sigset_t *set, sigset_t *oldset);
|
||||
void Sigemptyset(sigset_t *set);
|
||||
void Sigfillset(sigset_t *set);
|
||||
void Sigaddset(sigset_t *set, int signum);
|
||||
void Sigdelset(sigset_t *set, int signum);
|
||||
int Sigismember(const sigset_t *set, int signum);
|
||||
int Sigsuspend(const sigset_t *set);
|
||||
|
||||
/* Sio (Signal-safe I/O) routines */
|
||||
ssize_t sio_puts(char s[]);
|
||||
ssize_t sio_putl(long v);
|
||||
void sio_error(char s[]);
|
||||
|
||||
/* Sio wrappers */
|
||||
ssize_t Sio_puts(char s[]);
|
||||
ssize_t Sio_putl(long v);
|
||||
void Sio_error(char s[]);
|
||||
|
||||
/* Unix I/O wrappers */
|
||||
int Open(const char *pathname, int flags, mode_t mode);
|
||||
ssize_t Read(int fd, void *buf, size_t count);
|
||||
ssize_t Write(int fd, const void *buf, size_t count);
|
||||
off_t Lseek(int fildes, off_t offset, int whence);
|
||||
void Close(int fd);
|
||||
int Select(int n, fd_set *readfds, fd_set *writefds, fd_set *exceptfds,
|
||||
struct timeval *timeout);
|
||||
int Dup2(int fd1, int fd2);
|
||||
void Stat(const char *filename, struct stat *buf);
|
||||
void Fstat(int fd, struct stat *buf) ;
|
||||
|
||||
/* Directory wrappers */
|
||||
DIR *Opendir(const char *name);
|
||||
struct dirent *Readdir(DIR *dirp);
|
||||
int Closedir(DIR *dirp);
|
||||
|
||||
/* Memory mapping wrappers */
|
||||
void *Mmap(void *addr, size_t len, int prot, int flags, int fd, off_t offset);
|
||||
void Munmap(void *start, size_t length);
|
||||
|
||||
/* Standard I/O wrappers */
|
||||
void Fclose(FILE *fp);
|
||||
FILE *Fdopen(int fd, const char *type);
|
||||
char *Fgets(char *ptr, int n, FILE *stream);
|
||||
FILE *Fopen(const char *filename, const char *mode);
|
||||
void Fputs(const char *ptr, FILE *stream);
|
||||
size_t Fread(void *ptr, size_t size, size_t nmemb, FILE *stream);
|
||||
void Fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream);
|
||||
|
||||
/* Dynamic storage allocation wrappers */
|
||||
void *Malloc(size_t size);
|
||||
void *Realloc(void *ptr, size_t size);
|
||||
void *Calloc(size_t nmemb, size_t size);
|
||||
void Free(void *ptr);
|
||||
|
||||
/* Sockets interface wrappers */
|
||||
int Socket(int domain, int type, int protocol);
|
||||
void Setsockopt(int s, int level, int optname, const void *optval, int optlen);
|
||||
void Bind(int sockfd, struct sockaddr *my_addr, int addrlen);
|
||||
void Listen(int s, int backlog);
|
||||
int Accept(int s, struct sockaddr *addr, socklen_t *addrlen);
|
||||
void Connect(int sockfd, struct sockaddr *serv_addr, int addrlen);
|
||||
|
||||
/* Protocol independent wrappers */
|
||||
void Getaddrinfo(const char *node, const char *service,
|
||||
const struct addrinfo *hints, struct addrinfo **res);
|
||||
void Getnameinfo(const struct sockaddr *sa, socklen_t salen, char *host,
|
||||
size_t hostlen, char *serv, size_t servlen, int flags);
|
||||
void Freeaddrinfo(struct addrinfo *res);
|
||||
void Inet_ntop(int af, const void *src, char *dst, socklen_t size);
|
||||
void Inet_pton(int af, const char *src, void *dst);
|
||||
|
||||
/* DNS wrappers */
|
||||
struct hostent *Gethostbyname(const char *name);
|
||||
struct hostent *Gethostbyaddr(const char *addr, int len, int type);
|
||||
|
||||
/* Pthreads thread control wrappers */
|
||||
void Pthread_create(pthread_t *tidp, pthread_attr_t *attrp,
|
||||
void * (*routine)(void *), void *argp);
|
||||
void Pthread_join(pthread_t tid, void **thread_return);
|
||||
void Pthread_cancel(pthread_t tid);
|
||||
void Pthread_detach(pthread_t tid);
|
||||
void Pthread_exit(void *retval);
|
||||
pthread_t Pthread_self(void);
|
||||
void Pthread_once(pthread_once_t *once_control, void (*init_function)());
|
||||
|
||||
/* POSIX semaphore wrappers */
|
||||
void Sem_init(sem_t *sem, int pshared, unsigned int value);
|
||||
void P(sem_t *sem);
|
||||
void V(sem_t *sem);
|
||||
|
||||
/* Rio (Robust I/O) package */
|
||||
ssize_t rio_readn(int fd, void *usrbuf, size_t n);
|
||||
ssize_t rio_writen(int fd, void *usrbuf, size_t n);
|
||||
void rio_readinitb(rio_t *rp, int fd);
|
||||
ssize_t rio_readnb(rio_t *rp, void *usrbuf, size_t n);
|
||||
ssize_t rio_readlineb(rio_t *rp, void *usrbuf, size_t maxlen);
|
||||
|
||||
/* Wrappers for Rio package */
|
||||
ssize_t Rio_readn(int fd, void *usrbuf, size_t n);
|
||||
void Rio_writen(int fd, void *usrbuf, size_t n);
|
||||
void Rio_readinitb(rio_t *rp, int fd);
|
||||
ssize_t Rio_readnb(rio_t *rp, void *usrbuf, size_t n);
|
||||
ssize_t Rio_readlineb(rio_t *rp, void *usrbuf, size_t maxlen);
|
||||
|
||||
/* Reentrant protocol-independent client/server helpers */
|
||||
int open_clientfd(char *hostname, char *port);
|
||||
int open_listenfd(char *port);
|
||||
|
||||
/* Wrappers for reentrant protocol-independent client/server helpers */
|
||||
int Open_clientfd(char *hostname, char *port);
|
||||
int Open_listenfd(char *port);
|
||||
|
||||
|
||||
#endif /* __CSAPP_H__ */
|
||||
/* $end csapp.h */
|
480
A3/src/sha256.c
Normal file
480
A3/src/sha256.c
Normal file
@ -0,0 +1,480 @@
|
||||
/*-
|
||||
* Copyright (c) 2001-2003 Allan Saddi <allan@saddi.com>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY ALLAN SADDI AND HIS CONTRIBUTORS ``AS IS''
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL ALLAN SADDI OR HIS CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* $Id: sha256.c 680 2003-07-25 21:57:49Z asaddi $
|
||||
*/
|
||||
|
||||
/*
|
||||
* Define WORDS_BIGENDIAN if compiling on a big-endian architecture.
|
||||
*
|
||||
* Define SHA256_TEST to test the implementation using the NIST's
|
||||
* sample messages. The output should be:
|
||||
*
|
||||
* ba7816bf 8f01cfea 414140de 5dae2223 b00361a3 96177a9c b410ff61 f20015ad
|
||||
* 248d6a61 d20638b8 e5c02693 0c3e6039 a33ce459 64ff2167 f6ecedd4 19db06c1
|
||||
* cdc76e5c 9914fb92 81a1c7e2 84d73e67 f1809a48 a497200e 046d39cc c7112cd0
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "clamav-config.h"
|
||||
#endif /* HAVE_CONFIG_H */
|
||||
|
||||
#if HAVE_INTTYPES_H
|
||||
# include <inttypes.h>
|
||||
#else
|
||||
# if HAVE_STDINT_H
|
||||
# include <stdint.h>
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "sha256.h"
|
||||
|
||||
#ifndef lint
|
||||
static const char rcsid[] =
|
||||
"$Id: sha256.c 680 2003-07-25 21:57:49Z asaddi $";
|
||||
#endif /* !lint */
|
||||
|
||||
#define ROTL(x, n) (((x) << (n)) | ((x) >> (32 - (n))))
|
||||
#define ROTR(x, n) (((x) >> (n)) | ((x) << (32 - (n))))
|
||||
|
||||
#define Ch(x, y, z) ((z) ^ ((x) & ((y) ^ (z))))
|
||||
#define Maj(x, y, z) (((x) & ((y) | (z))) | ((y) & (z)))
|
||||
#define SIGMA0(x) (ROTR((x), 2) ^ ROTR((x), 13) ^ ROTR((x), 22))
|
||||
#define SIGMA1(x) (ROTR((x), 6) ^ ROTR((x), 11) ^ ROTR((x), 25))
|
||||
#define sigma0(x) (ROTR((x), 7) ^ ROTR((x), 18) ^ ((x) >> 3))
|
||||
#define sigma1(x) (ROTR((x), 17) ^ ROTR((x), 19) ^ ((x) >> 10))
|
||||
|
||||
#define DO_ROUND() { \
|
||||
t1 = h + SIGMA1(e) + Ch(e, f, g) + *(Kp++) + *(W++); \
|
||||
t2 = SIGMA0(a) + Maj(a, b, c); \
|
||||
h = g; \
|
||||
g = f; \
|
||||
f = e; \
|
||||
e = d + t1; \
|
||||
d = c; \
|
||||
c = b; \
|
||||
b = a; \
|
||||
a = t1 + t2; \
|
||||
}
|
||||
|
||||
static const uint32_t K[64] = {
|
||||
0x428a2f98L, 0x71374491L, 0xb5c0fbcfL, 0xe9b5dba5L,
|
||||
0x3956c25bL, 0x59f111f1L, 0x923f82a4L, 0xab1c5ed5L,
|
||||
0xd807aa98L, 0x12835b01L, 0x243185beL, 0x550c7dc3L,
|
||||
0x72be5d74L, 0x80deb1feL, 0x9bdc06a7L, 0xc19bf174L,
|
||||
0xe49b69c1L, 0xefbe4786L, 0x0fc19dc6L, 0x240ca1ccL,
|
||||
0x2de92c6fL, 0x4a7484aaL, 0x5cb0a9dcL, 0x76f988daL,
|
||||
0x983e5152L, 0xa831c66dL, 0xb00327c8L, 0xbf597fc7L,
|
||||
0xc6e00bf3L, 0xd5a79147L, 0x06ca6351L, 0x14292967L,
|
||||
0x27b70a85L, 0x2e1b2138L, 0x4d2c6dfcL, 0x53380d13L,
|
||||
0x650a7354L, 0x766a0abbL, 0x81c2c92eL, 0x92722c85L,
|
||||
0xa2bfe8a1L, 0xa81a664bL, 0xc24b8b70L, 0xc76c51a3L,
|
||||
0xd192e819L, 0xd6990624L, 0xf40e3585L, 0x106aa070L,
|
||||
0x19a4c116L, 0x1e376c08L, 0x2748774cL, 0x34b0bcb5L,
|
||||
0x391c0cb3L, 0x4ed8aa4aL, 0x5b9cca4fL, 0x682e6ff3L,
|
||||
0x748f82eeL, 0x78a5636fL, 0x84c87814L, 0x8cc70208L,
|
||||
0x90befffaL, 0xa4506cebL, 0xbef9a3f7L, 0xc67178f2L
|
||||
};
|
||||
|
||||
#ifndef RUNTIME_ENDIAN
|
||||
|
||||
#if WORDS_BIGENDIAN == 1
|
||||
|
||||
#define BYTESWAP(x) (x)
|
||||
#define BYTESWAP64(x) (x)
|
||||
|
||||
#else /* WORDS_BIGENDIAN */
|
||||
|
||||
#define BYTESWAP(x) ((ROTR((x), 8) & 0xff00ff00L) | \
|
||||
(ROTL((x), 8) & 0x00ff00ffL))
|
||||
#define BYTESWAP64(x) _byteswap64(x)
|
||||
|
||||
static inline uint64_t _byteswap64(uint64_t x)
|
||||
{
|
||||
uint32_t a = x >> 32;
|
||||
uint32_t b = (uint32_t) x;
|
||||
return ((uint64_t) BYTESWAP(b) << 32) | (uint64_t) BYTESWAP(a);
|
||||
}
|
||||
|
||||
#endif /* WORDS_BIGENDIAN */
|
||||
|
||||
#else /* !RUNTIME_ENDIAN */
|
||||
|
||||
#define BYTESWAP(x) _byteswap(sc->littleEndian, x)
|
||||
#define BYTESWAP64(x) _byteswap64(sc->littleEndian, x)
|
||||
|
||||
#define _BYTESWAP(x) ((ROTR((x), 8) & 0xff00ff00L) | \
|
||||
(ROTL((x), 8) & 0x00ff00ffL))
|
||||
#define _BYTESWAP64(x) __byteswap64(x)
|
||||
|
||||
static inline uint64_t __byteswap64(uint64_t x)
|
||||
{
|
||||
uint32_t a = x >> 32;
|
||||
uint32_t b = (uint32_t) x;
|
||||
return ((uint64_t) _BYTESWAP(b) << 32) | (uint64_t) _BYTESWAP(a);
|
||||
}
|
||||
|
||||
static inline uint32_t _byteswap(int littleEndian, uint32_t x)
|
||||
{
|
||||
if (!littleEndian)
|
||||
return x;
|
||||
else
|
||||
return _BYTESWAP(x);
|
||||
}
|
||||
|
||||
static inline uint64_t _byteswap64(int littleEndian, uint64_t x)
|
||||
{
|
||||
if (!littleEndian)
|
||||
return x;
|
||||
else
|
||||
return _BYTESWAP64(x);
|
||||
}
|
||||
|
||||
static inline void setEndian(int *littleEndianp)
|
||||
{
|
||||
union {
|
||||
uint32_t w;
|
||||
uint8_t b[4];
|
||||
} endian;
|
||||
|
||||
endian.w = 1L;
|
||||
*littleEndianp = endian.b[0] != 0;
|
||||
}
|
||||
|
||||
#endif /* !RUNTIME_ENDIAN */
|
||||
|
||||
static const uint8_t padding[64] = {
|
||||
0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
|
||||
};
|
||||
|
||||
void
|
||||
sha256_init (SHA256_CTX *sc)
|
||||
{
|
||||
#ifdef RUNTIME_ENDIAN
|
||||
setEndian (&sc->littleEndian);
|
||||
#endif /* RUNTIME_ENDIAN */
|
||||
|
||||
sc->totalLength = 0LL;
|
||||
sc->hash[0] = 0x6a09e667L;
|
||||
sc->hash[1] = 0xbb67ae85L;
|
||||
sc->hash[2] = 0x3c6ef372L;
|
||||
sc->hash[3] = 0xa54ff53aL;
|
||||
sc->hash[4] = 0x510e527fL;
|
||||
sc->hash[5] = 0x9b05688cL;
|
||||
sc->hash[6] = 0x1f83d9abL;
|
||||
sc->hash[7] = 0x5be0cd19L;
|
||||
sc->bufferLength = 0L;
|
||||
}
|
||||
|
||||
static void
|
||||
burnStack (int size)
|
||||
{
|
||||
char buf[128];
|
||||
|
||||
memset (buf, 0, sizeof (buf));
|
||||
size -= sizeof (buf);
|
||||
if (size > 0)
|
||||
burnStack (size);
|
||||
}
|
||||
|
||||
static void
|
||||
SHA256Guts (SHA256_CTX *sc, const uint32_t *cbuf)
|
||||
{
|
||||
uint32_t buf[64];
|
||||
uint32_t *W, *W2, *W7, *W15, *W16;
|
||||
uint32_t a, b, c, d, e, f, g, h;
|
||||
uint32_t t1, t2;
|
||||
const uint32_t *Kp;
|
||||
int i;
|
||||
|
||||
W = buf;
|
||||
|
||||
for (i = 15; i >= 0; i--) {
|
||||
*(W++) = BYTESWAP(*cbuf);
|
||||
cbuf++;
|
||||
}
|
||||
|
||||
W16 = &buf[0];
|
||||
W15 = &buf[1];
|
||||
W7 = &buf[9];
|
||||
W2 = &buf[14];
|
||||
|
||||
for (i = 47; i >= 0; i--) {
|
||||
*(W++) = sigma1(*W2) + *(W7++) + sigma0(*W15) + *(W16++);
|
||||
W2++;
|
||||
W15++;
|
||||
}
|
||||
|
||||
a = sc->hash[0];
|
||||
b = sc->hash[1];
|
||||
c = sc->hash[2];
|
||||
d = sc->hash[3];
|
||||
e = sc->hash[4];
|
||||
f = sc->hash[5];
|
||||
g = sc->hash[6];
|
||||
h = sc->hash[7];
|
||||
|
||||
Kp = K;
|
||||
W = buf;
|
||||
|
||||
#ifndef SHA256_UNROLL
|
||||
#define SHA256_UNROLL 4
|
||||
#endif /* !SHA256_UNROLL */
|
||||
|
||||
#if SHA256_UNROLL == 1
|
||||
for (i = 63; i >= 0; i--)
|
||||
DO_ROUND();
|
||||
#elif SHA256_UNROLL == 2
|
||||
for (i = 31; i >= 0; i--) {
|
||||
DO_ROUND(); DO_ROUND();
|
||||
}
|
||||
#elif SHA256_UNROLL == 4
|
||||
for (i = 15; i >= 0; i--) {
|
||||
DO_ROUND(); DO_ROUND(); DO_ROUND(); DO_ROUND();
|
||||
}
|
||||
#elif SHA256_UNROLL == 8
|
||||
for (i = 7; i >= 0; i--) {
|
||||
DO_ROUND(); DO_ROUND(); DO_ROUND(); DO_ROUND();
|
||||
DO_ROUND(); DO_ROUND(); DO_ROUND(); DO_ROUND();
|
||||
}
|
||||
#elif SHA256_UNROLL == 16
|
||||
for (i = 3; i >= 0; i--) {
|
||||
DO_ROUND(); DO_ROUND(); DO_ROUND(); DO_ROUND();
|
||||
DO_ROUND(); DO_ROUND(); DO_ROUND(); DO_ROUND();
|
||||
DO_ROUND(); DO_ROUND(); DO_ROUND(); DO_ROUND();
|
||||
DO_ROUND(); DO_ROUND(); DO_ROUND(); DO_ROUND();
|
||||
}
|
||||
#elif SHA256_UNROLL == 32
|
||||
for (i = 1; i >= 0; i--) {
|
||||
DO_ROUND(); DO_ROUND(); DO_ROUND(); DO_ROUND();
|
||||
DO_ROUND(); DO_ROUND(); DO_ROUND(); DO_ROUND();
|
||||
DO_ROUND(); DO_ROUND(); DO_ROUND(); DO_ROUND();
|
||||
DO_ROUND(); DO_ROUND(); DO_ROUND(); DO_ROUND();
|
||||
DO_ROUND(); DO_ROUND(); DO_ROUND(); DO_ROUND();
|
||||
DO_ROUND(); DO_ROUND(); DO_ROUND(); DO_ROUND();
|
||||
DO_ROUND(); DO_ROUND(); DO_ROUND(); DO_ROUND();
|
||||
DO_ROUND(); DO_ROUND(); DO_ROUND(); DO_ROUND();
|
||||
}
|
||||
#elif SHA256_UNROLL == 64
|
||||
DO_ROUND(); DO_ROUND(); DO_ROUND(); DO_ROUND();
|
||||
DO_ROUND(); DO_ROUND(); DO_ROUND(); DO_ROUND();
|
||||
DO_ROUND(); DO_ROUND(); DO_ROUND(); DO_ROUND();
|
||||
DO_ROUND(); DO_ROUND(); DO_ROUND(); DO_ROUND();
|
||||
DO_ROUND(); DO_ROUND(); DO_ROUND(); DO_ROUND();
|
||||
DO_ROUND(); DO_ROUND(); DO_ROUND(); DO_ROUND();
|
||||
DO_ROUND(); DO_ROUND(); DO_ROUND(); DO_ROUND();
|
||||
DO_ROUND(); DO_ROUND(); DO_ROUND(); DO_ROUND();
|
||||
DO_ROUND(); DO_ROUND(); DO_ROUND(); DO_ROUND();
|
||||
DO_ROUND(); DO_ROUND(); DO_ROUND(); DO_ROUND();
|
||||
DO_ROUND(); DO_ROUND(); DO_ROUND(); DO_ROUND();
|
||||
DO_ROUND(); DO_ROUND(); DO_ROUND(); DO_ROUND();
|
||||
DO_ROUND(); DO_ROUND(); DO_ROUND(); DO_ROUND();
|
||||
DO_ROUND(); DO_ROUND(); DO_ROUND(); DO_ROUND();
|
||||
DO_ROUND(); DO_ROUND(); DO_ROUND(); DO_ROUND();
|
||||
DO_ROUND(); DO_ROUND(); DO_ROUND(); DO_ROUND();
|
||||
#else
|
||||
#error "SHA256_UNROLL must be 1, 2, 4, 8, 16, 32, or 64!"
|
||||
#endif
|
||||
|
||||
sc->hash[0] += a;
|
||||
sc->hash[1] += b;
|
||||
sc->hash[2] += c;
|
||||
sc->hash[3] += d;
|
||||
sc->hash[4] += e;
|
||||
sc->hash[5] += f;
|
||||
sc->hash[6] += g;
|
||||
sc->hash[7] += h;
|
||||
}
|
||||
|
||||
void
|
||||
sha256_update (SHA256_CTX *sc, const void *vdata, uint32_t len)
|
||||
{
|
||||
const uint8_t *data = vdata;
|
||||
uint32_t bufferBytesLeft;
|
||||
uint32_t bytesToCopy;
|
||||
int needBurn = 0;
|
||||
#ifdef SHA256_FAST_COPY
|
||||
if (sc->bufferLength) {
|
||||
bufferBytesLeft = 64L - sc->bufferLength;
|
||||
|
||||
bytesToCopy = bufferBytesLeft;
|
||||
if (bytesToCopy > len)
|
||||
bytesToCopy = len;
|
||||
|
||||
memcpy (&sc->buffer.bytes[sc->bufferLength], data, bytesToCopy);
|
||||
|
||||
sc->totalLength += bytesToCopy * 8L;
|
||||
|
||||
sc->bufferLength += bytesToCopy;
|
||||
data += bytesToCopy;
|
||||
len -= bytesToCopy;
|
||||
|
||||
if (sc->bufferLength == 64L) {
|
||||
SHA256Guts (sc, sc->buffer.words);
|
||||
needBurn = 1;
|
||||
sc->bufferLength = 0L;
|
||||
}
|
||||
}
|
||||
|
||||
while (len > 63L) {
|
||||
sc->totalLength += 512L;
|
||||
|
||||
SHA256Guts (sc, data);
|
||||
needBurn = 1;
|
||||
|
||||
data += 64L;
|
||||
len -= 64L;
|
||||
}
|
||||
|
||||
if (len) {
|
||||
memcpy (&sc->buffer.bytes[sc->bufferLength], data, len);
|
||||
|
||||
sc->totalLength += len * 8L;
|
||||
|
||||
sc->bufferLength += len;
|
||||
}
|
||||
#else /* SHA256_FAST_COPY */
|
||||
while (len) {
|
||||
bufferBytesLeft = 64L - sc->bufferLength;
|
||||
|
||||
bytesToCopy = bufferBytesLeft;
|
||||
if (bytesToCopy > len)
|
||||
bytesToCopy = len;
|
||||
|
||||
memcpy (&sc->buffer.bytes[sc->bufferLength], data, bytesToCopy);
|
||||
|
||||
sc->totalLength += bytesToCopy * 8L;
|
||||
|
||||
sc->bufferLength += bytesToCopy;
|
||||
data += bytesToCopy;
|
||||
len -= bytesToCopy;
|
||||
|
||||
if (sc->bufferLength == 64L) {
|
||||
SHA256Guts (sc, sc->buffer.words);
|
||||
needBurn = 1;
|
||||
sc->bufferLength = 0L;
|
||||
}
|
||||
}
|
||||
#endif /* SHA256_FAST_COPY */
|
||||
|
||||
if (needBurn)
|
||||
burnStack (sizeof (uint32_t[74]) + sizeof (uint32_t *[6]) + sizeof (int));
|
||||
}
|
||||
|
||||
void
|
||||
sha256_final (SHA256_CTX *sc, uint8_t hash[SHA256_HASH_SIZE])
|
||||
{
|
||||
uint32_t bytesToPad;
|
||||
uint64_t lengthPad;
|
||||
int i;
|
||||
|
||||
bytesToPad = 120L - sc->bufferLength;
|
||||
if (bytesToPad > 64L)
|
||||
bytesToPad -= 64L;
|
||||
|
||||
lengthPad = BYTESWAP64(sc->totalLength);
|
||||
|
||||
sha256_update (sc, padding, bytesToPad);
|
||||
sha256_update (sc, &lengthPad, 8L);
|
||||
|
||||
if (hash) {
|
||||
for (i = 0; i < SHA256_HASH_WORDS; i++) {
|
||||
#ifdef SHA256_FAST_COPY
|
||||
*((uint32_t *) hash) = BYTESWAP(sc->hash[i]);
|
||||
#else /* SHA256_FAST_COPY */
|
||||
hash[0] = (uint8_t) (sc->hash[i] >> 24);
|
||||
hash[1] = (uint8_t) (sc->hash[i] >> 16);
|
||||
hash[2] = (uint8_t) (sc->hash[i] >> 8);
|
||||
hash[3] = (uint8_t) sc->hash[i];
|
||||
#endif /* SHA256_FAST_COPY */
|
||||
hash += 4;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef SHA256_TEST
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
int
|
||||
main (int argc, char *argv[])
|
||||
{
|
||||
SHA256_CTX foo;
|
||||
uint8_t hash[SHA256_HASH_SIZE];
|
||||
char buf[1000];
|
||||
int i;
|
||||
|
||||
sha256_init (&foo);
|
||||
sha256_update (&foo, "abc", 3);
|
||||
sha256_final (&foo, hash);
|
||||
|
||||
for (i = 0; i < SHA256_HASH_SIZE;) {
|
||||
printf ("%02x", hash[i++]);
|
||||
if (!(i % 4))
|
||||
printf (" ");
|
||||
}
|
||||
printf ("\n");
|
||||
|
||||
sha256_init (&foo);
|
||||
sha256_update (&foo,
|
||||
"abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq",
|
||||
56);
|
||||
sha256_final (&foo, hash);
|
||||
|
||||
for (i = 0; i < SHA256_HASH_SIZE;) {
|
||||
printf ("%02x", hash[i++]);
|
||||
if (!(i % 4))
|
||||
printf (" ");
|
||||
}
|
||||
printf ("\n");
|
||||
|
||||
sha256_init (&foo);
|
||||
memset (buf, 'a', sizeof (buf));
|
||||
for (i = 0; i < 1000; i++)
|
||||
sha256_update (&foo, buf, sizeof (buf));
|
||||
sha256_final (&foo, hash);
|
||||
|
||||
for (i = 0; i < SHA256_HASH_SIZE;) {
|
||||
printf ("%02x", hash[i++]);
|
||||
if (!(i % 4))
|
||||
printf (" ");
|
||||
}
|
||||
printf ("\n");
|
||||
|
||||
exit (0);
|
||||
}
|
||||
|
||||
#endif /* SHA256_TEST */
|
66
A3/src/sha256.h
Normal file
66
A3/src/sha256.h
Normal file
@ -0,0 +1,66 @@
|
||||
/*-
|
||||
* Copyright (c) 2001-2003 Allan Saddi <allan@saddi.com>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY ALLAN SADDI AND HIS CONTRIBUTORS ``AS IS''
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL ALLAN SADDI OR HIS CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* $Id: sha256.h 348 2003-02-23 22:12:06Z asaddi $
|
||||
*/
|
||||
|
||||
#ifndef _SHA256_H
|
||||
#define _SHA256_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#define SHA256_HASH_SIZE 32
|
||||
|
||||
/* Hash size in 32-bit words */
|
||||
#define SHA256_HASH_WORDS 8
|
||||
|
||||
struct _SHA256Context {
|
||||
uint64_t totalLength;
|
||||
uint32_t hash[SHA256_HASH_WORDS];
|
||||
uint32_t bufferLength;
|
||||
union {
|
||||
uint32_t words[16];
|
||||
uint8_t bytes[64];
|
||||
} buffer;
|
||||
#ifdef RUNTIME_ENDIAN
|
||||
int littleEndian;
|
||||
#endif /* RUNTIME_ENDIAN */
|
||||
};
|
||||
|
||||
typedef struct _SHA256Context SHA256_CTX;
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
void sha256_init (SHA256_CTX *sc);
|
||||
void sha256_update (SHA256_CTX *sc, const void *data, uint32_t len);
|
||||
void sha256_final (SHA256_CTX *sc, uint8_t hash[SHA256_HASH_SIZE]);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* !_SHA256_H */
|
BIN
A3/src/tests/shakespeare.100kib.txt.cascade
Normal file
BIN
A3/src/tests/shakespeare.100kib.txt.cascade
Normal file
Binary file not shown.
BIN
A3/src/tests/shakespeare.10kib.txt.cascade
Normal file
BIN
A3/src/tests/shakespeare.10kib.txt.cascade
Normal file
Binary file not shown.
BIN
A3/src/tests/shakespeare.10mib.txt.cascade
Normal file
BIN
A3/src/tests/shakespeare.10mib.txt.cascade
Normal file
Binary file not shown.
BIN
A3/src/tests/shakespeare.1kib.txt.cascade
Normal file
BIN
A3/src/tests/shakespeare.1kib.txt.cascade
Normal file
Binary file not shown.
BIN
A3/src/tests/shakespeare.1mib.txt.cascade
Normal file
BIN
A3/src/tests/shakespeare.1mib.txt.cascade
Normal file
Binary file not shown.
Reference in New Issue
Block a user