Compare commits

..

No commits in common. "master" and "task_2_4" have entirely different histories.

45 changed files with 27 additions and 1881 deletions

View File

@ -1,7 +1,23 @@
# AAE-CNAS-Labs
Tasks and solutions for WUST ETEA00008L.
Repository with tasks for Computer Networks and Systems laboratory classes
Sergiusz Warga
Wrocław University of Science and Technology
ETEA00008L: Computer Networks and Systems laboratory classes
## Topic 1 Little warmup
I'm sure you are all proficient C/C++ programmers, but - just in case you had a long break and forgot some things - lets do a little warmup.
Write your own version of Unix "cp" (copy) command.
As a bare minimum - please write a program that:
- [x] accepts source and destination filenames as its arguments (you DO remember how to use argc and argv ?)
- [x] makes a copy of indicated file
- [x] returns 0 on success, any non-zero value on error
- [x] uses ONLY POSIX I/O functions (open, close, read, write - consult appropriate manuals)
NOTICE: Do not assume, that you can read entire file into memory. Please read manuals carefully - pay attention to each function's return value!
I'm sure this task will prove to be to easy to some of you - in this case you can extend your program - for example you can add features to allow:
- [ ] copy source_file dest_dir (copy source file to the indicated directory, keeping its name)
- copy file1 file2 file3 dest_dir (copy files file1...file3 into destination directory)
- ... ?
As a solution - provide your source code here.

View File

@ -1,10 +0,0 @@
struct CircBuffer {
union {
struct {
int size;
int free_idx;
} info;
char padding[1024];
};
double data[8192];
};

View File

@ -1,28 +0,0 @@
// From https://github.com/veltzer/demos-linux
const long long NSEC_PER_SEC=1000000000;
static inline unsigned long long timespec_diff_nano(struct timespec* x, struct timespec* y) {
return (x->tv_sec-y->tv_sec)*NSEC_PER_SEC+(x->tv_nsec-y->tv_nsec);
}
static inline void timespec_sub(struct timespec* result, struct timespec* x, struct timespec* y) {
/* Perform the carry for the later subtraction by updating Y. */
if (x->tv_nsec < y->tv_nsec) {
int nsec = (y->tv_nsec - x->tv_nsec) / NSEC_PER_SEC + 1;
y->tv_nsec -= NSEC_PER_SEC * nsec;
y->tv_sec += nsec;
}
if (x->tv_nsec - y->tv_nsec > NSEC_PER_SEC) {
int nsec = (x->tv_nsec - y->tv_nsec) / NSEC_PER_SEC;
y->tv_nsec += NSEC_PER_SEC * nsec;
y->tv_sec -= nsec;
}
/* Compute the time remaining to wait. `tv_nsec' is certainly positive. */
result->tv_sec = x->tv_sec - y->tv_sec;
result->tv_nsec = x->tv_nsec - y->tv_nsec;
/* Check that result is not negative */
// CHECK_ASSERT(x->tv_sec >= y->tv_sec);
}
// END From https://github.com/veltzer/demos-linux

View File

@ -1,86 +0,0 @@
//
// Written for Computer Networks and Systems lab classes
// AUTHOR : Sergiusz Warga
#include <fcntl.h>
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/mman.h>
#include <sys/types.h>
#include <unistd.h>
#include <time.h>
#include "CircBuffer.h"
#include "funs.h"
void handle_arguments(int argc, char *argv[]) {
if (argc != 3) {
fprintf(stderr, "Usage: %s REFRESHING_FREQUENCY ALPHA\n", argv[0]);
exit(EXIT_FAILURE);
}
if (strtol(argv[1], NULL, 10) < 2) {
fprintf(stderr, "Refreshing frequency should be at least 2Hz!\n");
exit(EXIT_FAILURE);
}
if (strtod(argv[2], NULL) > 1 || strtod(argv[2], NULL) < 0) {
fprintf(stderr, "Alpha coefficient should be in range [0, 1]!\n");
exit(EXIT_FAILURE);
}
}
_Noreturn void k_avg(int fd, int refreshing_frequency, double alpha) {
// Exponential Moving Average
printf("A k_avg has been called\n");
//----- Initialize the buffer -----
struct CircBuffer *buffer;
buffer = mmap(NULL, sizeof(struct CircBuffer), PROT_READ, MAP_SHARED, fd, 0);
if (buffer == MAP_FAILED) {
fprintf(stderr, "mmap: ");
exit(EXIT_FAILURE);
}
struct timespec delay, tic, toc;
delay.tv_sec = 0;
delay.tv_nsec = (1./refreshing_frequency * NSEC_PER_SEC); // 1/f in nanoseconds
clock_gettime(CLOCK_REALTIME, &tic);
double ema;
int read_idx;
read_idx = buffer->info.free_idx - 1;
ema = buffer->data[read_idx];
printf("Refreshing period = %ldms\n", delay.tv_nsec/1000000);
while (1) {
clock_gettime(CLOCK_REALTIME, &toc);
if (timespec_diff_nano(&toc, &tic) > delay.tv_nsec) {
printf("EMA = %f\n", ema);
clock_gettime(CLOCK_REALTIME, &tic);
}
while (read_idx == ((buffer->info.free_idx - 1) % buffer->info.size)) {};
read_idx = ++read_idx % buffer->info.size;
ema = alpha * buffer->data[read_idx] + (1 - alpha) * ema;
}
}
int main(int argc, char *argv[]) {
handle_arguments(argc, argv);
//----- Open a shared memory -----
const char *memory_name = "/dsp";
int fd = shm_open(memory_name, O_RDONLY, 0777);
if (fd < 0) {
fprintf(stderr, "shm_open: ");
exit(EXIT_FAILURE);
}
printf("Shared memory file descriptor: %d\n", fd);
k_avg(fd, strtol(argv[1], NULL, 10), strtod(argv[2], NULL));
return 0;
}

View File

