From 22da63b4bcca3bf37926f379aaff1fb9411ed119 Mon Sep 17 00:00:00 2001 From: silverwizard Date: Tue, 10 Dec 2019 00:02:35 -0500 Subject: [PATCH] Chargen and Character Generator are out of sync, but ready for linking --- Makefile | 11 ++ character.c | 437 ++++++++++++++++++++++++++++++++++++++++++++++++++++ character.h | 97 ++++++++++++ chargen.c | 302 ++++++++++++++++++++++++++++++++++++ 4 files changed, 847 insertions(+) create mode 100644 Makefile create mode 100644 character.c create mode 100644 character.h create mode 100644 chargen.c diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..541828b --- /dev/null +++ b/Makefile @@ -0,0 +1,11 @@ +CC=cc +LIBS=-lm + +generator: + ${CC} -o charactergenerator ${LIBS} character.c +server: + ${CC} -o chargen chargen.c + +all: server generator + +.PHONY: all diff --git a/character.c b/character.c new file mode 100644 index 0000000..1766880 --- /dev/null +++ b/character.c @@ -0,0 +1,437 @@ +#include +#include +#include +#include +#include "character.h" + +int dieroll(int num,int sides){ + int total = 0; + for(num;num>0;num--){ + total = total + arc4random_uniform(sides)+1; + } + return total; +} + +void addLanguage(long lang){ + if((lang & languages ) == 0){ + languages = languages + lang; + }else{ + addLanguage(exp2l(arc4random_uniform(15))); + } +} + +void addProf(long prof){ + if((prof & profs) == 0){ + profs = profs + prof; + }else{ + addProf(exp2l(arc4random_uniform(18))); + } +} + +void classProfs(unsigned long* classprofs, int count, int num){ + //Remove existing profs from the array + for(int i=0; i<=count;i++){ + if((classprofs[i] & profs) != 0){ + classprofs[i] = classprofs[count]; + count--; + i = 0; + } + } + //Shuffle the array + for(int i=0; i<=count;i++){ + int newpos = i + arc4random_uniform(count - i); + unsigned long local = classprofs[newpos]; + classprofs[newpos] = classprofs[i]; + classprofs[i]=local; + } + //Grab the first N elements, based on the class's value, but first, if we have more profs than available profs, get some random ones + if(num > count){ + for(count;num > count;count--){ + addProf(exp2l(arc4random_uniform(18))); + } + } + for(int i=0;i<=num;i++){ + addProf(classprofs[num]); + } +} + +void genClass(){ + int c = arc4random_uniform(sizeof(classes)/sizeof(classes[0])); + class = classes[c]; + switch(c){ + case BARBARIAN:; + unsigned long barbskills[6] = {ANIMALHANDLING, ATHLETICS, INTIMIDATION, NATURE, PERCEPTION, SURVIVAL}; + hp = 12 + mods[CON]; + classProfs(barbskills, 6, 2); + break; + case BARD:; + addProf(exp2l(arc4random_uniform(18))); + addProf(exp2l(arc4random_uniform(18))); + addProf(exp2l(arc4random_uniform(18))); + strlcat(otherprofs, "Three Musical Instruments, ", sizeof(otherprofs)); + hp = 8 + mods[CON]; + break; + case CLERIC:; + unsigned long clericskills[5]= {HISTORY, INSIGHT, MEDICINE, PERSUASION, RELIGION}; + classProfs(clericskills, 5, 2); + hp = 8 + mods[CON]; + break; + case DRUID:; + unsigned long druidskills[8] = {ARCANA, ANIMALHANDLING, INSIGHT, MEDICINE, NATURE, PERCEPTION, RELIGION, SURVIVAL}; + classProfs(druidskills, 8, 2); + strlcat(otherprofs, "Herbalism Kit, ", sizeof(otherprofs)); + hp = 8 + mods[CON]; + break; + case FIGHTER:; + unsigned long fighterskills[8] = {ACROBATICS, ANIMALHANDLING, ATHLETICS, HISTORY, INSIGHT, INTIMIDATION, PERCEPTION, SURVIVAL}; + classProfs(fighterskills, 8, 2); + hp = 10 + mods[CON]; + break; + case MONK:; + unsigned long monkskills[6] = {ACROBATICS, ATHLETICS, HISTORY, INSIGHT, RELIGION, STEALTH}; + classProfs(monkskills, 6, 2); + strlcat(otherprofs, "Artisan Tool or Musical Instrument, ", sizeof(otherprofs)); + hp = 8 + mods[CON]; + break; + case PALADIN:; + unsigned long paladinskills[6] = {ATHLETICS, INSIGHT, INTIMIDATION, MEDICINE, PERSUASION, RELIGION}; + classProfs(paladinskills, 6, 2); + hp = 10 + mods[CON]; + break; + case RANGER:; + unsigned long rangerskills[8] = {ANIMALHANDLING, ATHLETICS, INSIGHT, INVESTIGATION, NATURE, PERCEPTION, STEALTH, SURVIVAL}; + classProfs(rangerskills, 8, 3); + hp = 10 + mods[CON]; + break; + case ROGUE:; + unsigned long rogueskills[11] = {ACROBATICS, ATHLETICS, DECEPTION, INSIGHT, INTIMIDATION, INVESTIGATION, PERCEPTION, PERFORMANCE, PERSUASION, SLEIGHTOFHAND, STEALTH}; + classProfs(rogueskills, 11, 4); + strlcat(otherprofs, "Thieves tools, ", sizeof(otherprofs)); + hp = 8 + mods[CON]; + break; + case SORCERER:; + unsigned long sorcererskills[6] = {ARCANA, DECEPTION, INSIGHT, INTIMIDATION, PERSUASION, RELIGION}; + classProfs(sorcererskills, 6, 2); + hp = 6 + mods[CON]; + break; + case WARLOCK:; + unsigned long warlockskills[7] = {ARCANA, DECEPTION, HISTORY, INTIMIDATION, INVESTIGATION, NATURE, RELIGION}; + classProfs(warlockskills, 7, 2); + hp = 8 + mods[CON]; + break; + case WIZARD:; + unsigned long wizardskills[5] = {ARCANA, HISTORY, INVESTIGATION, MEDICINE, RELIGION}; + classProfs(wizardskills, 5, 2); + hp = 6 + mods[CON]; + break; + default: + fprintf(stderr, "Incorrect class was generated for some reason"); + /* This should never happen */ + } +} + +void genRace(){ + int r = arc4random_uniform(sizeof(races)/sizeof(races[0])); + race = races[r]; + int subrace; + switch (r){ + case DRAGONBORN: + addLanguage(DRACONIC); + stats[STR]+=2; + stats[CHA]+=1; + break; + case DWARF: + addLanguage(DWARVISH); + stats[CON]+=2; + subrace = arc4random_uniform(2); + if(subrace == 0){ + race = "Hill Dwarf"; + stats[WIS]+=1; + }else{ + race = "Mountain Dwarf"; + stats[STR]+=2; + } + break; + case ELF: + addLanguage(ELVISH); + addProf(PERCEPTION); + stats[DEX]+=2; + subrace = arc4random_uniform(3); + if(subrace == 0){ + race = "High Elf"; + stats[INT]+=1; + addLanguage(exp2l(arc4random_uniform(15))); + }else if(subrace == 1){ + race = "Wood Elf"; + stats[WIS]+=1; + }else{ + race = "Drow"; + stats[CHA]+=1; + } + break; + case GNOME: + subrace = arc4random_uniform(2); + stats[INT]+=2; + addLanguage(GNOMISH); + if(subrace == 0){ + race = "Forest Gnome"; + stats[DEX]+=1; + }else{ + race = "Rock Gnome"; + stats[CON]+=1; + strlcat(otherprofs, "Artisan Tools, ", sizeof(otherprofs)); + } + break; + case HALFELF: + stats[CHA]+=2; + stats[arc4random_uniform(4)]+=1; + stats[arc4random_uniform(4)]+=1; + addProf(exp2l(arc4random_uniform(18))); + addProf(exp2l(arc4random_uniform(18))); + addLanguage(exp2l(arc4random_uniform(15))); + addLanguage(ELVISH); + break; + case HALFLING: + addLanguage(HALFLISH); + stats[DEX]+=2; + subrace = arc4random_uniform(2); + if(subrace == 0){ + race = "Lightfoot Halfling"; + stats[CHA]+=1; + }else{ + race = "Stout Halfling"; + stats[INT]+=1; + } + break; + case HALFORC: + addLanguage(ORC); + stats[STR]+=2; + stats[CON]+=1; + addProf(INTIMIDATION); + break; + case HUMAN: + stats[STR]+=1; + stats[DEX]+=1; + stats[CON]+=1; + stats[INT]+=1; + stats[WIS]+=1; + stats[CHA]+=1; + addLanguage(exp2l(arc4random_uniform(15))); + break; + case TIEFLING: + stats[INT]+=1; + stats[CHA]+=2; + addLanguage(INFERNAL); + break; + default: + fprintf(stderr, "Something went wrong in race selection"); + /*Hopefully should never happen*/ + } +} + +void genBackground(){ + int b = arc4random_uniform(sizeof(backgrounds)/sizeof(backgrounds[0])); + background = backgrounds[b]; + switch (b){ + case ACOLYTE: + addProf(INSIGHT); + addProf(RELIGION); + addLanguage(exp2l(arc4random_uniform(15))); + addLanguage(exp2l(arc4random_uniform(15))); + break; + case CHARLATAN: + addProf(DECEPTION); + addProf(SLEIGHTOFHAND); + strlcat(otherprofs, "Disguise Kit, ", sizeof(otherprofs)); + strlcat(otherprofs, "Forgery Kit, ", sizeof(otherprofs)); + break; + case CRIMINAL: + addProf(DECEPTION); + addProf(STEALTH); + strlcat(otherprofs, "Gaming Set, ", sizeof(otherprofs)); + strlcat(otherprofs, "Theives Tools, ", sizeof(otherprofs)); + break; + case ENTERTAINER: + addProf(ACROBATICS); + addProf(PERFORMANCE); + strlcat(otherprofs, "Disguise Kit, ", sizeof(otherprofs)); + strlcat(otherprofs, "Musical Instrument, ", sizeof(otherprofs)); + break; + case FOLKHERO: + addProf(ANIMALHANDLING); + addProf(SURVIVAL); + strlcat(otherprofs, "Artisan's Tools, ", sizeof(otherprofs)); + strlcat(otherprofs, "Land Vehicles, ", sizeof(otherprofs)); + break; + case GUILDARTISAN: + addProf(INSIGHT); + addProf(PERSUASION); + addLanguage(exp2l(arc4random_uniform(15))); + strlcat(otherprofs, "Artisan's Tools, ", sizeof(otherprofs)); + break; + case HERMIT: + addProf(MEDICINE); + addProf(RELIGION); + addLanguage(exp2l(arc4random_uniform(15))); + strlcat(otherprofs, "Herbalism Kit, ", sizeof(otherprofs)); + break; + case NOBLE: + addProf(HISTORY); + addProf(PERSUASION); + addLanguage(exp2l(arc4random_uniform(15))); + strlcat(otherprofs, "Gaming Set, ", sizeof(otherprofs)); + break; + case OUTLANDER: + addProf(ATHLETICS); + addProf(SURVIVAL); + addLanguage(exp2l(arc4random_uniform(15))); + strlcat(otherprofs, "Musical Instrument, ", sizeof(otherprofs)); + break; + case SAGE: + addProf(ARCANA); + addProf(HISTORY); + addLanguage(exp2l(arc4random_uniform(15))); + addLanguage(exp2l(arc4random_uniform(15))); + break; + case SAILOR: + addProf(ATHLETICS); + addProf(PERCEPTION); + strlcat(otherprofs, "Navigator's Tools, ", sizeof(otherprofs)); + strlcat(otherprofs, "Water Vehicles, ", sizeof(otherprofs)); + break; + case SOLDIER: + addProf(ATHLETICS); + addProf(INTIMIDATION); + strlcat(otherprofs, "Gaming Set, ", sizeof(otherprofs)); + strlcat(otherprofs, "Land Vehicles, ", sizeof(otherprofs)); + break; + case URCHIN: + addProf(SLEIGHTOFHAND); + addProf(STEALTH); + strlcat(otherprofs, "Theives Tools, ", sizeof(otherprofs)); + strlcat(otherprofs, "Disguise Kit, ", sizeof(otherprofs)); + break; + default: + fprintf(stderr, "Bad background was generated!"); + /* Ideally not reached */ + } +} + +int main(){ + int i; + strlcat(otherprofs, "", 1); + genRace(); + genClass(); + genBackground(); + for(i=0; i < 6; i++){ + stats[i] = dieroll(3,6); + mods[i] = floor((stats[i]/2)-5); + } + printf("Race = %s\nBackground = %s\nClass = %s\nStr = %d %d\nDex = %d %d\nCon = %d %d\nInt = %d %d\nWis = %d %d\nCha = %d %d\n\nHP: %d\n", race, background, class, stats[STR], mods[STR], stats[DEX], mods[DEX], stats[CON], mods[CON], stats[INT], mods[INT], stats[WIS], mods[WIS], stats[CHA], mods[CHA], hp); + + + printf("Proficiences:\n"); + if((ATHLETICS & profs) != 0){ + printf("Athletics\n"); + } + if((ACROBATICS & profs) != 0){ + printf("Acrobatics\n"); + } + if((SLEIGHTOFHAND & profs) != 0){ + printf("Sleight of Hand\n"); + } + if((STEALTH & profs) != 0){ + printf("Stealth\n"); + } + if((ARCANA & profs) != 0){ + printf("Arcana\n"); + } + if((HISTORY & profs) != 0){ + printf("History\n"); + } + if((INVESTIGATION & profs) != 0){ + printf("Investigation\n"); + } + if((NATURE & profs) != 0){ + printf("Nature\n"); + } + if((RELIGION & profs) != 0){ + printf("Regligion\n"); + } + if((ANIMALHANDLING & profs) != 0){ + printf("Animal Handling\n"); + } + if((INSIGHT & profs) != 0){ + printf("Insight\n"); + } + if((MEDICINE & profs) != 0){ + printf("Medicine\n"); + } + if((PERCEPTION & profs) != 0){ + printf("Perception\n"); + } + if((SURVIVAL & profs) != 0){ + printf("Survival\n"); + } + if((DECEPTION & profs) != 0){ + printf("Deception\n"); + } + if((INTIMIDATION & profs) != 0){ + printf("Intimidation\n"); + } + if((PERFORMANCE & profs) != 0){ + printf("Performance\n"); + } + if((PERSUASION & profs) != 0){ + printf("Persuaion\n"); + } + + printf("\nLanguages:\nCommon\n"); + if((ABYSSAL & languages) != 0){ + printf("Abyssal\n"); + } + if((CELESTIAL & languages) != 0){ + printf("Celestial\n"); + } + if((DRACONIC & languages) != 0){ + printf("Draconic\n"); + } + if((DEEPSPEECH & languages) != 0){ + printf("Deep Speech\n"); + } + if((INFERNAL & languages) != 0){ + printf("Infernal\n"); + } + if((PRIMORDIAL & languages) != 0){ + printf("Primordial\n"); + } + if((SYLVAN & languages) != 0){ + printf("Sylvan\n"); + } + if((UNDERCOMMON & languages) != 0){ + printf("Undercommon\n"); + } + if((DWARVISH & languages) != 0){ + printf("Dwarvish\n"); + } + if((ELVISH & languages) != 0){ + printf("Elvish\n"); + } + if((GIANT & languages) != 0){ + printf("Giant\n"); + } + if((GNOMISH & languages) != 0){ + printf("Gnome\n"); + } + if((GOBLIN & languages) != 0){ + printf("Goblin\n"); + } + if((HALFLISH & languages) != 0){ + printf("Halfling\n"); + } + if((ORC & languages) != 0){ + printf("Orcish\n"); + } + printf("\nOther Profs: %s\n", otherprofs); + return 1; +} diff --git a/character.h b/character.h new file mode 100644 index 0000000..be61f63 --- /dev/null +++ b/character.h @@ -0,0 +1,97 @@ +// Define skill proficiencies for prof array +#define ATHLETICS 1 +#define ACROBATICS 2 +#define SLEIGHTOFHAND 4 +#define STEALTH 8 +#define ARCANA 16 +#define HISTORY 32 +#define INVESTIGATION 64 +#define NATURE 128 +#define RELIGION 256 +#define ANIMALHANDLING 512 +#define INSIGHT 1024 +#define MEDICINE 2048 +#define PERCEPTION 4096 +#define SURVIVAL 8192 +#define DECEPTION 16384 +#define INTIMIDATION 32768 +#define PERFORMANCE 65536 +#define PERSUASION 131072 + +// Define language proficiences for prof array +#define ABYSSAL 1 +#define CELESTIAL 2 +#define DRACONIC 4 +#define DEEPSPEECH 8 +#define INFERNAL 16 +#define PRIMORDIAL 32 +#define SYLVAN 64 +#define UNDERCOMMON 128 +#define DWARVISH 256 +#define ELVISH 512 +#define GIANT 1024 +#define GNOMISH 2048 +#define GOBLIN 4096 +#define HALFLISH 8192 +#define ORC 16384 + +//Define values so we can make array references easier to read +#define BARBARIAN 0 +#define BARD 1 +#define CLERIC 2 +#define DRUID 3 +#define FIGHTER 4 +#define MONK 5 +#define PALADIN 6 +#define RANGER 7 +#define ROGUE 8 +#define SORCERER 9 +#define WARLOCK 10 +#define WIZARD 11 + +#define DRAGONBORN 0 +#define DWARF 1 +#define ELF 2 +#define GNOME 3 +#define HALFELF 4 +#define HALFLING 5 +#define HALFORC 6 +#define HUMAN 7 +#define TIEFLING 8 + +#define ACOLYTE 0 +#define CHARLATAN 1 +#define CRIMINAL 2 +#define ENTERTAINER 3 +#define FOLKHERO 4 +#define GUILDARTISAN 5 +#define HERMIT 6 +#define NOBLE 7 +#define OUTLANDER 8 +#define SAGE 9 +#define SAILOR 10 +#define SOLDIER 11 +#define URCHIN 12 + +#define STR 0 +#define DEX 1 +#define CON 2 +#define INT 3 +#define WIS 4 +#define CHA 5 + + + +unsigned long profs; +unsigned long languages; +char otherprofs[100]; +char* background; +char* race; +char* class; + +char* classes[] = {"Barbarian", "Bard", "Cleric", "Druid", "Fighter", "Monk", "Paladin", "Ranger", "Rogue", "Sorcerer", "Warlock", "Wizard" }; +char* races[] = { "Dragonborn", "Dwarf", "Elf", "Gnome", "Half-Elf", "Halfling", "Half-Orc", "Human", "Tiefling" }; +char* backgrounds[] = { "Acolyte", "Charlatan", "Criminal", "Entertainer", "Folk Hero", "Guild Artisan", "Hermit", "Noble", "Outlander", "Sage", "Sailor", "Soldier", "Urchin" }; +int stats[6]; +int mods[6]; +int hp; diff --git a/chargen.c b/chargen.c new file mode 100644 index 0000000..7834d8e --- /dev/null +++ b/chargen.c @@ -0,0 +1,302 @@ +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include + +void usage_and_die(const char *myname, const char *fmt, ...) +{ + if (fmt) + { + va_list ap; + va_start(ap, fmt); + vwarnx(fmt, ap); + } + errx(EXIT_FAILURE, "Usage: %s [-4 | -6] [-u | -t] [-l listen-addr] [-p listen-port]", myname); +} + +enum { MAX_LISTENERS = 8, MAX_CONNECTED = 64 }; +int listen_fds[MAX_LISTENERS]; +int packet_fds[MAX_LISTENERS]; +int stream_fds[MAX_CONNECTED]; +unsigned num_listen, num_stream, num_packet; + +int main(int argc, char **argv) +{ + int opt; + int ret; + + char hbuf[1024]; + char sbuf[32]; + + struct addrinfo hints = {0}; + struct addrinfo *bind_addrs; + + const char *listen_addr = NULL; + const char *listen_port = NULL; + + hints.ai_flags = AI_PASSIVE; + hints.ai_family = AF_UNSPEC; + + while ((opt = getopt(argc, argv, "46l:p:tu")) != -1) + { + switch (opt) + { + case '4': + case '6': + if (hints.ai_family != AF_UNSPEC) + usage_and_die(argv[0], "-4 and -6 are incompatible (leave out to use both)"); + hints.ai_family = (opt == '4') ? AF_INET : AF_INET6; + break; + case 't': + case 'u': + if (hints.ai_protocol != 0) + usage_and_die(argv[0], "-t and -u are incompatible (leave out to use both)"); + hints.ai_protocol = (opt == 't') ? IPPROTO_TCP : IPPROTO_UDP; + break; + case 'l': + if (listen_addr != NULL) + usage_and_die(argv[0], "Only one listen address allowed!"); + listen_addr = optarg; + break; + case 'p': + if (listen_port != NULL) + usage_and_die(argv[0], "Only one listen port allowed!"); + listen_port = optarg; + break; + default: + usage_and_die(argv[0], NULL); + /* not reached */ + } + } + + argc -= optind; + argv += optind; + + if (argc != 0) + usage_and_die(argv[0], NULL); + + if (listen_port == NULL) + listen_port = "chargen"; + + printf("Opening listeners on %s:%s...\n", (listen_addr == NULL) ? "*" : listen_addr, listen_port); + ret = getaddrinfo(listen_addr, listen_port, &hints, &bind_addrs); + if (ret) + errx(EXIT_FAILURE, "getaddrinfo: %s", gai_strerror(ret)); + for (struct addrinfo *a = bind_addrs; a != NULL; a = a->ai_next) + { + int s; + + ret = getnameinfo(a->ai_addr, a->ai_addrlen, hbuf, sizeof hbuf, sbuf, sizeof sbuf, NI_NUMERICHOST | NI_NUMERICSERV | (a->ai_socktype == SOCK_STREAM) ? 0 : NI_DGRAM); + if (ret) + warn("getnameinfo: %s", gai_strerror(ret)); + else + printf("Opening %s listener on %s:%s...\n", (a->ai_socktype == SOCK_STREAM) ? "stream" : "packet", hbuf, sbuf); + + s = socket(a->ai_family, a->ai_socktype, a->ai_protocol); + if (s == -1) + { + warn("socket"); + continue; + } + + if (bind(s, a->ai_addr, a->ai_addrlen) == -1) + { + warn("bind: %s:%s", hbuf, sbuf); + close(s); + continue; + } + + if (a->ai_socktype == SOCK_STREAM) + { + if (listen(s, 128) == -1) + { + warn("listen"); + close(s); + continue; + } + + if (num_stream >= MAX_LISTENERS) + { + warnx("Listener table full, discarding %s:%s", hbuf, sbuf); + close(s); + } + else + listen_fds[num_listen++] = s; + } + else + { + if (num_packet >= MAX_LISTENERS) + { + warnx("Listener table full, discarding %s:%s", hbuf, sbuf); + close(s); + } + else + packet_fds[num_packet++] = s; + } + } + + if (num_packet + num_listen == 0) + errx(EXIT_FAILURE, "No listeners to run on!\n"); + + if (pledge("stdio inet error", NULL) == -1) + warn("pledge"); + + while(1) + { + fd_set r, w; + int maxfd = 0; + + union + { + struct sockaddr_in a4; + struct sockaddr_in6 a6; + } addr; + /* 64k = max UDP payload size */ + static unsigned char data[64 * 1024]; + + FD_ZERO(&r); + FD_ZERO(&w); + + if (num_stream < MAX_CONNECTED) + { + for (unsigned i = 0; i < num_listen; i++) + { + FD_SET(listen_fds[i], &r); + if (listen_fds[i] > maxfd) + maxfd = listen_fds[i]; + } + } + for (unsigned i = 0; i < num_packet; i++) + { + FD_SET(packet_fds[i], &r); + if (packet_fds[i] > maxfd) + maxfd = packet_fds[i]; + } + for (unsigned i = 0; i < num_stream; i++) + { + FD_SET(stream_fds[i], &r); + FD_SET(stream_fds[i], &w); + if (stream_fds[i] > maxfd) + maxfd = stream_fds[i]; + } + + ret = select(maxfd+1, &r, &w, NULL, NULL); + if (ret == -1) + err(EXIT_FAILURE, "select"); + if (ret == 0) + { + printf("Huh, that's weird, select says nothing ready but I didn't ask for a timeout\n"); + continue; + } + + for (unsigned i = 0; i < num_listen; i++) + { + int l = listen_fds[i]; + if (FD_ISSET(l, &r)) + { + struct sockaddr *sa = (struct sockaddr *)&addr; + socklen_t len = sizeof addr; + int s = accept(l, sa, &len); + if (s == -1) + { + warn("accept"); + continue; + } + stream_fds[num_stream++] = s; + + ret = getnameinfo(sa, len, hbuf, sizeof hbuf, sbuf, sizeof sbuf, NI_NUMERICHOST | NI_NUMERICSERV); + if (ret) + warn("getnameinfo: %s", gai_strerror(ret)); + else + printf("Accepting stream connection from %s:%s...\n", hbuf, sbuf); + } + + if (num_stream >= MAX_CONNECTED) + break; + } + + for (unsigned i = 0; i < num_packet; i++) + { + int s = packet_fds[i]; + if (FD_ISSET(s, &r)) + { + ssize_t rval; + + struct sockaddr *sa = (struct sockaddr *)&addr; + socklen_t len = sizeof addr; + + rval = recvfrom(s, data, sizeof data, 0, sa, &len); + if (rval == -1) + { + warn("recvfrom"); + continue; + } + + ret = getnameinfo(sa, len, hbuf, sizeof hbuf, sbuf, sizeof sbuf, NI_NUMERICHOST | NI_NUMERICSERV); + if (ret) + warn("getnameinfo: %s", gai_strerror(ret)); + else + printf("Responding to packet from %s:%s...\n", hbuf, sbuf); + + rval = sendto(s, "chargen data\r\n", 14, 0, sa, len); + if (rval == -1) + warn("sendto"); + } + } + for (unsigned i = 0; i < num_stream; i++) + { + int s = stream_fds[i]; + if (FD_ISSET(s, &r)) + { + ssize_t rval; + rval = read(s, data, sizeof data); + if (rval <= 0) + { + if (rval == -1) + warn("read"); + printf("Closing stream connection\n"); + close(s); + + /* + * We will miss checking the socket we move down to fill the gap we're leaving. + * That's OK, if it's ready we'll get it next time. + */ + stream_fds[i] = stream_fds[--num_stream]; + continue; + } + /* Ignore data from a successful read */ + } + if (FD_ISSET(s, &w)) + { + if (s == 0) + { + printf("WTF? i=%u num_stream=%u stream_fds[i]=%d s=%d\n", i, num_stream, stream_fds[i], s); + continue; + } + if (write(s, "chargen data\r\n", 14) == -1) + { + warn("write"); + printf("Closing stream connection\n"); + close(s); + + /* + * We will miss checking the socket we move down to fill the gap we're leaving. + * That's OK, if it's ready we'll get it next time. + */ + stream_fds[i] = stream_fds[--num_stream]; + continue; + } + } + } + } + + /* not reached */ +}