diff options
Diffstat (limited to 'C')
| -rw-r--r-- | C/OOP/Makefile | 18 | ||||
| -rw-r--r-- | C/OOP/README | 4 | ||||
| -rw-r--r-- | C/OOP/animal/animal.c | 72 | ||||
| -rw-r--r-- | C/OOP/cat/cat.c | 41 | ||||
| -rw-r--r-- | C/OOP/include/animal_p.h | 23 | ||||
| -rw-r--r-- | C/OOP/include/animal_priv.h | 19 | ||||
| -rw-r--r-- | C/OOP/include/cat_p.h | 19 | ||||
| -rw-r--r-- | C/OOP/main.c | 30 | ||||
| -rw-r--r-- | C/Pointers/addr.c | 47 | ||||
| -rw-r--r-- | C/Pointers/multi_indirection.c | 42 | ||||
| -rw-r--r-- | C/README.md | 3 | ||||
| -rwxr-xr-x | C/enum | bin | 0 -> 12568 bytes | |||
| -rw-r--r-- | C/enum.c | 17 | ||||
| -rw-r--r-- | C/final-project-z2h/Makefile | 22 | ||||
| -rw-r--r-- | C/final-project-z2h/README.md | 1 | ||||
| -rw-r--r-- | C/final-project-z2h/fdb | bin | 0 -> 1044 bytes | |||
| -rw-r--r-- | C/final-project-z2h/include/common.h | 8 | ||||
| -rw-r--r-- | C/final-project-z2h/include/file.h | 7 | ||||
| -rw-r--r-- | C/final-project-z2h/include/parse.h | 26 | ||||
| -rw-r--r-- | C/final-project-z2h/src/file.c | 39 | ||||
| -rw-r--r-- | C/final-project-z2h/src/main.c | 108 | ||||
| -rw-r--r-- | C/final-project-z2h/src/parse.c | 162 | ||||
| -rw-r--r-- | C/netCode/.gitignore | 2 | ||||
| -rw-r--r-- | C/netCode/client.c | 66 | ||||
| -rw-r--r-- | C/netCode/server.c | 202 | ||||
| -rw-r--r-- | C/netCode/types.h | 26 |
26 files changed, 1004 insertions, 0 deletions
diff --git a/C/OOP/Makefile b/C/OOP/Makefile new file mode 100644 index 0000000..478ddab --- /dev/null +++ b/C/OOP/Makefile @@ -0,0 +1,18 @@ +oop_prog: main.o animal.o cat.o + gcc -Wall -o oop_prog main.o cat/cat.o animal/animal.o + +main.o: main.c + gcc -I./include -c main.c + +animal.o: animal/animal.c + gcc -I./include -c animal/animal.c -o animal/animal.o + +cat.o: cat/cat.c + gcc -I./include -c cat/cat.c -o cat/cat.o + + +clean: + rm animal/*.o + rm cat/*.o + rm main.o + rm oop_prog diff --git a/C/OOP/README b/C/OOP/README new file mode 100644 index 0000000..4aab525 --- /dev/null +++ b/C/OOP/README @@ -0,0 +1,4 @@ +This is a simple example on how to write Object-oriented code in C. + +The structure here is simple, we have a 'parent' class named Animal, +and its sub-classes based on different animals. diff --git a/C/OOP/animal/animal.c b/C/OOP/animal/animal.c new file mode 100644 index 0000000..01934d7 --- /dev/null +++ b/C/OOP/animal/animal.c @@ -0,0 +1,72 @@ +/* Animal class implementation */ + +#define MAX_NAME_LEN 10 +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "animal_priv.h" + + +struct animal * animal_new() { + return (struct animal *)malloc(sizeof(struct animal)); +} + +/* + * By passing the custom sound function to the constructor, we prevent the need to expose the + * Animal's private interface to the sub-class + * + * This is an attempt to get as much abstraction as possible of a C program. + * The sub-class has no business in understanding the inner functionality of the parent class, + * so, this is an attempt to hide the animal implementation as much as possible from the sub-class. + */ +void animal_ctor(struct animal *animal, + void (*sound_fn)(void)) +{ + animal->name = malloc(MAX_NAME_LEN * sizeof(char)); + + if (sound_fn) + animal->make_sound = sound_fn; + else + animal->make_sound = NULL; +} + +void animal_dtor(struct animal *animal) +{ + free(animal->name); +} + +void animal_get_name(struct animal *animal, char *name) +{ + strncpy(name, animal->name, MAX_NAME_LEN); +} + +void animal_set_name(struct animal *animal, const char *name) +{ + if (strlen(name) >= MAX_NAME_LEN) + strncpy(animal->name, "\0", 1); + else + strncpy(animal->name, name, MAX_NAME_LEN); +} + +/* + * To be able to access the object specific implementation of make_sound(), + * this function should somehow access the function pointer to the + * object-specific implementation. + * + * This could be done in two ways: + * - By having the Animal object embedded within the sub-class, so both + * the Animal object and the Sub-Class object will share the same address + * in memory, or: + * - We add an 'ops' field in the Animal object, which should be populated + * by the sub-class. + * + * In both ways, there is no way to really hide the Animal implementation from + * the sub-class, as in one way or another, we'll need to have access to the + * Animal class fields, so we can override the functions. + */ +void animal_sound(struct animal *animal) +{ + if (animal->make_sound) + animal->make_sound(); +} diff --git a/C/OOP/cat/cat.c b/C/OOP/cat/cat.c new file mode 100644 index 0000000..c513bb6 --- /dev/null +++ b/C/OOP/cat/cat.c @@ -0,0 +1,41 @@ +/* + * Cat class. + * + * This is a subclass of the animal class + */ + +#include <stdio.h> +#include <stdlib.h> + +#include "animal_priv.h" +#include "animal_p.h" + +/* + * We need access to animal's definition, so we can embbed it + * within our sub-class + */ +struct cat { + struct animal animal; +}; + +void __cat_sound(void) +{ + printf("The cat makes MEOOOOOW\n"); +} + +struct cat *cat_new(void) +{ + return (struct cat*)malloc(sizeof(struct cat)); +} + +void cat_ctor(struct cat *cat) +{ + animal_ctor((struct animal *)cat, + __cat_sound); + printf("cat_ctor: cat: %p animal: %p\n", cat, &cat->animal); +} + +void cat_dtor(struct cat *cat) +{ + animal_dtor((struct animal *)cat); +} diff --git a/C/OOP/include/animal_p.h b/C/OOP/include/animal_p.h new file mode 100644 index 0000000..e09aa7c --- /dev/null +++ b/C/OOP/include/animal_p.h @@ -0,0 +1,23 @@ +/* Animal class public interface */ + +#ifndef ANIMAL_P_H +#define ANIMAL_P_H + +/* Forward declaration */ +struct animal; + +/* Alloc new object */ +struct animal* animal_new(void); + +/* Constructor - make_sound may be NULL*/ +void animal_ctor(struct animal*, void (*make_sound)(void)); + +/* Destructor */ +void animal_dtor(struct animal*); + +/* Behavior */ +void animal_get_name(struct animal*, char*); +void animal_set_name(struct animal*, const char*); +void animal_sound(void *); + +#endif /* ANIMAL_P_H */ diff --git a/C/OOP/include/animal_priv.h b/C/OOP/include/animal_priv.h new file mode 100644 index 0000000..78a83c1 --- /dev/null +++ b/C/OOP/include/animal_priv.h @@ -0,0 +1,19 @@ +/* Animal class private definition */ + +#ifndef ANIMAL_PRIV_H +#define ANIMAL_PRIV_H + +/* + * We use a "private" definition as a way to encapsulate it, hiding + * it from the users. + * + * Access to its private definition is only allowed to its sub-classes. + * + * We could enforce it by moving here the allocator and constructors + */ +struct animal { + char *name; + void (*make_sound) (void); +}; + +#endif /* ANIMAL_PRIV_H */ diff --git a/C/OOP/include/cat_p.h b/C/OOP/include/cat_p.h new file mode 100644 index 0000000..82bcfb1 --- /dev/null +++ b/C/OOP/include/cat_p.h @@ -0,0 +1,19 @@ +/* Cat class public interface */ + +#ifndef CAT_P_H +#define CAT_P_H + +struct cat; + +/* Allocator */ +struct cat *cat_new(void); + +/* Constructor */ +void cat_ctor(struct cat *); + +/* Destructor */ +void cat_dtor(struct cat *); + +/* Behavior functions inherited from Animal class */ + +#endif /* CAT_P_H */ diff --git a/C/OOP/main.c b/C/OOP/main.c new file mode 100644 index 0000000..7943580 --- /dev/null +++ b/C/OOP/main.c @@ -0,0 +1,30 @@ +/* + * Simple program exemplifying the usage of Animal class + * and its sub-classes + */ +#include <stdio.h> + +/* + * The main program here, only need access to the public interfaces + * but the sub-classes will need access to the animal's private interface + */ +#include "animal_p.h" +#include "cat_p.h" + +int main(void) { + + /* We don't need to know how the cat object is implemented */ + struct cat *myCat = cat_new(); + + cat_ctor(myCat); + + /* + * For us to have the Animal class definition hidden, the animal_sound() + * should have a way to defer the parent Animal class, from the cat class. + * + * See its implementation within animal.c + */ + animal_sound((struct animal *)myCat); + return 0; +} + diff --git a/C/Pointers/addr.c b/C/Pointers/addr.c new file mode 100644 index 0000000..f77a9c6 --- /dev/null +++ b/C/Pointers/addr.c @@ -0,0 +1,47 @@ +#include <stdio.h> + +int main (void) +{ + /* + * Arrays in C are just sequential data items + * stored in a memory location + * The address of the array, is the same as the first + * element in the array + * The name of the array is also the address of the array. + */ + + char str1[] = "Hello cruel world"; /* \0 is automatically added */ + + /* Those variables look the same, but they are not. */ + + /* This is an array */ + + /* + * str2, is the address of the "ARRAY" which the characters + * of the string are stored + * str2 is not a 'pointer' to the location of the Hello char array + * str2 IS THE LOCATION of the array. + */ + char str2[] = "Hello"; + + /* + * This is a pointer. + * + * Whose value is not the string, but the - address of that string - + * + */ + char *str3 = "Goodbye"; + + str3 = NULL; + str2 = NULL; + /* + * &str1, &str1[0] and str1, all points to the very same address. + * + * The array name, str1, is also the address of the array. + * */ + printf("%s, %c, %d, %d %d\n", str1, str1[0], &str1, &str1[0], str1); + + printf("%p %p %s\n", &str2, str2, str2); + printf("%p %p %s\n", &str3, str3, str3); + +} diff --git a/C/Pointers/multi_indirection.c b/C/Pointers/multi_indirection.c new file mode 100644 index 0000000..92b677c --- /dev/null +++ b/C/Pointers/multi_indirection.c @@ -0,0 +1,42 @@ +#include <stdio.h> + +char *words[3]; + +int main(void) +{ + char *pc; + char **ppc; + int i; + char *foo, *bar; + + printf("multiple indirection example\n"); + + words[0] = "zero"; + foo = "FOO"; + words[1] = "one"; + bar = "BAR"; + words[2] = "two"; + + for (int i = 0; i < 3; i++) + printf("%s\n", words[i]); + + printf("Print each char in each string...\n"); + + ppc = words; + + printf("Addr of array head %p\n", words); + for (i = 0; i < 3; i ++) { + ppc = words + i; + pc = *ppc; + + printf("array %d -> loc %p -> deref: %p\n", i, &words[i], *ppc); + while (*pc != 0) { + printf("addr: %p - content: %c \n", pc, *pc); + pc += 1; + } + + printf("\n"); + } + + return 0; +} diff --git a/C/README.md b/C/README.md new file mode 100644 index 0000000..8b8d49d --- /dev/null +++ b/C/README.md @@ -0,0 +1,3 @@ +### Random C code ### + +Just a bunch of random C code with no specific purpose Binary files differdiff --git a/C/enum.c b/C/enum.c new file mode 100644 index 0000000..f177efa --- /dev/null +++ b/C/enum.c @@ -0,0 +1,17 @@ +#include <stdio.h> + +enum names { + BAR = 5, + FOO, + RONALDO +}; + +int main(void) { + enum names myName; + + myName = BAR; + printf("Enum: %d\n", myName); + myName = 99; + + return myName; +} diff --git a/C/final-project-z2h/Makefile b/C/final-project-z2h/Makefile new file mode 100644 index 0000000..be3cefa --- /dev/null +++ b/C/final-project-z2h/Makefile @@ -0,0 +1,22 @@ +TARGET = bin/dbview +SRC = $(wildcard src/*.c) +OBJ = $(patsubst src/%.c, obj/%.o, $(SRC)) + +run: clean default + ./$(TARGET) -f ./mynewdb.db -n + ./$(TARGET) -f ./mynewdb.db -a "Timmy H.,123 Sheshire Ln.,120" + +default: $(TARGET) + +clean: + rm -f obj/*.o + rm -f bin/* + rm -f *.db + +$(TARGET): $(OBJ) + gcc -o $@ $? + +obj/%.o : src/%.c + gcc -c $< -o $@ -Iinclude + + diff --git a/C/final-project-z2h/README.md b/C/final-project-z2h/README.md new file mode 100644 index 0000000..560d92e --- /dev/null +++ b/C/final-project-z2h/README.md @@ -0,0 +1 @@ +# This is a readme file diff --git a/C/final-project-z2h/fdb b/C/final-project-z2h/fdb Binary files differnew file mode 100644 index 0000000..394b7fb --- /dev/null +++ b/C/final-project-z2h/fdb diff --git a/C/final-project-z2h/include/common.h b/C/final-project-z2h/include/common.h new file mode 100644 index 0000000..839cc6f --- /dev/null +++ b/C/final-project-z2h/include/common.h @@ -0,0 +1,8 @@ +#ifndef COMMON_H +#define COMMON_H + +#define STATUS_ERROR -1 +#define STATUS_SUCCESS 0 + + +#endif diff --git a/C/final-project-z2h/include/file.h b/C/final-project-z2h/include/file.h new file mode 100644 index 0000000..73fd2a7 --- /dev/null +++ b/C/final-project-z2h/include/file.h @@ -0,0 +1,7 @@ +#ifndef FILE_H +#define FILE_H + +int create_db_file(char *filename); +int open_db_file(char *filename); + +#endif diff --git a/C/final-project-z2h/include/parse.h b/C/final-project-z2h/include/parse.h new file mode 100644 index 0000000..edcda9b --- /dev/null +++ b/C/final-project-z2h/include/parse.h @@ -0,0 +1,26 @@ +#ifndef PARSE_H +#define PARSE_H + +#define HEADER_MAGIC 0x4c4c4144 + +struct dbheader_t { + unsigned int magic; + unsigned short version; + unsigned short count; + unsigned int filesize; +}; + +struct employee_t { + char name[256]; + char address[256]; + unsigned int hours; +}; + +int create_db_header(int fd, struct dbheader_t **headerOut); +int validate_db_header(int fd, struct dbheader_t **headerOut); +int read_employees(int fd, struct dbheader_t *, struct employee_t **employeesOut); +int output_file(int fd, struct dbheader_t *, struct employee_t *employees); +void list_employees(struct dbheader_t *dbhdr, struct employee_t *employees); +int add_employee(struct dbheader_t *dbhdr, struct employee_t *employees, char *addstring); + +#endif diff --git a/C/final-project-z2h/src/file.c b/C/final-project-z2h/src/file.c new file mode 100644 index 0000000..fcdb036 --- /dev/null +++ b/C/final-project-z2h/src/file.c @@ -0,0 +1,39 @@ +#include <stdio.h> + +#include <unistd.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> + +#include "file.h" +#include "common.h" + + +int create_db_file(char *filename) { + int fd = open(filename, O_RDWR); + if (fd != -1) { + close(fd); + printf("File already exists\n"); + return STATUS_ERROR; + } + + fd = open(filename, O_RDWR | O_CREAT, 0644); + if (fd == -1) { + perror("open"); + return STATUS_ERROR; + } + + return fd; +} + +int open_db_file(char *filename) { + int fd = open(filename, O_RDWR, 0644); + if (fd == -1) { + perror("open"); + return STATUS_ERROR; + } + + return fd; +} + + diff --git a/C/final-project-z2h/src/main.c b/C/final-project-z2h/src/main.c new file mode 100644 index 0000000..09cbde1 --- /dev/null +++ b/C/final-project-z2h/src/main.c @@ -0,0 +1,108 @@ +#include <stdio.h> +#include <stdbool.h> +#include <getopt.h> +#include <stdlib.h> + +#include "common.h" +#include "file.h" +#include "parse.h" + +void print_usage(char *argv[]) { + printf("Usage: %s -n -f <database file>\n", argv[0]); + printf("\t -n - create new database file\n"); + printf("\t -f - (required) path to database file\n"); + return; +} + +int main(int argc, char *argv[]) { + char *filepath = NULL; + char *portarg = NULL; + unsigned short port = 0; + bool newfile = false; + bool list = false; + char *addstring = NULL; + int c; + + int dbfd = -1; + struct dbheader_t *dbhdr = NULL; + struct employee_t *employees = NULL; + + while ((c = getopt(argc, argv, "nf:a:l")) != -1) { + switch (c) { + case 'n': + newfile = true; + break; + case 'f': + filepath = optarg; + break; + case 'p': + portarg = optarg; + break; + case 'a': + addstring = optarg; + break; + case 'l': + list = true; + break; + case '?': + printf("Unknown option -%c\n", c); + break; + default: + return -1; + + } + } + + if (filepath == NULL) { + printf("Filepath is a required argument\n"); + print_usage(argv); + + return 0; + } + + + if (newfile) { + dbfd = create_db_file(filepath); + if (dbfd == STATUS_ERROR) { + printf("Unable to create database file\n"); + return -1; + } + + if (create_db_header(dbfd, &dbhdr) == STATUS_ERROR) { + printf("Failed to create database header\n"); + return -1; + } + } else { + dbfd = open_db_file(filepath); + if (dbfd == STATUS_ERROR) { + printf("Unable to open database file\n"); + return -1; + } + + if (validate_db_header(dbfd, &dbhdr) == STATUS_ERROR) { + printf("Failed to validate database header\n"); + return -1; + } + } + + if (read_employees(dbfd, dbhdr, &employees) != STATUS_SUCCESS) { + printf("Failed to read employees"); + return 0; + } + + if (addstring) { + dbhdr->count++; + employees = realloc(employees, dbhdr->count*(sizeof(struct employee_t))); + add_employee(dbhdr, employees, addstring); + } + + if (list) { + list_employees(dbhdr, employees); + } + + + output_file(dbfd, dbhdr, employees); + + + return 0; +} diff --git a/C/final-project-z2h/src/parse.c b/C/final-project-z2h/src/parse.c new file mode 100644 index 0000000..0f9b8e7 --- /dev/null +++ b/C/final-project-z2h/src/parse.c @@ -0,0 +1,162 @@ +#include <stdio.h> +#include <unistd.h> +#include <stdlib.h> +#include <arpa/inet.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <unistd.h> +#include <string.h> + +#include "common.h" +#include "parse.h" + +void list_employees(struct dbheader_t *dbhdr, struct employee_t *employees) { + int i = 0; + for (; i < dbhdr->count; i++) { + printf("Employee %d\n", i); + printf("\tName: %s\n", employees[i].name); + printf("\tAddress: %s\n", employees[i].address); + printf("\tHours: %d\n", employees[i].hours); + } +} + +int add_employee(struct dbheader_t *dbhdr, struct employee_t *employees, char *addstring) { + printf("%s\n", addstring); + + char *name = strtok(addstring, ","); + + char *addr = strtok(NULL, ","); + + char *hours = strtok(NULL, ","); + + printf("%s %s %s\n", name, addr, hours); + + + strncpy(employees[dbhdr->count-1].name, name, sizeof(employees[dbhdr->count-1].name)); + strncpy(employees[dbhdr->count-1].address, addr, sizeof(employees[dbhdr->count-1].address)); + + employees[dbhdr->count-1].hours = atoi(hours); + + + return STATUS_SUCCESS; +} + +int read_employees(int fd, struct dbheader_t *dbhdr, struct employee_t **employeesOut) { + if (fd < 0) { + printf("Got a bad FD from the user\n"); + return STATUS_ERROR; + } + + + int count = dbhdr->count; + + struct employee_t *employees = calloc(count, sizeof(struct employee_t)); + if (employees == (void*)-1) { + printf("Malloc failed\n"); + return STATUS_ERROR; + } + + read(fd, employees, count*sizeof(struct employee_t)); + + int i = 0; + for (; i < count; i++) { + employees[i].hours = ntohl(employees[i].hours); + } + + *employeesOut = employees; + return STATUS_SUCCESS; + +} + +int output_file(int fd, struct dbheader_t *dbhdr, struct employee_t *employees) { + if (fd < 0) { + printf("Got a bad FD from the user\n"); + return STATUS_ERROR; + } + + int realcount = dbhdr->count; + + dbhdr->magic = htonl(dbhdr->magic); + dbhdr->filesize = htonl(sizeof(struct dbheader_t) + (sizeof(struct employee_t) * realcount)); + dbhdr->count = htons(dbhdr->count); + dbhdr->version = htons(dbhdr->version); + + lseek(fd, 0, SEEK_SET); + + write(fd, dbhdr, sizeof(struct dbheader_t)); + + int i = 0; + for (; i < realcount; i++) { + employees[i].hours = htonl(employees[i].hours); + write(fd, &employees[i], sizeof(struct employee_t)); + } + + return STATUS_SUCCESS; + +} + +int validate_db_header(int fd, struct dbheader_t **headerOut) { + if (fd < 0) { + printf("Got a bad FD from the user\n"); + return STATUS_ERROR; + } + + struct dbheader_t *header = calloc(1, sizeof(struct dbheader_t)); + if (header == (void*)-1) { + printf("Malloc failed create a db header\n"); + return STATUS_ERROR; + } + + if (read(fd, header, sizeof(struct dbheader_t)) != sizeof(struct dbheader_t)) { + perror("read"); + free(header); + return STATUS_ERROR; + } + + header->version = ntohs(header->version); + header->count = ntohs(header->count); + header->magic = ntohl(header->magic); + header->filesize = ntohl(header->filesize); + + if (header->magic != HEADER_MAGIC) { + printf("Impromper header magic\n"); + free(header); + return -1; + } + + + if (header->version != 1) { + printf("Impromper header version\n"); + free(header); + return -1; + } + + struct stat dbstat = {0}; + fstat(fd, &dbstat); + if (header->filesize != dbstat.st_size) { + printf("Corrupted database\n"); + free(header); + return -1; + } + + *headerOut = header; +} + +int create_db_header(int fd, struct dbheader_t **headerOut) { + struct dbheader_t *header = calloc(1, sizeof(struct dbheader_t)); + if (header == (void*)-1) { + printf("Malloc failed to create db header\n"); + return STATUS_ERROR; + } + + header->version = 0x1; + header->count = 0; + header->magic = HEADER_MAGIC; + header->filesize = sizeof(struct dbheader_t); + + *headerOut = header; + + return STATUS_SUCCESS; +} + + diff --git a/C/netCode/.gitignore b/C/netCode/.gitignore new file mode 100644 index 0000000..f2ad853 --- /dev/null +++ b/C/netCode/.gitignore @@ -0,0 +1,2 @@ +client +server diff --git a/C/netCode/client.c b/C/netCode/client.c new file mode 100644 index 0000000..dafd1e8 --- /dev/null +++ b/C/netCode/client.c @@ -0,0 +1,66 @@ +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <arpa/inet.h> +#include <netinet/in.h> + +#include "types.h" + +void handle_client(int fd) +{ + char buf[4096] = {0}; + int *data; + proto_hdr_t *hdr = (proto_hdr_t*)buf; + + + read(fd, buf, sizeof(proto_hdr_t) + sizeof(int)); + + hdr->type = ntohl(hdr->type); + hdr->len = ntohs(hdr->len); + + data = (int *)&hdr[1]; + *data = ntohl(*data); + + if (hdr->type != PROTO_HELLO) + printf("Protocol mismatch\n"); + + if (*data != 1) + printf("Protocol version mismatch\n"); + + printf("Client connected - proto: %d ver: %d payload: %d\n", + hdr->type, hdr->len, *data); +} + +int main(int argc, char *argv[]) +{ + int err; + struct sockaddr_in serverInfo = {0}; + int fd = socket(AF_INET, SOCK_STREAM, 0); + + if (argc != 2) { + printf("Usage: ./client <ip>\n"); + exit(1); + } + + serverInfo.sin_family = AF_INET; + serverInfo.sin_addr.s_addr = inet_addr(argv[1]);; + serverInfo.sin_port = htons(SERVER_PORT); + + if (fd < 0) { + perror("socket"); + exit(1); + } + + err = connect(fd, (struct sockaddr*)&serverInfo, sizeof(serverInfo)); + if (err < 0) { + perror("connect"); + close(fd); + exit(1); + } + + handle_client(fd); + close(fd); + return 0; +} diff --git a/C/netCode/server.c b/C/netCode/server.c new file mode 100644 index 0000000..0b951eb --- /dev/null +++ b/C/netCode/server.c @@ -0,0 +1,202 @@ +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> +#include <poll.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <arpa/inet.h> +#include <netinet/in.h> +#include "types.h" + +clientstate_t clientStates[MAX_CLIENTS]; + +void init_clients(void) { + int i; + + for (i = 0; i < MAX_CLIENTS; i++) { + /* -1 means client slot is free */ + clientStates[i].fd = -1; + clientStates[i].state = STATE_NEW; + memset(&clientStates[i].buffer, 0, BUF_SIZE); + } +} + +int find_free_client(void) { + int i = 0; + + for (i = 0; i < MAX_CLIENTS; i++) + if (clientStates[i].fd == -1) + return i; + + return -1; +} + +int find_slot_by_fd(int fd) +{ + int i; + for (i = 0; i < MAX_CLIENTS; i++) { + if (clientStates[i].fd == fd) + return i; + } + return -1; +} + +void handle_client(int fd) +{ + char buf[4096] = {0}; + proto_hdr_t *hdr = (proto_hdr_t*)buf; + int *data; + int reallen; + + hdr->type = htonl(PROTO_HELLO); + reallen = sizeof(int); + hdr->len = htons(reallen); + + data = (int *)&hdr[1]; + *data = htonl(1); + + printf("hdr_ptr: %p data_ptr: %p\n", hdr, data); + write(fd, hdr, sizeof(proto_hdr_t) + reallen); + +} + + +int main(void) +{ + int err; + int listen_fd, conn_fd, nfds, freeSlot; + struct sockaddr_in serverInfo = {0}; + struct sockaddr_in clientInfo = {0}; + socklen_t csize; + int opt = 1; + + struct pollfd fds[MAX_CLIENTS + 1]; + + memset(fds, 9, sizeof(fds)); + serverInfo.sin_family = AF_INET; + serverInfo.sin_addr.s_addr = 0; /* bind to all IPs */ + serverInfo.sin_port = htons(SERVER_PORT); + + init_clients(); + + listen_fd = socket(AF_INET, SOCK_STREAM, 0); + if (listen_fd < 0) { + perror("socket"); + exit(1); + } + + err = bind(listen_fd, + (struct sockaddr *)&serverInfo, + sizeof(serverInfo)); + + if (err < 0) { + perror("bind"); + close(listen_fd); + exit(1); + } + + err = listen(listen_fd, 0); + if (err < 0) { + perror("listen"); + close(listen_fd); + exit(1); + } + + if (setsockopt(listen_fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)) == -1) { + perror("setsockopt"); + close(listen_fd); + exit(1); + } + + printf("Server listening to port: %d\n", SERVER_PORT); + + csize = sizeof(clientInfo); + + fds[0].fd = listen_fd; + fds[0].events = POLLIN; + nfds = 1; + + while (1) { + int i, j; + int nevents; + + /* fds is initialized with MAX_CLIENTS + 1 */ + for (i = 0, j = 1; i < MAX_CLIENTS; i++, j++) { + if (clientStates[i].fd != -1) { + /* Add open fd to the poll */ + fds[j].fd = clientStates[i].fd; + fds[j].events = POLLIN; + printf("FD %d added to poll\n", clientStates[i].fd); + } + } + + nevents = poll(fds, nfds, -1); + + if (nevents == -1) { + perror("poll"); + exit(1); + } + + /* if listen_fd is ready, accept it */ + if (fds[0].revents & POLLIN) { + conn_fd = accept(listen_fd, + (struct sockaddr*)&clientInfo, + &csize); + + if (conn_fd < 0) { + perror("accept"); + continue; + } + + printf("New connection from: %s:%d\n", + inet_ntoa(clientInfo.sin_addr), + ntohs(clientInfo.sin_port)); + + freeSlot = find_free_client(); + if (freeSlot < 0) { + printf("Server full - closing connection\n"); + close(conn_fd); + } else { + clientStates[freeSlot].fd = conn_fd; + clientStates[freeSlot].state = STATE_CONNECTED; + nfds++; + printf("Adding fd %d to slot %d\n", + conn_fd, freeSlot); + } + nevents--; + } + + printf("NFDS: %d\n", nfds); + for (i = 1; i <= nfds && nevents > 0; i++) { + int fd, slot; + ssize_t bytes_read; + + if (fds[i].revents & POLLIN) { + nevents--; + + fd = fds[i].fd; + slot = find_slot_by_fd(fd); + bytes_read = read(fd, + &clientStates[slot].buffer, + sizeof(clientStates[slot].buffer)); + if (bytes_read <= 0) { + close(fd); + printf("Connection error\n"); + if (slot == -1) { + printf("Trying to close an invalid fd\n"); + } else { + clientStates[slot].fd = -1; + clientStates[slot].state = STATE_DISCONNECTED; + printf("Client disconnected or error\n"); + nfds--; + } + } else { + printf("Data received: %s\n", clientStates[slot].buffer); + } + } + + } + } + return 0; +} diff --git a/C/netCode/types.h b/C/netCode/types.h new file mode 100644 index 0000000..e70974e --- /dev/null +++ b/C/netCode/types.h @@ -0,0 +1,26 @@ +#define SERVER_PORT 5555 +#define MAX_CLIENTS 5 +#define BUF_SIZE 4096 + +typedef enum { + PROTO_HELLO, +} proto_type_e; + +/* Type-Length-Value */ +typedef struct { + proto_type_e type; + unsigned short len; +} proto_hdr_t; + +typedef enum { + STATE_NEW, + STATE_CONNECTED, + STATE_DISCONNECTED, +} state_e; + +typedef struct { + int fd; + state_e state; + char buffer[BUF_SIZE]; +} clientstate_t; + |