@ -1,100 +0,0 @@
//
// Written for Computer Networks and Systems lab classes
// AUTHOR : Sergiusz Warga
#include <fcntl.h>
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/mman.h>
#include <sys/types.h>
#include <unistd.h>
#include <time.h>
#include "CircBuffer.h"
#include "funs.h"
void handle_arguments(int argc, char *argv[]) {
if (argc != 3) {
fprintf(stderr, "Usage: %s SAMPLING_FREQUENCY REFRESHING_FREQUENCY\n", argv[0]);
exit(EXIT_FAILURE);
}
if (strtol(argv[1], NULL, 10) < 2) {
fprintf(stderr, "Sampling frequency should be at least 400Hz!\n");
exit(EXIT_FAILURE);
}
if (strtol(argv[2], NULL, 10) > 1 || strtod(argv[2], NULL) < 0) {
fprintf(stderr, "Refreshing frequency should be at least 1Hz!\n");
exit(EXIT_FAILURE);
}
}
int crosses_zero(double prev, double curr) {
// let's just ignore 0 for now
return (prev > 0 && curr < 0) || (prev < 0 && curr > 0);
}
_Noreturn void k_f0(int fd, int sampling_frequency, int refreshing_frequency) {
printf("A k_f0 has been called\n");
//----- Initialize the buffer -----
struct CircBuffer *buffer;
buffer = mmap(NULL, sizeof(struct CircBuffer), PROT_READ, MAP_SHARED, fd, 0);
if (buffer == MAP_FAILED) {
fprintf(stderr, "mmap: ");
exit(EXIT_FAILURE);
}
struct timespec tic, toc;
unsigned long long delay = NSEC_PER_SEC*1./refreshing_frequency;
clock_gettime(CLOCK_REALTIME, &tic);
int transitions = 0;
int samples = 0;
int read_idx;
read_idx = buffer->info.free_idx - 1;
while (1) {
clock_gettime(CLOCK_REALTIME, &toc);
if (timespec_diff_nano(&toc, &tic) > delay) {
double t_samp = 1./sampling_frequency;
// printf("t_samp = %fs\n", t_samp);
// printf("n_samp = %d\n", samples);
double t_anal = t_samp*samples;
// printf("t_anal = %fs\n", t_anal);
// printf("n_tran = %d\n", transitions);
printf("f = %fHz\n", transitions/(2*t_anal));
transitions = 0;
samples = 0;
clock_gettime(CLOCK_REALTIME, &tic);
}
if (crosses_zero(buffer->data[read_idx-1], buffer->data[read_idx])) {
++transitions;
}
while (read_idx == ((buffer->info.free_idx - 1) % buffer->info.size)) {};
read_idx = ++read_idx % buffer->info.size;
++samples;
}
}
int main(int argc, char *argv[]) {
handle_arguments(argc, argv);
//----- Open a shared memory -----
const char *memory_name = "/dsp";
int fd = shm_open(memory_name, O_RDONLY, 0777);
if (fd < 0) {
fprintf(stderr, "shm_open: ");
exit(EXIT_FAILURE);
}
printf("Shared memory file descriptor: %d\n", fd);
k_f0(fd, strtol(argv[1], NULL, 10), strtol(argv[2], NULL, 10));
return 0;
}

View File

@ -1,108 +0,0 @@
//
// Written for Computer Networks and Systems lab classes
// AUTHOR : Sergiusz Warga
#include <fcntl.h>
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/mman.h>
// #include <sys/types.h>
#include <unistd.h>
#include <time.h>
#include "CircBuffer.h"
#include "funs.h"
#define PI 3.14
#define SIG_FREQ 100
void handle_arguments(int argc, char *argv[]) {
if (argc != 2) {
fprintf(stderr, "Usage: %s SAMPLING_FREQUENCY\n", argv[0]);
exit(EXIT_FAILURE);
}
if (strtol(argv[1], NULL, 10) < 400) {
fprintf(stderr, "Sampling frequency should be at least 400Hz!\n");
exit(EXIT_FAILURE);
}
}
double get_sample(int signal_frequeuncy, int sampling_frequency, unsigned int sample_no) {
// TODO: Just a sketch, gotta rewrite
double step = 2.*PI/((double)sampling_frequency/signal_frequeuncy); // Step in radians
return sin(sample_no*step);
}
_Noreturn void producer(int fd, int sampling_frequency) { // That's something new I've learned and I think that
// function specifiers are cute.
printf("The producer has been called\n");
//----- Initialize the buffer -----
struct CircBuffer *buffer;
buffer = mmap(NULL, sizeof(struct CircBuffer), PROT_WRITE, MAP_SHARED, fd, 0);
if (buffer == MAP_FAILED) {
fprintf(stderr, "mmap: ");
exit(EXIT_FAILURE);
}
unsigned int i = 0;
int free_idx;
struct timespec delay, tic, toc;
delay.tv_sec = 0;
delay.tv_nsec = (int) (1./sampling_frequency * NSEC_PER_SEC); // 1/f in nanoseconds
clock_gettime(CLOCK_REALTIME, &tic);
clock_gettime(CLOCK_REALTIME, &toc);
printf("Starting to sampling the signal at %dHz with t_s = %ldns\n", sampling_frequency, delay.tv_nsec);
//----- Fill the buffer -----
while (1) {
clock_gettime(CLOCK_REALTIME, &toc);
free_idx = buffer->info.free_idx;
buffer->data[free_idx] = get_sample(SIG_FREQ, sampling_frequency, i);
// printf("CircBuffer[%d] = \t %lf\n", free_idx, buffer->data[free_idx]);
buffer->info.free_idx = (free_idx + 1 ) % buffer->info.size;
++i;
while (timespec_diff_nano(&toc, &tic) < delay.tv_nsec) {
// printf("%lld\n", timespec_diff_nano(&toc, &tic));
clock_gettime(CLOCK_REALTIME, &toc);
}
clock_gettime(CLOCK_REALTIME, &tic);
}
}
int main(int argc, char *argv[]) {
//----- Arguments handling -----
handle_arguments(argc, argv);
int sampling_frequency = strtol(argv[1], NULL, 10) ;
//----- Create a shared memory -----
const char *memory_name = "/dsp";
int fd = shm_open(memory_name, O_CREAT | O_RDWR, 0777);
if (fd < 0) {
fprintf(stderr, "shm_open: ");
exit(EXIT_FAILURE);
}
// printf("Shared memory file descriptor: %d\n", fd);
//----- Truncate memory to the buffer's size
if (ftruncate(fd, sizeof(struct CircBuffer)) < 0) {
fprintf(stderr, "ftruncate: \n");
exit(EXIT_FAILURE);
}
//----- Initialize the buffer -----
struct CircBuffer *buffer;
buffer = (struct CircBuffer *)mmap(NULL, sizeof(struct CircBuffer), PROT_WRITE, MAP_SHARED, fd, 0);
if (buffer == MAP_FAILED) {
fprintf(stderr, "mmap: ");
exit(EXIT_FAILURE);
}
buffer->info.size = sizeof(buffer->data)/sizeof(double);
buffer->info.free_idx = 0;
//----- Sample the producer -----
producer(fd, sampling_frequency);
return 0;
}

View File

