├── README.md ├── C ├── sp.c ├── shellcode1.c ├── seg2.c ├── seg1.c ├── intloop.c ├── loopstomp.c ├── mem.c ├── shm1.c ├── shm2.c ├── p1.c ├── bbsem1.c ├── milk1.c ├── milk2.c ├── zombie.c ├── killer.c ├── bbsem2.c ├── fork1.c ├── sema1.c ├── dumbshell.c ├── syscalls.c ├── sig1.c ├── client.c ├── fork2.c ├── sig2.c ├── server.c ├── tlsclient.c ├── coredumper.c ├── tlsserver.c ├── iagree.c └── select_server.c └── python ├── sha256-example.py └── merkle-example.py /README.md: -------------------------------------------------------------------------------- 1 | 2 | Examples for undergraduate student use that I've used over the years. 3 | -------------------------------------------------------------------------------- /C/sp.c: -------------------------------------------------------------------------------- 1 | unsigned long get_sp(void) { 2 | __asm__("movl %esp,%eax"); 3 | } 4 | void main() { 5 | printf("0x%x\n", get_sp()); 6 | } 7 | -------------------------------------------------------------------------------- /C/shellcode1.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Run a shell via asm - ASCII only. 3 | * 4 | */ 5 | 6 | char shellcode[] = 7 | "LLLLYhb0pLX5b0pLHSSPPWQPPaPWSUTBRDJfh5tDS" 8 | "RajYX0Dka0TkafhN9fYf1Lkb0TkdjfY0Lkf0Tkgfh" 9 | "6rfYf1Lki0tkkh95h8Y1LkmjpY0Lkq0tkrh2wnuX1" 10 | "Dks0tkwjfX0Dkx0tkx0tkyCjnY0LkzC0TkzCCjtX0" 11 | "DkzC0tkzCj3X0Dkz0TkzC0tkzChjG3IY1LkzCCCC0" 12 | "tkzChpfcMX1DkzCCCC0tkzCh4pCnY1Lkz1TkzCCCC" 13 | "fhJGfXf1Dkzf1tkzCCjHX0DkzCCCCjvY0LkzCCCjd" 14 | "X0DkzC0TkzCjWX0Dkz0TkzCjdX0DkzCjXY0Lkz0tk" 15 | "zMdgvvn9F1r8F55h8pG9wnuvjrNfrVx2LGkG3IDpf" 16 | "cM2KgmnJGgbinYshdvD9d"; 17 | 18 | 19 | int main(int argc, char *argv[]) 20 | { 21 | int *ret; 22 | 23 | printf("Length is %d\n",strlen(shellcode)); 24 | ret = (int *)&ret + 2; 25 | (*ret) = (int)shellcode; 26 | return( 0 ); 27 | } 28 | -------------------------------------------------------------------------------- /python/sha256-example.py: -------------------------------------------------------------------------------- 1 | import hashlib 2 | 3 | # We talked very briefly about cryptographic hash functions. 4 | # sha256 is a very commonly used cryptographic hash function, 5 | # and we usually display the hash value as a hex encoded 6 | # sequence of bytes. 7 | 8 | # Python has an implmentation of sha256 in hashlib. 9 | 10 | stringtohash = "I'm a lumberjack and I'm ok" 11 | print("Hashing: "+str(stringtohash)) 12 | hashvalue = hashlib.sha256(stringtohash.encode('utf-8')).hexdigest() 13 | print("Hex sha256 hash: "+str(hashvalue)) 14 | print("If you have the 'openssl' command on your machine you can see that ") 15 | print(" echo -n \"I'm a lumberjack and I'm ok\" | openssl sha256") 16 | print("Will produce the exact same hash value as above.") 17 | stringtohash += "!" 18 | print("Changing string to : "+str(stringtohash)) 19 | hashvalue = hashlib.sha256(stringtohash.encode('utf-8')).hexdigest() 20 | print("Produces a different hash: "+str(hashvalue)) 21 | -------------------------------------------------------------------------------- /C/seg2.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2008 Bob Beck 3 | * 4 | * Permission to use, copy, modify, and distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | 17 | /* 18 | * how far can we read? this program should also segfault, but again 19 | * it will read far past the end of the array before doing so. 20 | */ 21 | 22 | /* 23 | * compile with "cc -o seg2 seg2.c", run with "./seg2" 24 | */ 25 | 26 | #include 27 | #include 28 | 29 | int main() 30 | { 31 | char carr[80]; 32 | char c; 33 | int i; 34 | 35 | printf ("let's go a reading... starting at %p, which ends at %p\n", 36 | carr, carr + 80); 37 | 38 | while(1) { 39 | printf("reading at %p\n", carr + i); 40 | c = carr[i++]; 41 | } 42 | } 43 | 44 | 45 | -------------------------------------------------------------------------------- /C/seg1.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2008 Bob Beck 3 | * 4 | * Permission to use, copy, modify, and distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | 17 | /* 18 | * how far can we stomp? - this program should segfault, but it 19 | * will most likely spit out a lot more than 80 lines of output. 20 | * notice you don't die immediately after the end of the array. 21 | */ 22 | 23 | /* 24 | * compile with "cc -o seg1 seg1.c", run with "./seg1" 25 | */ 26 | 27 | #include 28 | #include 29 | 30 | int main() 31 | { 32 | char carr[80]; 33 | int i; 34 | 35 | printf ("let's go a stomping... starting at %p, which ends at %p\n", 36 | carr, carr + 80); 37 | 38 | while(1) { 39 | printf("stomping at %p\n", carr + i); 40 | carr[i++] = 'a'; 41 | } 42 | } 43 | 44 | 45 | -------------------------------------------------------------------------------- /C/intloop.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2012 Bob Beck 3 | * 4 | * Permission to use, copy, modify, and distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | 17 | /* 18 | * Integers have finite sizes. 19 | */ 20 | 21 | /* 22 | * compile this program twice, once with 23 | * 24 | * gcc -o intloop1 intloop1.c 25 | * 26 | * and then 27 | * 28 | * gcc -DBIGIJ -o intloop2 intloop2.c 29 | * 30 | * be sure you understand why they behave differently. 31 | */ 32 | 33 | 34 | 35 | #include 36 | 37 | int main() 38 | { 39 | #ifndef BIGIJ 40 | unsigned int i, j; 41 | #else 42 | unsigned long i, j; 43 | #endif 44 | 45 | printf("starting\n"); 46 | for(j = i = 0; i < 0xffffffff; i+=4096) { 47 | if (i < j) 48 | printf("WTF? i=%u, j=%u\n", i, j); 49 | j = i; 50 | } 51 | printf("done\n"); 52 | } 53 | 54 | -------------------------------------------------------------------------------- /C/loopstomp.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2008 Bob Beck 3 | * 4 | * Permission to use, copy, modify, and distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | 17 | /* 18 | * a simple stomper - let's whack the loop variable - note this 19 | * program can run forever - thanks to i getting clobbered. 20 | */ 21 | 22 | /* 23 | * compile with "cc -o loopstomp loopstomp.c", run with "./loopstomp" 24 | */ 25 | 26 | #include 27 | #include 28 | 29 | /* may need to be adjusted depending on os and compiler... 30 | * not guaranteed to work on some os's (especially OpenBSD) 31 | * these constants work fine in the cs lab. 32 | */ 33 | #define LEN 4 34 | #define END (LEN * 2) 35 | 36 | int main() 37 | { 38 | int i; 39 | int array[LEN]; 40 | 41 | i = 0; 42 | while (i < END) { 43 | array[i] = 0; 44 | i++; 45 | /* you could add a few printf %p's in here to print out 46 | * &i, and array+i to see what's going on... 47 | */ 48 | } 49 | return(0); 50 | } 51 | 52 | 53 | -------------------------------------------------------------------------------- /C/mem.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2008 Bob Beck 3 | * 4 | * Permission to use, copy, modify, and distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | 17 | /* 18 | * A simple example of where stuff gets put. 19 | */ 20 | 21 | /* 22 | * compile with "cc -o mem mem.c", run with "./mem" 23 | */ 24 | 25 | #include 26 | #include 27 | #include 28 | #include 29 | 30 | int aglobal; 31 | 32 | int main() 33 | { 34 | int iarr[1024]; 35 | int *iarr2; 36 | 37 | iarr2 = malloc(1024 * sizeof(int)); 38 | if (iarr2 == NULL) 39 | err(1, "malloc failed"); 40 | 41 | printf("The address of main is %p\n", &main); 42 | printf("The address of aglobal is %p\n", &aglobal); 43 | printf("The address of iarr on main's stack is %p\n", iarr); 44 | printf("The address returned by malloc (heap) is %p\n", iarr2); 45 | printf("The address of the errno variable is %p\n", &errno); 46 | printf("The address of the err function is %p\n", &err); 47 | return(0); 48 | } 49 | 50 | 51 | -------------------------------------------------------------------------------- /C/shm1.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2008 Bob Beck 3 | * 4 | * Permission to use, copy, modify, and distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | 17 | /* Create and put stuff into a shared memory segment */ 18 | 19 | /* 20 | * compile with cc -o shm1 shm1.c 21 | * run with ./shm1 22 | */ 23 | 24 | 25 | #include 26 | #include 27 | #include 28 | 29 | #include 30 | #include 31 | #include 32 | #define SHMKEY 12345678L 33 | int main() 34 | { 35 | int shmid; 36 | char *shm_p; 37 | 38 | /* allocate 10 bytes of shared memory - identified by SHMKEY */ 39 | if((shmid=shmget(SHMKEY,10,IPC_CREAT|0660)) == -1) 40 | err(1, "shmget failed"); 41 | 42 | /* attach what I just allocated */ 43 | if((shm_p=shmat(shmid,0,0)) == (void *) -1) 44 | err(1, "shmat failed"); 45 | 46 | /* put some characters in those 10 bytes */ 47 | strlcpy(shm_p, "This is some stuff that's too long", 10); 48 | 49 | /* detach ourselves and exit */ 50 | if(shmdt(shm_p) == -1) 51 | err(1, "Could not detach..."); 52 | 53 | return(0); 54 | 55 | } 56 | -------------------------------------------------------------------------------- /C/shm2.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2008 Bob Beck 3 | * 4 | * Permission to use, copy, modify, and distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | 17 | /* Read from a shared memory segment, then destroy it */ 18 | 19 | /* 20 | * compile with cc -o shm2 shm2.c 21 | * run with ./shm2 22 | */ 23 | 24 | #include 25 | #include 26 | #include 27 | 28 | 29 | #include 30 | #include 31 | #include 32 | #define SHMKEY 12345678L 33 | 34 | int main() 35 | { 36 | int shmid; 37 | char *shm_p; 38 | 39 | /* go find the shm identified by SHMKEY */ 40 | if((shmid=shmget(SHMKEY,10,0)) == -1) 41 | err(1, "shmget failed"); 42 | 43 | /* attach what I just allocated */ 44 | if((shm_p=shmat(shmid,0,0)) == (void *) -1) 45 | err(1, "shmat failed"); 46 | 47 | /* hopefully, what's there is a C string or bad stuff will happen */ 48 | printf("Share mem contains \"%s\"\n", shm_p); 49 | 50 | /* detach ourselves */ 51 | if(shmdt(shm_p) == -1) 52 | err(1, "Could not detach..."); 53 | /* now REMOVE the shm segment to not leave it lying around */ 54 | if(shmctl(shmid,IPC_RMID,NULL) == -1) 55 | err(1, "Could not remove segment..."); 56 | 57 | 58 | return(0); 59 | } 60 | -------------------------------------------------------------------------------- /C/p1.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2008 Bob Beck 3 | * 4 | * Permission to use, copy, modify, and distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | 17 | /* A little pointers and strings review */ 18 | 19 | /* 20 | * compile with "cc -o p1 p1.c", run with "./mem" 21 | */ 22 | 23 | #include 24 | #include 25 | #include 26 | 27 | char *fred; 28 | char sam[]="I'm a lumberjack and I'm OK"; 29 | 30 | int main() 31 | { 32 | char *george; 33 | char bob[]="I sleep all night and I work all day"; 34 | 35 | /* an exercise in C variables, and pointers, and strings... */ 36 | /* think about why this is all so.... */ 37 | 38 | printf ("Variable fred, is at %p, size %d, contains value %p\n", 39 | &fred, sizeof(fred), fred); 40 | printf ("Variable sam, is at %p, size %d, contains value %p, a string of length %d: %s\n", 41 | &sam, sizeof(sam), sam, strlen(sam), sam); 42 | 43 | printf ("Variable george, is at %p, size %d, contains value %p\n", 44 | &george, sizeof(george), george); 45 | printf ("Variable bob, is at %p, size %d, contains value %p, a string of length %d: %s\n", 46 | &bob, sizeof(bob), bob, strlen(bob), bob); 47 | 48 | george = sam; 49 | fred = bob; 50 | 51 | printf ("Variable george, is at %p, size %d, contains value %p, a string of length %d: %s\n", 52 | &george, sizeof(george), george, strlen(george), george); 53 | printf ("Variable fred, is at %p, size %d, contains value %p, a string of length %d: %s\n", 54 | &fred, sizeof(fred), fred, strlen(fred), fred); 55 | exit(0); 56 | } 57 | 58 | -------------------------------------------------------------------------------- /C/bbsem1.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2013 Bob Beck 3 | * 4 | * Permission to use, copy, modify, and distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | 17 | /* 18 | * An implementation of general semaphores using pthreads mutexes 19 | * to protect testing and changing of the semaphore value. 20 | * 21 | * Note - this is intended as an example only, 22 | * You probably shouldn't roll your own semaphores, but rather use 23 | * the ones from semaphore.h. 24 | * 25 | * Note this example busy waits for the semaphore. So it's kind of 26 | * wasteful 27 | */ 28 | 29 | #include 30 | #include 31 | #include 32 | #include 33 | 34 | struct bbsem { 35 | pthread_mutex_t mutex; 36 | int value; 37 | }; 38 | 39 | struct bbsem * 40 | bbseminit(int val) 41 | { 42 | struct bbsem *tmp; 43 | tmp = malloc(sizeof(*tmp)); 44 | if (tmp == NULL) 45 | return(NULL); 46 | pthread_mutex_init(&tmp->mutex, NULL); 47 | tmp->value = val; 48 | return(tmp); 49 | } 50 | 51 | void 52 | bbsemdestroy(struct bbsem *bp) 53 | { 54 | if (pthread_mutex_destroy(&bp->mutex) != 0) 55 | err(1, "pthread_mutex_destroy failed:"); 56 | free(bp); 57 | } 58 | 59 | void 60 | bbsemwait(struct bbsem *bp) 61 | { 62 | pthread_mutex_lock(&bp->mutex); 63 | while (bp->value == 0) { 64 | pthread_mutex_unlock(&bp->mutex); 65 | pthread_yield(); 66 | pthread_mutex_lock(&bp->mutex); 67 | } 68 | /* come back from the wait with the mutex locked */ 69 | bp->value--; 70 | pthread_mutex_unlock(&bp->mutex); 71 | } 72 | 73 | void 74 | bbsemfree(struct bbsem *bp) 75 | { 76 | pthread_mutex_lock(&bp->mutex); 77 | bp->value++; 78 | pthread_mutex_unlock(&bp->mutex); 79 | } 80 | 81 | -------------------------------------------------------------------------------- /C/milk1.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2013 Bob Beck 3 | * 4 | * Permission to use, copy, modify, and distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | 17 | /* 18 | * milk1.c - a simplistic version of the roommates buying 19 | * milk problem using pthreads. 20 | * 21 | * to compile: 22 | * cc -o milk1 milk1.c -lpthread 23 | * 24 | * and jut run it as ./milk1 25 | * 26 | * you will notice how the amount of milk in the fridge goes 27 | * slightly strange quickly, as the global variable "milk" is 28 | * tested and modified in our thread's critical section without 29 | * any way of keeping other threads from getting in there 30 | * 31 | * This example cheats somewhat and makes it easy for the poor 32 | * interleaving to occur because it uses sleep() and pthread_yield() 33 | * to pretty much guarantee the problem will occur :) 34 | */ 35 | 36 | #include 37 | #include 38 | #include 39 | #include 40 | 41 | #define NUM_THREADS 5 42 | 43 | int milk = 1; 44 | 45 | void *CheckDaMilk(void *arg) 46 | { 47 | int mynum = *((int *)arg); 48 | printf ("Hi I am thread %d\n", mynum); 49 | while(1) { 50 | if (milk > 0) { 51 | sleep(1); 52 | milk--; 53 | printf("Now %d milks in the fridge, thread %d buying" 54 | " milk..\n", milk, mynum); 55 | milk++; 56 | } 57 | pthread_yield(); 58 | } 59 | } 60 | 61 | int 62 | main(int argc, char *argv[]) 63 | { 64 | pthread_t threads[NUM_THREADS]; 65 | int tids[NUM_THREADS]; 66 | int rc, t; 67 | 68 | for(t=0;t 3 | * 4 | * Permission to use, copy, modify, and distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | 17 | /* 18 | * milk2.c - a simplistic version of the roommates buying 19 | * milk problem using pthreads. 20 | * 21 | * to compile: 22 | * cc -o milk2 milk2.c -lpthread 23 | * 24 | * and jut run it as ./milk2 25 | * 26 | * Same program as "milk1.c" but this one is protected using 27 | * a posix semaphore to only allow one thread into the critical 28 | * section at any one time. 29 | */ 30 | 31 | #include 32 | #include 33 | #include 34 | #include 35 | #include 36 | 37 | #define NUM_THREADS 5 38 | 39 | sem_t mysem; /* My semaphone - a posix semaphore */ 40 | int milk = 1; 41 | 42 | void *CheckDaMilk(void *arg) 43 | { 44 | int mynum = *((int *)arg); 45 | printf ("Hi I am thread %d\n", mynum); 46 | while(1) { 47 | sem_wait(&mysem); /* "wait" (decrement) semaphore mysem */ 48 | if (milk > 0) { 49 | sleep(1); 50 | milk--; 51 | printf("Now %d milks in the fridge, thread %d buying" 52 | " milk..\n", milk, mynum); 53 | milk++; 54 | } 55 | sem_post(&mysem); /* "free" (incremenet) semaphore mysem */ 56 | pthread_yield(); 57 | } 58 | } 59 | 60 | int 61 | main(int argc, char *argv[]) 62 | { 63 | pthread_t threads[NUM_THREADS]; 64 | int tids[NUM_THREADS]; 65 | int rc, t; 66 | 67 | /* 68 | * Initialize posix semaphore "mysem" to have 1 as the initial 69 | * value 70 | */ 71 | sem_init(&mysem, 0, 1); 72 | 73 | for(t=0;t 3 | * 4 | * Permission to use, copy, modify, and distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | 17 | /* 18 | * Let's check out zombies, and waiting for our kids when they die. 19 | */ 20 | 21 | /* 22 | * compile with cc -o zombie zombie.c, run with "./zombie&" 23 | * note the "&" to run this program in the background. 24 | * 25 | * This program leaves a zombie for 30 seconds before exiting 26 | * if the environment variable "FLUFFY" is not set. It will 27 | * wait() for the child exiting if FLUFFY is set. So try it 28 | * two ways. 29 | * 30 | * unset FLUFFY 31 | * ./zombie & 32 | * 33 | * export FLUFFY=fluff 34 | * ./zombie & 35 | * 36 | */ 37 | #include 38 | #include 39 | 40 | #include 41 | #include 42 | #include 43 | #include 44 | 45 | int main(int argc, char *argv[]) 46 | { 47 | pid_t p; 48 | int i = 0; 49 | int reap = 0; /* should we wait, to get rid of the zombie? */ 50 | 51 | printf("Process %d, starting up\n", getpid()); 52 | 53 | p = fork(); 54 | if (p == 0) { 55 | /* I am the child process */ 56 | exit(0); /* A responsible parent knows when I go away */ 57 | } 58 | /* otherwise, I am in the parent */ 59 | /* 60 | * the fork could have failed (system resource limits, etc. so we 61 | * need to check for that.. 62 | */ 63 | if (p == -1) 64 | err(1, "Fork failed! Can't create child!"); 65 | /* 66 | * otherwise - p will have the pid of the child. 67 | */ 68 | 69 | if (getenv("FLUFFY") != NULL) { 70 | reap = 1; 71 | printf("I will be reaping my zombie children....\n"); 72 | } else 73 | printf("I will be ignoring my zombie children....\n"); 74 | 75 | printf("You have 10 seconds to look at the process table\n"); 76 | printf("with the command \"ps -x\"\n"); 77 | while (i++ < 10) { 78 | if (reap) 79 | waitpid(WAIT_ANY, NULL, WNOHANG); 80 | sleep(1); 81 | } 82 | exit(0); 83 | } 84 | -------------------------------------------------------------------------------- /C/killer.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2008 Bob Beck 3 | * 4 | * Permission to use, copy, modify, and distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | 17 | /* 18 | * In unix, processes can kill other processes... 19 | */ 20 | 21 | /* 22 | * compile with cc -o killer killer.c, run with "./killer&" 23 | * note the "&" to run this program in the background. 24 | * 25 | * This program makes a child who becomes very busy. After 10 26 | * seconds the parent kill()'s the child. you should see 27 | * a busy child for the first 10 seconds in ps -x, then 28 | * only the parent for the next 10 seconds. 29 | * 30 | */ 31 | #include 32 | #include 33 | #include 34 | 35 | #include 36 | #include 37 | #include 38 | #include 39 | 40 | int main(int argc, char *argv[]) 41 | { 42 | pid_t p; 43 | int i; 44 | 45 | printf("Process %d, starting up\n", getpid()); 46 | 47 | p = fork(); 48 | if (p == 0) 49 | while(1); /* run forever in a tight loop! */ 50 | 51 | /* otherwise, I am in the parent */ 52 | /* 53 | * the fork could have failed (system resource limits, etc. so we 54 | * need to check for that.. 55 | */ 56 | if (p == -1) 57 | err(1, "Fork failed! Can't create child!"); 58 | /* 59 | * otherwise - p will have the pid of the child. 60 | */ 61 | 62 | 63 | printf("You have 10 seconds to look at the process table\n"); 64 | printf("with the command \"ps -x\"\n"); 65 | while (i++ < 10) 66 | sleep(1); 67 | 68 | printf("Killing off child %d\n", p); 69 | if (kill(p, SIGTERM) == -1) 70 | err(1, "can't kill %d", p); 71 | 72 | printf("You have another 10 seconds to look at the process table\n"); 73 | printf("with the command \"ps -x\"\n"); 74 | i = 0; 75 | while (i++ < 10) { 76 | /* note, if you remove this wait, the killed child will show 77 | * up as a zombie until the parent exits.. 78 | */ 79 | waitpid(WAIT_ANY, NULL, WNOHANG); 80 | sleep(1); 81 | } 82 | exit(0); 83 | } 84 | -------------------------------------------------------------------------------- /C/bbsem2.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2013 Bob Beck 3 | * 4 | * Permission to use, copy, modify, and distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | 17 | /* 18 | * An implementation of general semaphores using pthreads mutexes and 19 | * condition variables. Note - this is intended as an example only, 20 | * You probably shouldn't roll your own semaphores, but rather use 21 | * the ones from semaphore.h. 22 | * 23 | * Unlike bbsem1 - this version does not busy wait. 24 | * This example is to show you how we use mutexes and 25 | * condition variables together. The mutex is used to protect 26 | * the critical section (where we change the semaphore value) and 27 | * the condition variable is used so we can wait for the value 28 | * of the semaphore to be non-zero so we can acquire it without 29 | * busy waiting. 30 | */ 31 | 32 | #include 33 | #include 34 | #include 35 | #include 36 | 37 | struct bbsem { 38 | pthread_mutex_t mutex; 39 | pthread_cond_t is_nonzero; 40 | int value; 41 | }; 42 | 43 | struct bbsem * 44 | bbseminit(int val) 45 | { 46 | struct bbsem *tmp; 47 | tmp = malloc(sizeof(*tmp)); 48 | if (tmp == NULL) 49 | return(NULL); 50 | pthread_cond_init(&tmp->is_nonzero, NULL); 51 | pthread_mutex_init(&tmp->mutex, NULL); 52 | tmp->value = val; 53 | return(tmp); 54 | } 55 | 56 | void 57 | bbsemdestroy(struct bbsem *bp) 58 | { 59 | if (pthread_mutex_destroy(&bp->mutex) != 0) 60 | err(1, "pthread_mutex_destroy failed:"); 61 | if (pthread_cond_destroy(&bp->is_nonzero) != 0) 62 | err(1, "pthread_cond_destroy failed:"); 63 | free(bp); 64 | } 65 | 66 | void 67 | bbsemwait(struct bbsem *bp) 68 | { 69 | pthread_mutex_lock(&bp->mutex); 70 | while (bp->value == 0) 71 | pthread_cond_wait(&bp->is_nonzero, &bp->mutex); 72 | /* come back from the wait with the mutex locked */ 73 | bp->value--; 74 | pthread_mutex_unlock(&bp->mutex); 75 | } 76 | 77 | void 78 | bbsemfree(struct bbsem *bp) 79 | { 80 | pthread_mutex_lock(&bp->mutex); 81 | bp->value++; 82 | pthread_cond_signal(&bp->is_nonzero); 83 | pthread_mutex_unlock(&bp->mutex); 84 | } 85 | 86 | -------------------------------------------------------------------------------- /C/fork1.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2008 Bob Beck 3 | * 4 | * Permission to use, copy, modify, and distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | 17 | /* 18 | * Let's make a new process with fork() 19 | */ 20 | 21 | /* 22 | * compile with cc -o fork1 fork1.c, run with "./fork1" 23 | * 24 | */ 25 | #include 26 | 27 | #include 28 | #include 29 | #include 30 | #include 31 | 32 | int main() 33 | { 34 | pid_t p; 35 | int seconds; 36 | 37 | printf("Process %d, starting up\n", getpid()); 38 | 39 | p = fork(); 40 | if (p == 0) { 41 | /* I am the child process */ 42 | printf("Process %d (child), fork returned %d\n", getpid(), p); 43 | /* Use the process id to seed the random number generator 44 | * I do this because it is convenient - and I do *NOT* care 45 | * about this random number being unpredictable for use in 46 | * any kind of security portion of this software. Please 47 | * remember that if I know or could predict the PID the random 48 | * number is as predictable as 49 | * http://dilbert.com/strips/comic/2001-10-25/ 50 | */ 51 | srandom(getpid()); 52 | seconds = random() % 5; 53 | printf("Process %d (child) will be sleeping for %d seconds\n", 54 | getpid(), seconds); 55 | sleep(seconds); 56 | printf("Process %d (child) now exiting\n", getpid()); 57 | exit(0); 58 | } 59 | /* otherwise, I am in the parent */ 60 | /* 61 | * the fork could have failed (system resource limits, etc. so we 62 | * need to check for that.. 63 | */ 64 | if (p == -1) 65 | err(1, "Fork failed! Can't create child!"); 66 | /* 67 | * otherwise - p will have the pid of the child. 68 | */ 69 | printf("Process %d (parent), fork returned %d\n", getpid(), p); 70 | srandom(getpid()); 71 | seconds = random() % 5; 72 | printf("Process %d (parent) will be sleeping for %d seconds\n", 73 | getpid(), seconds); 74 | sleep(seconds); 75 | printf("Process %d (parent) now exiting\n", getpid()); 76 | /* 77 | * for this example, we won't yet worry about what happens when 78 | * the child exits before the parent. - since eventually everyone 79 | * exits, all works out in the end. 80 | */ 81 | exit(0); 82 | } 83 | -------------------------------------------------------------------------------- /C/sema1.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2008-2013 Bob Beck 3 | * 4 | * Permission to use, copy, modify, and distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | 17 | /* 18 | * Example of system V semaphore use for locking and unlocking access 19 | * System V semaphores can be shared between *processes* - do *NOT* 20 | * use them for thread synchronization - they are old and nasty and 21 | * horrible. 22 | * 23 | * You may compare doing this with the use of a posix semaphore 24 | * in the milk1.c -> milk2.c example in this directory (which 25 | * is much more sane... 26 | */ 27 | 28 | /* 29 | * compile with cc -o sema1 sema1.c 30 | * run with ./sema1& ./sema1 31 | */ 32 | 33 | #include 34 | #include 35 | #include 36 | 37 | #include 38 | #include 39 | #include 40 | 41 | #define SEMKEY 87654321L 42 | 43 | int semid; 44 | 45 | locker(int num) 46 | { 47 | static struct sembuf lock_it[2] = { 48 | 0,0,0, 49 | 0,1,0 50 | }; 51 | lock_it[0].sem_num = num; /* we TEST semaphore first, that it is 0 */ 52 | lock_it[1].sem_num = num; /* Assuming that works we lock by 53 | raising the semaphore to 1 */ 54 | if (semop(semid,&lock_it[0],2) < 0) 55 | return 1; 56 | else 57 | return 0; 58 | } 59 | 60 | unlocker(int num) 61 | { 62 | static struct sembuf unlock_it[1] = { 63 | 0,-1,0 64 | }; 65 | unlock_it[0].sem_num = num; /* We just unlock (lower) semaphore */ 66 | if(semop(semid,&unlock_it[0],1) < 0) 67 | return 1; 68 | else 69 | return 0; 70 | } 71 | 72 | main() 73 | { 74 | semid=semget(SEMKEY,1,IPC_CREAT|0660); 75 | if (locker(0) != 0) 76 | err(1, "Problems locking semaphore"); 77 | else 78 | printf("Locked semaphore and pid is %d\n", getpid()); 79 | sleep(10); 80 | if (unlocker(0) !=0) 81 | err(1, "Problems unlocking semaphore"); 82 | else 83 | printf("Unlocked semaphore and pid is %d\n", getpid()); 84 | /* this is a gross hack - we sleep for 30 seconds and then remove the 85 | * semid */ 86 | /* note this will make any other programs acessing it fail. */ 87 | sleep(30); 88 | semctl(semid,0,IPC_RMID,NULL); /* remove shmid - fail silently */ 89 | /* 90 | * The problem with system V semaphores is that if we don't remove 91 | * them, they stay around in the system "forever" or until 92 | * the system administrator decides to find them and remove 93 | * them with the command "ipcrm". - that's gross and it's why 94 | * you should avoid using these things... 95 | */ 96 | } 97 | -------------------------------------------------------------------------------- /C/dumbshell.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2008 Bob Beck 3 | * 4 | * Permission to use, copy, modify, and distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | 17 | /* 18 | * A very dumb unix shell - does nothing like command history or tty 19 | * management. all it does it run commands in a child. - this demonstrates 20 | * how a shell accepts commands on the command line, and runs them 21 | * using the execution path, doing a fork() and then an exec() to 22 | * run the command. 23 | */ 24 | 25 | /* 26 | * compile with cc -o dumbshell dumbshell.c, run with "./dumbshell" 27 | * you get out of it by typing "exit". 28 | * 29 | */ 30 | #include 31 | 32 | #include 33 | #include 34 | #include 35 | #include 36 | #include 37 | #include 38 | #include 39 | 40 | 41 | char * getaline(char *buf, size_t size) 42 | { 43 | printf("dumbshell>"); 44 | if (fgets(buf, size, stdin) != NULL) { 45 | char *p; 46 | if ((p = strchr(buf, '\n')) == NULL) { 47 | fprintf(stderr, "input line too long\n"); 48 | return(NULL); 49 | } 50 | *p = '\0'; 51 | return(buf); 52 | } else 53 | return(NULL); 54 | } 55 | 56 | int runcmd(char *argv[]) { 57 | pid_t p; 58 | int status; 59 | 60 | if ((p = fork()) == 0) { 61 | /* 62 | * I am the child process. 63 | * we execvp the command from the command line 64 | */ 65 | if (execvp(argv[0], argv) == -1) { 66 | warn("command exec failed:"); 67 | status = -1; 68 | } 69 | } else 70 | waitpid(p, &status, 0); 71 | return(status); 72 | } 73 | 74 | 75 | #define MAX 80 76 | 77 | int main() 78 | { 79 | char *cp = NULL; 80 | char buf[MAX]; 81 | char *tokens[MAX], *p, *last; 82 | 83 | /* 84 | * A real shell is not quite as simple as this, 85 | * it needs to handle signals, and other things. 86 | * In particular, it can't change directories! ("cd" is 87 | * a builtin command to the usual unix shells). 88 | */ 89 | while(1) { 90 | int i = 0; 91 | cp = getaline(buf, sizeof(buf)); 92 | if (cp == NULL || (strcmp(cp, "exit") == 0)) 93 | err(0, "dumbshell exiting now\n"); 94 | /* 95 | * split the command given up into individual strings 96 | * so instead of buf containg one string of words 97 | * separated by spaces, we have tokens, an array 98 | * of strings where each string is one token (word) 99 | */ 100 | for ((p = strtok_r(cp, " ", &last)); p; 101 | (p = strtok_r(NULL, " ", &last))) { 102 | if (i < MAX - 1) 103 | tokens[i++] = p; 104 | } 105 | runcmd(tokens); 106 | } 107 | return(0); 108 | } 109 | -------------------------------------------------------------------------------- /C/syscalls.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2008 Bob Beck 3 | * 4 | * Permission to use, copy, modify, and distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | 17 | /* 18 | * System Calls are not without overhead - an example. 19 | */ 20 | 21 | /* 22 | * compile with "cc -o syscalls syscalls.c". 23 | * 24 | * this program writes a whole bunch of 'a's into a file. 25 | * 26 | * how efficiently it does it depends on how many you let it write 27 | * with each system call - it's one parameter should be the write 28 | * size which can be between 1 and 8192 characters to write each time. 29 | * 30 | * in order to see the overhead try the following, and use the 31 | * /usr/bin/time command to measure how much time the program takes 32 | * during it's execution. 33 | * 34 | * /usr/bin/time ./syscalls 4000 35 | * /usr/bin/time ./syscalls 1 36 | * 37 | * Notice the difference in "sys" time taken - that's system 38 | * call processing time. We still wrote the same amount of data 39 | * we just did it with fewer system calls. 40 | * 41 | * play around with a few different values of the write size 42 | * to see what a difference it makes. 43 | */ 44 | 45 | #include 46 | 47 | #include 48 | #include 49 | #include 50 | #include 51 | #include 52 | #include 53 | #include 54 | 55 | #define MAX_WRITE 8192 56 | 57 | void usage() 58 | { 59 | extern char * __progname; 60 | fprintf(stderr, "usage: %s size\n", __progname); 61 | exit(1); 62 | } 63 | 64 | int main(int argc, char *argv[]) 65 | { 66 | char filename[] = "/tmp/syscall.XXXXXXXXXX"; 67 | int count = 5000000; /* approximate bytes we'll write */ 68 | u_long wsize; 69 | char *buf, *ep; 70 | ssize_t w; 71 | int i, j, fd; 72 | 73 | /* 74 | * grab a parameter from the command line 75 | * so we can specify how big a write to do. 76 | */ 77 | if (argc != 2) 78 | usage(); 79 | errno = 0; 80 | wsize = strtoul(argv[1], &ep, 10); 81 | if (*argv[1] == '\0' || *ep != '\0') { 82 | /* parameter wasn't a number, or was empty */ 83 | fprintf(stderr, "%s - not a number\n", argv[1]); 84 | usage(); 85 | } 86 | if ((errno == ERANGE && wsize == ULONG_MAX) || (wsize > MAX_WRITE)) { 87 | /* It's a number, but can't fit in an unsigned long 88 | * or it's just bigger than we want to allow 89 | */ 90 | fprintf(stderr, "%s - value out of range\n", argv[1]); 91 | usage(); 92 | } 93 | 94 | /* allocate a buffer, and fill it with the letter 'a' */ 95 | buf = malloc(wsize * sizeof(char)); 96 | if (buf == NULL) 97 | err(1, "malloc failed"); 98 | memset(buf, 'a', wsize); 99 | 100 | /* open up a temporary file to write into */ 101 | if ((fd = mkstemp(filename)) == -1) 102 | err(1, "can't open a temporary file"); 103 | 104 | fprintf(stderr, "Writing %d 'a' to my output\n", count); 105 | 106 | w = 0; 107 | j = 0; 108 | for (i=0; i < count; i+=w) { 109 | if ((w = write(fd, buf, wsize)) == -1) { 110 | if (errno != EINTR) 111 | err(1, "write failed"); 112 | else 113 | w = 0; 114 | } 115 | j++; 116 | } 117 | printf("I did %d system calls\n", j); 118 | unlink(filename); /* remove file when we're done */ 119 | return(0); 120 | } 121 | -------------------------------------------------------------------------------- /C/sig1.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2008 Bob Beck 3 | * 4 | * Permission to use, copy, modify, and distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | 17 | /* 18 | * Signals example number 1 19 | */ 20 | 21 | /* 22 | * compile with cc -o sig1 sig1.c, run with "./sig1 3" 23 | * 24 | */ 25 | 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | 35 | static sig_atomic_t do_reread; 36 | static sig_atomic_t reset_count; 37 | 38 | static struct sigaction sa, oldsa; 39 | 40 | void usage() 41 | { 42 | extern char * __progname; 43 | fprintf(stderr, "usage: %s resets\n", __progname); 44 | exit(1); 45 | } 46 | 47 | 48 | static void handler(int signum) { 49 | reset_count++; 50 | do_reread = 1; 51 | } 52 | 53 | char * getaline(char *buf, size_t size) 54 | { 55 | printf("\nEnter a new string: "); 56 | if (fgets(buf, size, stdin) != NULL) { 57 | char *p; 58 | if ((p = strchr(buf, '\n')) == NULL) { 59 | fprintf(stderr, "input line too long\n"); 60 | return(NULL); 61 | } 62 | *p = '\0'; 63 | return(buf); 64 | } else 65 | return(NULL); 66 | } 67 | 68 | 69 | int main(int argc, char * argv[]) 70 | { 71 | char *ep, *buffer = NULL; 72 | char buf[80]; 73 | unsigned long resets; 74 | 75 | /* 76 | * grab a parameter from the command line 77 | * so we can specify how many times we can be reset. 78 | */ 79 | if (argc != 2) 80 | usage(); 81 | errno = 0; 82 | resets = strtoul(argv[1], &ep, 10); 83 | if (*argv[1] == '\0' || *ep != '\0') { 84 | /* parameter wasn't a number, or was empty */ 85 | fprintf(stderr, "%s - not a number\n", argv[1]); 86 | usage(); 87 | } 88 | if (errno == ERANGE && resets == ULONG_MAX) { 89 | /* It's a number, but can't fit in an unsigned long */ 90 | fprintf(stderr, "%s - value out of range\n", argv[1]); 91 | usage(); 92 | } 93 | 94 | /* set up a signal handler to catch SIGINT - which is by default 95 | * generated from Control-C on the keyboard. - we save whatever 96 | * the old action was for SIGINT - and set up a new action to 97 | * call "handler" when we get a SIGINT. 98 | */ 99 | sa.sa_handler = handler; 100 | sigemptyset(&sa.sa_mask); 101 | sa.sa_flags = 0; 102 | if (sigaction(SIGINT, NULL, &oldsa) == -1) 103 | err(1, "can't save old sigaction"); 104 | if (sigaction(SIGINT, &sa, NULL) == -1) 105 | err(1, "can't do new sigaction"); 106 | 107 | printf ("Hi there - I keep printing out a buffer...\n"); 108 | printf ("You can change what the buffer is by pressing Ctrl-C.\n"); 109 | printf ("You may change the buffer %ld times, after that, Ctrl-C\n", 110 | resets); 111 | printf ("will make me exit.\n"); 112 | while(1) { 113 | do_reread = 0; 114 | sleep(1); 115 | if (reset_count == resets) { 116 | /* restore old SIGINT signal handler */ 117 | if (sigaction(SIGINT, &oldsa, NULL) == -1) 118 | err(1, "can't restore old signal handler"); 119 | /* so now, Control-C will do the thing it used to do */ 120 | } 121 | if (do_reread) { 122 | buffer = getaline(buf, sizeof(buf)); 123 | do_reread = 0; 124 | } 125 | if (buffer == NULL) 126 | printf("my buffer is empty\n"); 127 | else 128 | printf("my buffer contains: %s\n", buffer); 129 | 130 | } 131 | } 132 | -------------------------------------------------------------------------------- /C/client.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2008 Bob Beck 3 | * 4 | * Permission to use, copy, modify, and distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | 17 | /* client.c - the "classic" example of a socket client */ 18 | #include 19 | 20 | #include 21 | 22 | #include 23 | #include 24 | 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | 34 | 35 | 36 | static void usage() 37 | { 38 | extern char * __progname; 39 | fprintf(stderr, "usage: %s ipaddress portnumber\n", __progname); 40 | exit(1); 41 | } 42 | 43 | int main(int argc, char *argv[]) 44 | { 45 | struct sockaddr_in server_sa; 46 | char buffer[80], *ep; 47 | size_t maxread; 48 | ssize_t r, rc; 49 | u_short port; 50 | u_long p; 51 | int sd; 52 | 53 | if (argc != 3) 54 | usage(); 55 | 56 | p = strtoul(argv[2], &ep, 10); 57 | if (*argv[1] == '\0' || *ep != '\0') { 58 | /* parameter wasn't a number, or was empty */ 59 | fprintf(stderr, "%s - not a number\n", argv[2]); 60 | usage(); 61 | } 62 | if ((errno == ERANGE && p == ULONG_MAX) || (p > USHRT_MAX)) { 63 | /* It's a number, but it either can't fit in an unsigned 64 | * long, or is too big for an unsigned short 65 | */ 66 | fprintf(stderr, "%s - value out of range\n", argv[2]); 67 | usage(); 68 | } 69 | /* now safe to do this */ 70 | port = p; 71 | 72 | /* 73 | * first set up "server_sa" to be the location of the server 74 | */ 75 | memset(&server_sa, 0, sizeof(server_sa)); 76 | server_sa.sin_family = AF_INET; 77 | server_sa.sin_port = htons(port); 78 | server_sa.sin_addr.s_addr = inet_addr(argv[1]); 79 | if (server_sa.sin_addr.s_addr == INADDR_NONE) { 80 | fprintf(stderr, "Invalid IP address %s\n", argv[1]); 81 | usage(); 82 | } 83 | 84 | /* ok now get a socket. we don't care where... */ 85 | if ((sd=socket(AF_INET,SOCK_STREAM,0)) == -1) 86 | err(1, "socket failed"); 87 | 88 | /* connect the socket to the server described in "server_sa" */ 89 | if (connect(sd, (struct sockaddr *)&server_sa, sizeof(server_sa)) 90 | == -1) 91 | err(1, "connect failed"); 92 | 93 | /* 94 | * finally, we are connected. find out what magnificent wisdom 95 | * our server is going to send to us - since we really don't know 96 | * how much data the server could send to us, we have decided 97 | * we'll stop reading when either our buffer is full, or when 98 | * we get an end of file condition from the read when we read 99 | * 0 bytes - which means that we pretty much assume the server 100 | * is going to send us an entire message, then close the connection 101 | * to us, so that we see an end-of-file condition on the read. 102 | * 103 | * we also make sure we handle EINTR in case we got interrupted 104 | * by a signal. 105 | */ 106 | r = -1; 107 | rc = 0; 108 | maxread = sizeof(buffer) - 1; /* leave room for a 0 byte */ 109 | while ((r != 0) && rc < maxread) { 110 | r = read(sd, buffer + rc, maxread - rc); 111 | if (r == -1) { 112 | if (errno != EINTR) 113 | err(1, "read failed"); 114 | } else 115 | rc += r; 116 | } 117 | /* 118 | * we must make absolutely sure buffer has a terminating 0 byte 119 | * if we are to use it as a C string 120 | */ 121 | buffer[rc] = '\0'; 122 | 123 | printf("Server sent: %s",buffer); 124 | close(sd); 125 | return(0); 126 | } 127 | -------------------------------------------------------------------------------- /C/fork2.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2008 Bob Beck 3 | * 4 | * Permission to use, copy, modify, and distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | 17 | /* 18 | * Let's make a new process with fork() - and demonstrate that processes 19 | * inherit file descriptors. This will have a race to see what ends up 20 | * getting written into the file 21 | */ 22 | 23 | /* 24 | * compile with cc -o fork2 fork2.c, run with "./fork2" 25 | * you will need to make sure "forktest" exists in the directory you 26 | * run it in, you can create the file with "touch forktest" 27 | * 28 | */ 29 | #include 30 | 31 | #include 32 | #include 33 | #include 34 | #include 35 | #include 36 | #include 37 | 38 | int main() 39 | { 40 | pid_t p; 41 | int seconds; 42 | int fd, s; 43 | char *msg; 44 | 45 | fd = open("./forktest", O_WRONLY|O_TRUNC, 0); 46 | if (fd == -1) 47 | err(-1, "I can't open ./forktest"); 48 | 49 | printf("Process %d, starting up\n", getpid()); 50 | 51 | p = fork(); 52 | if (p == 0) { 53 | /* I am the child process */ 54 | msg = "Blah Blah\n"; 55 | printf("Process %d (child), fork returned %d\n", getpid(), p); 56 | /* Use the process id to seed the random number generator 57 | * I do this because it is convenient - and I do *NOT* care 58 | * about this random number being unpredictable for use in 59 | * any kind of security portion of this software. Please 60 | * remember that if I know or could predict the PID the random 61 | * number is as predictable as 62 | * http://dilbert.com/strips/comic/2001-10-25/ 63 | */ 64 | srandom(getpid()); 65 | seconds = random() % 5; 66 | printf("Process %d (child) will be sleeping for %d seconds\n", 67 | getpid(), seconds); 68 | sleep(seconds); 69 | 70 | /* position at start of file */ 71 | if (lseek(fd, 0, SEEK_SET) == -1) 72 | err(1, "lseek failed"); 73 | 74 | /* let's write the message into the file */ 75 | s = write(fd, msg, strlen(msg)); 76 | if (s == -1) 77 | err(1, "write failed"); 78 | if (s != strlen(msg)) 79 | errx(1, "short write"); /* we could retry... */ 80 | close(fd); 81 | 82 | printf("Process %d (child) now exiting\n", getpid()); 83 | exit(0); 84 | } 85 | /* otherwise, I am in the parent */ 86 | /* 87 | * the fork could have failed (system resource limits, etc. so we 88 | * need to check for that.. 89 | */ 90 | if (p == -1) 91 | err(1, "Fork failed! Can't create child!"); 92 | /* 93 | * otherwise - p will have the pid of the child. 94 | */ 95 | msg = "Woof Woof\n"; 96 | printf("Process %d (parent), fork returned %d\n", getpid(), p); 97 | srandom(getpid()); 98 | seconds = random() % 5; 99 | printf("Process %d (parent) will be sleeping for %d seconds\n", 100 | getpid(), seconds); 101 | sleep(seconds); 102 | 103 | /* position at start of file */ 104 | if (lseek(fd, 0, SEEK_SET) == -1) 105 | err(1, "lseek failed"); 106 | 107 | /* let's write the message into the file */ 108 | s = write(fd, msg, strlen(msg)); 109 | if (s == -1) 110 | err(1, "write failed"); 111 | if (s != strlen(msg)) 112 | errx(1, "short write"); /* we could retry... */ 113 | close(fd); 114 | 115 | printf("Process %d (parent) now exiting\n", getpid()); 116 | /* 117 | * for this example, we won't yet worry about what happens when 118 | * the child exits before the parent. - since eventually everyone 119 | * exits, all works out in the end. 120 | */ 121 | exit(0); 122 | } 123 | -------------------------------------------------------------------------------- /python/merkle-example.py: -------------------------------------------------------------------------------- 1 | from typing import List 2 | import hashlib 3 | 4 | # We've been talking about a Merkle Tree. Here's a very very basic example 5 | # constructed with the inspiration of several internet sources. 6 | # This example uses sha256 for the hashes in the tree. 7 | 8 | class Node: 9 | def __init__(self, left, right, value: str, cert:str)-> None: 10 | self.left: Node = left 11 | self.right: Node = right 12 | self.value = value # The hash value of this node of the tree. 13 | self.cert = cert # If this node is a leaf, this is the 'certificate' data that was hashed. 14 | 15 | @staticmethod 16 | def sha256(val: str)-> str: 17 | return hashlib.sha256(val.encode('utf-8')).hexdigest() 18 | 19 | class MerkleTree: 20 | def __init__(self, values: List[str])-> None: 21 | self.__buildTreeFromValues(values) 22 | 23 | def __buildTreeFromValues(self, values: List[str])-> None: 24 | leaves: List[Node] = [Node(None, None, Node.sha256(e), e) for e in values] 25 | # Add a special element "PADDING" if we have an odd number of leaves. 26 | if len(leaves) % 2 == 1: 27 | leaves.append(Node(None, None, Node.sha256("PADDING"), "PADDING")) 28 | self.root: Node = self.__buildTree(leaves) 29 | 30 | def __buildTree(self, nodes: List[Node])-> Node: 31 | if len(nodes) % 2 == 1: 32 | nodes.append(Node(None, None, Node.sha256("PADDING"), "PADDING")) 33 | split: int = len(nodes) // 2 34 | if len(nodes) == 2: 35 | return Node(nodes[0], nodes[1], Node.sha256(nodes[0].value + nodes[1].value), "") 36 | left: Node = self.__buildTree(nodes[:split]) 37 | right: Node = self.__buildTree(nodes[split:]) 38 | value: str = Node.sha256(left.value + right.value) 39 | return Node(left, right, value, "") 40 | 41 | def printTree(self)-> None: 42 | self.__printTreePreorder(self.root) 43 | 44 | def __printTreePreorder(self, node)-> None: 45 | if node != None: 46 | print("Node Value: "+str(node.value)) 47 | if node.left != None: 48 | print(" Left: "+str(node.left.value)) 49 | print(" Right: "+str(node.right.value)) 50 | else: 51 | print (" Cert: "+str(node.cert)) 52 | self.__printTreePreorder(node.left) 53 | self.__printTreePreorder(node.right) 54 | 55 | def getRootHash(self)-> str: 56 | return self.root.value 57 | 58 | class MerkleTreeProof: 59 | def __init__(self, root: str) -> None: 60 | self.root = root 61 | 62 | def isValueInTree(self, cert: str, intermediateHashes: List[str]) -> bool: 63 | # This is unimplemented and always returns false. You should try to 64 | # implement this method. Don't forget to hash "cert" to get the 65 | # starting hash value. 66 | return False; 67 | 68 | def getRootHash(self)-> str: 69 | return self.root 70 | 71 | elems = [ "Bob signed cert for google.com", "Alice signed cert for microsoft.com", "Paul signed cert for ualberta.ca", "Mallory signed cert for google.com" ] 72 | mtree = MerkleTree(elems) 73 | print("Root of tree : " +str(mtree.getRootHash())) 74 | print("------") 75 | mtree.printTree() 76 | 77 | print("If we change anything in the tree, the root changes") 78 | elems = [ "Bob signed cert for gmail.com", "Alice signed cert for microsoft.com", "Paul signed cert for ualberta.ca", "Mallory signed cert for google.com" ] 79 | mtree2 = MerkleTree(elems) 80 | print("New Root of tree : " +str(mtree2.getRootHash())) 81 | print("------") 82 | mtree2.printTree() 83 | 84 | print("------") 85 | intermediates = [ "16bffac11115e3bd11a9ae95832edcabfa9d967ddf9524243b388ae87574c09b", "05a80af53889c59121a94054804df1320606b1c48baac7cce69473cda448b192", "9d2ef4878fa1e4d60b52a1a1bac7ae4bdfd9ef44dc931ddde7a09a7ff256764f" ] 86 | proof1 = MerkleTreeProof(str(mtree.getRootHash())) 87 | cert = "Bob signed cert for google.com" 88 | # The result below will be wrong until you fix isValueInTree above. 89 | if proof1.isValueInTree(cert, intermediates): 90 | print("\"" + cert + "\"" + " is in the tree with root " + str(proof1.getRootHash())) 91 | else: 92 | print("\"" + cert + "\"" + " is not in the tree with root " + str(proof1.getRootHash())) 93 | -------------------------------------------------------------------------------- /C/sig2.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2008 Bob Beck 3 | * 4 | * Permission to use, copy, modify, and distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | 17 | /* Signals example number 2 this differs from example number 1 in 18 | * that is uses a sigsetjmp() and siglongjmp() to control where we return 19 | * to from the signal handler. Note how it is different from number 1 20 | * in behaviour. 21 | */ 22 | 23 | /* 24 | * compile with cc -o sig2 sig2.c, run with "./sig2 3" 25 | * 26 | */ 27 | 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include 35 | #include 36 | #include 37 | 38 | static sig_atomic_t do_reread; 39 | static sig_atomic_t reset_count; 40 | static sigjmp_buf jumpbuf; 41 | 42 | static struct sigaction sa, oldsa; 43 | 44 | void usage() 45 | { 46 | extern char * __progname; 47 | fprintf(stderr, "usage: %s resets\n", __progname); 48 | exit(1); 49 | } 50 | 51 | static void handler(int signum) { 52 | reset_count++; 53 | do_reread = 1; 54 | siglongjmp(jumpbuf, 1); 55 | } 56 | 57 | char * getaline(char *buf, size_t size) 58 | { 59 | printf("\nEnter a new string: "); 60 | if (fgets(buf, size, stdin) != NULL) { 61 | char *p; 62 | if ((p = strchr(buf, '\n')) == NULL) { 63 | fprintf(stderr, "input line too long\n"); 64 | return(NULL); 65 | } 66 | *p = '\0'; 67 | return(buf); 68 | } else 69 | return(NULL); 70 | } 71 | 72 | 73 | int main(int argc, char * argv[]) 74 | { 75 | char *ep, *buffer = NULL; 76 | char buf[80]; 77 | unsigned long resets; 78 | 79 | /* 80 | * grab a parameter from the command line 81 | * so we can specify how many times we can be reset. 82 | */ 83 | if (argc != 2) 84 | usage(); 85 | errno = 0; 86 | resets = strtoul(argv[1], &ep, 10); 87 | if (*argv[1] == '\0' || *ep != '\0') { 88 | /* parameter wasn't a number, or was empty */ 89 | fprintf(stderr, "%s - not a number\n", argv[1]); 90 | usage(); 91 | } 92 | if (errno == ERANGE && resets == ULONG_MAX) { 93 | /* It's a number, but can't fit in an unsigned long */ 94 | fprintf(stderr, "%s - value out of range\n", argv[1]); 95 | usage(); 96 | } 97 | 98 | /* set up a signal handler to catch SIGINT - which is by default 99 | * generated from Control-C on the keyboard. - we save whatever 100 | * the old action was for SIGINT - and set up a new action to 101 | * call "handler" when we get a SIGINT. 102 | */ 103 | sa.sa_handler = handler; 104 | sigemptyset(&sa.sa_mask); 105 | sa.sa_flags = 0; 106 | if (sigaction(SIGINT, NULL, &oldsa) == -1) 107 | err(1, "can't save old sigaction"); 108 | if (sigaction(SIGINT, &sa, NULL) == -1) 109 | err(1, "can't do new sigaction"); 110 | 111 | printf ("Hi there - I keep printing out a buffer...\n"); 112 | printf ("You can change what the buffer is by pressing Ctrl-C.\n"); 113 | printf ("You may change the buffer %ld times, after that, Ctrl-C\n", 114 | resets); 115 | printf ("will make me exit.\n"); 116 | while(1) { 117 | do_reread = 0; 118 | if (sigsetjmp(jumpbuf, 1) == 0) 119 | sleep(1); 120 | if (reset_count == resets) { 121 | /* restore old SIGINT signal handler */ 122 | if (sigaction(SIGINT, &oldsa, NULL) == -1) 123 | err(1, "can't restore old signal handler"); 124 | /* so now, Control-C will do the thing it used to do */ 125 | } 126 | if (do_reread) { 127 | buffer = getaline(buf, sizeof(buf)); 128 | do_reread = 0; 129 | } 130 | if (buffer == NULL) 131 | printf("my buffer is empty\n"); 132 | else 133 | printf("my buffer contains: %s\n", buffer); 134 | 135 | } 136 | } 137 | -------------------------------------------------------------------------------- /C/server.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2008 Bob Beck 3 | * 4 | * Permission to use, copy, modify, and distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | 17 | /* server.c - the "classic" example of a socket server */ 18 | 19 | /* 20 | * compile with gcc -o server server.c 21 | * or if you are on a crappy version of linux without strlcpy 22 | * thanks to the bozos who do glibc, do 23 | * gcc -c strlcpy.c 24 | * gcc -o server server.c strlcpy.o 25 | * 26 | */ 27 | 28 | #include 29 | #include 30 | #include 31 | #include 32 | 33 | #include 34 | #include 35 | #include 36 | #include 37 | #include 38 | #include 39 | #include 40 | #include 41 | 42 | static void usage() 43 | { 44 | extern char * __progname; 45 | fprintf(stderr, "usage: %s portnumber\n", __progname); 46 | exit(1); 47 | } 48 | 49 | static void kidhandler(int signum) { 50 | /* signal handler for SIGCHLD */ 51 | waitpid(WAIT_ANY, NULL, WNOHANG); 52 | } 53 | 54 | 55 | int main(int argc, char *argv[]) 56 | { 57 | struct sockaddr_in sockname, client; 58 | char buffer[80], *ep; 59 | struct sigaction sa; 60 | int clientlen, sd; 61 | u_short port; 62 | pid_t pid; 63 | u_long p; 64 | 65 | /* 66 | * first, figure out what port we will listen on - it should 67 | * be our first parameter. 68 | */ 69 | 70 | if (argc != 2) 71 | usage(); 72 | errno = 0; 73 | p = strtoul(argv[1], &ep, 10); 74 | if (*argv[1] == '\0' || *ep != '\0') { 75 | /* parameter wasn't a number, or was empty */ 76 | fprintf(stderr, "%s - not a number\n", argv[1]); 77 | usage(); 78 | } 79 | if ((errno == ERANGE && p == ULONG_MAX) || (p > USHRT_MAX)) { 80 | /* It's a number, but it either can't fit in an unsigned 81 | * long, or is too big for an unsigned short 82 | */ 83 | fprintf(stderr, "%s - value out of range\n", argv[1]); 84 | usage(); 85 | } 86 | /* now safe to do this */ 87 | port = p; 88 | 89 | /* the message we send the client */ 90 | strlcpy(buffer, 91 | "What is the air speed velocity of a coconut laden swallow?\n", 92 | sizeof(buffer)); 93 | 94 | memset(&sockname, 0, sizeof(sockname)); 95 | sockname.sin_family = AF_INET; 96 | sockname.sin_port = htons(port); 97 | sockname.sin_addr.s_addr = htonl(INADDR_ANY); 98 | sd=socket(AF_INET,SOCK_STREAM,0); 99 | if ( sd == -1) 100 | err(1, "socket failed"); 101 | 102 | if (bind(sd, (struct sockaddr *) &sockname, sizeof(sockname)) == -1) 103 | err(1, "bind failed"); 104 | 105 | if (listen(sd,3) == -1) 106 | err(1, "listen failed"); 107 | 108 | /* 109 | * we're now bound, and listening for connections on "sd" - 110 | * each call to "accept" will return us a descriptor talking to 111 | * a connected client 112 | */ 113 | 114 | 115 | /* 116 | * first, let's make sure we can have children without leaving 117 | * zombies around when they die - we can do this by catching 118 | * SIGCHLD. 119 | */ 120 | sa.sa_handler = kidhandler; 121 | sigemptyset(&sa.sa_mask); 122 | /* 123 | * we want to allow system calls like accept to be restarted if they 124 | * get interrupted by a SIGCHLD 125 | */ 126 | sa.sa_flags = SA_RESTART; 127 | if (sigaction(SIGCHLD, &sa, NULL) == -1) 128 | err(1, "sigaction failed"); 129 | 130 | /* 131 | * finally - the main loop. accept connections and deal with 'em 132 | */ 133 | printf("Server up and listening for connections on port %u\n", port); 134 | for(;;) { 135 | int clientsd; 136 | clientlen = sizeof(&client); 137 | clientsd = accept(sd, (struct sockaddr *)&client, &clientlen); 138 | if (clientsd == -1) 139 | err(1, "accept failed"); 140 | /* 141 | * We fork child to deal with each connection, this way more 142 | * than one client can connect to us and get served at any one 143 | * time. 144 | */ 145 | 146 | pid = fork(); 147 | if (pid == -1) 148 | err(1, "fork failed"); 149 | 150 | if(pid == 0) { 151 | ssize_t written, w; 152 | /* 153 | * write the message to the client, being sure to 154 | * handle a short write, or being interrupted by 155 | * a signal before we could write anything. 156 | */ 157 | w = 0; 158 | written = 0; 159 | while (written < strlen(buffer)) { 160 | w = write(clientsd, buffer + written, 161 | strlen(buffer) - written); 162 | if (w == -1) { 163 | if (errno != EINTR) 164 | err(1, "write failed"); 165 | } 166 | else 167 | written += w; 168 | } 169 | close(clientsd); 170 | exit(0); 171 | } 172 | close(clientsd); 173 | } 174 | } 175 | -------------------------------------------------------------------------------- /C/tlsclient.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2015 Bob Beck 3 | * 4 | * Permission to use, copy, modify, and distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | 17 | /* client.c - the "classic" example of a socket client */ 18 | #include 19 | 20 | #include 21 | 22 | #include 23 | #include 24 | 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | 35 | 36 | 37 | static void usage() 38 | { 39 | extern char * __progname; 40 | fprintf(stderr, "usage: %s ipaddress portnumber certhash\n", __progname); 41 | exit(1); 42 | } 43 | 44 | int main(int argc, char *argv[]) 45 | { 46 | struct sockaddr_in server_sa; 47 | char buffer[80], *ep; 48 | size_t maxread; 49 | ssize_t r, rc; 50 | u_short port; 51 | u_long p; 52 | int sd, i; 53 | struct tls_config *tls_cfg = NULL; 54 | struct tls *tls_ctx = NULL; 55 | 56 | if (argc != 4) 57 | usage(); 58 | 59 | p = strtoul(argv[2], &ep, 10); 60 | if (*argv[1] == '\0' || *ep != '\0') { 61 | /* parameter wasn't a number, or was empty */ 62 | fprintf(stderr, "%s - not a number\n", argv[2]); 63 | usage(); 64 | } 65 | if ((errno == ERANGE && p == ULONG_MAX) || (p > USHRT_MAX)) { 66 | /* It's a number, but it either can't fit in an unsigned 67 | * long, or is too big for an unsigned short 68 | */ 69 | fprintf(stderr, "%s - value out of range\n", argv[2]); 70 | usage(); 71 | } 72 | /* now safe to do this */ 73 | port = p; 74 | 75 | /* 76 | * first set up "server_sa" to be the location of the server 77 | */ 78 | memset(&server_sa, 0, sizeof(server_sa)); 79 | server_sa.sin_family = AF_INET; 80 | server_sa.sin_port = htons(port); 81 | server_sa.sin_addr.s_addr = inet_addr(argv[1]); 82 | if (server_sa.sin_addr.s_addr == INADDR_NONE) { 83 | fprintf(stderr, "Invalid IP address %s\n", argv[1]); 84 | usage(); 85 | } 86 | 87 | /* now set up TLS */ 88 | if (tls_init() == -1) 89 | errx(1, "unable to initialize TLS"); 90 | if ((tls_cfg = tls_config_new()) == NULL) 91 | errx(1, "unable to allocate TLS config"); 92 | if (tls_config_set_ca_file(tls_cfg, "server.crt") == -1) 93 | errx(1, "unable to set root CA file server.crt"); 94 | 95 | /* ok now get a socket. we don't care where... */ 96 | if ((sd=socket(AF_INET,SOCK_STREAM,0)) == -1) 97 | err(1, "socket failed"); 98 | 99 | /* connect the socket to the server described in "server_sa" */ 100 | if (connect(sd, (struct sockaddr *)&server_sa, sizeof(server_sa)) == -1) 101 | err(1, "connect failed"); 102 | 103 | if ((tls_ctx = tls_client()) == NULL) 104 | errx(1, "tls client creation failed"); 105 | tls_config_insecure_noverifyname(tls_cfg); 106 | if (tls_configure(tls_ctx, tls_cfg) == -1) 107 | errx(1, "tls configuration failed (%s)", 108 | tls_error(tls_ctx)); 109 | if (tls_connect_socket(tls_ctx, sd, "name") == -1) { 110 | errx(1, "tls connection failed (%s)", 111 | tls_error(tls_ctx)); 112 | } 113 | do { 114 | if ((i = tls_handshake(tls_ctx)) == -1) 115 | errx(1, "tls handshake failed (%s)", 116 | tls_error(tls_ctx)); 117 | } while (i == TLS_WANT_POLLIN || i == TLS_WANT_POLLOUT); 118 | if (strcmp(argv[3], tls_peer_cert_hash(tls_ctx)) != 0) 119 | errx(1, "Peer certificate is not %s", argv[3]); 120 | 121 | /* 122 | * finally, we are connected. find out what magnificent wisdom 123 | * our server is going to send to us - since we really don't know 124 | * how much data the server could send to us, we have decided 125 | * we'll stop reading when either our buffer is full, or when 126 | * we get an end of file condition from the read when we read 127 | * 0 bytes - which means that we pretty much assume the server 128 | * is going to send us an entire message, then close the connection 129 | * to us, so that we see an end-of-file condition on the read. 130 | * 131 | * we also make sure we handle EINTR in case we got interrupted 132 | * by a signal. 133 | */ 134 | r = -1; 135 | rc = 0; 136 | maxread = sizeof(buffer) - 1; /* leave room for a 0 byte */ 137 | while ((r != 0) && rc < maxread) { 138 | r = tls_read(tls_ctx, buffer + rc, maxread - rc); 139 | if (r == TLS_WANT_POLLIN || r == TLS_WANT_POLLOUT) 140 | continue; 141 | if (r < 0) { 142 | errx(1, "tls_read failed (%s)", tls_error(tls_ctx)); 143 | } else 144 | rc += r; 145 | } 146 | /* 147 | * we must make absolutely sure buffer has a terminating 0 byte 148 | * if we are to use it as a C string 149 | */ 150 | buffer[rc] = '\0'; 151 | printf("Server sent: %s",buffer); 152 | close(sd); 153 | return(0); 154 | } 155 | -------------------------------------------------------------------------------- /C/coredumper.c: -------------------------------------------------------------------------------- 1 | /* Originally written by Theo de Raadt 2 | * Modified by Bob Beck for instructional use. 3 | * Copyright (c) 2013 Bob Beck 4 | * 5 | * Permission to use, copy, modify, and distribute this software for any 6 | * purpose with or without fee is hereby granted, provided that the above 7 | * copyright notice and this permission notice appear in all copies. 8 | * 9 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 | */ 17 | 18 | 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | 29 | #define CHUNKS 1000 30 | 31 | char *dir; 32 | int nproc; 33 | 34 | /* 35 | * coredumper - dump nproc huge core files in parallel 36 | * 37 | * compile with 38 | * cc -o coredumper coredumper.c 39 | * 40 | * run with 41 | * 42 | * ./coredumper size nproc directory 43 | * 44 | * where "size" is the size of each core image to dump in megabytes 45 | * "nproc" is the number of core dumps to do in parallel, and 46 | * "directory" is the name of a directory where the places to dump cores 47 | * can be created. 48 | * 49 | * This is a wonderfully evil program. The main program allocates "size" 50 | * megabytes of memory, and touches every page it allocates. 51 | * 52 | * it then forks nproc copies of itself, changes it's working directory 53 | * and calls abort in each one. 54 | * 55 | * The result is nproc processes all dumping "size" megabytes of 56 | * core images simultaneously. This program can seriously stress 57 | * a unix machine. You should not run it on a system you share with 58 | * anyone else - i.e. run it on your own machine, and don't cry if it 59 | * locks up or crashes. 60 | * 61 | * start with "coredumper 10 10 crap" 62 | * and proress to "coredumper 100 100 crap" or something like that 63 | * but beware of your memory limitations - if you start swapping these 64 | * you'll hurt a lot on many systems. 65 | * 66 | * note that some systems have issues where the will not actually write 67 | * out more than one core. technically this is a bug, but it may 68 | * prevent worse problems.... 69 | * 70 | * You should likely *NOT* run this on a machine that is owned by 71 | * by someone other than yourself. In particular the university 72 | * could frown on you running this on a lab or other university computer 73 | * so you should not do that. 74 | * 75 | */ 76 | 77 | int 78 | main(int argc, char *argv[]) 79 | { 80 | char string[200]; 81 | char *p; 82 | int i, ms, size, count, nbpg = getpagesize(); 83 | 84 | if (argc != 4) { 85 | fprintf(stderr, "usage: coredumper size nproc dir\n"); 86 | exit(1); 87 | } 88 | size = atoi(argv[1]); 89 | nproc = atoi(argv[2]); 90 | dir = argv[3]; 91 | 92 | ms = CHUNKS * nbpg; 93 | count = (size * 1048576) / ms; 94 | 95 | while (count--) { 96 | p = malloc(ms); 97 | if (p == NULL) /* if we can't allocate any more, dump anyway */ 98 | goto dump; 99 | for (i = 0; i < ms; i += nbpg) 100 | p[i] = 1; /* touch each page so it is dirty. */ 101 | } 102 | dump: 103 | /* 104 | * We do a printf this way, because we anticipate we might be 105 | * here when we are out of memory and malloc won't give us any 106 | * more. (see the loop above) so we use the pre-allocated 107 | * variable (string) on the stack to sprintf into, and then 108 | * call write to write it out, instead of directly calling printf. 109 | * This is because we know printf will itself attempt to allocate 110 | * memory with malloc and it could fail at this point. 111 | */ 112 | snprintf(string, sizeof string, "crashing...\n"); 113 | write(STDOUT_FILENO, string, strlen(string)); 114 | 115 | /* now comes the evil - we fork nproc copies of ourselves... */ 116 | for (i = 0; i < nproc; i++) { 117 | switch (fork()) { 118 | case 0: 119 | /* 120 | * In each copy of ourselves 121 | * we first make a directory... 122 | */ 123 | snprintf(string, sizeof string, 124 | "%s/crash-%d", dir, i); 125 | if (mkdir(string, 0770) != 0) 126 | err(1, "mkdir %s", string); 127 | /* 128 | * We then change into that directory that we 129 | * made... 130 | */ 131 | if (chdir(string) != 0) 132 | err(1, "chdir %s", string); 133 | /* 134 | * We write a message that we are going to 135 | * crash... 136 | */ 137 | snprintf(string, sizeof string, 138 | "%d to %s/crash-%d\n", getpid(), dir, i); 139 | write(STDOUT_FILENO, string, strlen(string)); 140 | /* 141 | * we now call abort, to make ourselves dump core. 142 | */ 143 | abort(); 144 | break; 145 | default: 146 | break; 147 | } 148 | } 149 | 150 | /* 151 | * We now wait for all of our nproc copies of ourself 152 | * to finish dumping core... 153 | */ 154 | snprintf(string, sizeof string, "waiting...\n"); 155 | write(STDOUT_FILENO, string, strlen(string)); 156 | for (i = 0; i < nproc; i++) { 157 | int j; 158 | wait(&j); 159 | if (j && WCOREDUMP(j)) 160 | snprintf(string, sizeof string, 161 | "finished %d with core dump\n", i); 162 | else 163 | snprintf(string, sizeof string, 164 | "finished %d with no core dump\n", i); 165 | write(STDOUT_FILENO, string, strlen(string)); 166 | } 167 | /* 168 | * And print out a helpful message that we have successfully 169 | * finished. 170 | */ 171 | snprintf(string, sizeof string, "done.\n"); 172 | write(STDOUT_FILENO, string, strlen(string)); 173 | return(0); 174 | } 175 | -------------------------------------------------------------------------------- /C/tlsserver.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2015 Bob Beck 3 | * 4 | * Permission to use, copy, modify, and distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | 17 | /* server.c - the "classic" example of a socket server */ 18 | 19 | /* 20 | * compile with gcc -o server server.c -ltls -lssl -lcrypto 21 | * or if you are on a crappy version of linux without strlcpy 22 | * thanks to the bozos who do glibc, do 23 | * gcc -c strlcpy.c 24 | * gcc -o server server.c strlcpy.o 25 | * 26 | */ 27 | 28 | #include 29 | #include 30 | #include 31 | #include 32 | 33 | #include 34 | #include 35 | #include 36 | #include 37 | #include 38 | #include 39 | #include 40 | #include 41 | #include 42 | 43 | static void usage() 44 | { 45 | extern char * __progname; 46 | fprintf(stderr, "usage: %s portnumber\n", __progname); 47 | exit(1); 48 | } 49 | 50 | static void kidhandler(int signum) { 51 | /* signal handler for SIGCHLD */ 52 | waitpid(WAIT_ANY, NULL, WNOHANG); 53 | } 54 | 55 | 56 | int main(int argc, char *argv[]) 57 | { 58 | struct sockaddr_in sockname, client; 59 | char buffer[80], *ep; 60 | struct sigaction sa; 61 | int clientlen, sd, i; 62 | u_short port; 63 | pid_t pid; 64 | u_long p; 65 | struct tls_config *tls_cfg = NULL; 66 | struct tls *tls_ctx = NULL; 67 | struct tls *tls_cctx = NULL; 68 | 69 | /* 70 | * first, figure out what port we will listen on - it should 71 | * be our first parameter. 72 | */ 73 | 74 | if (argc != 2) 75 | usage(); 76 | errno = 0; 77 | p = strtoul(argv[1], &ep, 10); 78 | if (*argv[1] == '\0' || *ep != '\0') { 79 | /* parameter wasn't a number, or was empty */ 80 | fprintf(stderr, "%s - not a number\n", argv[1]); 81 | usage(); 82 | } 83 | if ((errno == ERANGE && p == ULONG_MAX) || (p > USHRT_MAX)) { 84 | /* It's a number, but it either can't fit in an unsigned 85 | * long, or is too big for an unsigned short 86 | */ 87 | fprintf(stderr, "%s - value out of range\n", argv[1]); 88 | usage(); 89 | } 90 | /* now safe to do this */ 91 | port = p; 92 | 93 | /* now set up TLS */ 94 | if (tls_init() == -1) 95 | errx(1, "unable to initialize TLS"); 96 | if ((tls_cfg = tls_config_new()) == NULL) 97 | errx(1, "unable to allocate TLS config"); 98 | if (tls_config_set_ca_file(tls_cfg, "server.crt") == -1) 99 | errx(1, "unable to set root CA file server.crt"); 100 | if (tls_config_set_cert_file(tls_cfg, "server.crt") == -1) 101 | errx(1, "unable to set TLS certificate file server.crt"); 102 | if (tls_config_set_key_file(tls_cfg, "server.key") == -1) 103 | errx(1, "unable to set TLS key file server.key"); 104 | if ((tls_ctx = tls_server()) == NULL) 105 | errx(1, "tls server creation failed"); 106 | if (tls_configure(tls_ctx, tls_cfg) == -1) 107 | errx(1, "tls configuration failed (%s)", tls_error(tls_ctx)); 108 | 109 | /* the message we send the client */ 110 | strlcpy(buffer, 111 | "What is the air speed velocity of a coconut laden swallow?\n", 112 | sizeof(buffer)); 113 | 114 | memset(&sockname, 0, sizeof(sockname)); 115 | sockname.sin_family = AF_INET; 116 | sockname.sin_port = htons(port); 117 | sockname.sin_addr.s_addr = htonl(INADDR_ANY); 118 | sd=socket(AF_INET,SOCK_STREAM,0); 119 | if ( sd == -1) 120 | err(1, "socket failed"); 121 | 122 | if (bind(sd, (struct sockaddr *) &sockname, sizeof(sockname)) == -1) 123 | err(1, "bind failed"); 124 | 125 | if (listen(sd,3) == -1) 126 | err(1, "listen failed"); 127 | 128 | /* 129 | * we're now bound, and listening for connections on "sd" - 130 | * each call to "accept" will return us a descriptor talking to 131 | * a connected client 132 | */ 133 | 134 | 135 | /* 136 | * first, let's make sure we can have children without leaving 137 | * zombies around when they die - we can do this by catching 138 | * SIGCHLD. 139 | */ 140 | sa.sa_handler = kidhandler; 141 | sigemptyset(&sa.sa_mask); 142 | /* 143 | * we want to allow system calls like accept to be restarted if they 144 | * get interrupted by a SIGCHLD 145 | */ 146 | sa.sa_flags = SA_RESTART; 147 | if (sigaction(SIGCHLD, &sa, NULL) == -1) 148 | err(1, "sigaction failed"); 149 | 150 | /* 151 | * finally - the main loop. accept connections and deal with 'em 152 | */ 153 | printf("Server up and listening for connections on port %u\n", port); 154 | for(;;) { 155 | int clientsd; 156 | clientlen = sizeof(&client); 157 | clientsd = accept(sd, (struct sockaddr *)&client, &clientlen); 158 | if (clientsd == -1) 159 | err(1, "accept failed"); 160 | /* 161 | * We fork child to deal with each connection, this way more 162 | * than one client can connect to us and get served at any one 163 | * time. 164 | */ 165 | 166 | pid = fork(); 167 | if (pid == -1) 168 | err(1, "fork failed"); 169 | 170 | if(pid == 0) { 171 | i = 0; 172 | ssize_t written, w; 173 | if (tls_accept_socket(tls_ctx, &tls_cctx, clientsd) == -1) 174 | errx(1, "tls accept failed (%s)", tls_error(tls_ctx)); 175 | else { 176 | do { 177 | if ((i = tls_handshake(tls_cctx)) == -1) 178 | errx(1, "tls handshake failed (%s)", tls_error(tls_cctx)); 179 | } while(i == TLS_WANT_POLLIN || i == TLS_WANT_POLLOUT); 180 | } 181 | 182 | /* 183 | * write the message to the client, being sure to 184 | * handle a short write, or being interrupted by 185 | * a signal before we could write anything. 186 | */ 187 | w = 0; 188 | written = 0; 189 | while (written < strlen(buffer)) { 190 | w = tls_write(tls_cctx, buffer + written, 191 | strlen(buffer) - written); 192 | if (w == TLS_WANT_POLLIN || w == TLS_WANT_POLLOUT) 193 | continue; 194 | if (w < 0) 195 | errx(1, "tls_write failed (%s)", tls_error(tls_ctx)); 196 | else 197 | written += w; 198 | } 199 | i = 0; 200 | do { 201 | i = tls_close(tls_ctx); 202 | } while(i == TLS_WANT_POLLIN || i == TLS_WANT_POLLOUT); 203 | close(clientsd); 204 | exit(0); 205 | } 206 | close(clientsd); 207 | } 208 | } 209 | -------------------------------------------------------------------------------- /C/iagree.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2013 Bob Beck 3 | * 4 | * Permission to use, copy, modify, and distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | 17 | /* 18 | * iagree.c - modified in class from the c379 "client.c" to show 19 | * how we can send useful stuff to a web server with sockets. 20 | * 21 | * compile with 22 | * gcc -o iagree iagree.c 23 | * or 24 | * gcc -DDEBUG -o iagree iagree.c 25 | * 26 | * In this case what we did was capture the http POST request that 27 | * is sent to the annoying captive proxy server on the "Guest@UofA" 28 | * network - the result that we developed in class from client.c 29 | * is a C program that can be run on the command line or in a shell 30 | * script that will attempt to send the "yes I agree" request. 31 | * 32 | * You could wrap the body of the main funciton in a while loop 33 | * that repeatedly tries and sleeps, and change the SIGALRM handler 34 | * to sigsetjmp/siglongjmp to sleep and retry if anything times out. 35 | * 36 | * Alternatively, you could simply wrapper this progam in a simple 37 | * shell script on your machine: 38 | * 39 | * #!/bin/sh 40 | * 41 | * while :; do 42 | * iagree 43 | * sleep 5 44 | * done 45 | * 46 | * if you compile the program into iagree and run the above program in 47 | * a shell script you will then happily be authenticated any time you 48 | * wander onto Guest@UofA without having to click the annoying button 49 | * 50 | * Of course, since this is C code, you could always compile it into 51 | * your dhcp server, or other system program to fire when it sees 52 | * certain networks. The posisbilities are endless if you start reading 53 | * your system code... 54 | * 55 | * integrating on your own laptop, or integrating onto your own laptop 56 | * is left as an exercise to the reader. 57 | */ 58 | 59 | #include 60 | 61 | #include 62 | 63 | #include 64 | #include 65 | 66 | #include 67 | #include 68 | #include 69 | #include 70 | #include 71 | #include 72 | #include 73 | #include 74 | 75 | /* 76 | * The http 1.1 POST request we are interested in sending. in this 77 | * case we got this from a tcpdump -A watching the traffic to the 78 | * 1.1.1.1 server as we hit the "I agree" button in our web browser. 79 | * (I used 'tcpdump -i -n -A -s 1500 host 1.1.1.1' for 80 | * this) We looked at it and put it here as a big ugly C string 81 | * because we are lazy. If we wanted to make a generic button pusher 82 | * we could put these in files and read them and try multiple 83 | * servers.. think about modifying the program to include the 84 | * acceptance string for your local starbucks, and other annoying 85 | * captive proxy networks. 86 | */ 87 | char iagree[] = "POST /login.html HTTP/1.1\r\nUser-Agent: curl/7.28.1\r\nHost: 1.1.1.1\r\nAccept: */*\r\nContent-Length: 15\r\nContent-Type: application/x-www-form-urlencoded\r\n\r\nbuttonClicked=4\r\n"; 88 | 89 | /* A signal handler so we exit after we get a SIGALRM */ 90 | struct sigaction sa; 91 | static void alarmhandler(int signum) { 92 | /* signal handler for SIGALARM */ 93 | exit(1); 94 | } 95 | 96 | int main(int argc, char *argv[]) 97 | { 98 | ssize_t written, w; 99 | struct sockaddr_in server_sa; 100 | char buffer[256]; 101 | size_t maxread; 102 | ssize_t r, rc; 103 | u_short port; 104 | int sd; 105 | 106 | /* 107 | * first set up "server_sa" to be the location of the server 108 | * we know the server we are interested in is "1.1.1.1", and 109 | * we know it is port 80, so we just hardcode that right in 110 | * here. 111 | */ 112 | port = 80; 113 | memset(&server_sa, 0, sizeof(server_sa)); 114 | server_sa.sin_family = AF_INET; 115 | server_sa.sin_port = htons(port); 116 | server_sa.sin_addr.s_addr = inet_addr("1.1.1.1"); 117 | if (server_sa.sin_addr.s_addr == INADDR_NONE) { 118 | fprintf(stderr, "Invalid IP address %s\n", argv[1]); 119 | exit(1); 120 | } 121 | 122 | /* ok now get a socket. we don't care where... */ 123 | if ((sd=socket(AF_INET,SOCK_STREAM,0)) == -1) 124 | err(1, "socket failed"); 125 | 126 | /* let's set ourselves up to get a signal after 3 seconds */ 127 | /* 128 | * set up the sa to call "alarmhandler" above, and call sigaction 129 | * to set it up as the signal handler for SIGALRM, then call "alarm" 130 | * to give us a signal in 3 seconds. 131 | */ 132 | sa.sa_handler = alarmhandler; 133 | sigemptyset(&sa.sa_mask); 134 | if (sigaction(SIGALRM, &sa, NULL) == -1) 135 | err(1, "sigaction failed"); 136 | alarm(3); 137 | 138 | /* connect the socket to the server described in "server_sa" */ 139 | if (connect(sd, (struct sockaddr *)&server_sa, sizeof(server_sa)) 140 | == -1) 141 | err(1, "connect failed"); 142 | 143 | /* 144 | * finally, we are connected. 145 | */ 146 | 147 | /* 148 | * Write the message to the client, being sure to 149 | * handle a short write, or being interrupted by 150 | * a signal before we could write anything. 151 | */ 152 | w = 0; 153 | written = 0; 154 | while (written < strlen(iagree)) { 155 | w = write(sd, iagree + written, 156 | strlen(iagree) - written); 157 | if (w == -1) { 158 | if (errno != EINTR) 159 | err(1, "write failed"); 160 | } 161 | else 162 | written += w; 163 | } 164 | 165 | /* 166 | * Now let's read the answer back in case the 167 | * server cares. if we compile with -DDEBUG 168 | * we can print out the answer so we can look at it 169 | */ 170 | 171 | r = -1; 172 | rc = 0; 173 | maxread = sizeof(buffer) - 1; /* leave room for a 0 byte */ 174 | while ((r != 0) && rc < maxread) { 175 | r = read(sd, buffer + rc, maxread - rc); 176 | if (r == -1) { 177 | if (errno != EINTR) 178 | err(1, "read failed"); 179 | } else 180 | rc += r; 181 | } 182 | /* 183 | * we must make absolutely sure buffer has a terminating 0 byte 184 | * if we are to use it as a C string 185 | */ 186 | buffer[rc] = '\0'; 187 | #ifdef DEBUG 188 | printf("Server sent: %s",buffer); 189 | #endif 190 | alarm(0); /* cancel our alarm.. we made it through */ 191 | close(sd); 192 | return(0); 193 | } 194 | -------------------------------------------------------------------------------- /C/select_server.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2008 Bob Beck 3 | * 4 | * Permission to use, copy, modify, and distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | 17 | /* 18 | * select_server.c - an example of using select to implement a non-forking 19 | * server. In this case this is an "echo" server - it simply reads 20 | * input from clients, and echoes it back again to them, one line at 21 | * a time. 22 | * 23 | * to use, cc -DDEBUG -o select_server select_server.c 24 | * or cc -o select_server select_server.c after you read the code :) 25 | * 26 | * then run with select_server PORT 27 | * where PORT is some numeric port you want to listen on. 28 | * 29 | * to connect to it, then use telnet or nc 30 | * i.e. 31 | * telnet localhost PORT 32 | * or 33 | * nc localhost PORT 34 | * 35 | */ 36 | 37 | 38 | #include 39 | #include 40 | #include 41 | #include 42 | 43 | #include 44 | 45 | #include 46 | #include 47 | #include 48 | #include 49 | #include 50 | #include 51 | #include 52 | #include 53 | 54 | 55 | /* we use this structure to keep track of each connection to us */ 56 | struct con { 57 | int sd; /* the socket for this connection */ 58 | int state; /* the state of the connection */ 59 | struct sockaddr_in sa; /* the sockaddr of the connection */ 60 | size_t slen; /* the sockaddr length of the connection */ 61 | char *buf; /* a buffer to store the characters read in */ 62 | char *bp; /* where we are in the buffer */ 63 | size_t bs; /* total size of the buffer */ 64 | size_t bl; /* how much we have left to read/write */ 65 | }; 66 | 67 | /* 68 | * we will accept a maximum of 256 simultaneous connections to us. 69 | * While you could make this a dynamically allocated array, and 70 | * use a variable for maxconn instead of a #define, that is left 71 | * as an exercise to the reader. The necessity of doing this 72 | * in the real world is debatable. Even the most monsterous of 73 | * daemons on real unix machines can typically only deal with several 74 | * thousand simultaeous connections, due to limitations of the 75 | * operating system and process limits. so it might not be worth it 76 | * in general to make this part fully dynamic, depending on your 77 | * application. For example, there is no point in allowing for 78 | * more connections than the kernel will allow your process to 79 | * have open files - so run 'ulimit -a' to see what that is as 80 | * an example of a typical reasonable number, and bear in mind 81 | * you may have a few more files open than just your sockets 82 | * in order to do anything really useful 83 | */ 84 | #define MAXCONN 256 85 | struct con connections[MAXCONN]; 86 | 87 | #define BUF_ASIZE 256 /* how much buf will we allocate at a time. */ 88 | 89 | /* states used in struct con. */ 90 | #define STATE_UNUSED 0 91 | #define STATE_READING 1 92 | #define STATE_WRITING 2 93 | 94 | 95 | static void usage() 96 | { 97 | extern char * __progname; 98 | fprintf(stderr, "usage: %s portnumber\n", __progname); 99 | exit(1); 100 | } 101 | 102 | 103 | /* 104 | * get a free connection structure, to save a new connection in 105 | */ 106 | struct con * get_free_conn() 107 | { 108 | int i; 109 | for (i = 0; i < MAXCONN; i++) { 110 | if (connections[i].state == STATE_UNUSED) 111 | return(&connections[i]); 112 | } 113 | return(NULL); /* we're all full - indicate this to our caller */ 114 | } 115 | 116 | 117 | 118 | /* 119 | * close or initialize a connection - resets a connection to the default, 120 | * unused state. 121 | */ 122 | void closecon (struct con *cp, int initflag) 123 | { 124 | if (!initflag) { 125 | if (cp->sd != -1) 126 | close(cp->sd); /* close the socket */ 127 | free(cp->buf); /* free up our buffer */ 128 | } 129 | memset(cp, 0, sizeof(struct con)); /* zero out the con struct */ 130 | cp->buf = NULL; /* unnecessary because of memset above, but put here 131 | * to remind you NULL is 0. 132 | */ 133 | cp->sd = -1; 134 | } 135 | 136 | /* 137 | * handlewrite - deal with a connection that we want to write stuff 138 | * to. assumes the caller has checked that cp->sd is writeable 139 | * by using select(). once we write everything out, change the 140 | * state of the connection to the reading state. 141 | */ 142 | void handlewrite(struct con *cp) 143 | { 144 | ssize_t i; 145 | 146 | /* 147 | * assuming before we are called, cp->sd was put into an fd_set 148 | * and checked for writeability by select, we know that we can 149 | * do one write() and write something. We are *NOT* guaranteed 150 | * how much we can write. So while we will be able to write bytes 151 | * we don't know if we will get a whole line, or even how much 152 | * we will get - so we do *exactly* one write. and keep track 153 | * of where we are. If we don't want to block, we can't do 154 | * multiple writes to write everything out without calling 155 | * select() again between writes. 156 | */ 157 | 158 | i = write(cp->sd, cp->bp, cp->bl); 159 | if (i == -1) { 160 | if (errno != EAGAIN) { 161 | /* the write failed */ 162 | closecon(cp, 0); 163 | } 164 | /* 165 | * note if EAGAIN, we just return, and let our caller 166 | * decide to call us again when socket is writable 167 | */ 168 | return; 169 | } 170 | /* otherwise, something ok happened */ 171 | cp->bp += i; /* move where we are */ 172 | cp->bl -= i; /* decrease how much we have left to write */ 173 | if (cp->bl == 0) { 174 | /* we wrote it all out, hooray, so go back to reading */ 175 | cp->state = STATE_READING; 176 | cp->bl = cp->bs; /* we can read up to this much */ 177 | cp->bp = cp->buf; /* we'll start at the beginning */ 178 | } 179 | } 180 | 181 | /* 182 | * handleread - deal with a connection that we want to read stuff 183 | * from. assumes the caller has checked that cp->sd is writeable 184 | * by using select(). If a newline is seen at the end of what we 185 | * are reading, change the state of this connection to the writing 186 | * state. 187 | */ 188 | void handleread(struct con *cp) 189 | { 190 | ssize_t i; 191 | 192 | /* 193 | * first, let's make sure we have enough room to do a 194 | * decent sized read. 195 | */ 196 | 197 | if (cp->bl < 10) { 198 | char *tmp; 199 | tmp = realloc(cp->buf, (cp->bs + BUF_ASIZE) * sizeof(char)); 200 | if (tmp == NULL) { 201 | /* we're out of memory */ 202 | closecon(cp, 0); 203 | return; 204 | } 205 | cp->buf = tmp; 206 | cp->bs += BUF_ASIZE; 207 | cp->bl += BUF_ASIZE; 208 | cp->bp = cp->buf + (cp->bs - cp->bl); 209 | } 210 | 211 | /* 212 | * assuming before we are called, cp->sd was put into an fd_set 213 | * and checked for readability by select, we know that we can 214 | * do one read() and get something. We are *NOT* guaranteed 215 | * how much we can get. So while we will be able to read bytes 216 | * we don't know if we will get a whole line, or even how much 217 | * we will get - so we do *exactly* one read. and keep track 218 | * of where we are. If we don't want to block, we can't do 219 | * multiple reads to read in a whole line without calling 220 | * select() to check for readability between each read. 221 | */ 222 | i = read(cp->sd, cp->bp, cp->bl); 223 | if (i == 0) { 224 | /* 0 byte read means the connection got closed */ 225 | closecon(cp, 0); 226 | return; 227 | } 228 | if (i == -1) { 229 | if (errno != EAGAIN) { 230 | /* read failed */ 231 | err(1, "read failed! sd %d\n", cp->sd); 232 | closecon(cp, 0); 233 | } 234 | /* 235 | * note if EAGAIN, we just return, and let our caller 236 | * decide to call us again when socket is readable 237 | */ 238 | return; 239 | } 240 | /* 241 | * ok we really got something read. chage where we're 242 | * pointing 243 | */ 244 | cp->bp += i; 245 | cp->bl -= i; 246 | 247 | /* 248 | * now check to see if we should change state - i.e. we got 249 | * a newline on the end of the buffer 250 | */ 251 | if (*(cp->bp - 1) == '\n') { 252 | cp->state = STATE_WRITING; 253 | cp->bl = cp->bp - cp->buf; /* how much will we write */ 254 | cp->bp = cp->buf; /* and we'll start from here */ 255 | } 256 | } 257 | 258 | int main(int argc, char *argv[]) 259 | { 260 | struct sockaddr_in sockname; 261 | int max = -1, omax; /* the biggest value sd. for select */ 262 | int sd; /* our listen socket */ 263 | fd_set *readable = NULL , *writable = NULL; /* fd_sets for select */ 264 | u_short port; 265 | u_long p; 266 | char *ep; 267 | int i; 268 | 269 | /* 270 | * first, figure out what port we will listen on - it should 271 | * be our first parameter. 272 | */ 273 | 274 | if (argc != 2) 275 | usage(); 276 | errno = 0; 277 | p = strtoul(argv[1], &ep, 10); 278 | if (*argv[1] == '\0' || *ep != '\0') { 279 | /* parameter wasn't a number, or was empty */ 280 | fprintf(stderr, "%s - not a number\n", argv[1]); 281 | usage(); 282 | } 283 | if ((errno == ERANGE && p == ULONG_MAX) || (p > USHRT_MAX)) { 284 | /* It's a number, but it either can't fit in an unsigned 285 | * long, or is too big for an unsigned short 286 | */ 287 | fprintf(stderr, "%s - value out of range\n", argv[1]); 288 | usage(); 289 | } 290 | /* now safe to do this */ 291 | port = p; 292 | 293 | /* now before we get going, decide if we want to daemonize, that 294 | * is, run in the background like a real system process 295 | */ 296 | #ifndef DEBUG 297 | /* don't daemonize if we compile with -DDEBUG */ 298 | if (daemon(1, 0) == -1) 299 | err(1, "daemon() failed"); 300 | #endif 301 | 302 | /* now off to the races - let's set up our listening socket */ 303 | memset(&sockname, 0, sizeof(sockname)); 304 | sockname.sin_family = AF_INET; 305 | sockname.sin_port = htons(port); 306 | sockname.sin_addr.s_addr = htonl(INADDR_ANY); 307 | sd=socket(AF_INET,SOCK_STREAM,0); 308 | if ( sd == -1) 309 | err(1, "socket failed"); 310 | 311 | if (bind(sd, (struct sockaddr *) &sockname, sizeof(sockname)) == -1) 312 | err(1, "bind failed"); 313 | 314 | if (listen(sd,3) == -1) 315 | err(1, "listen failed"); 316 | 317 | /* 318 | * We're now bound, and listening for connections on "sd". 319 | * Each call to "accept" will return us a descriptor talking to 320 | * a connected client. 321 | */ 322 | 323 | /* 324 | * finally - the main loop. accept connections and deal with 'em 325 | */ 326 | #ifndef DEBUG 327 | /* 328 | * since we'll be running as a daemon if we're not compiled with 329 | * -DDEBUG, we better not be using printf - since stdout will be 330 | * unusable 331 | */ 332 | printf("Server up and listening for connections on port %u\n", port); 333 | #endif 334 | 335 | /* initialize all our connection structures */ 336 | for (i = 0; i < MAXCONN; i++) 337 | closecon(&connections[i], 1); 338 | 339 | for(;;) { 340 | int i; 341 | int maxfd = -1; /* the biggest value sd we are interested in.*/ 342 | 343 | /* 344 | * first we have to initialize the fd_sets to keep 345 | * track of readable and writable sockets. we have 346 | * to make sure we have fd_sets that are big enough 347 | * to hold our largest valued socket descriptor. 348 | * so first, we find the max value by iterating through 349 | * all the connections, and then we allocate fd sets 350 | * that are big enough, if they aren't already. 351 | */ 352 | omax = max; 353 | max = sd; /* the listen socket */ 354 | 355 | for (i = 0; i < MAXCONN; i++) { 356 | if (connections[i].sd > max) 357 | max = connections[i].sd; 358 | } 359 | if (max > omax) { 360 | /* we need bigger fd_sets allocated */ 361 | 362 | /* free the old ones - does nothing if they are NULL */ 363 | free(readable); 364 | free(writable); 365 | 366 | /* 367 | * this is how to allocate fd_sets for select 368 | */ 369 | readable = (fd_set *)calloc(howmany(max + 1, NFDBITS), 370 | sizeof(fd_mask)); 371 | if (readable == NULL) 372 | err(1, "out of memory"); 373 | writable = (fd_set *)calloc(howmany(max + 1, NFDBITS), 374 | sizeof(fd_mask)); 375 | if (writable == NULL) 376 | err(1, "out of memory"); 377 | omax = max; 378 | /* 379 | * note that calloc always returns 0'ed memory, 380 | * (unlike malloc) so these sets are all set to 0 381 | * and ready to go 382 | */ 383 | } else { 384 | /* 385 | * our allocated sets are big enough, just make 386 | * sure they are cleared to 0. 387 | */ 388 | memset(readable, 0, howmany(max+1, NFDBITS) * 389 | sizeof(fd_mask)); 390 | memset(writable, 0, howmany(max+1, NFDBITS) * 391 | sizeof(fd_mask)); 392 | } 393 | 394 | /* 395 | * Now, we decide which sockets we are interested 396 | * in reading and writing, by setting the corresponding 397 | * bit in the readable and writable fd_sets. 398 | */ 399 | 400 | /* 401 | * we are always interesting in reading from the 402 | * listening socket. so put it in the read set. 403 | */ 404 | 405 | FD_SET(sd, readable); 406 | if (maxfd < sd) 407 | maxfd = sd; 408 | 409 | /* 410 | * now go through the list of connections, and if we 411 | * are interested in reading from, or writing to, the 412 | * connection's socket, put it in the readable, or 413 | * writable fd_set - in preparation to call select 414 | * to tell us which ones we can read and write to. 415 | */ 416 | for (i = 0; i 0) { 439 | 440 | /* something is readable or writable... */ 441 | 442 | /* 443 | * First things first. check the listen socket. 444 | * If it was readable - we have a new connection 445 | * to accept. 446 | */ 447 | 448 | if (FD_ISSET(sd, readable)) { 449 | struct con *cp; 450 | int newsd; 451 | socklen_t slen; 452 | struct sockaddr_in sa; 453 | 454 | slen = sizeof(sa); 455 | newsd = accept(sd, (struct sockaddr *)&sa, 456 | &slen); 457 | if (newsd == -1) 458 | err(1, "accept failed"); 459 | 460 | cp = get_free_conn(); 461 | if (cp == NULL) { 462 | /* 463 | * we have no connection structures 464 | * so we close connection to our 465 | * client to not leave him hanging 466 | * because we are too busy to 467 | * service his request 468 | */ 469 | close(newsd); 470 | } else { 471 | /* 472 | * ok, if this worked, we now have a 473 | * new connection. set him up to be 474 | * READING so we do something with him 475 | */ 476 | cp->state = STATE_READING; 477 | cp->sd = newsd; 478 | cp->slen = slen; 479 | memcpy(&cp->sa, &sa, sizeof(sa)); 480 | } 481 | } 482 | /* 483 | * now, iterate through all of our connections, 484 | * check to see if they are readble or writable, 485 | * and if so, do a read or write accordingly 486 | */ 487 | for (i = 0; i