@ -1,68 +0,0 @@
// man ftruncate
// pass any message between two processes using shared memory
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <time.h>
#include <unistd.h>
#include <sys/wait.h>
int main(int argc, char *argv[]) {
srandom(time(NULL));
const char *memory_name = "/memory";
char message[] = "Hello there";
int fd = shm_open(memory_name, O_CREAT | O_RDWR, 0777);
if (fd < 0) {
fprintf(stderr, "shm_open: ");
exit(EXIT_FAILURE);
}
printf("Shred memory file descriptor: %d\n", fd);
if (ftruncate(fd, sizeof(message)) < 0) {
fprintf(stderr, "ftruncate: \n");
exit(EXIT_FAILURE);
}
pid_t pid;
pid = fork();
if (pid == -1) {
perror("fork: ");
exit(EXIT_FAILURE);
}
if (pid == 0) {
char *addr = mmap(NULL, sizeof(message), PROT_READ, MAP_SHARED, fd, 0);
printf("Value: %s\n", addr);
if (addr == MAP_FAILED) {
fprintf(stderr, "mmap: ");
exit(EXIT_FAILURE);
}
exit(EXIT_SUCCESS);
}
char *addr = mmap(NULL, sizeof(message), PROT_WRITE, MAP_SHARED, fd, 0);
if (addr == MAP_FAILED) {
fprintf(stderr, "mmap: ");
exit(EXIT_FAILURE);
}
strcpy(addr, message);
shm_unlink(memory_name);
int status;
wait(&status);
munmap(addr, sizeof(message));
return 0;
}

View File

@ -2,12 +2,13 @@
// Wrote for Computer Networks and Systems lab classes
// AUTHOR : Sergiusz Warga
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/stat.h>
#include <string.h>
#define BUFFER_SIZE 8 // TODO: Think about it.

View File

@ -1,46 +0,0 @@
#include <arpa/inet.h>
#include <netinet/in.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/types.h>
void handle_arguments(int argc, char *argv[]) {
if (argc != 2) {
fprintf(stderr, "Usage: %s QUERRY\n", argv[0]);
exit(EXIT_FAILURE);
}
if (strlen(argv[1]) > 100) {
fprintf(stderr, "QUERRY must not exceed 100 characters!\n");
exit(EXIT_FAILURE);
}
}
void run_client(char *msg) {
int sockfd = socket(AF_INET, SOCK_DGRAM, 0);
if (sockfd < 0) {
fprintf(stderr, "socket: ");
exit(EXIT_FAILURE);
}
struct sockaddr_in serv_addr;
memset(&serv_addr, 0, sizeof(serv_addr)); //Clears the memory
serv_addr.sin_family = AF_INET;
serv_addr.sin_port = htons(2137);
serv_addr.sin_addr.s_addr = INADDR_ANY;
int rv = sendto(sockfd, msg, strlen(msg), 0, (const struct sockaddr *)&serv_addr, sizeof(serv_addr));
if (rv < 0) {
fprintf(stderr, "sendto: ");
exit(EXIT_FAILURE);
}
char response[100];
//rv = recvfrom(sockfd, response, sizeof(response), 0, NULL, NULL);
}
int main(int argc, char *argv[]) {
handle_arguments(argc, argv);
run_client(argv[1]);
return 0;
}

View File

@ -1,103 +0,0 @@
#include <arpa/inet.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
struct TokenizedQuerry {
int left;
char operand;
int right;
};
void handle_arguments(int argc, char *argv[]) {
if (argc != 2) {
fprintf(stderr, "Usage: %s PORT\n", argv[0]);
exit(EXIT_FAILURE);
}
}
struct TokenizedQuerry tokenize(const char *querry) {
struct TokenizedQuerry tokenized_querry;
// printf("QUERRY: %s\n", querry);
char left[50], *operand_ptr, right[50];
char valid_operands[4] = {'+', '-', '/', '*'};
for (int i = 0; i < sizeof(valid_operands); ++i) {
operand_ptr = strchr(querry, valid_operands[i]);
if (operand_ptr != NULL) break;
}
if (operand_ptr == NULL) {
fprintf(stderr, "Wrong operand!\n");
exit(EXIT_FAILURE);
}
int left_length = operand_ptr - querry;
strncpy(left, querry, left_length);
strcpy(right, querry + left_length + 1);
// printf("Tokenized: %s %c %s\n", left, *operand_ptr, right);
tokenized_querry.left = strtol(left, NULL, 10);
tokenized_querry.operand = *operand_ptr;
tokenized_querry.right = strtol(right, NULL, 10);
return tokenized_querry;
}
int calculate_TokenizedQuerry(struct TokenizedQuerry expression) {
switch (expression.operand) {
case '+':
return expression.left + expression.right;
case '-':
return expression.left - expression.right;
case '*':
return expression.left * expression.right;
case '/':
return expression.left / expression.right;
}
return 0;
}
void run_server(int port) {
int sockfd = socket(AF_INET, SOCK_DGRAM, 0);
if (sockfd < 0) {
fprintf(stderr, "socket: ");
exit(EXIT_FAILURE);
}
struct sockaddr_in serv_addr, client_addr;
memset(&serv_addr, 0, sizeof(serv_addr));
memset(&client_addr, 0, sizeof(client_addr));
serv_addr.sin_family = AF_INET;
serv_addr.sin_port = htons(port);
serv_addr.sin_addr.s_addr = INADDR_ANY;
int rv = bind(sockfd, (const struct sockaddr *)&serv_addr, sizeof(serv_addr));
if (rv < 0) {
fprintf(stderr, "bind: ");
exit(EXIT_FAILURE);
}
size_t buffer_size = 100;
char buffer[buffer_size];
memset(&buffer, 0, buffer_size);
socklen_t client_addr_len;
struct TokenizedQuerry tokenized_querry;
while (1) {
rv = recvfrom(sockfd, buffer, buffer_size, 0, (struct sockaddr *)&client_addr, &client_addr_len);
tokenized_querry = tokenize(buffer);
int result = calculate_TokenizedQuerry(tokenized_querry);
memset(&buffer, 0, buffer_size);
snprintf(buffer, buffer_size, "%d", result);
rv = sendto(sockfd, buffer, sizeof(buffer), 0, (const struct sockaddr *)&client_addr, sizeof(client_addr));
memset(&buffer, 0, sizeof(buffer));
}
}
int main(int argc, char *argv[]) {
handle_arguments(argc, argv);
run_server(strtol(argv[1], NULL, 10));
return 0;
}

View File

@ -1,51 +0,0 @@
#include <arpa/inet.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <unistd.h>
void run_client(int port, char *msg) {
int sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd < 0) {
fprintf(stderr, "socket: ");
exit(EXIT_FAILURE);
}
struct sockaddr_in server_addr;
memset(&server_addr, 0, sizeof(server_addr));
server_addr.sin_family = AF_INET;
server_addr.sin_addr.s_addr = INADDR_ANY;
server_addr.sin_port = htons(port);
if (connect(sockfd, (const struct sockaddr *)&server_addr, sizeof(server_addr))) {
fprintf(stderr, "connect: ");
exit(EXIT_FAILURE);
}
int rv = sendto(sockfd, msg, strlen(msg), 0, (const struct sockaddr *)&server_addr, sizeof(server_addr));
if (rv < 0) {
fprintf(stderr, "sendto: ");
exit(EXIT_FAILURE);
}
char buffer[100];
memset(&buffer, 0, sizeof(buffer));
socklen_t server_addr_len = sizeof(server_addr);
rv = recvfrom(sockfd, buffer, sizeof(buffer), 0, (struct sockaddr *)&server_addr, &server_addr_len);
if (rv < 0) {
fprintf(stderr, "recvfrom: ");
exit(EXIT_FAILURE);
}
printf("Server reply: %s\n", buffer);
close(sockfd);
}
int main(int arc, char *argv[]) {
run_client(2137, argv[1]);
return 0;
}

View File

@ -1,85 +0,0 @@
#include <arpa/inet.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <unistd.h>
void handle_arguments(int argc, char *argv[]) {
if (argc != 2) {
fprintf(stderr, "Usage: %s PORT\n", argv[0]);
exit(EXIT_FAILURE);
}
}
void send_integers(int sockfd, struct sockaddr_in * server_addr) {
int buffer = 42;
while (1) {
// int rv = sendto(sockfd, buffer.array, sizeof(buffer), 0, (const struct sockaddr *)&server_addr, sizeof(server_addr));
int rv = sendto(sockfd, &buffer, sizeof(buffer), 0, (const struct sockaddr *)&server_addr, sizeof(server_addr));
if (rv == -1) {
perror("sendto: ");
exit(EXIT_FAILURE);
}
// printf("Sent %x to the server\n", buffer.number);
sleep(10);
}
}
void run_client(int port) {
int sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd < 0) {
fprintf(stderr, "socket: ");
exit(EXIT_FAILURE);
}
struct sockaddr_in server_addr;
memset(&server_addr, 0, sizeof(server_addr));
server_addr.sin_family = AF_INET;
server_addr.sin_addr.s_addr = INADDR_ANY;
server_addr.sin_port = htons(port);
if (connect(sockfd, (const struct sockaddr *)&server_addr, sizeof(server_addr))) {
perror("connect");
exit(EXIT_FAILURE);
}
pid_t pid;
pid = fork();
if (pid == -1) {
perror("fork: ");
exit(EXIT_FAILURE);
}
if (pid == 0) {
send_integers(sockfd, &server_addr);
}
char response[] = "DATA RECEIVED";
char buffer[100];
int rv;
while (1) {
rv = recv(sockfd, buffer, sizeof(buffer), 0);
if (rv < 0) {
fprintf(stderr, "recvfrom: ");
exit(EXIT_FAILURE);
}
if (strlen(buffer)) {
printf("From server: %s\n", buffer);
rv = send(sockfd, response, sizeof(response), 0);
if (rv == -1) {
perror("send");
exit(EXIT_FAILURE);
}
}
memset(&buffer, 0, sizeof(buffer));
}
}
int main(int argc, char *argv[]) {
handle_arguments(argc, argv);
run_client(strtol(argv[1], NULL, 10));
return 0;
}

View File

@ -1,72 +0,0 @@
#include <arpa/inet.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <unistd.h>
void handle_arguments(int argc, char *argv[]) {
if (argc != 2) {
fprintf(stderr, "Usage: %s PORT\n", argv[0]);
exit(EXIT_FAILURE);
}
}
void run_server(int port) {
// create a socket using Internet protocol
int sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd == -1) {
perror("socket");
exit(EXIT_FAILURE);
}
struct sockaddr_in serv_addr, client_addr;
socklen_t client_addr_len = sizeof(client_addr);
memset(&serv_addr, 0, sizeof(serv_addr));
memset(&client_addr, 0, sizeof(client_addr));
serv_addr.sin_family = AF_INET;
serv_addr.sin_port = htons(port);
serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
// bind sockfd to serv_addr
int rv = bind(sockfd, (const struct sockaddr *)&serv_addr, sizeof(serv_addr));
if (rv == -1) {
perror("bind");
exit(EXIT_FAILURE);
}
rv = listen(sockfd, 5);
if (rv == -1) {
perror("listen");
exit(EXIT_FAILURE);
}
int accfd = accept(sockfd, (struct sockaddr *)&client_addr, &client_addr_len);
if (accfd == -1) {
perror("accept");
exit(EXIT_FAILURE);
}
size_t buffer_size = sizeof(uint32_t);
union {
uint32_t number;
char array[buffer_size];
} buffer;
memset(&buffer, 0, buffer_size);
while (1) {
read(accfd, buffer.array, buffer_size);
printf("%d\n", ntohl(buffer.number));
write(accfd, buffer.array, buffer_size);
memset(&buffer, 0, buffer_size);
}
}
int main(int argc, char *argv[]) {
handle_arguments(argc, argv);
run_server(strtol(argv[1], NULL, 10));
return 0;
}

View File

@ -1,100 +0,0 @@
#include <arpa/inet.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
void handle_arguments(int argc, char *argv[]) {
if (argc != 3) {
fprintf(stderr, "Usage: %s PORT N_OF_CLIENTS\n", argv[0]);
exit(EXIT_FAILURE);
}
}
void run_child(int sockfd) {
struct sockaddr_in client_addr;
socklen_t client_addr_len = sizeof(client_addr);
memset(&client_addr, 0, sizeof(client_addr));
while (1) {
int accfd = accept(sockfd, (struct sockaddr *)&client_addr, &client_addr_len);
if (accfd == -1) {
perror("accept");
exit(EXIT_FAILURE);
}
printf("A new connection has been accepted!\n");
size_t buffer_size = sizeof(int);
int buffer;
while (read(accfd, &buffer, buffer_size)) {
printf("%d\n", buffer);
// write(accfd, buffer.array, buffer_size);
memset(&buffer, 0, buffer_size);
}
printf("A connection with the client has been closed!\n");
}
}
void run_server(int port, int n_of_clients) {
// create a socket using Internet protocol
int sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd == -1) {
perror("socket");
exit(EXIT_FAILURE);
}
struct sockaddr_in serv_addr;
memset(&serv_addr, 0, sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
serv_addr.sin_port = htons(port);
serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
// bind sockfd to serv_addr
int rv = bind(sockfd, (const struct sockaddr *)&serv_addr, sizeof(serv_addr));
if (rv == -1) {
perror("bind");
exit(EXIT_FAILURE);
}
// man 2 listen
// The behavior of the backlog argument on TCP sockets changed with Linux 2.2. Now it specifies the queue length for completely established sockets waiting to be accepted, instead of the number of
// incomplete connection requests. The maximum length of the queue for incomplete sockets can be set using /proc/sys/net/ipv4/tcp_max_syn_backlog. When syncookies are enabled there is no logical
// maximum length and this setting is ignored. See tcp(7) for more information.
rv = listen(sockfd, 5);
if (rv == -1) {
perror("listen");
exit(EXIT_FAILURE);
}
pid_t pid;
int status[n_of_clients];
int children_pids[n_of_clients];
for (int i = 0; i < n_of_clients; ++i) {
pid = fork();
if (pid == -1) {
perror("fork: ");
exit(EXIT_FAILURE);
}
if (pid == 0) {
printf("A new child has been spawned!\n");
run_child(sockfd);
}
}
for (int i = 0; i < n_of_clients; ++i) {
children_pids[i] = pid;
waitpid(children_pids[i], &status[i], 0);
}
}
int main(int argc, char *argv[]) {
handle_arguments(argc, argv);
run_server(strtol(argv[1], NULL, 10), strtol(argv[2], NULL, 10));
return 0;
}

View File

@ -1,22 +0,0 @@
# Topic 2 Little warmup
## Task
I'm sure you are all proficient C/C++ programmers, but - just in case you had a long break and forgot some things - lets do a little warmup.
Write your own version of Unix "cp" (copy) command.
As a bare minimum - please write a program that:
- [x] accepts source and destination filenames as its arguments (you DO remember how to use argc and argv ?)
- [x] makes a copy of indicated file
- [x] returns 0 on success, any non-zero value on error
- [x] uses ONLY POSIX I/O functions (open, close, read, write - consult appropriate manuals)
NOTICE: Do not assume, that you can read entire file into memory. Please read manuals carefully - pay attention to each function's return value!
I'm sure this task will prove to be to easy to some of you - in this case you can extend your program - for example you can add features to allow:
- [x] copy source_file dest_dir (copy source file to the indicated directory, keeping its name)
- copy file1 file2 file3 dest_dir (copy files file1...file3 into destination directory)
- ... ?
As a solution - provide your source code here.

View File

@ -18,6 +18,8 @@ void print_pids() {
int main() {
pid_t pid;
pid = fork();
if (pid == -1) { // If something went wrong.

View File

@ -13,6 +13,7 @@ void child_task() {
void print_pids() {
printf("My PID is %d\nMy parent's PID is %d\n", getpid(), getppid());
}
void print_pids_child() {

View File

@ -1,34 +0,0 @@
# Topic 3 Forking
## Task 1
Write a simple program, where you create one child process.
Parent proces should write a "I am a parent" message, while your child process should write "I am a child".
man 2 fork
## Task 2
Please extend last program - make both processes display their process ID (PID) and their parent's PID.
man 2 getpid
man 2 getppid
## Task 3
Modify last program, so that it creates not one but 5 child processes.
## Task 4
Go back to the code from Task 2 (with one child process)
Please check, what happens when
1. parent finishes execution before its child
2. child finishes execution before its parent
Use sleep(..) function to force a delaay.
You can check process state using `ps -f <pid>` command

View File

@ -1,53 +0,0 @@
# Topic 4 More forking
## Task 1
The main program creates one child process. The offspring is supposed to write numbers from 1 to 10 (every second) to the screen.
The parent process should wait for the child process to finish and then output the message "END OF WORK"
man 3 sleep
man 2 wait
## Task 2
The main program generates two random integers:
a - from the range 0...10
b - from the range 20...30
Then it creates a child process.
The child process calculates the sum of a+b values and returns it as its exit status.
The parent process waits for the child process to finish calculating, receives its execution status, and displays returned sum.
man 2 exit
man 2 wait
Please read the description of WEXITSTATUS macro carefully.
## Task 3
The main program allocates a 1000000-element integer array on the heap (free-store)
Then it fills it with random values from the range 0....100
After preparing the array it creates 10 child processes. The task of each of the child processes is to determine the average value of the array fragment (rounded to the nearest integer):
descendant 0 - from index 0 to 99999
descendant 1 - from index 100000 to 199999
descendant 2 - from index 200000 to 299999
...
The parent process waits for the descendant processes to complete their calculations and then determines the average value of the array elements based on the obtained partial averages.
## Task 4
The main program allocates a 1000000-element array of floating point numbers on the heap.
Then it fills it with random values from the range -1....1
After preparing the array it creates 10 child processes. The task of each of the child processes is to determine the sum of the elements of the array fragment:
descendant 0 - from index 0 to 99999
descendant 1 - from index 100000 to 199999
descendant 2 - from index 200000 to 299999
...
After determining the sum the child processes write it to the file named "sum<PID>.txt" and finish their work.
The parent process waits for the completion of calculations by the child processes and then determines the average value of the array elements based on the contents of files with partial results.

View File

@ -1,36 +0,0 @@
//
// Written for Computer Networks and Systems lab classes
// AUTHOR : Sergiusz Warga
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>
void child_task() {
for (int i = 1; i <= 10; ++i) {
printf("%d\n", i);
fflush(stdout);
if (i < 10) sleep(1);
}
}
int main() {
pid_t pid;
pid = fork();
if (pid == -1) { // If something went wrong.
perror("Fork: ");
exit(EXIT_FAILURE);
}
if (pid == 0) { // If this is a child process.
child_task();
exit(EXIT_SUCCESS);
}
wait();
printf("END OF WORK\n");
return 0;
}

View File

@ -1,40 +0,0 @@
//
// Written for Computer Networks and Systems lab classes
// AUTHOR : Sergiusz Warga
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>
#include <time.h>
#include <sys/wait.h>
int child_task(int a, int b) {
return a + b;
}
int main() {
srandom(time(NULL));
int a = random() % 11;
int b = random() % 11 + 20;
int sum = 0;
pid_t pid;
pid = fork();
if (pid == -1) { // If something went wrong.
perror("Fork: ");
exit(EXIT_FAILURE);
}
if (pid == 0) { // If this is a child process.
sum = child_task(a, b);
exit(sum);
}
wait(&sum);
while (!(WIFEXITED(sum)));
printf("%d\n", WEXITSTATUS(sum));
return 0;
}

Binary file not shown.

View File

@ -1,66 +0,0 @@
//
// Written for Computer Networks and Systems lab classes
// AUTHOR : Sergiusz Warga
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>
#include <time.h>
#include <sys/wait.h>
#define N_OF_ELEMENTS 1e6
#define N_OF_CHILDREN 10
#define SPAN (int)(N_OF_ELEMENTS/N_OF_CHILDREN)
int child_task(int * array, int start) {
int sum = 0;
for (int i = start; i < start + SPAN; ++i ) {
sum += array[i];
}
return (int)(sum/SPAN);
}
int avg(int * array) {
int sum = 0;
for (int i = 0; i < N_OF_CHILDREN; ++i) {
sum += array[i];
}
return sum/N_OF_CHILDREN;
}
int main() {
srandom(time(NULL));
int status[N_OF_CHILDREN];
int sums[N_OF_CHILDREN] = {0};
int children_pids[N_OF_CHILDREN];
int * array = malloc(N_OF_ELEMENTS * sizeof(int));
for (int i = 0; i < N_OF_ELEMENTS; ++i) {
array[i] = random() % 101;
}
pid_t pid;
for (int i = 0; i < N_OF_CHILDREN; ++i) {
pid = fork();
if (pid == -1) { // If something went wrong.
perror("Fork: ");
exit(EXIT_FAILURE);
}
if (pid == 0){ // If this is a child process.
int avg = child_task(array, (int)(i*SPAN));
exit(avg);
}
children_pids[i] = pid;
}
for (int i = 0; i < N_OF_CHILDREN; ++i) {
waitpid(children_pids[i], &status[i], 0);
sums[i] = WEXITSTATUS(status[i]);
}
printf("%d\n", avg(sums));
return 0;
}

View File

@ -1,91 +0,0 @@
//
// Written for Computer Networks and Systems lab classes
// AUTHOR : Sergiusz Warga
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <time.h>
#include <unistd.h>
#define N_OF_ELEMENTS 1e6
#define N_OF_CHILDREN 10
#define SPAN (int)(N_OF_ELEMENTS/N_OF_CHILDREN)
union floaty {
float number;
char bytes[sizeof(float)];
};
int child_task(float * array, int start) {
union floaty sum;
for (int i = start; i < start + SPAN; ++i ) {
sum.number += array[i];
}
char filename[16];
snprintf(filename, 16, "sum%d.txt", getpid());
int file = open(filename, O_CREAT | O_WRONLY);
write(file, sum.bytes, sizeof(sum));
close(file);
return 0;
}
float avg(float * array) {
float sum = 0;
for (int i = 0; i < N_OF_CHILDREN; ++i) {
sum += array[i];
}
return sum/N_OF_ELEMENTS;
}
int main() {
srandom(time(NULL));
int status[N_OF_CHILDREN];
float sums[N_OF_CHILDREN] = {0};
int children_pids[N_OF_CHILDREN];
float * array = malloc(N_OF_ELEMENTS * sizeof(float));
for (int i = 0; i < N_OF_ELEMENTS; ++i) {
array[i] = 2*(float)random()/RAND_MAX - 1; // Nasty
}
pid_t pid;
for (int i = 0; i < N_OF_CHILDREN; ++i) {
pid = fork();
if (pid == -1) { // If something went wrong.
perror("Fork: ");
exit(EXIT_FAILURE);
}
if (pid == 0){ // If this is a child process.
child_task(array, (int)(i*SPAN));
exit(EXIT_SUCCESS);
}
children_pids[i] = pid;
}
for (int i = 0; i < N_OF_CHILDREN; ++i) {
waitpid(children_pids[i], &status[i], 0);
}
char filename[16];
union floaty sum;
for (int i = 0; i < N_OF_CHILDREN; ++i) {
sum.number = 0;
snprintf(filename, 16, "sum%d.txt", children_pids[i]);
int file = open(filename, O_RDONLY);
read(file, sum.bytes, sizeof(sum));
sums[i] = sum.number;
close(file);
}
printf("avg = %f\n", avg(sums));
return 0;
}

View File

@ -1,54 +0,0 @@
# Topic 5 Pipes
# Task 1
Perform basic test with pipe in single process
1) create a pipe
2) write some data
3) read it back
4) verify
man 2 pipe
man 2 read
man 2 write
## Task 2
As you remember - fork() creates an almost identical copy of the parent process. Interestingly, this copy "inherits" parent's process open file descriptors
The child inherits copies of the parent's set of open file descriptors. Each file descriptor in the child refers to the same open file description (see open(2)) as the corresponding file descriptor in the parent. This means that the two file descriptors share open file status flags, file offset, and signal-driven I/O attributes (see the description of F_SETOWN and F_SETSIG in fcntl(2)).
This means that if you use pipe before fork, you get a pipeline that you can write to in one process and read in another
Please modify your program from Task 2.1 so that the parent writes to the pipe and the child reads and displays received data
## Task 3
Usually - for added security - you close unnecessary ends of the pipe after the fork. That is, if the pipeline is used to send data from the parent to the child, then the parent closes its 'reading' endpoint, and the child closes its writing side.
If we want two-way communication, we create two pipes (and close their ends accordingly)
Task:
Create a simple "echo server"
The child in an infinite loop:
receives data from the parent (line of text, you can assume it is not longer than 8000 characters)
converts all lowercase letters into uppercase (you can use the toupper function)
sends the result back to the parent
In the parent process, test sending several texts to the child, read and display the answers
## Task 4
Modify Task-3-4 to use pipes to pass return values from child processes to their parent.
You may want to create a separate pipe for each child (or deal with buffering issues...)

View File

@ -1,27 +0,0 @@
//
// Written for Computer Networks and Systems lab classes
// AUTHOR : Sergiusz Warga
#include <fcntl.h>
#include <stdio.h>
#include <unistd.h>
int main() {
int pipefd[2];
if (pipe(pipefd) < 0){
fprintf(stderr,"Something went wrong!\n");
return -1;
}
int in = 42;
int out = 0;
write(pipefd[1], &in, sizeof(in));
read(pipefd[0], &out, sizeof(out));
close(pipefd[0]);
if (!(in-out)) printf("Pipe works just fine!\n");
return 0;
}

View File

@ -1,43 +0,0 @@
//
// Written for Computer Networks and Systems lab classes
// AUTHOR : Sergiusz Warga
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <unistd.h>
int main() {
int pipefd[2];
if (pipe(pipefd) < 0){
fprintf(stderr,"Something went wrong!\n");
return -1;
}
int in = 42;
int out = 0;
int status;
pid_t pid;
pid = fork();
if (pid == -1) { // If something went wrong.
perror("Fork: ");
exit(EXIT_FAILURE);
}
if (pid == 0) { // If this is a child process.
read(pipefd[0], &out, sizeof(out));
printf("%d\n", out);
close(pipefd[0]);
exit(EXIT_SUCCESS);
}
write(pipefd[1], &in, sizeof(in));
wait(&status);
close(pipefd[1]);
return 0;
}

View File

@ -1,54 +0,0 @@
//
// Written for Computer Networks and Systems lab classes
// AUTHOR : Sergiusz Warga
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <unistd.h>
void echo(int parent_to_child, int child_to_parent) {
while(1) {
char buff[8000] = {0};
int read_bytes = read(parent_to_child, &buff, sizeof(buff));
write(child_to_parent, &buff, read_bytes);
}
}
int main() {
int parent_to_child[2], child_to_parent[2];
if (pipe(parent_to_child) < 0 || pipe(child_to_parent) < 0 ){
fprintf(stderr,"Something went wrong!\n");
return -1;
}
int status;
pid_t pid;
pid = fork();
if (pid == -1) { // If something went wrong.
perror("Fork: ");
exit(EXIT_FAILURE);
}
if (pid == 0) { // If this is a child process.
echo(parent_to_child[0], child_to_parent[1]);
exit(EXIT_SUCCESS);
}
char buff[8000];
char messages[3][32] = {"Hello there!", "Second message.", "Bye!"};
for (int i = 0; i < 3; ++i) {
write(parent_to_child[1], &messages[i], sizeof(messages[i]));
read(child_to_parent[0], buff, sizeof(buff));
printf("%s\n", buff);
}
wait(&status);
close(parent_to_child[1]);
close(child_to_parent[0]);
return 0;
}

View File

@ -1,79 +0,0 @@
//
// Written for Computer Networks and Systems lab classes
// AUTHOR : Sergiusz Warga
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <time.h>
#include <unistd.h>
#define N_OF_ELEMENTS 1e6
#define N_OF_CHILDREN 10
#define SPAN (int)(N_OF_ELEMENTS/N_OF_CHILDREN)
int child_task(double * array, int start, int pipe) {
double sum;
for (int i = start; i < start + SPAN; ++i ) {
sum += array[i];
}
write(pipe, &sum, sizeof(sum));
close(pipe);
return 0;
}
double avg(double * array) {
double sum = 0;
for (int i = 0; i < N_OF_CHILDREN; ++i) {
sum += array[i];
}
return sum/N_OF_ELEMENTS;
}
int main() {
int children_pids[N_OF_CHILDREN];
pid_t pid;
double sums[N_OF_CHILDREN] = {0};
double * array = malloc(N_OF_ELEMENTS * sizeof(double));
srandom(time(NULL));
for (int i = 0; i < N_OF_ELEMENTS; ++i) {
array[i] = 2*(double)random()/RAND_MAX - 1; // Nasty
}
int child_to_parent[N_OF_CHILDREN][2];
for (int i = 0; i < N_OF_CHILDREN; ++i) {
if (pipe(child_to_parent[i]) < 0 ){
fprintf(stderr,"Something went wrong!\n");
return -1;
}
pid = fork();
if (pid == -1) { // If something went wrong.
perror("Fork: ");
exit(EXIT_FAILURE);
}
if (pid == 0){ // If this is a child process.
child_task(array, (int)(i*SPAN), child_to_parent[i][1]);
exit(EXIT_SUCCESS);
}
children_pids[i] = pid;
}
for (int i = 0; i < N_OF_CHILDREN; ++i) {
read(child_to_parent[i][0], &sums[i], sizeof(double));
close(child_to_parent[i][0]);
}
printf("avg = %f\n", avg(sums));
return 0;
}

Binary file not shown.

View File

@ -1,32 +0,0 @@
//
// Written for Computer Networks and Systems lab classes
// AUTHOR : Sergiusz Warga
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>
void child_task() {
execl("/usr/bin/cal", "cal", "2021", NULL);
}
int main() {
pid_t pid;
int status;
pid = fork();
if (pid == -1) { // If something went wrong.
perror("Fork: ");
exit(EXIT_FAILURE);
}
if (pid == 0) { // If this is a child process.
child_task();
exit(EXIT_SUCCESS);
}
wait(&status);
return 0;
}

Binary file not shown.

View File

@ -1,17 +0,0 @@
//
// Written for Computer Networks and Systems lab classes
// AUTHOR : Sergiusz Warga
#include <stdio.h>
#include <unistd.h>
int main() {
char msg_write[] = "write() to dup(1)\n";
int soutfd = dup(STDOUT_FILENO);
write(soutfd, msg_write, sizeof(msg_write));
FILE *fakeout = fdopen(soutfd, "w");
fprintf(fakeout, "using fprintf() on fakeout\n");
return 0;
}

Binary file not shown.

View File

@ -1,44 +0,0 @@
//
// Written for Computer Networks and Systems lab classes
// AUTHOR : Sergiusz Warga
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
int main() {
int pipefd[2];
if (pipe(pipefd) < 0) {
fprintf(stderr, "Something went wrong!\n");
return -1;
}
pid_t pid;
pid = fork();
if (pid == -1) { // If something went wrong.
perror("Fork: ");
exit(EXIT_FAILURE);
}
if (pid == 0) { // If this is a child process.
dup2(pipefd[1], STDOUT_FILENO);
printf("printf() from a child\n");
close(pipefd[1]);
exit(EXIT_SUCCESS);
}
char buff[100] = {};
while (read(pipefd[0], &buff, sizeof(buff)) > 0) {
printf("PARENT: %s", buff);
}
int status;
wait(&status);
return 0;
}

Binary file not shown.

View File

@ -1,44 +0,0 @@
//
// Written for Computer Networks and Systems lab classes
// AUTHOR : Sergiusz Warga
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
int main() {
int pipefd[2];
if (pipe(pipefd) < 0) {
fprintf(stderr, "Something went wrong!\n");
return -1;
}
pid_t pid;
pid = fork();
if (pid == -1) { // If something went wrong.
perror("Fork: ");
exit(EXIT_FAILURE);
}
if (pid == 0) { // If this is a child process.
dup2(pipefd[1], STDOUT_FILENO);
execl("/usr/bin/cal", "cal", NULL);
close(pipefd[1]);
exit(EXIT_SUCCESS);
}
char buff[200] = {};
while (read(pipefd[0], &buff, sizeof(buff)) > 0) {
printf("%s", buff);
}
int status;
wait(&status);
return 0;
}

Binary file not shown.

View File

@ -1,281 +0,0 @@
#include <errno.h>
#include <fcntl.h>
#include <mqueue.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <time.h>
#include <unistd.h>
void handle_arguments(int argc, char *argv[]) {
if (!(argc == 2 || argc == 4)) {
fprintf(stderr, "Usage: %s #_OF_TASKS [#_OF_PRODUCERS] [#_OF_CONSUMERS]\n", argv[0]);
exit(EXIT_FAILURE);
}
if (atoi(argv[1]) < 1) {
fprintf(stderr, "I need at least one task!\n");
exit(EXIT_FAILURE);
}
// if (atoi(argv[1]) > MAXMSG) {
// fprintf(stderr, "I can handle up to %d tasks!\n", MAXMSG);
// exit(EXIT_FAILURE);
// }
if (argc == 4) {
if (atoi(argv[2]) < 1) {
fprintf(stderr, "I need at least one producer!\n");
exit(EXIT_FAILURE);
}
if (atoi(argv[3]) < 1) {
fprintf(stderr, "I need at least one consumer!\n");
exit(EXIT_FAILURE);
}
}
if (atoi(argv[2]) > 32) {
fprintf(stderr, "I am lazy so I can create up to 32 producers!\n");
exit(EXIT_FAILURE);
}
if (atoi(argv[3]) > 32) {
fprintf(stderr, "I am lazy so I can create up to 32 consumers!\n");
exit(EXIT_FAILURE);
}
}
struct Task {
pid_t prod_pid;
int sqc;
int a;
int b;
int result;
};
struct Task generate_task(int sqc) {
struct Task task;
task.prod_pid = getpid();
task.sqc = sqc;
task.a = random()/2;
task.b = random()/2;
task.result = 0;
return task;
};
void print_task(struct Task task) {
printf("====v TASK v====\n");
printf("Producer PID: %d\n", task.prod_pid);
printf("Sequence no: %d\n", task.sqc);
printf("A: %d\n", task.a);
printf("B: %d\n", task.b);
if (task.result != 0) { // Cloud replace it with bool solved in Task
printf("A + B = %d\n", task.result);
}
printf("====^ TASK ^====\n");
}
void producer(int n_tasks, int prio) {
printf("A producer has been called with PID of %d\n", getpid());
// printf("The queue was created with fd = %d\n", queue);
mqd_t queue = mq_open("/tasks", O_WRONLY);
if (queue == (mqd_t) -1) {
perror("mq_open: ");
exit(EXIT_FAILURE);
}
struct Task tasks[n_tasks];
for (int i = 0; i < n_tasks; ++i) {
tasks[i] = generate_task(i);
// print_task(tasks[i]);
if (mq_send(queue, (const char *)&tasks[i], sizeof(struct Task), prio)) {
perror("mq_send: ");
exit(EXIT_FAILURE);
}
printf("Task %d of %d sent...\n", i + 1, n_tasks);
}
mqd_t results_queue;
do {
char pid_s[10];
sprintf(pid_s, "%d", getpid());
char results_name[30] = "/results";
strcat(results_name, pid_s);
results_queue = mq_open(results_name, O_RDONLY);
if (results_queue == (mqd_t) -1) {
if (errno != ENOENT) {
perror("mq_open('/results'): ");
exit(EXIT_FAILURE);
}
}
} while(results_queue == (mqd_t) -1);
struct Task tmp;
for (int i = 0; i < n_tasks; ++i) {
int received_bytes = mq_receive(results_queue, (char *) &tmp, sizeof(struct Task), NULL);
if (received_bytes < 0) {
perror("producer mq_receive('/results')");
exit(EXIT_FAILURE);
}
tasks[tmp.sqc] = tmp;
printf("%d received %d of %d results...\n", tmp.prod_pid, i + 1, n_tasks);
}
for (int i = 0; i < n_tasks; ++i) {
print_task(tasks[i]);
}
mq_unlink("/test");
}
int solve_difficult_problem(int a, int b) {
sleep(random()%3 + 1);
return a + b;
}
void consumer() {
printf("A consumer has been called with PID of %d\n", getpid());
mqd_t queue;
do {
queue = mq_open("/tasks", O_RDONLY);
if (queue == (mqd_t) -1) {
if (errno != ENOENT) {
perror("mq_open('/tasks'): ");
exit(EXIT_FAILURE);
}
}
} while(queue == (mqd_t) -1);
struct Task task;
struct timespec interval;
interval.tv_nsec = 0;
while (1) {
interval.tv_sec = time(NULL) + 5;
int received_bytes = mq_timedreceive(queue, (char *) &task, sizeof(struct Task), NULL, &interval);
if (received_bytes < 0) {
perror("consumer mq_receive('/tasks'): ");
exit(EXIT_FAILURE);
}
task.result = solve_difficult_problem(task.a, task.b);
if (received_bytes < 0) {
perror("mq_receive: ");
exit(EXIT_FAILURE);
}
char prod_pid[10];
sprintf(prod_pid, "%d", task.prod_pid);
char results_name[30] = "/results";
strcat(results_name, prod_pid);
mqd_t results_queue = mq_open(results_name, O_WRONLY);
if (results_queue == (mqd_t) -1) {
perror("consumer mq_open('/results'): ");
exit(EXIT_FAILURE);
}
if (mq_send(results_queue, (const char *)&task, sizeof(struct Task), 0)) {
perror("mq_send: ");
exit(EXIT_FAILURE);
}
}
mq_unlink("/results");
}
int main(int argc, char *argv[]) {
srandom(time(NULL));
handle_arguments(argc, argv);
int n_tasks = atoi(argv[1]);
int n_producers = atoi(argv[2]);
int n_consumers = atoi(argv[3]);
char tasks_name[] = "/tasks";
// char results_name[] = "/results";
struct mq_attr attr;
attr.mq_flags = 0;
attr.mq_maxmsg = 10; // Probably more can be obtained by modifying /proc/sys/fs/mqueue/msg_max
attr.mq_msgsize = sizeof(struct Task);
attr.mq_curmsgs = 0;
mq_unlink(tasks_name);
// mq_unlink(results_name);
mqd_t tasks_queue = mq_open(tasks_name, O_RDWR | O_CREAT, S_IRWXU, &attr);
if (tasks_queue == (mqd_t) -1) {
perror("mq_open: ");
exit(EXIT_FAILURE);
}
pid_t pid;
int status[n_producers + n_consumers];
int producers_pids[n_producers];
int consumers_pids[n_consumers];
for (int i = 0; i < n_producers; ++i) {
pid = fork();
if (pid == -1) {
perror("fork: ");
exit(EXIT_FAILURE);
}
if (pid == 0) {
producer(n_tasks, i);
exit(EXIT_SUCCESS);
}
char pid_s[10];
sprintf(pid_s, "%d", pid);
char results_name[30] = "/results";
strcat(results_name, pid_s);
unlink(results_name);
mqd_t results_queue = mq_open(results_name, O_RDWR | O_CREAT, S_IRWXU, &attr);
if (results_queue == (mqd_t) -1) {
perror("mq_open: ");
exit(EXIT_FAILURE);
}
producers_pids[i] = pid;
}
for (int i = 0; i < n_consumers; ++i) {
pid = fork();
if (pid == -1) {
perror("fork: ");
exit(EXIT_FAILURE);
}
if (pid == 0) {
consumer();
exit(EXIT_SUCCESS);
}
consumers_pids[i] = pid;
}
for (int i = 0; i < n_producers; ++i) {
waitpid(producers_pids[i], &status[i], 0);
}
for (int i = 0; i < n_consumers; ++i) {
waitpid(consumers_pids[i], &status[i], 0);
}
printf("This is the end!\n");
return 0;
}