DBS 0.12 Finally server stays up

Kaikki oikeudet pidätetään. Maailman parhaat satunnaisbitit: https://moijari.com:5006. Älä kuitenkaan käytä näitä sellaisenaan, summaa useampi generaattori, ja mielellään viimeinen omassa ohjelmassa.

Edit korjailen raporttia lähipäivien ja viikkojen aikana. Sorsia en ole vielä kokeillut kääntää… Sain käännettyä sorsan. Myös html lokit kirjoitetaan useammassa osassa. Lisätty palvelimiin vuorot lokien kirjoittamiseen. Raportti postin lopussa ennen sorsia. Korjattu pari bugia (uusi versio 0.14) ja lisätty koodia aktiivisuuden laskentaan ja lisätty yhteinen loki terttu hengessä kaikille palvelimille. Lisätty vielä muutoksia newressu.c tiedostoon, kappaleita lisätty loppuun ennen lähdekoodia.

Aiemmassa versiossa oli ongelmana se, että jos asiakas ei toteuta protokollaa oikein, palvelin saattoi pysähtyä ns blokkaavaan eli odottamaan jäävään funktioon. Tämän vuoksi uudet palvelimet (http ja https) luovat fork():lla lapsiprosessin, joka suorittaa toiminnot access() kutsusta lähtien. Näin jos lapsiprosessi “hyytyy” se ei hyydytä koko palvelinta. Seuraavana https palvelimen lapsiprosessi:

Jos palvelimeen tulee useita päällekkäisiä kyselyitä ne periaatteessa suoritetaan uudessa versiossa samaan aikaan, ja lokiin tulostuvat useamman prosessin lokirivit sekoittuneina. Tätä korjaamaan on lisätty uusi log_printf, jossa yhden prosessin lokirivit kerätään muistialueeseen ja tämä puskuri kirjoitetaan yhdellä kertaa prosessin päättyessä. Näin eri kutsujen lokirivit pysyvät eroteltuina.

Lisäksi yhteiset osat https_client:istä ja http_clientistä on yhdistetty dbs_server_vars() funktioon.

SSL_read yrittää lukua uudelleen viisi kertaa (error 1 ja error 5). Uudelleen lukujen välissä on kymmenesosasekunnin odotus (usleep()).

static void https_client(int news, SSL_CTX *ctx, struct sockaddr_in sa_cli, int addr_size, char *name)
{
  int status, ok;
  unsigned char buffer10[10];

  SSL *ssl;
  X509 *peer_cert;

  ok=1;
  // plus space for '\0'  
  htmlin = malloc(htmlinlen+1);

  dbs_server_vars(sa_cli,addr_size,name);
  
  if((ssl=SSL_new(ctx)) == NULL) {
    log_printf("\n%s: cannot SSL_new()", procname);
  }
  
  if(SSL_set_fd(ssl,news) != 1) {
    log_printf("\n%s: cannot SSL_set_fd()", procname);
  }
  
  status=SSL_accept(ssl);
  
  peer_cert = SSL_get_peer_certificate(ssl);
  if(peer_cert == NULL) {
    log_printf(", No peer certificate");
  }
  
  log_printf("\n");
  
  int clen = 0;
  int reads = 0;
  int first = 1;
  htmlparams = NULL;
  int bytes, totalbytes = 0;

  htmlin[0]='\0';
  while(htmlparams==NULL || clen-strlen(htmlparams) > 0) {
    if(!first) {
      log_printf(", ");
    }
#ifdef DEBUG68
    log_printf("SSL_read\n");
#endif
    int tries=0;
    for(;;) {
      bytes = SSL_read(ssl, htmlin+totalbytes, htmlinlen-totalbytes);

      int errerrno, err, err2;

      errerrno=errno;
      err=SSL_get_error(ssl,bytes);
      err2=ERR_get_error();

      log_printf("\nSSL_read()");
      log_printf(", retval %d", bytes);
      log_printf(", errno: %d", errerrno);
      log_printf(", SSL_get_error(): %d", err);
      log_printf(", ERR_get_error(): %d", err2);

      while((err2=ERR_get_error())!=0)
	log_printf(", %d",err2);
      if(bytes>=0) {
	reads++;
	break;
      }
      if(bytes<0) {
	if(++tries<5 && (err==1 || err==5)) {
	  log_printf(" try:%d",tries);
	  usleep(1024*512/5);
	  continue;
	}
	log_printf("\n%s: cannot SSL_read()", procname);
	ok=0;
	break;
      } // if(bytes
      break;
    } // for(;;)
    log_printf("(%d bytes)", bytes);
    if(!ok)
      break;

    *(htmlin+totalbytes+bytes) = '\0';
    if(bytes==0)
      break;

    totalbytes+=bytes;
    if(totalbytes >= htmlinlen) {
      // plus space for '\0'
      htmlin=realloc(htmlin, htmlinlen*2+1);
      htmlinlen *= 2;
    }
    
    htmlparams = dbs_html_get_params();
    unsigned char *p=htmlin;
    dbs_html_parse_string(sizeof(htmlmethod), htmlmethod,&p);
    if(!strcmp(htmlmethod,"GET"))
      break;
    dbs_html_get_request_line_num("Content-Length",
				  sizeof(buffer10), buffer10);
    clen = atoi(buffer10);
    first = 0;
  }
  
  log_printf("\n%d reads", reads);
  log_printf(", received %d chars", totalbytes);
  log_printf(", read %d total bytes", totalbytes);
  log_printf(", input buffer size %d chars", htmlinlen);
  log_printf(", data=\"");
  log_dump_string(htmlin);
  log_printf("\"\n");
  
  strncpy(htmlsslcipher, SSL_get_cipher(ssl), sizeof(htmlsslcipher));
  
  if(ok) 
    dbs_run_loop();
  
  if(ok) {
    log_printf("buffers(ssl):");
    for(int c=0;c<HTML_BUFFERS;c++) {
      log_printf(" %d:%ld",c,strlen(html_get_string(c)));
      if(strlen(html_get_string(c))>0) {
#ifdef DEBUG68
	log_printf("SSL_write\n");
#endif
	if((status=SSL_write(ssl, html_get_string(c), strlen(html_get_string(c))))<1) {
	  log_printf("\n%s: cannot SSL_write(), buffer %d, status: %d, SSL error: %d",
		  procname, c, status, SSL_get_error(ssl,status));
	}
      }
    }
  }
  log_printf("\n");
  log_printf("\nSSL connection using %s", htmlsslcipher);
  log_printf("\n");
 
#ifdef DEBUG68
  log_printf("SSL_free\n");
#endif
  SSL_free(ssl);

  free(htmlin);
}

Edellinen tuottaa joillekin käyttäjille seuraavia virheitä, joita en ole vielä saanut pois: Ne tosin voivat johtua myös kutsujan protokollaongelmasta. Listassa on tietenkin viisi uudelleen yritystä. Virheet tulevat vain joillekin käyttäjille, omissa testeissäni niitä ei esiinny.

SSL_read(), retval -1, errno: 0, SSL_get_error(): 5, ERR_get_error(): 0 try:1
SSL_read(), retval -1, errno: 0, SSL_get_error(): 5, ERR_get_error(): 0 try:2
SSL_read(), retval -1, errno: 0, SSL_get_error(): 5, ERR_get_error(): 0 try:3
SSL_read(), retval -1, errno: 0, SSL_get_error(): 5, ERR_get_error(): 0 try:4
SSL_read(), retval -1, errno: 0, SSL_get_error(): 5, ERR_get_error(): 0
./ressu4: cannot SSL_read()(-1 bytes)

Toisaalta SSL_write() tulostaa joskus tälläisen:

./ressu4: cannot SSL_write(), buffer 0, status: -1, SSL error: 6
./ressu4: cannot SSL_write(), buffer 8, status: -1, SSL error: 1, htmlparamslen: "0"

Seuraavassa varsinainen palvelinohjelma: se on samankaltainen kuin edellinenkin versio, tähän on lisätty fork() kutsu, joka luo aina asiakkaan protokollaa varten uuden lapsiprosessin.

Reset kytkintä ei ole vielä koodattu kokonaan, mutta ajatus on se että palvelin huomaisi SSL avainmuutoksen ja palvelin ottaisi resetin avulla käyttöön uudet avaimet.

log_clear() kutsu tyhjentää lokin lapsiprosessin alussa (eli fork():in paluuarvolla 0). Kuten mainittu lapsiprosessissa lokiin kirjoitukset kirjoitetaan log_printf():llä, siitä lisää myöhemmin. log_free() vapauttaa lokin puskurialueen.

Fork() suoritetaan yhden kerran, ja se palaa kahdesti, kerran lapsiprosessille paluuarvolla 0 ja kerran vanhempi prosessille, jolloin paluuarvo on lapsen prosessin id.

Jos käynnistät palvelimen $ nohup ./ressu4 –port5006 –https >>ressu4.nohup & -komennolla voit seurata palvelimen kutsuja $ tail *.nohup -f -komennolla.

https_server() kutsuu edellistä asiakasfunktiota.

#define DEBUG59 2

static void https_server()
{
  int quit, reset, addr_size;
  
  SSL_METHOD *method=NULL;
  SSL_CTX *ctx=NULL;

  struct sockaddr_in sa_cli;
  struct addrinfo *res;

  signal(SIGPIPE, SIG_IGN);
  signal(SIGCHLD, SIG_IGN);

  reset=1;
  quit=0;
  
  for(;;) {

    if(quit) {
      if(ctx!=NULL)
	SSL_CTX_free(ctx);
      break;
    }
    if(reset) {
      if(ctx!=NULL)
	SSL_CTX_free(ctx);  

#ifdef DEBUG68
      fprintf(stdout,"SSL_library_init\n");
      fflush(stdout);
#endif

      SSL_library_init();
#ifdef DEBUG68
      fprintf(stdout,"OpenSSL_add_ssl_algorithms\n");
      fflush(stdout);
#endif
      OpenSSL_add_ssl_algorithms();
#ifdef DEBUG68
      fprintf(stdout,"OpenSSL_add_ciphers\n");
      fflush(stdout);
#endif
      OpenSSL_add_all_ciphers();
      
#ifdef DEBUG68
      fprintf(stdout,"OpenSSL_load_error_strings\n");
      fflush(stdout);
#endif
      SSL_load_error_strings();
      
#ifdef DEBUG68
      fprintf(stdout,"SSLv23_server_method\n");
      fflush(stdout);
#endif
      if((method = (SSL_METHOD *)    
	  SSLv23_server_method()) == NULL) {
	fprintf(stderr,"\n%s: cannot SSLv3_server_method()", procname);
	fflush(stderr);
      }
      
#ifdef DEBUG68
      fprintf(stdout,"SSL_CTX_new\n");
      fflush(stdout);
#endif
      if((ctx=SSL_CTX_new(method)) == NULL) {
	fprintf(stderr,"\n%s: cannot SSL_CTX_new()", procname);
	fflush(stderr);
      }
      
#ifdef DEBUG68
      fprintf(stdout,"SSL_CTX_use_certificate_file\n");
      fflush(stdout);
#endif
      if(SSL_CTX_use_certificate_file(ctx,
				      cert_file, SSL_FILETYPE_PEM) <= 0) {
	fprintf(stderr,"\n%s: cannot SSL_CTX_use_certificate()", procname);
	fflush(stderr);
      }
      
#ifdef DEBUG68
      fprintf(stdout,"SSL_CTX_use_PrivateKey_file\n");
      fflush(stdout);
#endif
      if(SSL_CTX_use_PrivateKey_file(ctx,
				     privatekey_file, SSL_FILETYPE_PEM)<=0) {
	fprintf(stderr,"\n%s: cannot SSL_CTX_use_certificate()", procname);
	fflush(stderr);
      }
      
#ifdef DEBUG68
      fprintf(stdout,"SSL_CTX_load_verify_locations\n");
      fflush(stdout);
#endif
      if(!SSL_CTX_load_verify_locations(ctx, 
					cert_file, NULL)) {
	fprintf(stderr,"\n%s: cannot SSL_CTX_verify_locations()", procname);
	fflush(stderr);
      }
      
      server_getaddrinfo(myport, &res);
      s=server_socket(res);
      server_bind(s, res);
      freeaddrinfo(res);
      server_listen(s);

      reset=0;
    } // if(reset)

    fprintf(stdout,"\n");
    fflush(stdout);
    
    addr_size = sizeof(sa_cli);
#ifdef DEBUG68
    fprintf(stdout,"accept\n");
    fflush(stdout);
#endif
    if((news=accept(s, (struct sockaddr *)&sa_cli, &addr_size))==-1) {
      fprintf(stderr,"\n%s: cannot accept()\n", procname);
      perror("accept");
      fflush(stderr);
    }

    if(beepaccept)
      fprintf(stderr,"\a");

    pid_t pid;
#ifdef DEBUG59
    fprintf(stdout,"Fork start (parent)");
    fprintf(stdout," getpid:%d getppid:%d\n",getpid(),getppid()); 
    fflush(stdout);
#endif
    if((pid=fork())==0) {

      log_clear();
      log_printf("==========");
#ifdef DEBUG59
      fprintf(stdout,"Fork start (child)");
      fprintf(stdout," pid:%d getpid:%d getppid:%d\n",pid,getpid(),getppid());
#endif
      close(s);
      https_client(news,ctx,sa_cli,addr_size,"https");
      server_close(news);
      fprintf(stdout,"%s",logbuf);
#ifdef DEBUG59
      fprintf(stdout,"Fork end (child)");
      fprintf(stdout," pid:%d getpid:%d getppid:%d\n",pid,getpid(),getppid());
      fflush(stdout);
#endif
      log_free();
      exit(0);
    }
#ifdef DEBUG59
    fprintf(stdout,"Fork end (parent)");
    fprintf(stdout," pid:%d getpid:%d getppid:%d\n",pid,getpid(),getppid());
    fflush(stdout);
#endif
  } // for(;;)
  SSL_CTX_free(ctx);  
}

Seuraavassa lokin tulostukseen tarkoitetut clear(), free, ja printf rutiinit:

#include <stdarg.h>

unsigned char *logbuf=NULL;
int logbuf_length=0;

void log_clear()
{
  if(logbuf!=NULL)
    logbuf[0]='\0';
}

void log_free()
{
  if(logbuf!=NULL) {
    free(logbuf);
    logbuf=NULL;
  }
}

void log_printf(const char *format, ...)
{
  int count,size;
  va_list args;
  static char *printbuf=NULL;
  static int printbuf_len=0;

  va_start(args,format);
  count=vsnprintf(printbuf, printbuf_len, format, args) + 1;
  va_end(args);
  if(printbuf_len < count) {
    printbuf_len = count;
    printbuf=realloc(printbuf, printbuf_len);
    va_start(args,format);
    count=vsnprintf(printbuf, printbuf_len, format, args) + 1;
    va_end(args);
  }
  if(logbuf==NULL ||
     logbuf_length<(size=(logbuf==NULL? 0:strlen(logbuf))+count)) {
    unsigned char *temp=logbuf;
    logbuf_length=size;
    logbuf=realloc(logbuf,size);
    if(temp==NULL)
      logbuf[0]='\0';
  }
  strcat(logbuf,printbuf);
}

Seuraavassa satunnaislukuohjelma joka on osoitteessa https://moijari.com:5006. Tietenkin siellä on myös nämä muut postissa mainitut osuudet. Ja kuten aina lopussa on kopipastattavat sorsat.

Ohjelma ajaa skriptin joka sisältää html rivejä ja /bin/newressu komentoja. Jos scriptiä ei ole, sellainen luodaan. Scriptin luonnissa se kirjoitetaan tiedostoon ressu4script.html. Jos ajat palvelinta, muuta scripti haluamaksesi.

Varsinaisessa palvelimessa scripti käydään rivi riviltä läpi, ja suoritetaan “/bin/newressu ” alkuiset rivit. Loput rivit tulostetaan sellaisenaan. Jos lisäät palvelimeen komentoja, komennon nimi kannattaa varmaankin kovakoodata kuten tässä “/bin/newressu”.

Puolipisteellä alkavat rivit ohitetaan kommentteina. Funktiolla popen() suoritetaan newressu-komento parametreineen ja saadaan fp2 tiedostohandle, josta voidaan lukea newressun tulostamat rivit.

ressuoriginal.html sisältää html-scriptin joka tulostaa sivun lopun linkit.

#define aDEBUG8

void ressu4_app()
{
  unsigned char *p;
  unsigned char command[128];
  unsigned char buffer[1024];
  unsigned char script_file[128]="ressu4script.html";
  FILE *fp1,*fp2;
  
  if((fp1=fopen(script_file,"r"))!=NULL) {
    fclose(fp1);
  } else {
    if((fp1=fopen(script_file,"w"))!=NULL) {

      fprintf(fp1,";\n");
      fprintf(fp1,"; Script for ressu4 ©\n");
      fprintf(fp1,";\n");
      fprintf(fp1,"<h1>%s</h1>\n",procheader);
      fprintf(fp1,";\n");
      fprintf(fp1,"<p>The next chapter consists of characters that\n");
      fprintf(fp1," try to resemble throws of a 64 sided dice as closely as possible.\n");
      fprintf(fp1," Characters have numbers from '0' to '9' (10 entries),\n");
      fprintf(fp1," uppercase letters from 'A' to 'Z' (26 entries), lowercase letters\n");
      fprintf(fp1," 'a' to 'z' (26 entries), '-' and '_' (2 entries).\n");
      fprintf(fp1," Total is 10+26+26+2 = 64 values.\n");
      fprintf(fp1," Characters are grouped into sets of 8 each. Throws\n");
      fprintf(fp1," are random, so you cannot deduce value from\n");
      fprintf(fp1," previous or next value(s).</p>\n");
      fprintf(fp1,"<h3>Newressu random numbers</h3>\n");
      fprintf(fp1,"/bin/newressu -2 -s8 -l1 -c5120 --space --lineno\n");
      fprintf(fp1,";\n");
      fprintf(fp1,"<h3>Random digits</h3>\n");
      fprintf(fp1,"/bin/newressu -11 -s8 -l1 -c1792 --space --lineno\n");
      fprintf(fp1,";\n");
      fprintf(fp1,"<h3>Random uppercase letters</h3>\n");
      fprintf(fp1,"/bin/newressu -12 -s8 -l1 -c1792 --space --lineno\n");
      fprintf(fp1,";\n");
      fprintf(fp1,"<h3>Random lowercase letters</h3>\n");
      fprintf(fp1,"/bin/newressu -13 -s8 -l1 -c1792 --space --lineno\n");
      fprintf(fp1,";\n");
      fprintf(fp1,"<h2>Random characters in number systems</h2>\n");
      fprintf(fp1,";\n");
      fprintf(fp1,"<h3>Random binary digits</h3>\n");
      fprintf(fp1,"<p>Following binary numbers are eight bits from 0 to 255 decimal.\n");
      fprintf(fp1," From right to left the bit multipliers are 1, 2, 4, 8, 16, 32, 64 and 128 (2^b) in decimal.\n");
      fprintf(fp1," So 10000000b is 128d, 11111111b is 255d, 00000010b is 2d, 00000011b is 3d etc.\n");
      fprintf(fp1," Here d after number means of course decimal. Digit numbers, b in 2^b, vary from 0 to 7.</p>\n");
      fprintf(fp1,"/bin/newressu -b -s8 -l1 -c1792 --space --lineno\n");
      fprintf(fp1,";\n");
      fprintf(fp1,"<h3>Random octal digits</h3>\n");
      fprintf(fp1,"<p>These octal numbers are also from 0 to 255 decimal (0 to 377 octal).\n");
      fprintf(fp1," From right to left octal digit multipliers are 1, 8, 64 (8^o) in decimal.\n");
      fprintf(fp1," Here 377o is 255d, 010o is 8d, 100o is 64d.\n");
      fprintf(fp1," Each octal digit contains 3 binary bits, and 377o can be grouped\n");
      fprintf(fp1," in binary like this 011 111 111.</p>\n");
      fprintf(fp1,"/bin/newressu -o --lim400 -l1 -c1792 --lineno\n");
      fprintf(fp1,";\n");
      fprintf(fp1,"<h3>Random decimal digits</h3>\n");
      fprintf(fp1,"<p>These decimal numbers are from 0 to 99999. From right\n");
      fprintf(fp1," to left decimal digit multipliers are 1, 10, 100, 1000 and 10000 (10^d).</p>\n");
      fprintf(fp1,"/bin/newressu -d -s5 -l1 -c1792 --space --lineno\n");
      fprintf(fp1,";\n");
      fprintf(fp1,"<h3>Random hexadecimal digits</h3>\n");
      fprintf(fp1,"<p>Next hexadecimal numbers are from 0000h to ffffh meaning 0 to 65535 decimal.\n");
      fprintf(fp1," Hexadecimal digit has numbers from 0 to 9 and letters a(10),\n");
      fprintf(fp1," b(11), c(12), d(13), e(14) and f(15). From right to left hexadecimal multipliers\n");
      fprintf(fp1," are 1, 16, 256, 4096 decimal (16^h). Each hexadecimal digit contains 4 bits so ffffh can be\n");
      fprintf(fp1," grouped in binary like this 1111 1111 1111 1111.</p>\n");
      fprintf(fp1,"/bin/newressu -x -s4 -l1 -c1792 --space --lineno\n");
      fprintf(fp1,";\n");
      fprintf(fp1,"<h2>Random characters in languages</h2>\n");
      fprintf(fp1,";\n");
      fprintf(fp1,"<p>The next chapters consists of random characters in various\n");
      fprintf(fp1," languages. Most randomness is in chinese, japanese and\n");
      fprintf(fp1," korean characters. Chinese has 20976 values per character,\n");
      fprintf(fp1," japanese has 21158 values per character and korean has\n");
      fprintf(fp1," 11172 values per character.</p>\n");
      fprintf(fp1,"<p>Latin (or roman) based alphabets have characters as follows:\n");
      fprintf(fp1," danish alphabet has 58 characters,\n");
      fprintf(fp1," deutsch alphabet has 60 characters,\n");
      fprintf(fp1," english has 52 characters,\n");
      fprintf(fp1," estonian has 64 characters,\n");
      fprintf(fp1," finnish alphabet has 58 characters,\n");
      fprintf(fp1," french character set has 52 characters,\n");
      fprintf(fp1," italian character set has 52 characters,\n");
      fprintf(fp1," latvian has 66 characters,\n");
      fprintf(fp1," lithuanian has 64 characters,\n");
      fprintf(fp1," norwegian has 58 characters,\n");
      fprintf(fp1," swedish has 58 characters.\n");
      fprintf(fp1," </p>\n");
      fprintf(fp1,";\n");
      fprintf(fp1,"<h3>Chinese random characters</h3>\n");
      fprintf(fp1,"/bin/newressu --cn -s8 -l1 -c1792 --lineno\n");
      fprintf(fp1,";\n");
      fprintf(fp1,"<h3>Danish random characters</h3>\n");
      fprintf(fp1,";ABCDEFGHIJKLMNOPQRSTUVWXYZÆØÅ\n");
      fprintf(fp1,";abcdefghijklmnopqrstuvwxyzæøå\n");
      fprintf(fp1,"/bin/newressu --dnk -s8 -l1 -c1792 --space --lineno\n");
      fprintf(fp1,";\n");
      fprintf(fp1,"<h3>Deutsch random characters</h3>\n");
      fprintf(fp1,";ABCDEFGHIJKLMNOPQRSTUVWXYZÄÖÜẞ\n");
      fprintf(fp1,";abcdefghijklmnopqrstuvwxyzäöüß\n");
      fprintf(fp1,"/bin/newressu --deu -s8 -l1 -c1792 --space --lineno\n");
      fprintf(fp1,";\n");
      fprintf(fp1,"<h3>English random characters</h3>\n");
      fprintf(fp1,";ABCDEFGHIJKLMNOPQRSTUVWXYZ\n");
      fprintf(fp1,";abcdefghijklmnopqrstuvwxyz\n");
      fprintf(fp1,"/bin/newressu --eng -s8 -l1 -c1792 --space --lineno\n");
      fprintf(fp1,";\n");
      fprintf(fp1,"<h3>Estonian random characters</h3>\n");
      fprintf(fp1,";ABCDEFGHIJKLMNOPQRSŠZŽTUVWÕÄÖÜXY\n");
      fprintf(fp1,";abcdefghijklmnopqrsšzžtuvwõäöüxy\n");
      fprintf(fp1,"/bin/newressu --est -s8 -l1 -c1792 --space --lineno\n");
      fprintf(fp1,";\n");
      fprintf(fp1,"<h3>Finnish random characters</h3>\n");
      fprintf(fp1,";ABCDEFGHIJKLMNOPQRSTUVWXYZÅÄÖ\n");
      fprintf(fp1,";abcdefghijklmnopqrstuvwxyzåäö\n");
      fprintf(fp1,"/bin/newressu --fin -s8 -l1 -c1792 --space --lineno\n");
      fprintf(fp1,";\n");
      fprintf(fp1,"<h3>French random characters</h3>\n");
      fprintf(fp1,";ABCDEFGHIJKLMNOPQRSTUVWXYZ\n");
      fprintf(fp1,";abcdefghijklmnopqrstuvwxyz\n");
      fprintf(fp1,"/bin/newressu --fra -s8 -l1 -c1792 --space --lineno\n");
      fprintf(fp1,";\n");
      fprintf(fp1,"<h3>Gothic random characters</h3>\n");
      fprintf(fp1,"/bin/newressu --got -s8 -l1 -c1792 --space --lineno\n");
      fprintf(fp1,";\n");
      fprintf(fp1,"<h3>Greek random characters</h3>\n");
      fprintf(fp1,";ΑΒΓΔΕΖΗΘΙΚΛΜΝΞΟΠΡΣΤΥΦΧΨΩ\n");
      fprintf(fp1,";αβγδεζηθικλμνξοπρστυφχψω\n");
      fprintf(fp1,"/bin/newressu --grc -s8 -l1 -c1792 --space --lineno\n");
      fprintf(fp1,";\n");
      fprintf(fp1,"<h3>Italian random characters</h3>\n");
      fprintf(fp1,";ABCDEFGHIJKLMNOPQRSTUVWXYZ\n");
      fprintf(fp1,";abcdefghijklmnopqrstuvwxyz\n");
      fprintf(fp1,"/bin/newressu --ita -s8 -l1 -c1792 --space --lineno\n");
      fprintf(fp1,";\n");
      fprintf(fp1,"<h3>Japanese random characters</h3>\n");
      fprintf(fp1,"/bin/newressu --jp -s8 -l1 -c1792 --lineno\n");
      fprintf(fp1,";\n");
      fprintf(fp1,"<h3>Korean random characters</h3>\n");
      fprintf(fp1,"/bin/newressu --kor -s8 -l1 -c1792 --lineno\n");
      fprintf(fp1,";\n");
      fprintf(fp1,"<h3>Latvian random characters</h3>\n");
      fprintf(fp1,";AĀBCČDEĒFGĢHIĪJKĶLĻMNŅOPRSŠTUŪVZŽ\n");
      fprintf(fp1,";aābcčdeēfgģhiījkķlļmnņoprsštuūvzž\n");
      fprintf(fp1,"/bin/newressu --lva -s8 -l1 -c1792 --space --lineno\n");
      fprintf(fp1,";\n");
      fprintf(fp1,"<h3>Lithuanian random characters</h3>\n");
      fprintf(fp1,";AĄBCČDEĘĖFGHIĮYJKLMNOPRSŠTUŲŪVZŽ\n");
      fprintf(fp1,";aąbcčdeęėfghiįyjklmnoprsštuųūvzž\n");
      fprintf(fp1,"/bin/newressu --ltu -s8 -l1 -c1792 --space --lineno\n");
      fprintf(fp1,";\n");
      fprintf(fp1,"<h3>Norwegian random characters</h3>\n");
      fprintf(fp1,";ABCDEFGHIJKLMNOPQRSTUVWXYZÆØÅ\n");
      fprintf(fp1,";abcdefghijklmnopqrstuvwxyzæøå\n");
      fprintf(fp1,"/bin/newressu --nor -s8 -l1 -c1792 --space --lineno\n");
      fprintf(fp1,";\n");
      fprintf(fp1,"<h3>Russian random characters</h3>\n");
      fprintf(fp1,";АБВГДЕЁЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯ\n");
      fprintf(fp1,";абвгдеёжзийклмнопрстуфхцчшщъыьэюя\n");
      fprintf(fp1,"/bin/newressu --rus -s8 -l1 -c1792 --space --lineno\n");
      fprintf(fp1,";\n");
      fprintf(fp1,"<h3>Swedish random characters</h3>\n");
      fprintf(fp1,";ABCDEFGHIJKLMNOPQRSTUVWXYZÅÄÖ\n");
      fprintf(fp1,";abcdefghijklmnopqrstuvwxyzåäö\n");
      fprintf(fp1,"/bin/newressu --swe -s8 -l1 -c1792 --space --lineno\n");
      fprintf(fp1,";\n");
      fprintf(fp1,"<h2>Technical</h2>\n");
      fprintf(fp1,"<p>This version runs newressu new for all of the previous\n");
      fprintf(fp1," random number chapters (25 runs), so the buffer is empty in\n");
      fprintf(fp1," the beginning of the chapter runs.\n");
      fprintf(fp1," This whole page is created (including randomness) after your\n");
      fprintf(fp1," network query is received,\n");
      fprintf(fp1," so time newressu runs is quite reasonable.</p>\n");
      fprintf(fp1,"<p>This version does random skips on clock material,\n");
      fprintf(fp1," which makes it harder to guess it. Ressu skips\n");
      fprintf(fp1," 0-255 bytes every ~1000 bytes.\n");
      fprintf(fp1," This version also is ressu only, there is no whitening\n");
      fprintf(fp1," or combining of other generators.</p>\n");
      fclose(fp1);
    }
  } // if((fp1=fopen
  if((fp1=fopen(script_file,"r"))!=NULL) {    
    while(fgets(command,sizeof(command),fp1)!=NULL) {
      if(command[0]==';')
	continue;
      else if(!strncmp(command,"/bin/newressu ",14)) {
	if((fp2=popen(command, "r"))!=NULL) {
	  dbs_html_printf("<code>");
	  while(fgets(buffer,sizeof(buffer),fp2)!=NULL) {
#ifdef DEBUG8
	    fprintf(stdout,"\"%s\"",buffer);
#endif
	    p=buffer;
	    while(*p!='\0') {
	      if(*p!='-') 
		dbs_html_printf("%c",*p);
	      else {
		if(safari)
		  dbs_html_printf("&#8209;");
		//dbs_html_printf("&minus;");
		//dbs_html_printf("&ndash;");
		//dbs_html_printf("&hyphen;");
		//dbs_html_printf("&#45;");
		else
		  dbs_html_printf("&minus;");
	      }
	      p++;
	    } // while(*p!='\0') {
	    //dbs_html_printf(" ");
	    //dbs_html_printf("\n");
	    //dbs_html_printf("<br>");
	  } // while(fgets(
	  dbs_html_printf("</code>");
	  fclose(fp2);
	} // if((fp2
      } else { // if(!strncmp(command
	if(useragent)
	  dbs_html_printf("%s",command);
	else if(strstr(command,"<h1>")!=NULL ||
		strstr(command,"<h2>")!=NULL ||
		strstr(command,"<h3>")!=NULL ||
		strstr(command,"<h4>")!=NULL )
	  dbs_html_printf("%s",command);
      } // if(strncmp
    } // while(fgets
    fclose(fp1);
  } // if((fp1=fopen
  if((fp1=fopen("ressuoriginal.html","r"))!=NULL) {
    while(fgets(buffer,sizeof(buffer),fp1)!=NULL)
      if(buffer[0]!=';')
	dbs_html_printf("%s",buffer);
    fclose(fp1);
  }
}

Seuraavassa palvelimen kutsumat ressu4 funktiot: dbs_html_set valitsee puskurin, johon rivit tulostetaan tässä otsake(0) tai payload(1) (html.c). dba_loop tulostaa html sivun, dba_loop2 laskee sivun merkkien lukumäärän (Content-Length) otsakkeelle. Näiden välissä palvelin suorittaa html prettyprinter:in josta myöhemmin.

void dba_loop()
{
  html_clear_all();
  if(!strcmp(htmlfileextension,"ico") ||
     !strcmp(htmlfileextension,"png")) {
    dbs_html_set(0);
    dbs_html_printf("HTTP/1.0 404 Not Found\r\n");
    //dbs_html_printf("Location: \r\n");
    //dbs_html_printf("Server: %s\r\n", programname);
  } else {  
    dbs_html_set(0);
    dbs_html_printf("HTTP/1.0 200 OK\r\n");
    dbs_html_printf("Location: \r\n");
    dbs_html_printf("Server: %s\r\n", programname);
    dbs_html_printf("Date: %s\r\n", htmltime);
    
    dbs_html_set(1);
    
    dbs_html_printf("<!doctype html>\r\n");
    dbs_html_printf("<html lang=\"fi\">");
    
    dbs_html_printf("<head>");
    dbs_html_printf("<meta charset=\"utf-8\">");
    dbs_html_printf("<title>%s</title>",proctitle);
    dbs_html_printf("<meta name=\"author\" content=\"Jari Kuivaniemi\">");
    dbs_html_printf("<meta name=\"copyright\" content=\"Jari Kuivaniemi\">");
    dbs_html_printf("<meta name=\"format-detection\" content=\"telephone=no\">"); // Safari
    dbs_html_printf("<meta name=\"format-detection\" content=\"telephone=no\"/>"); // Safari
    dbs_html_printf("<meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">");
    dbs_html_printf("</head>");
    
    dbs_html_printf("<body>");
    
    ressu4_app();

    dbs_html_printf("<p>%s", programname);
    dbs_html_printf(",  sha256(%s)", htmldigest);
    dbs_html_printf("</p>");

    dbs_html_printf("</body>");
  
    dbs_html_printf("</html>");
  }
}

Prettyprinter formatoi html scriptin uudestaan, ja tällöin payload puskurin pituus muuttuu. Content-Length lasketaan vasta prettyprinter:in jälkeen: Lisäksi tulostetaan otsakkeen ja payloadin välillä oleva cr-lf-cr-lf sarja.

Content-Length riville lasketaan kaikki muut puskurit paitsi 0 eli otsake.

void dba_loop2()
{
  int len;

  dbs_html_set(0);

  len=strlen(html_get_string(1)) +
    strlen(html_get_string(2)) +
    strlen(html_get_string(3)) +
    strlen(html_get_string(4)) +
    strlen(html_get_string(5)) +
    strlen(html_get_string(6)) +
    strlen(html_get_string(7)) +
    strlen(html_get_string(8));
  log_printf("Content-Length: %d\n",len);
  dbs_html_printf("Content-Length: %d", len);
  dbs_html_printf("\r\n\r\n");
}

Tämä on klassinen joka ohjelmaan kuuluva write only pätkä. Se käy asiakas-ohjelman muodostaman html-scriptin läpi, ja muotoilee sen lisäten sisennykset. Ohjelmassa on iso iffi, jossa on erilaiset käsittelyt alkutagille, lopputagille ja teksteille. Ennen koodia muotoiltu html-scripti:

<!doctype html>
<html lang="fi">
	<head>
		<meta charset="utf-8">
		<title>Ressu random numbers</title>
		<meta name="author" content="Jari Kuivaniemi">
		<meta name="copyright" content="Jari Kuivaniemi">
		<meta name="format-detection" content="telephone=no">
		<meta name="format-detection" content="telephone=no"/>
		<meta name="viewport" content="width=device-width, initial-scale=1.0">
	</head>
	<body>
		<h1>Ressu random numbers (3rd edition)</h1>
		<p>The next chapter consists of characters that try to resemble throws of a 64 sided dice as closely
		as possible. Characters have numbers from '0' to '9' (10 entries), uppercase letters from 'A' to 'Z'
		(26 entries), lowercase letters 'a' to 'z' (26 entries), '-' and '_' (2 entries). Total is
		10+26+26+2 = 64 values. Characters are grouped into sets of 8 each. Throws are random, so you cannot
		deduce value from previous or next value(s).</p>
		<h3>Newressu random numbers</h3>
		<code>_&minus;MnnU0t zMILwAzz _2QvgUvn ZiTlUvUa NFQ8SAWH Y16F&minus;WfQ SuNISxyL pcfa1veB
		SwY&minus;Sv_s nGU8zPEL eEJXLzHh CM88ViFN dQOdn8G2 NlGtAMYI iGpPs7SH bzRse_PQ CZ0qnLpd
		cARyjtSX 0WAhwrf&minus; i0kNx3W2 9Z6Acz5q 8Ik0hsxy fHHT1jRD XXbwNO4_ AsIbJD7O MSiJX&minus;wv
		bDkAVVcu r9PHGcS0 IzCtSytI g8E565wO GyPga1LE 4aud&minus;VdS RHJDDQL&minus; CLd4oo4L oX9evdxW
...
		kLq1ipRv gAx50HPh DmYWlnC6 YE3cFz6n SUXaGxNO VomWkvak PCIi0TZ0 &minus;Aji6Ic_ o97UH&minus;cf
		c&minus;bcT66x DBJZfuyP 0DInhV72 h3tg10Ut EemFvFM2 Vgqb7dTT rRu5cieb d525p4Mt P7dl5NK&minus;
		gz6nADAr b3NmlG2p yX6J2GiL 3_aQPB&minus;F 2btVCtEI IVFKckK9 Z5Td_Efe IytGwbob kHZoXbOC
		xVRHgtq7</code>
		<h3>Random digits</h3>
		<code>80313684 35745972 00745113 11965506 39675183 31627471 96260247 63282566 20584179
		75300052 77578427 13585911 50498322 42744053 50358954 49905271 58259581 03942398 26828764
		04379099 26025983 87357515 02820498 26270068 02318240 95638924 41550156 07366984 73725656
		95465312 57023555 71860218 26527096 64829893 47562651 26652479 99838964 11307190 84028643
...
		43822905 45192876 80902045 91287056 62271398 18354252 09842608 58491390 36494150 06737249
		79097332 78982704 51002048 98004383 30727141 69582220 67771805 16857046 37252823 02127291
		75806553 92973387 12285285 12582540 79234018 40546782 14578681 84859328 04505090 18357251
		99180783 65733520 48631827 20279470 04679868 94102024 34890821 98137030 73108089 41263404</code>
		<h3>Random uppercase letters</h3>
		<code>AUBQMVVZ IDBFUNFU EWSQJXLI PESJYIUG RJKITODE IDWXMVAG KDEIQBJV YWVBTERK KXNHHMRD
		JTDHVEQW VQUNSMSX JERKHYVQ WATLYHIM HOXBQRSX AWZEBOMC IURFFOEZ NICWPOBT YLHFCFFK LNYDTXXE
		GVRVMCFM JZWLHOZF GDOYZIPU QARHVPHO PEAEHOIJ LWSAJEPN UWOAICBV OEZUEKYD PTCVQCUM EDLYCDOQ
		RAANTTVG TTXVXNFM NZOLDAJS FTWIFKFE UUTDBSRA DAJGRZCY VDPVBAVM SYLLMMRQ MLAMPJOJ ZLPEMKSE
		ISYDWSBF DHQMLMBM IUWRCHAZ KEZTQHWT NSFCBRDJ IVYCEYHG BRBJZOIP GRDHFPHE MALPLXHN SHPGMKIB
...
		CLLLBWQV BBNZRWXD HUWJBBJR WEJYWLIJ NAJODNVH JRVLIWTY OGLLYFSF JRPMMCSY JLFJKQTO YUOZUKUM
		WMGKGWET SRFZZGFK WSHLWUPX RKALRMFV XBHHHTTF GJNXCHAY FWCDAGCI BRGYQJKD XNTHBNUY YOLWRYCK
		MCLIUAKU WERPDLSD WBFPJWGQ EUTNUJII VAJOLVPV ATVOVPQT PFUCXWZL JXYGYXOG EXMYXKYT EPOZVXFZ
		WTHXVPUF OMMTIXXE BVNYVSVB MLZHOZNT NGZGYCRN SDBVJUEJ CCUCJBEF GZBFSXET PRRRMSBI PVBSQKKQ</code>
		<h3>Random lowercase letters</h3>
		<code>ncdxfqnc aouweehi hamohwtd rhccumkp zvsxtkbm kmkncixk poucraok gvgxnqmt xjddvykh
		kqackiak krojmfsn gjgonlio sptakqqu jzzwsqmw bvkexphf exujzvtl moraehkn snthsdwb yvpcptom
		roifedpi wzglxgvq rcuwbbje qbbohgvy pxqxsnmu mccldckk idcwlths vnfgeeaz xjnhwxyq gbuscedb
		zowriyfe pjbqeoad hrqynigj vhrjlyui iokaxxmo zafimxzv pdjgldxs ocmaljlz mjbvdofr bhwudqkg
		zzjgygoz fjhrqyru nwuivcqy vyfjsmzy xxznieam omzgczbu gcxppsqv azpworcc hbyyjcga hinulxnt
...
		mjoxwldd aczipohr diltdgol olrccnqg nkmxjieo ttyxznjf zqzteonk inalvyvq esystahu zeesrmdv
		pbdazwoy bkivauss tkvnizfk rwtsdsny otcdoaxv ttoewgtf utjkaqpc vqcbedri gluifwmx sevbupal
		gowmzyia ruwvzzrg uqgmskzv onwwurib fwwginyp dklxxfwf hywmhqlc cyyfyenb hddfngsw zybqvptd
		dwaixegk drrwmccs vouyjvwb spfxctdn onyjwcap zprretng ccemcduj lnrngwpj rsrqpucm onbeixhh</code>
		<h2>Random characters in number systems</h2>
		<h3>Random binary digits</h3>
		<p>Following binary numbers are eight bits from 0 to 255 decimal. From right to left the bit
		multipliers are 1, 2, 4, 8, 16, 32, 64 and 128 (2^b) in decimal. So 10000000b is 128d, 11111111b is
		255d, 00000010b is 2d, 00000011b is 3d etc. Here d after number means of course decimal. Digit
		numbers, b in 2^b, vary from 0 to 7.</p>
		<code>10000100 10001011 00000101 01010110 10111101 01001011 01001010 01111100 10010111
		11010010 11110111 11011111 00001100 10110101 10010110 11100011 01010001 10000101 00010010
		10111111 10010101 01100011 01110110 10101010 01001100 10100011 11101101 00001011 10110011
		10100001 11011101 10000000 10100100 01000010 11001000 11101110 00100000 00000010 01111000
...
		10100011 11001000 01101010 11101001 10011001 10110010 11011110 11110001 11010110 00011000
		01000100 00010011 00100100 01100010 11100110 01011101 10000110 10111000 11010110 11001111
		01111101 10001000 00010110 11011010 10011101 11111001 01101011 00111011 00111111 10000111
		11010111 11110010 10001110 11100011 11101010 00101111 01100101 11100110 10111100 11010011</code>
		<h3>Random octal digits</h3>
		<p>These octal numbers are also from 0 to 255 decimal (0 to 377 octal). From right to left octal digit
		multipliers are 1, 8, 64 (8^o) in decimal. Here 377o is 255d, 010o is 8d, 100o is 64d. Each octal digit
		contains 3 binary bits, and 377o can be grouped in binary like this 011 111 111.</p>
		<code>102 025 024 061 277 033 242 213 004 334 107 102 144 367 150 247 237 016 217 134 042 370 267 162 175 301
		230 373 125 115 272 123 014 026 112 351 047 132 252 326 053 344 073 364 174 017 150 324 326 040 224 231 165 173
		143 011 160 175 143 010 021 136 076 017 231 164 135 167 313 021 245 230 300 234 314 267 150 271 367 352 042 177
		125 070 337 074 061 342 117 353 176 331 372 100 152 110 012 340 016 362 161 322 323 032 227 061 047 215 006 216
		003 157 212 001 005 375 326 125 227 154 354 345 063 214 263 120 257 255 037 276 305 234 214 137 277 075 134 267
...
		011 343 304 205 146 152 276 223 110 115 334 250 115 173 027 371 376 317 133 234 107 352 053 155 212 044 032 253
		323 127 347 231 066 011 026 366 102 260 227 344 231 153 044 371 115 264 352 237 330 071 322 156 173 307 133 065
		066 245 275 270 321 145 222 036 140 060 362 077 270 166 330 117 173 017 223 066 170 304 063 221 036 223 165 073
		357 066 353 334 116 025 201 360 321 200 073 020 077 156 141 162 011 126 157 344 111 240 164 315 122 252 137 244
		072 015</code>
		<h3>Random decimal digits</h3>
		<p>These decimal numbers are from 0 to 99999. From right to left decimal digit multipliers are 1, 10,
		100, 1000 and 10000 (10^d).</p>
		<code>24419 31184 02393 04466 14613 16133 79118 27250 72887 08069 71932 68501 99089 75389 78600
		27515 57258 86941 81577 34050 41156 02253 30409 02904 90536 95086 10717 44661 01654 28649 86938
		26666 79745 87626 91850 86989 19827 11135 23508 12355 64724 04439 52568 63139 02473 05829 50914
		32411 25782 02409 28444 63704 68532 86493 85871 00441 49962 73554 67031 15180 33919 12141 79904
...
		38024 67921 62186 26159 42438 04270 78192 54364 96314 96670 15650 08550 35165 55312 71523 22212
		72163 37309 41644 68769 28343 04812 81462 73380 88334 07695 95749 74636 93787 97867 26227 76150
		78417 48706 88812 68138 53680 08453 31168 40950 14859 98299 53943 96364 12848 63945 66586 98180
		15320 25092 79344 35777 71710 10193 88538 72530 37765 40684 49186 99440 96100 79970 63910 57759
		00684 63359 12128 10759 83732 87712 36846 03493 36866 61989 50384</code>
...
		<h2>Technical</h2>
		<p>This version runs newressu new for all of the previous random number chapters (25 runs), so the
		buffer is empty in the beginning of the chapter runs. This whole page is created (including
		randomness) after your network query is received, so time newressu runs is quite reasonable.</p>
		<p>This version does random skips on clock material, which makes it harder to guess it. Ressu skips
		0-255 bytes every ~1000 bytes. This version also is ressu only, there is no whitening or combining of
		other generators.</p>
		<p>Original url(s):<br>
			ressu:
			<a href="https://moijari.com:5006">https://moijari.com:5006</a>(third edition)<br>
			ressu:
			<a href="https://moijari.com:5005">https://moijari.com:5005</a>(second
			edition)<br>
			ressu:
			<a href="https://moijari.com:5001">https://moijari.com:5001</a>(first edition)<br>
			terttu:
			<a href="https://moijari.com:5004">https://moijari.com:5004</a>
		</p>
		<p>Ressu4 version 0.2 ©,
		sha256(1b1c265ad48cefcdc43032f475775ab3ef68f2348e24f94f3282dce5e1e89e40)</p>
	</body>
</html>

Here is prettyprinter code:

#define aDEBUG36 2
#define aDEBUG37 2

void html_indent(unsigned char *p2)
{
  int space, ch, tags, tagfound, intag, inchar;
  unsigned char *p,*q,*q2,name[32],tag[48];

  p=p2;
  ch=0;
  indent=0;
  inchar=0;
  while(*p!='\0') {
    space = 0;
    while(*p=='\r' || *p=='\n' || *p=='\t' || *p==' ') {
      p++;
      space = 1;
    }
    if(!strncmp(p,"<br>",4)) {
      p+=4;
      html_printf("<br>");
#ifdef DEBUG36
      fprintf(stdout,"<br>");
#endif
      printedchars+=4;
      
      while(*p=='\r' || *p=='\n' || *p=='\t' || *p==' ')
	p++;
#ifdef DEBUG36
      fprintf(stdout,"[nextchar:%c]",*p);
#endif
      if(strncmp(p,"</",2))
	html_out_crlf();
    }

    if(!strncmp(p,"</",2)) { // Check for end tag

      q2 = p;
      p += 2;
      q = p;
      html_parse_name(sizeof(name), name, &q);
      q = q2 - 1;
      tags = 0;
      tagfound = 0;

      // Search for start tag backward
      sprintf(tag,"<%s", name);
      while(q >= p2) {
        if(*q == '<') {
          if(!strncmp(tag, q, strlen(tag))) {
#ifdef DEBUG36    
            fprintf(stdout,"[tag:%s]", tag);
#endif
            tagfound = 1;
            break;
          } else
            tags++;
        }
        q--;
      }
      if(tags && indent > 0) {
        indent--;
#ifdef DEBUG36
        fprintf(stdout,"[indent:%d]",indent);
        fprintf(stdout,"[tagfound:%d]",tagfound);
#endif
        html_out_crlf();
      }
      html_printf("</");
#ifdef DEBUG36
      fprintf(stdout,"</");
#endif
      space = 0;
      intag = 1;
      inchar = 0;
#ifdef DEBUG36
      fprintf(stdout,"[inchar:%d]",inchar);
#endif
      printedchars+=2;

    } else if(*p=='<') { // Check for start tag

      p++;
      q = p;
      html_parse_name(sizeof(name),name,&q);
      tags = 0;
      tagfound = 0;

      // Search for end tag forward
      sprintf(tag,"</%s",name);
      while(*q!='\0') {
        if(*q=='<') {
          if(!strncmp(tag, q, strlen(tag))) {
#ifdef DEBUG36
            fprintf(stdout,"[tag:%s]",tag);
#endif
            tagfound = 1;
            break;
          } else
            tags++;
        }
        q++;
      }
      html_out_crlf();
      if(tags && tagfound) {
        indent++;
#ifdef DEBUG36
        fprintf(stdout,"[indent:%d]",indent);
        fprintf(stdout,"[tagfound:%d]",tagfound);
#endif
      }
      html_printf("<");
#ifdef DEBUG36
      fprintf(stdout,"<");
#endif
      space = 0;
      intag = 1;
      inchar = 0;
#ifdef DEBUG36
      fprintf(stdout,"[inchar:%d]",inchar);
#endif
      printedchars++;
    } else if((isprint(*p) || *p>=128) && *p!='\0') {
      if(!inchar && !intag) {
	inchar=1;
#ifdef DEBUG36
	fprintf(stdout,"[inchar:%d]",inchar);
#endif
	//html_out_crlf();
      }
      int count=0;
      for(q=p;(isprint(*q) || *q>=128) && *q!='\0';q++) {
	if(*q=='\r' || *q=='\n' || *q=='\t' || *q==' ')
	  break;
#ifdef DEBUG36
	fprintf(stdout,"%c",*q);
#endif
	count++;
      }
#ifdef DEBUG36
      fprintf(stdout,"(%d)",count);
#endif
    }

    int chars = 0;

    // calculate number of chars
    q = p;
    while((*q!='<' && (isprint(*q) || *q>=128)) && *q!='\0') {
      if(*q=='\r' || *q=='\n' || *q=='\t' || *q==' ')
        break;
      if(*q<0x80 || *q>0xbf) // utf8 too
        chars++;
      if(*q=='>')
	break;
      q++;
    }

    // print line break if needed
    if(indent*8+printedchars+chars > 100 && !intag) {
      html_out_crlf(); // print nl+indent
      space = 0;
    }
    
    // print space if needed
    if(ch != '>' && // no space after tag
       *p != '<' && // no space before tag
       printedchars > 0 &&
       space) {
      html_printf(" ");
#ifdef DEBUG36
      fprintf(stdout," ");
#endif
      space = 0;
    }

    //print the string
    while((*p != '<' && (isprint(*p) || *p >= 128)) && *p != '\0') {
      if(*p == '>') {
        intag = 0;
      }
      if(*p == '\r' || *p == '\n' || *p == '\t' || *p == ' ')
        break;
      ch = *p;
      html_printf("%c", *p);
#ifdef DEBUG36
      fprintf(stdout,"%c",*p);
#endif
      printedchars++;
      if(*p=='>') {
	p++;
	break;
      }
      p++;
    }
#ifdef DEBUG36
    fprintf(stdout,"(%d)",chars);
#endif
  } //while(*p!='\0')
#ifdef DEBUG37
  fprintf(stdout,"%s",html[html_now]);
#endif
}

Asiakas palvelin kutsuu newressu komentoa saadakseen satunnaisbittejä. Seuraavassa newressun päämuutos, eli satunnaisten bittien ohitus kellojonossa:

Ohituksen (skip) satunnaisuutta ei tietenkään voi ottaa puskurista, koska silloin se ei vaikuttaisi ollenkaan kahteen samalla kellojonolla tehtyyn ajoon. Tässä sitä varten lasketaan puskurimerkin numero, jolla varsinainen 8 bittinen satunnaismerkki luetaan puskurista. Puskurimerkin numeroon lasketaan muunmuassa kellon sekunnit (katso koodi).

#define MORESECURE 2
#define aDEBUG3 2

static unsigned char ressu_clockbyte() /* JariK 2013 */
{
  unsigned char ch;

  ch=ressu_clockbyte2();
  
#ifdef MORESECURE
  static unsigned int rndbits2pausecount=1000, rndbits2pausebase=0;
  
  if(--rndbits2pausecount == 0) {
#ifdef FORT
    if(input == INPUT_FORT ||
       input == INPUT_FORTXOR)
      rndbits2pausebase += cvar[0] + 256 * cvar[1];
#endif    
    rndbits2pausebase = rndbits2pausebase +
      rndbits2pausecount +
      clockbytes +
      genbytes +
      gent_pos +
      time(NULL) +
      ch;

    int skip=ressut[rndbits2pausebase % ressut_bytes];

    while(skip>0) { // compare usleep(skip);
      ch=ressu_clockbyte2();
      skip--;
    }

    rndbits2+=8;
    
    rndbits2pausecount=500+ressut[(rndbits2pausebase + 1) % ressut_bytes]*4; // value 500-1500
#ifdef DEBUG3
    fprintf(stdout,"\n%05d",pausecount);
    newressu_output=1;
#endif
  }
#ifdef DEBUG3
  fprintf(stdout," %02x",ch);
  newressu_output=1;
#endif

#endif // #ifdef MORESECURE
  return(ch);
}

Newressua on nopeutettu hieman lisäämällä väliinputoaja sanan pituuksille käsittelyitä: Ennen tässä rutiinissa oli käsittely vain yksimerkkisille (byte) 2 merkkisille (short), 4 merkkisille (int) ja 8 merkkisille (long) tietotyypeille. Uudessa versiossa on erilliset käsittelyt myös 3, 5, 6 ja 7 merkkisille satunnaislukusanoille.

// Little faster on middle byte numbers (3,5,6,7),
// try --rand & --timer
#define GENMIDBYTES 2
#define aDEBUG19 2

int ressu_genbyte_limit(int limit) // 1 byte
{
  int c;
  while((c=ressu_genbyte()) >= (0x100/limit)*limit);
#ifdef DEBUG19
  fprintf(stdout," byte %x(%d)",c,c);
  fflush(stdout);
#endif
  return(c%limit);
}

int ressu_genshort() // 2 bytes
{
  return(ressu_genbyte() | ressu_genbyte()<<8);
}

int ressu_genshort_limit(int limit) // 2 bytes
{
  int c;
  while((c=ressu_genshort()) >= (0x10000/limit)*limit);
#ifdef DEBUG19
  fprintf(stdout," short %x(%d)",c,c);
  fflush(stdout);
#endif
  return(c%limit);
}

#ifdef GENMIDBYTES

int ressu_gen3bytes() // 3 bytes
{
  return(ressu_genshort() | ressu_genbyte()<<16);
}

int ressu_gen3bytes_limit(int limit) // 3 bytes
{
  int c;
  while((c=ressu_gen3bytes()) >= (0x1000000/limit)*limit);
#ifdef DEBUG19
  fprintf(stdout," 3 bytes %x(%d)",c,c);
  fflush(stdout);
#endif
  return(c%limit);
}

#endif // #ifdef GENMIDBYTES

unsigned int ressu_genint() // 4 bytes
{
  return(ressu_genshort() | ressu_genshort()<<16);
}

unsigned int ressu_genint_limit(unsigned long limit) // 4 bytes
{
  unsigned int c;
  while((c=ressu_genint()) >= (((unsigned long)0x100000000)/limit)*limit);
#ifdef DEBUG19
  fprintf(stdout," int %x(%d)",c,c);
  fflush(stdout);
#endif
  return(c%limit);
}

#ifdef GENMIDBYTES

unsigned long ressu_gen5bytes() // 5 bytes
{
  return(ressu_genint() | ((unsigned long)ressu_genbyte())<<32);
}

unsigned long ressu_gen5bytes_limit(unsigned long limit) // 5 bytes
{
  unsigned long c;
  while((c=ressu_gen5bytes()) >= (((unsigned long)0x10000000000)/limit)*limit);
#ifdef DEBUG19
  fprintf(stdout," 5 bytes %lx(%ld)",c,c);
  fflush(stdout);
#endif
  return(c%limit);
}

unsigned long ressu_gen6bytes() // 6 bytes
{
  return(ressu_genint() | ((unsigned long)ressu_genshort())<<32);
}

unsigned long ressu_gen6bytes_limit(unsigned long limit) // 6 bytes
{
  unsigned long c;
  while((c=ressu_gen6bytes()) >= (((unsigned long)0x1000000000000)/limit)*limit);
#ifdef DEBUG19
  fprintf(stdout," 6 bytes %lx(%ld)",c,c);
  fflush(stdout);
#endif
  return(c%limit);
}

unsigned long ressu_gen7bytes() // 7 bytes
{
  return(ressu_genint() | ((unsigned long)ressu_gen3bytes())<<32);
}

#define aDEBUG22

unsigned long ressu_gen7bytes_limit(unsigned long limit) // 7 bytes
{
  unsigned long c;
  while((c=ressu_gen7bytes()) >= (((unsigned long)0x100000000000000)/limit)*limit);
#ifdef DEBUG19
  fprintf(stdout," 7 bytes %lx(%ld)",c,c);
  fflush(stdout);
#endif
  return(c%limit);
}

#endif // #ifdef GENMIDBYTES

unsigned long ressu_genlong() // 8 bytes
{
  return(((unsigned long)ressu_genint()) | ((unsigned long)ressu_genint())<<32);
}

unsigned long ressu_genlong_limit(unsigned long limit) // 8 bytes
{
  unsigned long c;
  while((c=ressu_genlong()) >= (((unsigned long)0xffffffffffffffff)/limit)*limit);
#ifdef DEBUG19
  fprintf(stdout," long %lx(%lu)",c,c);
  fflush(stdout);
#endif
  return(c%limit);
}

#define aDEBUG24 2

unsigned long ressu_gen_limit(unsigned long limit)
{
  unsigned long c;

  if(limit<=0x100) // 1 byte
    c=ressu_genbyte_limit(limit);
  else if(limit<=0x10000) // 2 bytes
    c=ressu_genshort_limit(limit);
#ifdef GENMIDBYTES
  else if(limit<=0x1000000) // 3 bytes
    c=ressu_gen3bytes_limit(limit);
#endif
  else if(limit<=(unsigned long)0x100000000) // 4 bytes
    c=ressu_genint_limit(limit);
#ifdef GENMIDBYTES
  else if(limit<=(unsigned long)0x10000000000) // 5 bytes
    c=ressu_gen5bytes_limit(limit);
  else if(limit<=(unsigned long)0x1000000000000) // 6 bytes
    c=ressu_gen6bytes_limit(limit);
  else if(limit<=(unsigned long)0x100000000000000) // 7 bytes
    c=ressu_gen7bytes_limit(limit);
#endif
  else if(limit<=(unsigned long)0xffffffffffffffff) // 8 bytes
    c=ressu_genlong_limit(limit);
  else
    c=-1;

#ifdef DEBUG24
  fprintf(stdout,"/%ld/",c);
#endif

  return(c);
}

Seuraavalla pääohjelmasta löytyvällä –screen optiolla voidaan tehdä satunnaismerkkejä näytöllinen.

  for(c=1;c<argc;c++) {
    if(!strncmp("-",argv[c],1)) {
...
      } else if(!strncmp("--screen",argv[c],8)) {
	struct winsize w;
	ioctl(0, TIOCGWINSZ, &w);
	chars = w.ws_col;
	lines = w.ws_row-1;
	words = 0;
	screen = 1;
#ifdef DEBUG71
	fprintf(stdout,"screencolumns:%d",chars);
	fprintf(stdout," screenlines:%lld\n",lines);
#endif

Seuraavalla voidaan tulostaa heksadesimaalisatunnaismerkkejä isoilla kirjaimilla:

  for(c=1;c<argc;c++) {
    if(!strncmp("-",argv[c],1)) {
...
      } else if(!strcmp("-X",argv[c])) {
	digits = "0123456789ABCDEF";
	charspaces = 0;
	charwidth = 1;
	size = 4;
	type = 16;

Seuraavilla voidaan tulostaa japanilaisia, kiinalaisia ja korealaisia satunnaismerkkejä.

      } else if(!strcmp("--jp",argv[c])) { // japanese hiragana alphabet

	digits = NULL;
	digits_add_string(&digits,
	    "ぁあぃいぅうぇえぉおかがきぎく"
	  "ぐけげこごさざしじすずせぜそぞた"
	  "だちぢっつづてでとどなにぬねのは"
	  "ばぱひびぴふぶぷへべぺほぼぽまみ"
	  "むめもゃやゅゆょよらりるれろゎわ"
	  "ゐゑをんゔゕゖ");
	digits_add_string(&digits,
	  "゠ァアィイゥウェエォオカガキギク"
	  "グケゲコゴサザシジスズセゼソゾタ"
	  "ダチヂッツヅテデトドナニヌネノハ"
	  "バパヒビピフブプヘベペホボポマミ"
	  "ムメモャヤュユョヨラリルレロヮワ"
	  "ヰヱヲンヴヵヶヷヸヹヺ・ーヽヾヿ");
	digits_add_limits(&digits,0x4e00,0x9fef);

	digitsext = digits;
	charspaces = 0;
	charwidth = 2;
	size = 8;

	
      } else if(!strcmp("--jp1",argv[c]) // japanese hiragana alphabet
		||!strcmp("--hir",argv[c])) { // japanese hiragana alphabet
	digits=
	    "ぁあぃいぅうぇえぉおかがきぎく"
	  "ぐけげこごさざしじすずせぜそぞた"
	  "だちぢっつづてでとどなにぬねのは"
	  "ばぱひびぴふぶぷへべぺほぼぽまみ"
	  "むめもゃやゅゆょよらりるれろゎわ"
	  "ゐゑをんゔゕゖ";
	charspaces = 0;
	charwidth = 2;
	size = 8;

      } else if(!strcmp("--jp2",argv[c]) // japanese katakana alphabet
		||!strcmp("--kat",argv[c])) {  // japanese katakana alphabet
	digits=
	  "゠ァアィイゥウェエォオカガキギク"
	  "グケゲコゴサザシジスズセゼソゾタ"
	  "ダチヂッツヅテデトドナニヌネノハ"
	  "バパヒビピフブプヘベペホボポマミ"
	  "ムメモャヤュユョヨラリルレロヮワ"
	  "ヰヱヲンヴヵヶヷヸヹヺ・ーヽヾヿ";
	charspaces = 0;
	charwidth = 2;
	size = 8;

      } else if(!strcmp("--cn",argv[c]) // chinese alphabet 
		||!strcmp("--jp3",argv[c]) // japanese kanji alphabet
		||!strcmp("--kan",argv[c])) { // japanese kanji alphabet

	digits = NULL;
	digits_add_limits(&digits,0x4e00,0x9fef);

	digitsext = digits;
	charspaces = 0;
	charwidth = 2;
	size = 8;

      } else if(!strcmp("--kor",argv[c])) { // korean alphabet 

	digits = NULL;
	digits_add_limits(&digits,0xac00,0xd7a3);   // Hangul Syllables (AC00–D7A3)
	//digits_add_limits(&digits,0x1100,0x11ff); // Hangul Jamo (1100–11FF)
	//digits_add_limits(&digits,0x3130,0x318f); // Hangul Compatibility Jamo (3130–318F)
	//digits_add_limits(&digits,0xa960,0xa97f); // Hangul Jamo Extended-A (A960–A97F)
	//digits_add_limits(&digits,0xd7b0,0xd7ff); //Hangul Jamo Extended-B (D7B0–D7FF)

	digitsext = digits;
	charspaces = 0;
	charwidth = 2;
	size = 8;

Mallituloste japanin satunnaisista merkeistä: (hirakana, katakana ja kanji)

$ newressu --hir
00000 にきこねのいにぺでいべえいほこづずおぼちとぬべもみぴややよばりや
00001 っすゔちでわておゖけゑゃぴいあぶどへぞかやのぇきむげだぱのぞろち
00002 つぺけゖゐだもをゅあにだぴっぁでげゕどたぅえぃゃれとてけはゆぇか
00003 つずばぇぺこぃげあそぷゑしわげびだろばろこぽべどたぶもちごにょな
00004 つにだぉやゃぐゃいほりりゆぺそぜゔべゐぱっぉごけこはゆぃひなぱや
00005 ゅめろっぺぺだへぎぃたいわのばはぜぇゑゃべくちまぬばひぞげっばの
00006 ゆそだほゔるびゐずぺやもゕのゅぁがさぞぃだゖぷだべやきわぱぞぉね
00007 けせばさわそぐぅべばごむやぐろぇになそしまをずぽずどべるぱぃきぶ
00008 だゖわゃゕんまぅよゔらみぞぢのぶべぃゖねぬゐぴほくばびぷめめゅぺ
00009 ぷすけぇかべぬしちぐがいてぬゕめろぬりぅぇひへゕやくへぢくゕこす
$ newressu --kat
00000 ヅァヌリブアスヷフヘケヰネヽヷブヺワリベツイトセッレペヲゾチヲェ
00001 ュハグルホマドゼーサヶヶヽテプユケヱヴフホゴヨョゲヺテグードゲガ
00002 ヨグペブヺパニジヅヘルキゥリイゾワンキオキジョパゲペボヒ゠ロヨピ
00003 ヿィベコセダノテダポヨヴフヵヅズヤースヘーヨーキヨツャヱオダ゠フ
00004 ヱカハメナムツリビヸヹキカンナダエオヱズヅモテマオザツヮゼレジパ
00005 ョエキヷセペヿ゠ゲヒカミメヺヰノガフキヽーナズグカプ゠オネカペネ
00006 ヵキカヾオンヨゼベヰモミボルヒプマトテヺヤヰスダヺバヒィヴロヷリ
00007 ワゥデヽフヽダヴメユヅマリラヅュブボピアマゲコヺセァネスヴモヂワ
00008 ンニバワヹユヨユベヂナツマヅププピミキウヶヸノトメブヰヮサペアズ
00009 ゠イヶモ゠ラヅホムツチガソホポメスヂドハトラバラ゠コリィョネアリ
$ newressu --kan
00000 賵媵眼甙倐賔歌明卣鼜藕喍咽嘖鳨烉鋺丁飧巎樣换凈詋筃耫吋昀汓菂嵫娻
00001 钼仒盜楃禄戨及耥湂循倾檟夅蘡榸來霢煯淯犪祘嘏彨萾簲癐亮驘晏禜焳喇
00002 釿縐鏄賢崠夑膗遈枆倍椕乗瑳邂炉糲贠停櫃姵鄹墱漱岷镨鰠駲啝壢屌卸睘
00003 裂梶娜奕登銴溏羅默祱嵷琠犛劭灥鰈麸駂夕聂剘蜈齾取壻铬尢唋祳蓿獂孀
00004 央镩塛镋薁觵俩蹘榣溃萱婖泠珎欝秓咈怋郃湷摘篡緹楑篑邒濝偃瞆聬綣饑
00005 矝龼撎畮龯徉惖嵜鴕鎮粎销攢煣籱氛揮誑筣抮殬渕勎顓牤豠課膵緣劎闝齮
00006 戏十諻劊壴銀阘誥闄吡堼羷籒皙鲻踑佑躍斛瘛旓餺茘髳何萣憊鱃祜枑搠堦
00007 腣闂媿辏巎鿘梶錢褶痈喕盡再哿劀粸幐豞湉噻髏慜淍嬳垎喇驾铕灠婿庭姑
00008 筎砏紻兮眮旋赀窤蚟膞霑唊鲙鐀鄒袴橆碙岅饛耉礮憴婲偈驞竇鰉晃鱃镘嵒
00009 儚湾埈劾醽莋癎鲄料偌卤嵹斵涷蒬仓睏咋霿鲺埽骘霖痰驞怊龜刚鞃炷筘蠊

Mallituloste kiinan satunnaisista merkeistä:

$ newressu --cn
00000 嚡拪帎鐓萱潞殣僓闚邐鈸薏道鴳鞇诡扙迊峐弧掐龀閏缋痗尛弦徑叮湃郏玮
00001 礒瘤陟郭葶錞縈乺哇肥裲蛫撼岔膓嘠圑榤瘝焟荅屛彰檺敯鳶跅綊赧蝐伀鋴
00002 憊轺搕遨嫟摄订紐俢屉递覵耎梍昊鲅类唇潪楺竅皨鼐繯涜瘳喡牊板鞟嵝霡
00003 綠溲騐氜栯惛暪圫蜤施忸犱雔聵殒陠褟帄寭圂惛惓絾蛁溸扴畺珘涵竰智冸
00004 縀纂齜圀瑸螗諮憆怼昃窐琥橺竊葝鲴噧飞譒螃瓤狶雷笭撥芖朳匐椛牁帘嘐
00005 鍎烧澹虣堛傽鶙覦惧壌嗔潏竲襼匚篲叼丞眕宐估縍飩岙逧阭蛵厂复譲卌禬
00006 蕜靨琝瘻锐歴鍘澃卥嬴鸕儥萐嬞元醌酅樃仃疍贇蘉蚽伸萅繢捬蓭舦亂釺脊
00007 笈唇縱旮軚屔浳侙岔赅層鴔艧咴舧犬燩愣緆鄎悭厓呱瞶卉傮斠咘鋪醔韔逶
00008 発預缹鳻殅皨捦弴緖懹總扈鲜琏为傸槟贩厠嘇梽圶乣廝糰啵毋鋣亷晟犲蜶
00009 罹才祛柛梓缾眻闒萛铿吴氖栍軷淡绣裕嗡装恩姾烁峸鎉醪冰呷獽亁圊推渫

Mallituloste korean satunnaisista merkeistä:

$ newressu --kor
00000 엁쵦믥씝뉩텝얨첨늭뵶얥벶뚷힛쟃숶쫺을햸헔즹쥍는뒯묒밼묧웳먢뷶궋쐫
00001 껱쬡쓘쇲쨭쿵맏욱섡픩땡툯윳놴껍꺗혍쁴횢퉸워긻휊쌅뎷령굼큟뚏왵쳜얅
00002 뙥놱튆뢷졋뤸괁뫁뭖왒횜붍쩹꽇퀐묑쾵됖쳵뭒붽콞댟먰췸개쑷햽쿅쫍켹쨷
00003 뤥톉췒뚪쨧힉늸겨뢉려쳵뿠쵦톩즙스씺꺘둱쾬쒎깃뒻뢼컢릴받튯뎀잢깢곞
00004 철뉩랪옵꾲췖졸슮빡귕휲툋뱿럟깥쳎횣뇂쀭넱쩌뙹뵐굊븞펮홄뷞퀬뿴빘탙
00005 갰욙끎삕쵟큆벢혛쓣츅봶쨇깃윆찜녊휧셣줋쭻퐠활찦몮맩씊빠푏뿎댔괓올
00006 톩좸끨꺑똏탢즆뤹뺿놕긌쨁옗쭬믜휃멬쥪먅볂험넥쎴힋쨫춱려읪걅뀤퍏퓦
00007 릏뢲륋쯁뼴퇧틩칟믔쥷퐵셾끀힝큇졣뿩겂뭳삅뛀샺픅쾑릫덞귊웲빆뛞턧뫿
00008 긌룼팴앮쯠눍셲쐪쇐쨋횔몰쩝쑲뻆밪왑썵늺셸뿁릿뷹툚앶뀖핗늬놨춧랤퍯
00009 씄쮽숟퇍뜋읶킔웬목뻽쟫셎쑞뇫헤빭엶준곆렭찔탋첟첩퓧뻈쨣핽맱쨅삑퓵

Edellisten apuohjelmat: digits_add_string() lisää merkkijonon digits merkkijonoon. digits_add_limits() lisää utf8 merkkivälin digits merkkijonoon.

#define aDEBUG55 2

void digits_add_string(unsigned char **digits, char *str)
{
  int digitssize;

#ifdef DEBUG55
  fprintf(stdout,"\nolddigits %s",*digits);
  fprintf(stdout,"\nadddigits %s",str);
#endif
  digitssize=0;
  if(*digits!=NULL)
    digitssize+=strlen(*digits);
  digitssize+=strlen(str);
  *digits=realloc(*digits,digitssize+1);
  strcat(*digits,str);
#ifdef DEBUG55
  fprintf(stdout,"\nnewdigits %s",*digits);
  fprintf(stdout,"\n");
#endif
}

void digits_add_limits(unsigned char **digits, int start, int end)
{
  int c, digitssize;
  unsigned char buffer[10];

#ifdef DEBUG55
  fprintf(stdout,"\nolddigits %s",*digits);
  fprintf(stdout,"\nadddigits start:%d, end:%d",start,end);
#endif
  digitssize=0;
  if(*digits!=NULL)
    digitssize+=strlen(*digits);
  
  for(c=start;c<=end;c++) {
    codetoutf8(buffer,c);
    digitssize+=strlen(buffer);
  }
  *digits=realloc(*digits,digitssize+1);
  for(c=start;c<=end;c++) {
    codetoutf8(buffer,c);
    strcat(*digits,buffer);
  }
#ifdef DEBUG55
  fprintf(stdout,"\nnewdigits %s",*digits);
  fprintf(stdout,"\n");
#endif
}

Ja apuohjelmien apuohjelma:

#define aDEBUG42 2

static void codetoutf8(unsigned char *buf2, unsigned long code)
{
  unsigned char *buf;

  buf=buf2;
  if(code<=0x7f) {
    *buf++=code;
  } else if(code<=0x7ff) {
    *buf++=(0xc0 | ((code>>6)&0x1f));
    *buf++=(0x80 | (code&0x3f));
  } else if(code<=0xffff) {
    *buf++=(0xe0 | ((code>>12)&0x0f));
    *buf++=(0x80 | ((code>>6)&0x3f));
    *buf++=(0x80 | (code&0x3f));
  } else if(code<=0x10ffff) {
    *buf++=(0xf0 | ((code>>18)&0x07));
    *buf++=(0x80 | ((code>>12)&0x3f));      
    *buf++=(0x80 | ((code>>6)&0x3f));      
    *buf++=(0x80 | ((code&0x3f)));      
  } else if(code<=0x3ffffff) { // these not yet needed
    *buf++=(0xf8 | ((code>>24)&0x03));
    *buf++=(0x80 | ((code>>18)&0x3f));      
    *buf++=(0x80 | ((code>>12)&0x3f));      
    *buf++=(0x80 | ((code>>6)&0x3f));      
    *buf++=(0x80 | ((code&0x3f)));      
  } else if(code<=0x7fffffff) { // these not yet needed
    *buf++=(0xfc | ((code>>30)&0x01));
    *buf++=(0x80 | ((code>>24)&0x3f));      
    *buf++=(0x80 | ((code>>18)&0x3f));      
    *buf++=(0x80 | ((code>>12)&0x3f));      
    *buf++=(0x80 | ((code>>6)&0x3f));      
    *buf++=(0x80 | ((code&0x3f)));      
  } else if(code<=0xfffffffff) { // these not yet needed
    *buf++=(0xfe);
    *buf++=(0x80 | ((code>>30)&0x3f));      
    *buf++=(0x80 | ((code>>24)&0x3f));      
    *buf++=(0x80 | ((code>>18)&0x3f));      
    *buf++=(0x80 | ((code>>12)&0x3f));      
    *buf++=(0x80 | ((code>>6)&0x3f));      
    *buf++=(0x80 | ((code&0x3f)));      
  } else if(code<=0x3ffffffffff) { // these not yet needed
    *buf++=(0xff);
    *buf++=(0x80 | ((code>>36)&0x3f));      
    *buf++=(0x80 | ((code>>30)&0x3f));      
    *buf++=(0x80 | ((code>>24)&0x3f));      
    *buf++=(0x80 | ((code>>18)&0x3f));      
    *buf++=(0x80 | ((code>>12)&0x3f));      
    *buf++=(0x80 | ((code>>6)&0x3f));      
    *buf++=(0x80 | ((code&0x3f)));      
  }
  *buf='\0';

#ifdef DEBUG42
  int c;

  fprintf(stdout,"codepoint: %11lx, utf8: ",code);
  for(c=0;c<8;c++) {
    if(buf2[c]=='\0')
      break;
    fprintf(stdout,"%02x",buf2[c]);
  }
  fprintf(stdout,",");
  for(;c<8;c++) {
    fprintf(stdout,"  ");
  }
  fprintf(stdout," utf8bin: ");
  for(c=0;c<8;c++) {
    if(buf2[c]=='\0')
      break;
    for(int d=7;d>=0;d--)
      fprintf(stdout,"%d",buf2[c]>>d&1);
  }
  fprintf(stdout,",");
  for(;c<8;c++) {
    fprintf(stdout,"        ");
  }
  fprintf(stdout," character: %s",buf2);
  fprintf(stdout,"\n");
#endif
}

DEBUG42 tulostaa tälläisen infon konvertoidessaan kokonaislukuja utf8 merkkijonoiksi:

codepoint:        735e, utf8: e78d9e,           utf8bin: 111001111000110110011110,                                         character: 獞
codepoint:        735f, utf8: e78d9f,           utf8bin: 111001111000110110011111,                                         character: 獟
codepoint:        7360, utf8: e78da0,           utf8bin: 111001111000110110100000,                                         character: 獠
codepoint:        7361, utf8: e78da1,           utf8bin: 111001111000110110100001,                                         character: 獡
codepoint:        7362, utf8: e78da2,           utf8bin: 111001111000110110100010,                                         character: 獢
codepoint:        7363, utf8: e78da3,           utf8bin: 111001111000110110100011,                                         character: 獣
codepoint:        7364, utf8: e78da4,           utf8bin: 111001111000110110100100,                                         character: 獤
codepoint:        7365, utf8: e78da5,           utf8bin: 111001111000110110100101,                                         character: 獥
codepoint:        7366, utf8: e78da6,           utf8bin: 111001111000110110100110,                                         character: 獦
codepoint:        7367, utf8: e78da7,           utf8bin: 111001111000110110100111,                                         character: 獧

Seuraavalla newressu:n –timer kytkimellä voidaan tulostaa raporttirivi komennon suoritusajasta:

$ ./newressu --timer
00000 14201844240371822100253951836708816138416704547327938279020612823
00001 96317707705252111732289508490822470980426867566840559420270289362
00002 00689262243741247223559402961899678231026820771707893001586218306
00003 58979497167864424785641519129614693821588197298234540350089230127
00004 79789151626389687113003359838448204303247463484081137703428742320
00005 11646624843275547205294740326170331083195859451166500230279215257
00006 73962496095430961154950496584940973872290305555433845726378885241
00007 50019973396634088019938782699506630602624836322165073299771817377
00008 45442780578169763986650183569757727708029002163610361259691700882
00009 66002136323947761070898295750362946156839041366424942241622661094
run time 0.010476 seconds, 10 lines, 1059.484482 useconds/line, 65 characters/line, 16.308931 useconds/character
#ifdef USE_TIMER
      } else if(!strcmp("--timer",argv[c])) {
        timer=1;
#endif
#ifdef USE_TIMER
  timerstart=getseconds();
#endif
#ifdef USE_TIMER
  if(timer) {
    double timertook=getseconds()-timerstart;
    fprintf(stdout,"run time %f seconds",timertook);
    fprintf(stdout,", %lld lines",plines);
    fprintf(stdout,", %f useconds/line",timertook*1000000/plines);
    fprintf(stdout,", %d characters/line",pwords*size);
    fprintf(stdout,", %f useconds/character",(timertook*1000000/plines)/(pwords*size));
    fprintf(stdout,"\n");
   }
#endif

Korjattu lokien kirjoitus siten että vain yksi prosessi voi kirjoittaa niitä kerrallaan. Tässä se on toteutettu semaphore:illa. Aluksi https-palvelin, johon on lisätty kutsut semaphore funktioille: Funktion alussa poistetaan vanha semaphore sem_unlink() kutsulla. Sen jälkeen avataan uusi sem_open() kutsulla. Vuoroa odotetaan sem_wait() kutsulla. Semaphore vapautetaan seuraavalle käyttäjälle sem_post() kutsulla. Semaphore:t poistetaan lopuksi sem_unlink ja sem_close komennoilla.

Lisäksi https_server() funktiosta on ulkoistettu tavalliset socket kutsut (getaddrinfo(), server_socket(), server_bind(), freeaddrinfo() ja server_listen()) funktioon server_basic_socket(). Https palvelimesta ulkoistetut funktiot (SSL_library_init(), OpenSSL_add_ssl_algorithms(), OpenSSL_add_ciphers(), OpenSSL_load_error_strings(), SSLv23_server_method(), SSL_CTX_new(), SSL_CTX_use_certificate_file(), SSL_CTX_use_PrivateKey_file() ja SSL_CTX_load_verify_locations()) on sijoitettu funktioon server_https_init(). Ohjelmassa on samat rivit samassa järjestyksessä, niitä on vain vähän siirrelty.

#define DEBUG59 2
#define DEBUG81 2

static void https_server()
{
  int quit, reset, addr_size;
  
  //SSL_METHOD *method=NULL;
  SSL_CTX *ctx=NULL;

  struct sockaddr_in sa_cli;

  signal(SIGPIPE, SIG_IGN);
  signal(SIGCHLD, SIG_IGN);

#ifdef USE_SEMAPHORES

  unsigned char semname[32];
  sem_t *mutex;

  sprintf(semname,"dbssem%s",myport);

  if(sem_unlink(semname)==0) {
    fprintf(stdout,"%s: previous semaphore %s removed\n",procname,semname);
  }
  mutex=sem_open(semname, O_CREAT | O_EXCL, 0644, 1);

#endif

  // plus space for '\0'  
  htmlin = malloc(htmlinlen+1);
    
  reset=1;
  quit=0;
  
  for(;;) {

    if(quit) {
      if(ctx!=NULL)
	SSL_CTX_free(ctx);
      break;
    }
    if(reset) {
      if(ctx!=NULL) {
#ifdef DEBUG42
	fprintf(stdout,"SSL_CTX_free()\n");
#endif
	SSL_CTX_free(ctx);  
      }

      ctx=server_https_init();
      s=server_basic_socket();

      reset=0;
    } // if(reset)

    fprintf(stdout,"\n");
    fflush(stdout);
    
    addr_size = sizeof(sa_cli);
#ifdef DEBUG42
    fprintf(stdout,"accept()\n");
#endif
    if((news=accept(s, (struct sockaddr *)&sa_cli, &addr_size))==-1) {
      fprintf(stderr,"\n%s: cannot accept()\n", procname);
      perror("accept");
    }

    if(beepaccept) {
      fprintf(stderr,"\a");
      fflush(stderr);
    }

    pid_t pid;
#ifdef DEBUG59
    fprintf(stdout,"Fork start (parent)");
    fprintf(stdout," getpid:%d getppid:%d",getpid(),getppid()); 
    fprintf(stdout,"\n");
    fflush(stdout);
#endif
    if((pid=fork())<0) {
#ifdef USE_SEMAPHORES
      sem_unlink(semname);
      sem_close(mutex);
#endif
      fprintf(stderr,"\n%s: cannot fork()\n", procname);
      perror("fork");
    }
    if(pid==0) {
      log_clear();
      log_printf("==========\n");
#ifdef DEBUG59
      fprintf(stdout,"Fork start (child)");
      fprintf(stdout," pid:%d getpid:%d getppid:%d",pid,getpid(),getppid());
      fprintf(stdout,"\n");
      fflush(stdout);
#endif
      close(s);

      https_client(news,ctx,sa_cli,addr_size,"https");

#ifdef DEBUG81
      fprintf(stdout,"%s",logbuf);
      fflush(stdout);
      log_clear();
#endif

#ifdef USE_SEMAPHORES
      
      fprintf(stdout,"locking semaphore(child)");
      fprintf(stdout," pid:%d getpid:%d getppid:%d",pid,getpid(),getppid());
      fprintf(stdout,"\n");
      fflush(stdout);
      
      if(sem_wait(mutex)==-1) {
	fprintf(stderr, "%s: cannot sem_wait(), error: %d\n", procname, errno);
	perror("sem_wait");
      }
      
      fprintf(stdout,"critical section (child)");
      fprintf(stdout," pid:%d getpid:%d getppid:%d",pid,getpid(),getppid());
      fprintf(stdout,"\n");
      fflush(stdout);
#endif
      
      dbs_run_critical();

#ifdef USE_SEMAPHORES
      
      fprintf(stdout,"end critical section (child)");
      fprintf(stdout," pid:%d getpid:%d getppid:%d",pid,getpid(),getppid());
      fprintf(stdout,"\n");
      fflush(stdout);

      if(sem_post(mutex)==-1) {
	fprintf(stderr, "%s: cannot sem_post(), error: %d\n", procname, errno);
	perror("sem_post");
      }

      fprintf(stdout,"release semaphore(child)");
      fprintf(stdout," pid:%d getpid:%d getppid:%d",pid,getpid(),getppid());
      fprintf(stdout,"\n");
      fflush(stdout);
      
#endif
      
      server_close(news);
      fprintf(stdout,"%s",logbuf);
      fflush(stdout);
      log_clear();
      
#ifdef DEBUG59
      fprintf(stdout,"Fork end (child)");
      fprintf(stdout," pid:%d getpid:%d getppid:%d",pid,getpid(),getppid());
      fprintf(stdout,"\n");
      fflush(stdout);
#endif
      exit(0);
    }
#ifdef DEBUG59
    fprintf(stdout,"Fork end (parent)");
    fprintf(stdout," pid:%d getpid:%d getppid:%d",pid,getpid(),getppid());
    fprintf(stdout,"\n");
    fflush(stdout);
#endif
  } // for(;;)
  SSL_CTX_free(ctx);  

#ifdef USE_SEMAPHORES
  sem_unlink(semname);
  sem_close(mutex);
#endif
}

Seuraavaksi server_basic_socket() funktio:

static int server_basic_socket()
{
  int s;
  struct addrinfo *res;

  server_getaddrinfo(myport,&res);
  s = server_socket(res);
  server_bind(s,res);
  freeaddrinfo(res);
  server_listen(s);

  return(s);
}

Sitten server_https_init():

static SSL_CTX *server_https_init()
{
  SSL_METHOD *method=NULL;
  SSL_CTX *ctx=NULL;
  
#ifdef DEBUG42
  fprintf(stdout,"SSL_library_init()\n");
#endif
  SSL_library_init();
  
#ifdef DEBUG42
  fprintf(stdout,"OpenSSL_add_ssl_algorithms()\n");
#endif
  OpenSSL_add_ssl_algorithms();
  
#ifdef DEBUG42
  fprintf(stdout,"OpenSSL_add_ciphers()\n");
#endif
  OpenSSL_add_all_ciphers();
  
#ifdef DEBUG42
  fprintf(stdout,"OpenSSL_load_error_strings()\n");
#endif
  SSL_load_error_strings();
  
#ifdef DEBUG42
  fprintf(stdout,"SSLv23_server_method()\n");
#endif
  if((method = (SSL_METHOD *)    
      SSLv23_server_method()) == NULL) {
    fprintf(stderr,"\n%s: cannot SSLv3_server_method()\n", procname);
    //fflush(stderr);
  }
  
#ifdef DEBUG42
  fprintf(stdout,"SSL_CTX_new()\n");
#endif
  if((ctx=SSL_CTX_new(method)) == NULL) {
    fprintf(stderr,"\n%s: cannot SSL_CTX_new()\n", procname);
  }
  
#ifdef DEBUG42
  fprintf(stdout,"SSL_CTX_use_certificate_file()\n");
#endif
  if(SSL_CTX_use_certificate_file(ctx, cert_file, SSL_FILETYPE_PEM) <= 0) {
    fprintf(stderr,"\n%s: cannot SSL_CTX_use_certificate()\n", procname);
    fflush(stderr);
  }
  
#ifdef DEBUG42
  fprintf(stdout,"SSL_CTX_use_PrivateKey_file()\n");
#endif
  if(SSL_CTX_use_PrivateKey_file(ctx, privatekey_file, SSL_FILETYPE_PEM)<=0) {
    fprintf(stderr,"\n%s: cannot SSL_CTX_use_certificate()\n", procname);
  }
  
#ifdef DEBUG42
  fprintf(stdout,"SSL_CTX_load_verify_locations()\n");
#endif
  if(!SSL_CTX_load_verify_locations(ctx, cert_file, NULL)) {
    fprintf(stderr,"\n%s: cannot SSL_CTX_verify_locations()\n", procname);
  }
  return(ctx);
}

Tässä vielä tuo vuoroja tarvitseva rutiini:

static void dbs_run_critical()
{
  FILE *fp1;
  char filename[128];
  char filename2[128];

  sprintf(filename,"%stimelog.deb",filenamehead);
#ifdef DEBUG34
  fprintf(stdout,"Writing %s\n",filename);
#endif
  if((fp1=fopen(filename,"a"))!=NULL) {
    fprintf(fp1,"%s, ip=\"%s\"\n",htmltimeshort, htmlip);
    fclose(fp1);
  }
  
  sprintf(filename,"%sips.deb",filenamehead);
#ifdef DEBUG34
  fprintf(stdout,"Writing %s\n",filename);
#endif
  dbs_add_end_new_str(filename, htmlip);

  sprintf(filename,"%shostname.deb",filenamehead);
#ifdef DEBUG34
  fprintf(stdout,"Writing %s\n",filename);
#endif
  dbs_add_end_new_str(filename, htmlhostname);

  if(htmlsslcipher[0]!='\0') {
    sprintf(filename,"%sciphers.deb",filenamehead);
#ifdef DEBUG34
    fprintf(stdout,"Writing %s\n",filename);
#endif
    dbs_add_end_new_str(filename,htmlsslcipher);
  }

  fprintf(stdout,"Fetching User-Agent\n");
  unsigned char *p,buffer[1024];
  if((p=dbs_html_get_request_line("User-Agent",sizeof(buffer),buffer))!=NULL) {
#ifdef DEBUG35
    fprintf(stdout,"fetch User-Agent: \"%s\"\n",p);
#endif
    sprintf(filename,"%suseragent.deb",filenamehead);
#ifdef DEBUG34
    fprintf(stdout,"Writing %s\n",filename);
#endif
    dbs_add_end_new_str(filename,buffer);
  }

  sprintf(filename2,"%scallid.deb",filenamehead);
#ifdef DEBUG34
  fprintf(stdout,"Reading %s\n",filename2);
#endif
  if((fp1=fopen(filename2,"r"))!=NULL) {
    unsigned char buffer16[16];
    fgets(buffer16,sizeof(buffer16),fp1);
    callid=atoi(buffer16);
    fclose(fp1);
  }
  log_printf("callid:%d\n",callid);
  sprintf(filename,"%shtml.deb",filenamehead);
#ifdef DEBUG34
  fprintf(stdout,"Writing %s\n",filename);
#endif
  if((fp1 = fopen(filename,"a")) != NULL) {
    fprintf(fp1,"htmltime: \"%s\", htmltimeshort: \"%s\", ip=\"%s\", callid=\"%d\"\n",htmltime, htmltimeshort, htmlip, callid);
    fprintf(fp1,"%s\n",htmlin);
    for(int c=0;c<HTML_BUFFERS;c++) {
#ifdef DEBUG31
      fprintf(stdout,"%d",c);
      fprintf(stdout," %p",html_get_string(c));
      if(html_get_string(c)!=NULL)
	fprintf(stdout,"%s",html_get_string(c));
#endif
      if(html_get_string(c)!=NULL &&
	 strlen(html_get_string(c))>0) {
	fprintf(fp1,"%d: %s\n",c,html_get_string(c));
      }
    }
    fclose(fp1);
  }
  
  callid++; // next call id
#ifdef DEBUG34
  fprintf(stdout,"Writing %s\n",filename2);
#endif
  if((fp1=fopen(filename2,"w"))!=NULL) {
    fprintf(fp1,"%d\n",callid);
    fclose(fp1);
  }
}

Lisätty terttu henkinen yhteinen loki palvelimille: aluksi mallitietue lokista: (rullaa oikealle) Tietueen lopussa uudet kentät useconds ja prevminutes, joista ensimmäinen kertoo asiakkaan prosessin viemän ajan ja toinen viimeisten kutsujen määrän. Näitä tarkkailemalla on tarkoituksena löytää raja, jolla palvelin ei voi enää suoriutua ja poistaa asiakkaan töitä (tässä satunnaislukujen muodostus+tulostus). Tässä voidaan muuttaa sivusisältö johonkin palvelin on nyt ruuhkaantunut tekstiin ja jättää asiakkaan töistä osa pois.

'procname' = "./dbs", 'timeshort' = "EET20220317002226", 'time' = "Thu, 17 Mar 2022 00:22:26 EET", 'host' = "1.2.3.4:5006", 'hostname' = "1.2.3.4", 'useragent' = "", 'method' = "GET", 'path' = "/", 'version' = "HTTP/1.1", 'filename' = "", 'fileextension' = "", 'cookie' = "", 'sessionid' = "", 'params' = "", 'digest' = "aaaabbbbccccdddd", 'mode' = "", 'ip' = "1.2.3.4", 'sslcipher' = "TLS_AES_128_GCM_SHA256", 'port' = "10227", 'language' = "fi", 'useconds' = "118438", 'prevminutes' = "2 2 1 0 0 0 0 0 0 0 0 0 0 0 0"

Sitten lokin tarvitsema tietorakenne:

struct lfield {
  unsigned char *name;
  int valuetype;
  unsigned char *value;
  int size;
} lfields[] = {
  { "procname", 1, (unsigned char *)&procname, 32 },
  { "timeshort", 0, htmltimeshort, sizeof(htmltimeshort) },
  { "time", 0, htmltime, sizeof(htmltime) },
  { "host", 0, htmlhost, sizeof(htmlhost) },
  { "hostname", 0, htmlhostname, sizeof(htmlhostname) },
  { "useragent", 0, htmluseragent, sizeof(htmluseragent) },
  { "method", 0, htmlmethod, sizeof(htmlmethod) },
  { "path", 0, htmlpath, sizeof(htmlpath) },
  { "version", 0, htmlversion, sizeof(htmlversion) },
  { "filename", 0, htmlfilename, sizeof(htmlfilename) },
  { "fileextension", 0, htmlfileextension, sizeof(htmlfileextension) },
  { "cookie", 0, htmlcookie, sizeof(htmlcookie) },
  { "sessionid", 0, htmlsessionid, sizeof(htmlsessionid) },
  { "params", 1, (unsigned char *)&htmlparams, 0 },
  { "digest", 0, htmldigest, sizeof(htmldigest) },
  { "mode", 0, htmlmode, sizeof(htmlmode) },
  { "ip", 0, htmlip, sizeof(htmlip) },
  { "sslcipher", 0, htmlsslcipher, sizeof(htmlsslcipher) },
  { "port", 0, htmlport, sizeof(htmlport) },
  { "language", 0, htmllanguage, sizeof(htmllanguage) },
  { "useconds", 0, htmluseconds, sizeof(htmluseconds) },
  { "prevminutes", 0, htmlprevminutes, sizeof(htmlprevminutes) },
};

Kentän tulostusrutiini: saa puskurin osoitteen ja vapaan tilan puskurissa. Jos kentän nimi ja arvo pari mahtuu puskuriin, se tulostetaan sinne. Aina palautetaan nimi arvoparin pituus.

int db4_compile_field(int buflength, unsigned char *buf, unsigned char *name)
{
  int size=0;
  unsigned char *value=NULL;

  for(int c=0;c<sizeof(lfields)/sizeof(struct lfield);c++) {
    if(!strcmp(name,lfields[c].name)) {
      if(lfields[c].valuetype==0) {
	value=lfields[c].value;
	break;
      } else if(lfields[c].valuetype==1) {
	value=*((unsigned char **)lfields[c].value);
	break;
      }

    }
  }
  size=7+strlen(name);
  if(value!=NULL)
    size+=strlen(value);
  
  if(size<buflength) {
    strcat(buf,"'");
    strcat(buf,name);
    strcat(buf,"' = \"");
    if(value!=NULL)
      strcat(buf,value);
    strcat(buf,"\"");
  }
  return(size);
}

(Loki)rivin tulostusrutiini: Taas sama juttu, tulostetaan mahtuvat kentät puskuriin ja palautetaan koko tietueen pituus (ilman ‘\0’ merkkiä)

int db4_compile_set(int buflen, unsigned char *buf2)
{
  int size, count, first=1;
  unsigned char *buf = buf2;
  size=0;
  if(buflen>0)
    buf[0]='\0';
  
  for(int c=0;c<sizeof(lfields)/sizeof(struct lfield);c++) {
    count=0;
    if(!first) {
      if(2<buflen)
	strcat(buf,", ");
      count+=2;
    }
    count+=db4_compile_field(buflen,buf,lfields[c].name);
    buf+=count;
    buflen-=count;
    size+=count;
    first=0;
  }
  
  return(size);
}

Ja edellistä kutsuva pätkä: (jos koko tietue ei mahdu puskuriin suurennetaan puskuria ja yritetään uudestaan).

#define DEBUG39

static void dbs_run_critical_all() {
  int count, buflen=0;
  unsigned char *buf=NULL;

#ifdef DEBUG39
  fprintf(stdout,"db4_compile_set() %d\n",buflen);
  fflush(stdout);
#endif
  count=db4_compile_set(buflen,buf)+1;
    
  if(buflen<count) {
    buflen=count;
    buf=realloc(buf,buflen);
#ifdef DEBUG39
    fprintf(stdout,"db4_compile_set() %d\n",buflen);
    fflush(stdout);
#endif
    count=db4_compile_set(buflen,buf)+1;
  }
  FILE *fp1;
  if((fp1 = fopen("dbs.skk","a")) != NULL) {
    fprintf(fp1,"%s\n",buf);
    fclose(fp1);
  }
  fprintf(stdout,"%s(%ld)\n",buf,strlen(buf));
  fflush(stdout);
  //for(int c=0;c<sizeof(lfiles)/sizeof(struct lfile);c++) {
  //fprintf(stdout,"%s",lfiles[c].filename);
  //}
}

Korjattu bugi intelrandom.c ohjelman rdseed rutiinissa lisäämällä toistoja, jos rdseed ei toimi: (while tries kappale)

int rdseed_bytes(int buflen, unsigned char *buf)
{
  int n, ret = 0;
  unsigned long l;

  if(_is_cpu_vendor("GenuineIntel") && _has_rdseed()) {
    if(fort_verbose)
      fprintf(stdout,"Intel rdseed");
    ret=1;
  } else if(_is_cpu_vendor("AuthenticAMD") && _has_rdseed()) {
    if(fort_verbose)
      fprintf(stdout,"AMD rdseed");
    ret=1;
  }

  if(ret) {
    while(buflen > 0) {
      int tries=0;
      while(++tries < 100) {
	if((ret = _rdseed_long(&l)) == 1) { // 1 ok, 0 fail
	  break;
	}
      }
      if(ret==0)
	break;
      if(fort_verbose) {
	fprintf(stdout," %016lx",l);
	newressu_output=1;
      }
      n = (buflen < sizeof(l) ? buflen : sizeof(l));
      memcpy(buf, (unsigned char *)&l, n);
      buf+=n;
      buflen-=n;
    }
  }
  return(ret);
}

Huomasin, että codepointilla ja muodostetulla utf8 koodilla on yhteys, joka näkyy oktaalina: lisäsin oktaaliversion debug42:n tulostukseen: vertaile oktaalista codepoint:ia ja myöhempää utf8 koodia oktaalina.

codepoint: 4e03, bin:1001110|00000011, oct:47003, utf8: e4b883, bin: 11100100|10111000|10000011, oct:
 344 270 203, character: 七
codepoint: 4e04, bin:1001110|00000100, oct:47004, utf8: e4b884, bin: 11100100|10111000|10000100, oct:
 344 270 204, character: 丄

Seuraavassa uusi versio koodista, jossa oktaalikentät on lisätty ja lisäksi debukkirivi muotoiltu uudelleen:

#define aDEBUG42 2

static void codetoutf8(unsigned char *buf2, unsigned long code)
{
  unsigned char *buf;

  buf=buf2;
  if(code<=0x7f) {
    *buf++=code;
  } else if(code<=0x7ff) {            // 110xxxxx 10xxxxxx
    *buf++=(0xc0 | ((code>>6)&0x1f));
    *buf++=(0x80 | (code&0x3f));
  } else if(code<=0xffff) {           // 1110xxxx 10xxxxxx 10xxxxxx
    *buf++=(0xe0 | ((code>>12)&0x0f));
    *buf++=(0x80 | ((code>>6)&0x3f));
    *buf++=(0x80 | (code&0x3f));
  } else if(code<=0x10ffff) {         // 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
    *buf++=(0xf0 | ((code>>18)&0x07));
    *buf++=(0x80 | ((code>>12)&0x3f));      
    *buf++=(0x80 | ((code>>6)&0x3f));      
    *buf++=(0x80 | ((code&0x3f)));      
  } else if(code<=0x3ffffff) {        // 111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx // these not yet needed
    *buf++=(0xf8 | ((code>>24)&0x03));
    *buf++=(0x80 | ((code>>18)&0x3f));      
    *buf++=(0x80 | ((code>>12)&0x3f));      
    *buf++=(0x80 | ((code>>6)&0x3f));      
    *buf++=(0x80 | ((code&0x3f)));      
  } else if(code<=0x7fffffff) {       // 1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx // these not yet needed
    *buf++=(0xfc | ((code>>30)&0x01));
    *buf++=(0x80 | ((code>>24)&0x3f));      
    *buf++=(0x80 | ((code>>18)&0x3f));      
    *buf++=(0x80 | ((code>>12)&0x3f));      
    *buf++=(0x80 | ((code>>6)&0x3f));      
    *buf++=(0x80 | ((code&0x3f)));      
  } else if(code<=0xfffffffff) {      // 11111110 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx // these not yet needed
    *buf++=(0xfe);
    *buf++=(0x80 | ((code>>30)&0x3f));      
    *buf++=(0x80 | ((code>>24)&0x3f));      
    *buf++=(0x80 | ((code>>18)&0x3f));      
    *buf++=(0x80 | ((code>>12)&0x3f));      
    *buf++=(0x80 | ((code>>6)&0x3f));      
    *buf++=(0x80 | ((code&0x3f)));      
  } else if(code<=0x3ffffffffff) {    // 11111111 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx // these not yet needed
    *buf++=(0xff);
    *buf++=(0x80 | ((code>>36)&0x3f));      
    *buf++=(0x80 | ((code>>30)&0x3f));      
    *buf++=(0x80 | ((code>>24)&0x3f));      
    *buf++=(0x80 | ((code>>18)&0x3f));      
    *buf++=(0x80 | ((code>>12)&0x3f));      
    *buf++=(0x80 | ((code>>6)&0x3f));      
    *buf++=(0x80 | ((code&0x3f)));      
  }
  *buf='\0';

#ifdef DEBUG42
  int c,print;

  fprintf(stdout,"codepoint: %lx",code);

  fprintf(stdout,", bin:");

  print=0;
  for(c=(sizeof(code)*8)-1;c>=0;c--) {
    int bit=(code>>c)&1;
    if(bit!=0)
      print=1;
    if(print) {
      fprintf(stdout,"%d",bit);
      if(c>0 && c%8==0)
	fprintf(stdout,"|");
    }
  }

  fprintf(stdout,", oct:");
  print=0;
  fprintf(stdout,"%lo",code);

  fprintf(stdout,", utf8: ");
  for(c=0;c<8;c++) {
    if(buf2[c]=='\0')
      break;
    fprintf(stdout,"%02x",buf2[c]);
  }

  fprintf(stdout,", bin: ");
  for(c=0;c<8;c++) {
    if(buf2[c]=='\0')
      break;
    if(c>0)
      fprintf(stdout,"|");
    for(int d=7;d>=0;d--) {
      fprintf(stdout,"%d",buf2[c]>>d&1);
    }
  }

  fprintf(stdout,", oct:");
  for(c=0;c<8;c++) {
    if(buf2[c]=='\0')
      break;
    fprintf(stdout," %3o",buf2[c]);
  }
  
  fprintf(stdout,", character: %s",buf2);
  fprintf(stdout,"\n");
#endif
}

Uudelleen kirjoitettu häkkyrä ressu_gen_limit(), joka palauttaa annettua rajaa pienemmän satunnaisluvun. Aiemmin uuden funktion toiminnon teki useampi funktio. Edellisessä oli funktioita ressu_genbyte_limit(), ressu_genshort() ressu_genshort_limit, ressu genint() ja niin edelleen. Uudessa versiossa ne on tiivistetty simppelimpään muotoon: (vanha koodi on mukana lopun sorsassa #ifdef OLD1 blokissa tämän uudemman funktion jälkeen)

#define aDEBUG19 2
#define aDEBUG24 2

unsigned long ressu_gen_limit(unsigned long limit)
{
  int c, bytes;
  unsigned long word, highlimit;
  
  if(limit<=0x100) { // 1 byte
    highlimit=0x100;
    bytes=1;
  } else if(limit<=0x10000) { // 2 bytes
    highlimit=0x10000;
    bytes=2;
  } else if(limit<=0x1000000) { // 3 bytes
    highlimit=0x1000000;
    bytes=3;
  } else if(limit<=(unsigned long)0x100000000) { // 4 bytes
    highlimit=0x100000000;
    bytes=4;
  } else if(limit<=(unsigned long)0x10000000000) { // 5 bytes
    highlimit=0x10000000000;
    bytes=5;
  } else if(limit<=(unsigned long)0x1000000000000) { // 6 bytes
    highlimit=0x1000000000000;
    bytes=6;
  } else if(limit<=(unsigned long)0x100000000000000) { // 7 bytes
    highlimit=0x100000000000000;
    bytes=7;
  } else { // if(limit<=(unsigned long)0xffffffffffffffff) { // 8 bytes
    highlimit=0xffffffffffffffff;
    bytes=8;
  }

  for(;;) {
    word=0;
    for(c=0;c<bytes;c++)
      word = word << 8 | ressu_genbyte();
    if(word < (highlimit/limit)*limit)
      break;
  }

  word%=limit;
  
#ifdef DEBUG24
  fprintf(stdout,"/");
#ifdef DEBUG19
  fprintf(stdout,"%d bytes: ", bytes);
#endif
  if(type==2)
    fprintf(stdout,"%lx", word);
  else if(type==8)
    fprintf(stdout,"%lo", word);
  else if(type==10)
    fprintf(stdout,"%lu", word);
  else if(type==16)
    fprintf(stdout,"%lx", word);
  else
    fprintf(stdout,"%lu", word);
  fprintf(stdout,"/");
  fflush(stdout);
#endif

  return(word);
}

Lisäksi lisätty kaksi uutta laskentatapaa ressun ns teoreettisten satunnaisbittien laskentaan: Ensimmäisessä mallissa (rndbits3) eniten ilmestynyttä ketjun pituutta pidetään satunnaisuuden suhteen neutraalina, eli että se ei sisällä yhtään satunnaisuutta. Kaikkien muiden pituiset ketjut lasketaan sisältävän yhden bitin satunnaisuutta. Toisessa mallissa (rndbits4) pituudeltaan pisimmät ketjut lasketaan neutraaleiksi ja niitä lyhyemmät ketjut sisältävät yhden bitin satunnaisuutta. Pisimmät ketjut voivat olla esimerkiksi ne, joiden esiintymismäärä sisältää neljä numeroa (esimerkiksi 1234, 2222, 3443) ja kolme numeroa tai lyhyemmät lasketaan teoreettisiin satunnaisbitteihin.

void ressu_genbytes(int size, unsigned char *buffer) // 6.5.2021 JariK
{
  int c, d, e, f;
  static int ressut_first = 1,
    ressut_pos = 0,
    ressut_f = 0;
  unsigned long prevperiods[1024];
  
  for(c = 0; c < size; c++) {
    if(ressut_pos == 0) {
      if(ressut_first) {
	memset(ressut, 0, ressut_bytes);
	ressut_first = 0;
      }

      clockbytes=0;
      for(d = 0; d < 1024; d++) {
	periods[d] = 0;
      }
      
      rndbits1 = 0;
      rndbits2 = 0;
      rndbits3 = 0;
      rndbits4 = 0;

      int lim, lim1 = 0, lim2 = 0;
      int lim1a, lim1b;
      int high1, high2;

      int rndbits3high;
#ifdef DEBUG6
      int rndbits4high;
#endif
      int rndbits4highdigits;
      
      for(d = 0;
	  rndbits1 < ressu_bits1_needed ||
	  rndbits2 < ressu_bits2_needed ||
	  rndbits3 < ressu_bits3_needed ||
	  rndbits4 < ressu_bits4_needed ||
	  d < RESSU_MIN_ROUNDS ||
	    clockbytes < RESSU_MIN_CLOCKBYTES; d++) {

	//
	//  calculate rndbits1
	//
	
...

	ressu_genbytes_single(ressut_bytes, ressut);
...
	//
	//  calculate rndbits3
	//

	rndbits3high=0;
	rndbits3=0;
	for(e=0; e < 1024; e++) {
	  if(rndbits3high < periods[e])
	    rndbits3high = periods[e];
	}
#ifdef DEBUG8
	fprintf(stdout,"\n%d:", rndbits3high);
#endif
	for(e=0; e < 1024; e++) {
	  if(rndbits3high > periods[e]) {
	    rndbits3 += periods[e];
#ifdef DEBUG8
	    if(periods[e]>0)
	      fprintf(stdout," %ld(%d)", periods[e],rndbits3);
#endif
	  }
	}

	//
	//  calculate rndbits4
	//

	rndbits4highdigits=0;
#ifdef DEBUG6
	rndbits4high=0;
#endif
	rndbits4=0;
	for(e=0; e < 1024; e++) {
	  if(rndbits4highdigits < (int)log10((double)periods[e]) + 1) {
	    rndbits4highdigits = (int)log10((double)periods[e]) + 1;
#ifdef DEBUG6
	    rndbits4high = periods[e];
#endif
	  }
	}
#ifdef DEBUG6
	fprintf(stdout,"\n%d:", rndbits4high);
#endif
	for(e=0; e < 1024; e++) {
	  if(rndbits4highdigits > (int)log10((double)periods[e]) + 1) {
	    rndbits4 += periods[e];
#ifdef DEBUG6
	    if(periods[e]>0)
	      fprintf(stdout," %ld(%d)", periods[e],rndbits4);
#endif
	  }
	}
      } // for(d=0;
---
    } // if(ressut_pos == 0)
    ressut_f = (ressut_f + ressut[ressut_pos]) % ressut_bytes;
    buffer[c] ^= ressut[ressut_f];
    ressut_pos = (ressut_pos+1) % ressut_bytes;
  } // for(c=0; c<size; c++)

#ifdef DEBUG7
  for(c = 0; c < size; c++) {
    if(c%32 == 0)
      fprintf(stdout, "\ngenbytes  ");
    fprintf(stdout, "%02x", buffer[c]);
    newressu_output = 1;
  }
  fprintf(stdout, "\n");
#endif
  
  genbytes+=size;
}

Lähdekoodi ressu4 palvelimelle

Makefile

CC =            cc
CFLAGS =        -g -Wall -Wno-pointer-sign
newressuobjs =  newressu.mfs.o fort.o sha256.o intelrandom.o webrandom.o commandrandom.o
ressu4objs =    ressu4.o html.o dbs.o sha256.o

all:            newressu ressu4

newressu:       $(newressuobjs)
                cc $(CFLAGS) $(newressuobjs) -o newressu -lssl -lcrypto -lm

ressu4:         $(ressu4objs)
                cc $(CFLAGS) $(ressu4objs) -pthread -o ressu4 -lssl -lcrypto -lm

sha256:         $(sha256objs)
                cc $(CFLAGS) $(sha256objs) -o sha256

%.mfs.o:        %.c
                $(CC) $(CFLAGS) -DMAIN -DFORT -DSHA256 -c -o $@ $<

%.fs.o:         %.c
                $(CC) $(CFLAGS) -DFORT -DSHA256 -c -o $@ $<

%.m.o:          %.c
                $(CC) $(CFLAGS) -DMAIN -c -o $@ $<

%.o:            %.c
                $(CC) $(CFLAGS) -c -o $@ $<

clean:
                rm -f *~ \#*\# *.o

newressu.c

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <malloc.h>
#include <string.h>
#include <ctype.h>
#include <math.h>
#include <sys/time.h>
#include <time.h>

//#define SHA256 2 // in Makefile

#ifdef SHA256
#include "sha256.h"
#endif

//#define FORT 2 // in Makefile

#ifdef FORT
#include "fort.h"
#endif

//#define MAIN 2 // in Makefile

#include "newressu.h"

extern unsigned char *procname;
static unsigned char *programname = "Newressu version 2.6 ©";
static unsigned char *copyright = "Copyright (c) 2013-2022 Jari Kuivaniemi, Helsinki, Finland. Kaikki oikeudet pidätetäänn!";

static unsigned long periods[1024];
static unsigned long genbytes=0;
static unsigned long clockbytes=0;

int size=5, type=10;

#define RESSUT_BYTES 2048
#define RESSU_BITS1_NEEDED 256
#define RESSU_BITS2_NEEDED 300
#define RESSU_MIN_ROUNDS 2
#define RESSU_MIN_CLOCKBYTES 16384+1024

#define aWRITE_SAMPLE 2
#define aUSE_RANDOM 2
#define USE_TIMER 2
#define DEBUG_SORTED 2

#ifdef MAIN
static unsigned char samplefilename[128]="newressusample.rnd";
#endif
static unsigned char urandomfilename[128]="/dev/urandom";
#ifdef USE_RANDOM
static unsigned char randomfilename[128]="/dev/random";
#endif

static int ressut_bytes = RESSUT_BYTES;
static unsigned char ressut[RESSUT_BYTES];
static int ressu_bits1_needed = RESSU_BITS1_NEEDED;
static int ressu_bits2_needed = RESSU_BITS2_NEEDED;
static int ressu_bits3_needed = RESSUT_BYTES;
static int ressu_bits4_needed = RESSUT_BYTES;

#define GENT_SIZE 1024
static unsigned char gent[GENT_SIZE];
static unsigned int gent_pos=0;

int rndbits1;
int rndbits2;
int rndbits3;
int rndbits4;

int newressu_output=0;

unsigned long long get_useconds()
{
  struct timeval tv;
  gettimeofday(&tv, NULL);
  return(tv.tv_usec + 1000000 * tv.tv_sec);
}

void ressut_clear()
{
  memset(ressut, 0, sizeof(ressut));
}

static int stats=0;
#define MORESECURE 2
#define aDEBUG3 2

static unsigned char ressu_clockbyte2() /* JariK 2013 */
{
  struct timeval tv;
  gettimeofday(&tv, NULL);
  return(tv.tv_usec & 0xff);
}

static unsigned char ressu_clockbyte() /* JariK 2013 */
{
  unsigned char ch;

  ch=ressu_clockbyte2();

#ifdef MORESECURE
  static unsigned int rndbits2pausecount=1000, rndbits2pausebase=0;
  
  if(--rndbits2pausecount == 0) {
#ifdef FORT
    if(input == INPUT_FORT ||
       input == INPUT_FORTXOR)
      rndbits2pausebase += cvar[0] + 256 * cvar[1];
#endif    
    rndbits2pausebase = rndbits2pausebase +
      rndbits2pausecount +
      clockbytes +
      genbytes +
      gent_pos +
      time(NULL) +
      get_useconds() +
      ch;

    int skip=ressut[rndbits2pausebase % ressut_bytes];

    while(skip>0) { // compare usleep(skip);
      ch=ressu_clockbyte2();
      skip--;
    }

    //
    //  calculate rndbits2
    //
    rndbits2+=8;
    
    rndbits2pausecount=500+ressut[(rndbits2pausebase + 1) % ressut_bytes]*4; // value 500-1500
#ifdef DEBUG3
    fprintf(stdout,"\n%05d",pausecount);
    newressu_output=1;
#endif
  }
#ifdef DEBUG3
  fprintf(stdout," %02x",ch);
  newressu_output=1;
#endif

#endif // #ifdef MORESECURE
  return(ch);
}

#define RR8(byte,bits) ( ((byte) >> (bits)) | ((byte) << (8 - (bits))) )
#define RL8(byte,bits) ( ((byte) >> (8 - (bits))) | ((byte) << (bits)) )

#define aDEBUG5 2

void ressu_genbytes_single(int size, unsigned char *buffer)
{
  int c, d;
  unsigned char e, byte;
  static int f = 0, prevbyte = -1, count = 0;

  for(c = 0; c < 8; c++) {
    for(d = 0; d < size; d++) {
      e = buffer[d];
      e = RL8(e,1); // rotate byte left 1 bits
      //e = RL8(e,3); // rotate byte left 3 bits
      //e = RR8(e,1); // rotate byte right 1 bits
      byte = ressu_clockbyte();
      if(prevbyte == -1)
	prevbyte = byte;
      buffer[d] = e^byte;
      if(prevbyte != byte) {
	periods[count]++;
	clockbytes += count;
	count = 0;
	prevbyte = byte;
      }
      count++;
    }
#ifdef DEBUG5
    if(newressu_output)
      fprintf(stdout, "\n");
    fprintf(stdout, "single 1  ");
    for(c = 0; c < 32; c++) {
      fprintf(stdout,"%02x", buffer[c]);
      newressu_output = 1;
    }
#endif
    for(d = 0; d < size; d++) {
      f = (f + buffer[d]) % size;
      e = buffer[d];
      buffer[d] = buffer[f];
      buffer[f] = e;
    }
#ifdef DEBUG5
    if(newressu_output)
      fprintf(stdout,"\n");
    fprintf(stdout,"single 2  ");
    for(c = 0; c < 32; c++) {
      fprintf(stdout,"%02x",buffer[c]);
      newressu_output=1;
    }
#endif
  }
}

void ressu_genbytes_fast(int size, unsigned char *buffer)
{
  int c;

  clockbytes = 0;
  for(c = 0; c < RESSU_MIN_ROUNDS ||
	clockbytes < RESSU_MIN_CLOCKBYTES; c++) {
    ressu_genbytes_single(size, buffer);
  }
}

#define aDEBUG6 2
#define aDEBUG7 2
#define aDEBUG8 2

void ressu_genbytes(int size, unsigned char *buffer) // 6.5.2021 JariK
{
  int c, d, e, f;
  static int ressut_first = 1,
    ressut_pos = 0,
    ressut_f = 0;
  unsigned long prevperiods[1024];
  
  for(c = 0; c < size; c++) {
    if(ressut_pos == 0) {
      if(ressut_first) {
	memset(ressut, 0, ressut_bytes);
	ressut_first = 0;
      }

      clockbytes=0;
      for(d = 0; d < 1024; d++) {
	periods[d] = 0;
      }
      
      rndbits1 = 0;
      rndbits2 = 0;
      rndbits3 = 0;
      rndbits4 = 0;

      int lim, lim1 = 0, lim2 = 0;
      int lim1a, lim1b;
      int high1, high2;

      int rndbits3high;
#ifdef DEBUG6
      int rndbits4high;
#endif
      int rndbits4highdigits;
      
      for(d = 0;
	  rndbits1 < ressu_bits1_needed ||
	  rndbits2 < ressu_bits2_needed ||
	  rndbits3 < ressu_bits3_needed ||
	  rndbits4 < ressu_bits4_needed ||
	  d < RESSU_MIN_ROUNDS ||
	    clockbytes < RESSU_MIN_CLOCKBYTES; d++) {


	//
	//  calculate rndbits1
	//
	
	// save previous round

        for(e = 0; e < 1024; e++) {
	  prevperiods[e] = periods[e];
	}

	ressu_genbytes_single(ressut_bytes, ressut);

	// find new lim1
	
	lim = lim1;
	f = -1;
	for(e = 0; e < 1024; e++) {
	  if(prevperiods[e] > 0 && prevperiods[e] == lim) {
	    if(f == -1 || (periods[e]>0 && f<periods[e])) {
	      f  = periods[e];
	    }
	  }
	}

	if(f != -1)
	  lim = f;

	lim1a = lim;
	
	// find highest amount of chains
	
	high1 = -1;
	for(e = 0; e < 1024; e++) {
	  if(high1 == -1 || high1 < periods[e]) {
	    high1 = periods[e];
	  }
	}

	// and second highest
	
	high2 = -1;
	for(e = 0; e < 1024; e++) {
	  if( (high2 == -1 && periods[e] < high1) ||
	      (high2 < periods[e] && periods[e] < high1) ) {
	    high2 = periods[e];
	  }
	}

	// and average

	int psum = 0;
	int pcnt = 0;
	for(e = 0; e < 1024; e++) {
	  if(periods[e] > 0) {
	    psum += periods[e];
	    pcnt++;
	  }
	}

	lim1b = (int)((double)psum / pcnt);
	
	// find next smaller than average

	f = -1;
	for(e = 0; e < 1024; e++) {
	  if( (f == -1 && periods[e] < lim1b) ||
	      (f<periods[e] && periods[e] < lim1b) ) {
	    f = periods[e];
	  }
	}

	if(f != -1)
	  lim1b = f;

	if(lim == 0 || lim > lim1b)
	  lim = lim1b;

	// if lim greater that second highest,
	// set to second highest

	if(lim > high2) {
	  lim = high2;
	}
		
	lim1 = lim;

	// find next greater than lim
	
	f = -1;
	for(e = 0; e < 1024; e++) {
	  if(periods[e] > lim &&
	     (f == -1 || periods[e] < f))
	    f = periods[e];
	}
	if(f != -1)
	  lim = f;

	lim2 = lim;

	// calculate rndbits1
		
	rndbits1=0;
	for(e = 0; e < 1024; e++) {
	  if(periods[e] > 0 && periods[e] < lim) {
	    rndbits1 += periods[e];
	  }
	}
	
	//
	//  calculate rndbits3
	//

	rndbits3high=0;
	rndbits3=0;
	for(e=0; e < 1024; e++) {
	  if(rndbits3high < periods[e])
	    rndbits3high = periods[e];
	}
#ifdef DEBUG8
	fprintf(stdout,"\n%d:", rndbits3high);
#endif
	for(e=0; e < 1024; e++) {
	  if(rndbits3high > periods[e]) {
	    rndbits3 += periods[e];
#ifdef DEBUG8
	    if(periods[e]>0)
	      fprintf(stdout," %ld(%d)", periods[e],rndbits3);
#endif
	  }
	}

	//
	//  calculate rndbits4
	//

	rndbits4highdigits=0;
#ifdef DEBUG6
	rndbits4high=0;
#endif
	rndbits4=0;
	for(e=0; e < 1024; e++) {
	  if(rndbits4highdigits < (int)log10((double)periods[e]) + 1) {
	    rndbits4highdigits = (int)log10((double)periods[e]) + 1;
#ifdef DEBUG6
	    rndbits4high = periods[e];
#endif
	  }
	}
#ifdef DEBUG6
	fprintf(stdout,"\n%d:", rndbits4high);
#endif
	for(e=0; e < 1024; e++) {
	  if(rndbits4highdigits > (int)log10((double)periods[e]) + 1) {
	    rndbits4 += periods[e];
#ifdef DEBUG6
	    if(periods[e]>0)
	      fprintf(stdout," %ld(%d)", periods[e],rndbits4);
#endif
	  }
	}
      } // for(d=0;

      if(stats) {
	//
	//  display statistics
	//
	fprintf(stdout, "rounds: %d", d);
	for(e = 0; e < 1024; e++) {
	  if(periods[e] > 0)
	    fprintf(stdout, " %d:%lu", e, periods[e]);
	}

#ifdef DEBUG_SORTED
	
	fprintf(stdout, ", sorted:");
	int g = 0;
	for(;;) {
	  f = -1;
	  for(e = 0; e < 1024; e++) {
	    if( (f==-1 && periods[e]>g) ||
		(periods[e]>g && f>periods[e]) )
	      f = periods[e];
	  }
	  if(f == -1)
	    break;

	  g=f;
	  fprintf(stdout," %d", g);
	}

#endif
	fprintf(stdout, ", high1:%d", high1);
	fprintf(stdout, ", high2:%d", high2);
	fprintf(stdout, ", lim1a:%d", lim1a);
	fprintf(stdout, ", lim1b:%d", lim1b);
	fprintf(stdout, ", lim1:%d", lim1);
	fprintf(stdout, ", lim2:%d", lim2);
	fprintf(stdout, ", div:%f", (double)lim2 / lim1);
	fprintf(stdout, ", clockbytes:%ld", clockbytes);
	fprintf(stdout, ", rndbits1:%d", rndbits1);
	fprintf(stdout, ", rndbits2:%d", rndbits2);
	fprintf(stdout, ", rndbits3high:%d", rndbits3high);
	fprintf(stdout, ", rndbits3:%d", rndbits3);
	fprintf(stdout, ", rndbits4highdigits:%d", rndbits4highdigits);
	fprintf(stdout, ", rndbits4:%d", rndbits4);
	fprintf(stdout, "\n");
	fflush(stdout);
      }
    } // if(ressut_pos == 0)
    ressut_f = (ressut_f + ressut[ressut_pos]) % ressut_bytes;
    buffer[c] ^= ressut[ressut_f];
    ressut_pos = (ressut_pos+1) % ressut_bytes;
  } // for(c=0; c<size; c++)

#ifdef DEBUG7
  for(c = 0; c < size; c++) {
    if(c%32 == 0)
      fprintf(stdout, "\ngenbytes  ");
    fprintf(stdout, "%02x", buffer[c]);
    newressu_output = 1;
  }
  fprintf(stdout, "\n");
#endif
  
  genbytes+=size;
}

static unsigned char ressu_clockbyte_debug() /* JariK 2013 */
{
  unsigned char ch;

  ch=ressu_clockbyte2();
#ifdef MORESECURE
  static unsigned int pausecount=1000, pausebase=0;
  // every 1001 bytes skip randon
  // clockbytes by usleeping
  if(--pausecount == 0) {
#ifdef FORT
    if(input == INPUT_FORT ||
       input == INPUT_FORTXOR)
      pausebase += cvar[0] + 256 * cvar[1];
#endif    
    pausebase = pausebase +
      pausecount +
      clockbytes +
      genbytes +
      gent_pos +
      time(NULL) +
      get_useconds() +
      ch;
    
    int skip=ressut[pausebase % ressut_bytes];
    while(skip>0) { // compare usleep(skip);
      ch=ressu_clockbyte2();
      skip--;
    }

    rndbits2+=8;
    
    pausecount=500+ressut[(pausebase + 1) % ressut_bytes]*4; // value 500-1500
  }
#endif // #ifdef MORESECURE
  return(ch);
}

void ressu_genbytes_single_debug(int size, unsigned char *buffer)
{
  int c, d;
  unsigned char e, byte;
  static int f = 0, prevbyte = -1, count = 0;

  for(c = 0; c < 8; c++) {
    for(d = 0; d < size; d++) {
      e = buffer[d];
      e = RL8(e,1); // rotate byte left 1 bits
      //e = RL8(e,3); // rotate byte left 3 bits
      //e = RR8(e,1); // rotate byte right 1 bits
      byte = ressu_clockbyte_debug();
      if(prevbyte == -1)
	prevbyte = byte;
      buffer[d] = e^byte;
      if(prevbyte != byte) {
	periods[count]++;
	clockbytes += count;
	count = 0;
	prevbyte = byte;
      }
      count++;
    }
    for(d = 0; d < size; d++) {
      f = (f + buffer[d]) % size;
      e = buffer[d];
      buffer[d] = buffer[f];
      buffer[f] = e;
    }
  }
}

void ressu_genbytes_debug(int size, unsigned char *buffer) // 6.5.2021 JariK
{
  int c, d;
  static int ressut_first=1,
    ressut_pos = 0,
    ressut_f = 0;
  
  for(c = 0; c < size; c++) {
    if(ressut_pos == 0) {
      if(ressut_first) {
	memset(ressut, 0, ressut_bytes);
	ressut_first = 0;
      }

      rndbits2 = 0;
      clockbytes = 0;

      for(d = 0;rndbits2 < ressu_bits2_needed ||
	  d < RESSU_MIN_ROUNDS; d++) {
	ressu_genbytes_single_debug(ressut_bytes, ressut);
      }
      
      if(stats) {
	fprintf(stdout, "rounds: %d", d);
	fprintf(stdout, ", clockbytes:%ld", clockbytes);
	fprintf(stdout, ", rndbits2:%d", rndbits2);
	fprintf(stdout, "\n");
	fflush(stdout);
      }
    } // if(ressut_pos == 0)
    ressut_f = (ressut_f + ressut[ressut_pos]) % ressut_bytes;
    buffer[c] ^= ressut[ressut_f];
    ressut_pos = (ressut_pos+1) % ressut_bytes;
  } // for(c=0; c<size; c++)

#ifdef DEBUG7
  for(c = 0; c < size; c++) {
    if(c % 32 == 0)
      fprintf(stdout, "\ngenbytes  ");
    fprintf(stdout, "%02x", buffer[c]);
    newressu_output = 1;
  }
  fprintf(stdout, "\n");
#endif

  genbytes += size;
}

static void readfile_xor(int len,
    unsigned char *buf,
    unsigned char *filename)
{
  int c, n, n2;
  unsigned char temp[64];
  FILE *fp1;

  if((fp1 = fopen(filename, "rb"))
      != NULL) {
    while(len != 0) {
      n = (len < sizeof(temp)) ?
          len : sizeof(temp);
      n2=fread(temp, 1, n, fp1);
      for(c = 0; c < n2; c++)
        buf[c] ^= temp[c];
      len -= n2;
      buf += n2;
    }
    fclose(fp1);
  }
}

int input=0;

#define aDEBUG9 2

char *randomgen[] = { "ressu", "debug","fast","single","4","5","fort","fortxor","urandom","random" };

void gent_clear()
{
  memset(gent,0,sizeof(gent));
}

#define aDEBUG17 2
#define aDEBUG18 2

int ressu_genbyte()
{
  unsigned char ch;

  if(gent_pos == 0) {
    if(input == INPUT_RESSU) // ressu prod
      ressu_genbytes(sizeof(gent), gent);
    else if(input == INPUT_DEBUG) // ressu debug
      ressu_genbytes_debug(sizeof(gent), gent);
    else if(input == INPUT_FAST) // ressu_fast
      ressu_genbytes_fast(sizeof(gent),gent);
    else if(input == INPUT_SINGLE) // ressu single
      ressu_genbytes_single(sizeof(gent), gent);
#ifdef FORT
    else if(input == INPUT_FORT) // ressu fort
      fort_random_data(sizeof(gent), gent);
    else if(input == INPUT_FORTXOR) // ressu fort
      fort_random_data_xor(sizeof(gent), gent);
#endif
    else if(input == INPUT_URANDOM) // urandom
      readfile_xor(sizeof(gent), gent, urandomfilename);
#ifdef USE_RANDOM
    else if(input == INPUT_RANDOM) // random
      readfile_xor(sizeof(gent), gent, randomfilename);
#endif
    else {
      fprintf(stdout,"%s: mode '%d'(%s) not available\n",
	      procname, input, randomgen[input]);
      exit(1);
    }
#ifdef DEBUG17
    for(int c=0; c < sizeof(gent); c++) {
      if(c % 32 == 0)
	fprintf(stdout,"\ngenbyte   ");
      fprintf(stdout,"%02x", gent[c]);
    }
    fprintf(stdout,"\n");
#endif
  
  } // if(gent_pos==0
  ch = gent[gent_pos];
  gent_pos = (gent_pos + 1) % sizeof(gent);

#ifdef DEBUG18
  fprintf(stdout,"{%02x}",ch);
#endif
  return(ch);
}


#define aDEBUG19 2
#define aDEBUG24 2

unsigned long ressu_gen_limit(unsigned long limit)
{
  int c, bytes;
  unsigned long word, highlimit;
  
  if(limit<=0x100) { // 1 byte
    highlimit=0x100;
    bytes=1;
  } else if(limit<=0x10000) { // 2 bytes
    highlimit=0x10000;
    bytes=2;
  } else if(limit<=0x1000000) { // 3 bytes
    highlimit=0x1000000;
    bytes=3;
  } else if(limit<=(unsigned long)0x100000000) { // 4 bytes
    highlimit=0x100000000;
    bytes=4;
  } else if(limit<=(unsigned long)0x10000000000) { // 5 bytes
    highlimit=0x10000000000;
    bytes=5;
  } else if(limit<=(unsigned long)0x1000000000000) { // 6 bytes
    highlimit=0x1000000000000;
    bytes=6;
  } else if(limit<=(unsigned long)0x100000000000000) { // 7 bytes
    highlimit=0x100000000000000;
    bytes=7;
  } else { // if(limit<=(unsigned long)0xffffffffffffffff) { // 8 bytes
    highlimit=0xffffffffffffffff;
    bytes=8;
  }

  for(;;) {
    word=0;
    for(c=0;c<bytes;c++)
      word = word << 8 | ressu_genbyte();
    if(word < (highlimit/limit)*limit)
      break;
  }

  word%=limit;
  
#ifdef DEBUG24
  fprintf(stdout,"/");
#ifdef DEBUG19
  fprintf(stdout,"%d bytes: ", bytes);
#endif
  if(type==2)
    fprintf(stdout,"%lx", word);
  else if(type==8)
    fprintf(stdout,"%lo", word);
  else if(type==10)
    fprintf(stdout,"%lu", word);
  else if(type==16)
    fprintf(stdout,"%lx", word);
  else
    fprintf(stdout,"%lu", word);
  fprintf(stdout,"/");
  fflush(stdout);
#endif

  return(word);
}

#ifdef OLD1

// Little faster on middle byte numbers (3,5,6,7),
// try --rand & --timer
#define GENMIDBYTES 2

int ressu_genbyte_limit(int limit) // 1 byte
{
  int c;
  while((c=ressu_genbyte()) >= (0x100/limit)*limit);
#ifdef DEBUG19
  fprintf(stdout," byte %x(%d)",c,c);
  fflush(stdout);
#endif
  return(c%limit);
}

int ressu_genshort() // 2 bytes
{
  return(ressu_genbyte() | ressu_genbyte()<<8);
}

int ressu_genshort_limit(int limit) // 2 bytes
{
  int c;
  while((c=ressu_genshort()) >= (0x10000/limit)*limit);
#ifdef DEBUG19
  fprintf(stdout," short %x(%d)",c,c);
  fflush(stdout);
#endif
  return(c%limit);
}

#ifdef GENMIDBYTES

int ressu_gen3bytes() // 3 bytes
{
  return(ressu_genshort() | ressu_genbyte()<<16);
}

int ressu_gen3bytes_limit(int limit) // 3 bytes
{
  int c;
  while((c=ressu_gen3bytes()) >= (0x1000000/limit)*limit);
#ifdef DEBUG19
  fprintf(stdout," 3 bytes %x(%d)",c,c);
  fflush(stdout);
#endif
  return(c%limit);
}

#endif // #ifdef GENMIDBYTES

unsigned int ressu_genint() // 4 bytes
{
  return(ressu_genshort() | ressu_genshort()<<16);
}

unsigned int ressu_genint_limit(unsigned long limit) // 4 bytes
{
  unsigned int c;
  while((c=ressu_genint()) >= (((unsigned long)0x100000000)/limit)*limit);
#ifdef DEBUG19
  fprintf(stdout," int %x(%d)",c,c);
  fflush(stdout);
#endif
  return(c%limit);
}

#ifdef GENMIDBYTES

unsigned long ressu_gen5bytes() // 5 bytes
{
  return(ressu_genint() | ((unsigned long)ressu_genbyte())<<32);
}

unsigned long ressu_gen5bytes_limit(unsigned long limit) // 5 bytes
{
  unsigned long c;
  while((c=ressu_gen5bytes()) >= (((unsigned long)0x10000000000)/limit)*limit);
#ifdef DEBUG19
  fprintf(stdout," 5 bytes %lx(%ld)",c,c);
  fflush(stdout);
#endif
  return(c%limit);
}

unsigned long ressu_gen6bytes() // 6 bytes
{
  return(ressu_genint() | ((unsigned long)ressu_genshort())<<32);
}

unsigned long ressu_gen6bytes_limit(unsigned long limit) // 6 bytes
{
  unsigned long c;
  while((c=ressu_gen6bytes()) >= (((unsigned long)0x1000000000000)/limit)*limit);
#ifdef DEBUG19
  fprintf(stdout," 6 bytes %lx(%ld)",c,c);
  fflush(stdout);
#endif
  return(c%limit);
}

unsigned long ressu_gen7bytes() // 7 bytes
{
  return(ressu_genint() | ((unsigned long)ressu_gen3bytes())<<32);
}

#define aDEBUG22

unsigned long ressu_gen7bytes_limit(unsigned long limit) // 7 bytes
{
  unsigned long c;
  while((c=ressu_gen7bytes()) >= (((unsigned long)0x100000000000000)/limit)*limit);
#ifdef DEBUG19
  fprintf(stdout," 7 bytes %lx(%ld)",c,c);
  fflush(stdout);
#endif
  return(c%limit);
}

#endif // #ifdef GENMIDBYTES

unsigned long ressu_genlong() // 8 bytes
{
  return(((unsigned long)ressu_genint()) | ((unsigned long)ressu_genint())<<32);
}

unsigned long ressu_genlong_limit(unsigned long limit) // 8 bytes
{
  unsigned long c;
  while((c=ressu_genlong()) >= (((unsigned long)0xffffffffffffffff)/limit)*limit);
#ifdef DEBUG19
  fprintf(stdout," long %lx(%lu)",c,c);
  fflush(stdout);
#endif
  return(c%limit);
}


unsigned long ressu_gen_limit2(unsigned long limit)
{
  unsigned long c;

  if(limit<=0x100) // 1 byte
    c=ressu_genbyte_limit(limit);
  else if(limit<=0x10000) // 2 bytes
    c=ressu_genshort_limit(limit);
#ifdef GENMIDBYTES
  else if(limit<=0x1000000) // 3 bytes
    c=ressu_gen3bytes_limit(limit);
#endif
  else if(limit<=(unsigned long)0x100000000) // 4 bytes
    c=ressu_genint_limit(limit);
#ifdef GENMIDBYTES
  else if(limit<=(unsigned long)0x10000000000) // 5 bytes
    c=ressu_gen5bytes_limit(limit);
  else if(limit<=(unsigned long)0x1000000000000) // 6 bytes
    c=ressu_gen6bytes_limit(limit);
  else if(limit<=(unsigned long)0x100000000000000) // 7 bytes
    c=ressu_gen7bytes_limit(limit);
#endif
  else if(limit<=(unsigned long)0xffffffffffffffff) // 8 bytes
    c=ressu_genlong_limit(limit);
  else
    c=-1;

#ifdef DEBUG24
  fprintf(stdout,"/%ld/",c);
#endif

  return(c);
}

#endif

void newressu_version()
{
  fprintf(stderr,"%s",programname); // touch these outside MAIN
  fprintf(stderr,", %s",copyright);
}

#ifdef MAIN

#include <stdarg.h>

#define aDEBUG31

static int stat_line_chars=0;
static int stat_line_edchars=0;

unsigned char *procname=NULL;

static void stat_line_begin()
{
#ifdef DEBUG31
  fprintf(stderr,"\n");
#else
  fprintf(stderr,"\r");
#endif  
  stat_line_edchars=stat_line_chars;
  stat_line_chars=0;
}

static void stat_line_printf(const unsigned char *format, ...)
{
  int count;
  va_list args;
  static unsigned char *stat_line_buf;
  static size_t stat_line_buf_length;

  va_start(args, format);
  count = vsnprintf(stat_line_buf, stat_line_buf_length, format, args) + 1;
  va_end(args);
  if(stat_line_buf_length < count) {
    stat_line_buf_length=count;
    stat_line_buf=realloc(stat_line_buf, stat_line_buf_length);
    va_start(args, format);
    count = vsnprintf(stat_line_buf, stat_line_buf_length, format, args) + 1;
    va_end(args);
  }
  fprintf(stderr,"%s",stat_line_buf);
  stat_line_chars+=strlen(stat_line_buf);
}

#define READABLE_NUMBER_BIN 2

#ifdef READABLE_NUMBER_BIN
#define READABLE_NUMBER_HIGH 1023
#define READABLE_NUMBER_DIVIDER 1024
#else
#define READABLE_NUMBER_HIGH 999
#define READABLE_NUMBER_DIVIDER 1000
#endif

#define READABLE_NUMBER_WIDTH 32

static void stat_line_readable(unsigned long length)
{
  int c, low;
  double length2;
  unsigned char buf10[10];
  // B = byte
  // K = kilo   10^3   2^10
  // M = mega   10^6   2^20
  // G = giga   10^9   2^30
  // T = tera   10^12  2^40
  // P = peta   10^15  2^50
  // E = exa    10^18  2^60
  // Z = zetta  10^21  2^70
  // Y = yotta  10^24  2^80
  char units[] = "BKMGTPEZY";

  strcpy(buf10,"***");
  low=0;

  for(c=0; length>=low &&
      c<sizeof(units)-1; c++) {
    if(length>=low &&
       length<=READABLE_NUMBER_HIGH) {
      if(units[c]=='B')
        sprintf(buf10,"%ld", length);
      else if(units[c]=='K')
	sprintf(buf10,"%ld%cB", length, units[c]);
      else if(length==length2)
	sprintf(buf10,"%ld%cB", length, units[c]);
      else
	sprintf(buf10,"%.1f%cB", length2, units[c]);
	
      break;
    }
    length2=(double)length/READABLE_NUMBER_DIVIDER;
    length/=READABLE_NUMBER_DIVIDER;
    low=1;
  }
  stat_line_printf("%s",buf10);
}

void stat_line_end()
{
  int c,d;

  // previous line longer than this one,
  // overwrite with spaces and backspace to
  // end
  
  if(stat_line_edchars>stat_line_chars) {
    d=stat_line_edchars-stat_line_chars;
    for(c=0;c<d;c++) {
#ifdef DEBUG31
      fprintf(stderr,"*");
#else
      fprintf(stderr," ");
#endif
    }
    for(c=0;c<d;c++)
      fprintf(stderr,"\b");
  }
  fflush(stderr);
}

int help=0;

static int utf8characters(unsigned char *buf)
{
  int characters;
  unsigned char *p;
  
  p=buf;
  characters=0;
  while(*p!='\0') {
    if(*p<0x80 || // ascii char
       *p>0xbf) // first utf8 byte
      characters++;
    p++;
  }
  return(characters);
}

#define aDEBUG29 2

int utf8lengths(unsigned char *buf)
{
  int lengths,len,first=1;
  unsigned char *p;

#ifdef DEBUG29 
  fprintf(stdout,"digits    %s",buf);
  fprintf(stdout,"\nlengths   ");
#endif
  
  p=buf;
  len=0;
  lengths=-1;
  first=1;

  while(*p!='\0') {
    if(!first &&
       (*p<0x80 || // ascii char
	*p>0xbf)) { // first utf8 byte
#ifdef DEBUG29
      fprintf(stdout,"%d",len);
#endif
      if(lengths==-1)
	lengths=len;
      else if(lengths!=len)
	lengths=0;
      len=0;
    }
    p++;
    len++;
    first=0;
  }

#ifdef DEBUG29
  fprintf(stdout,"%d",len);
#endif
  if(lengths==-1)
    lengths=len;
  else if(lengths!=len)
    lengths=0;

#ifdef DEBUG29
  fprintf(stdout,"\nlengths   %d\n\n",lengths);
#endif
  return(lengths);
}

#define aDEBUG42 2

static void codetoutf8(unsigned char *buf2, unsigned long code)
{
  unsigned char *buf;

  buf=buf2;
  if(code<=0x7f) {
    *buf++=code;
  } else if(code<=0x7ff) {            // 110xxxxx 10xxxxxx
    *buf++=(0xc0 | ((code>>6)&0x1f));
    *buf++=(0x80 | (code&0x3f));
  } else if(code<=0xffff) {           // 1110xxxx 10xxxxxx 10xxxxxx
    *buf++=(0xe0 | ((code>>12)&0x0f));
    *buf++=(0x80 | ((code>>6)&0x3f));
    *buf++=(0x80 | (code&0x3f));
  } else if(code<=0x10ffff) {         // 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
    *buf++=(0xf0 | ((code>>18)&0x07));
    *buf++=(0x80 | ((code>>12)&0x3f));      
    *buf++=(0x80 | ((code>>6)&0x3f));      
    *buf++=(0x80 | ((code&0x3f)));      
  } else if(code<=0x3ffffff) {        // 111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx // these not yet needed
    *buf++=(0xf8 | ((code>>24)&0x03));
    *buf++=(0x80 | ((code>>18)&0x3f));      
    *buf++=(0x80 | ((code>>12)&0x3f));      
    *buf++=(0x80 | ((code>>6)&0x3f));      
    *buf++=(0x80 | ((code&0x3f)));      
  } else if(code<=0x7fffffff) {       // 1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx // these not yet needed
    *buf++=(0xfc | ((code>>30)&0x01));
    *buf++=(0x80 | ((code>>24)&0x3f));      
    *buf++=(0x80 | ((code>>18)&0x3f));      
    *buf++=(0x80 | ((code>>12)&0x3f));      
    *buf++=(0x80 | ((code>>6)&0x3f));      
    *buf++=(0x80 | ((code&0x3f)));      
  } else if(code<=0xfffffffff) {      // 11111110 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx // these not yet needed
    *buf++=(0xfe);
    *buf++=(0x80 | ((code>>30)&0x3f));      
    *buf++=(0x80 | ((code>>24)&0x3f));      
    *buf++=(0x80 | ((code>>18)&0x3f));      
    *buf++=(0x80 | ((code>>12)&0x3f));      
    *buf++=(0x80 | ((code>>6)&0x3f));      
    *buf++=(0x80 | ((code&0x3f)));      
  } else if(code<=0x3ffffffffff) {    // 11111111 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx // these not yet needed
    *buf++=(0xff);
    *buf++=(0x80 | ((code>>36)&0x3f));      
    *buf++=(0x80 | ((code>>30)&0x3f));      
    *buf++=(0x80 | ((code>>24)&0x3f));      
    *buf++=(0x80 | ((code>>18)&0x3f));      
    *buf++=(0x80 | ((code>>12)&0x3f));      
    *buf++=(0x80 | ((code>>6)&0x3f));      
    *buf++=(0x80 | ((code&0x3f)));      
  }
  *buf='\0';

#ifdef DEBUG42
  int c,print;

  fprintf(stdout,"codepoint: %lx",code);

  fprintf(stdout,", bin:");

  print=0;
  for(c=(sizeof(code)*8)-1;c>=0;c--) {
    int bit=(code>>c)&1;
    if(bit!=0)
      print=1;
    if(print) {
      fprintf(stdout,"%d",bit);
      if(c>0 && c%8==0)
	fprintf(stdout,"|");
    }
  }

  fprintf(stdout,", oct:");
  print=0;
  fprintf(stdout,"%lo",code);

  fprintf(stdout,", utf8: ");
  for(c=0;c<8;c++) {
    if(buf2[c]=='\0')
      break;
    fprintf(stdout,"%02x",buf2[c]);
  }

  fprintf(stdout,", bin: ");
  for(c=0;c<8;c++) {
    if(buf2[c]=='\0')
      break;
    if(c>0)
      fprintf(stdout,"|");
    for(int d=7;d>=0;d--) {
      fprintf(stdout,"%d",buf2[c]>>d&1);
    }
  }

  fprintf(stdout,", oct:");
  for(c=0;c<8;c++) {
    if(buf2[c]=='\0')
      break;
    fprintf(stdout," %3o",buf2[c]);
  }
  
  fprintf(stdout,", character: %s",buf2);
  fprintf(stdout,"\n");
#endif
}

#ifdef NOTUSED

#define aDEBUG43 2

static void utf8tocode(unsigned long *code, unsigned char *buf2)
{
  unsigned char *buf;
  
  *code=0;
  buf=buf2;
  
  if(*buf<=0x7f) {                  // 0xxxxxxx
    *code=*buf;
  } else if(*buf<0xc0) {            // 110xxxxx 10xxxxxx
    *code=0;
  } else if(*buf<0xe0) {            // 110xxxxx 10xxxxxx
    *code=*buf++&0x1f;
    *code=(*code<<6)+(*buf++&0x3f);
  } else if(*buf<0xf0) {            // 1110xxxx 10xxxxxx 10xxxxxx
    *code=*buf++&0x0f;
    *code=(*code<<6)+(*buf++&0x3f);
    *code=(*code<<6)+(*buf++&0x3f);
  } else if(*buf<0xf8) {            // 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
    *code=*buf++&0x07;
    *code=(*code<<6)+(*buf++&0x3f);
    *code=(*code<<6)+(*buf++&0x3f);
    *code=(*code<<6)+(*buf++&0x3f);
  } else if(*buf<0xfc) {            // 111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx
    *code=*buf++&0x03;
    *code=(*code<<6)+(*buf++&0x3f);
    *code=(*code<<6)+(*buf++&0x3f);
    *code=(*code<<6)+(*buf++&0x3f);
    *code=(*code<<6)+(*buf++&0x3f);
  } else if(*buf<0xfe) {            // 1111110x 10xxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx
    *code=*buf++&0x01;
    *code=(*code<<6)+(*buf++&0x3f);
    *code=(*code<<6)+(*buf++&0x3f);
    *code=(*code<<6)+(*buf++&0x3f);
    *code=(*code<<6)+(*buf++&0x3f);
    *code=(*code<<6)+(*buf++&0x3f);
  } else if(*buf<0xff) {            // 11111110 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx
    buf++;
    *code=*buf++&0x3f;
    *code=(*code<<6)+(*buf++&0x3f);
    *code=(*code<<6)+(*buf++&0x3f);
    *code=(*code<<6)+(*buf++&0x3f);
    *code=(*code<<6)+(*buf++&0x3f);
    *code=(*code<<6)+(*buf++&0x3f);
  } else if(*buf==0xff) {            // 11111111 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx
    buf++;
    *code=*buf++&0x3f;
    *code=(*code<<6)+(*buf++&0x3f);
    *code=(*code<<6)+(*buf++&0x3f);
    *code=(*code<<6)+(*buf++&0x3f);
    *code=(*code<<6)+(*buf++&0x3f);
    *code=(*code<<6)+(*buf++&0x3f);
    *code=(*code<<6)+(*buf++&0x3f);
  }
#ifdef DEBUG43
  int c;

  fprintf(stdout,"character: %s",buf2);

  fprintf(stdout,", utf8: ");
  for(c=0;c<8;c++) {
    if(buf2[c]=='\0')
      break;
    fprintf(stdout,"%02x",buf2[c]);
  }

  fprintf(stdout,", bin: ");
  for(c=0;c<8;c++) {
    if(buf2[c]=='\0')
      break;
    if(c>0)
      fprintf(stdout,"|");
    for(int d=7;d>=0;d--)
      fprintf(stdout,"%d",buf2[c]>>d&1);
  }

  fprintf(stdout,", oct:");
  for(c=0;c<8;c++) {
    if(buf2[c]=='\0')
      break;
    fprintf(stdout," %3o",buf2[c]);
  }
  
  fprintf(stdout,", codepoint: %lx",*code);
  fprintf(stdout,", bin:");
  int print=0;
  for(c=(sizeof(code)*8)-1;c>=0;c--) {
    int bit=(*code>>c)&1;
    if(bit!=0)
      print=1;
    if(print) {
      fprintf(stdout,"%d",bit);
      if(c>0 && c%8==0)
	fprintf(stdout,"|");
    }
  }

  fprintf(stdout,", oct:");
  fprintf(stdout,"%lo",*code);
  
  fprintf(stdout,"\n");
#endif
}

#endif

int characterlengths=0; // 0 multiple lengths, x lengths are same

#define aDEBUG30 2

static void utf8getcharacter(int size, unsigned char *buf, int n, unsigned char *string)
{
  int d;
  unsigned char *p,*q;
  
  d=0;
  p=string;
  q=buf;

  // find first byte of character

  if(characterlengths!=0)
    p+=characterlengths*n;
  else {
    while(*p!='\0') {
      if(*p<0x80 || // ascii char
	 *p>0xbf) { // first utf8 char
	if(d==n)
	  break;
	d++;
      }
      p++;
    }
  }

  // copy first byte and rest
  // of character
  
  if(*p!='\0') {
    *q++=*p; // copy first byte
    if(*p>0xbf) { // if first is utf8 char
      p++;
      for(;;) {
	if(*p>0xbf || // first utf8 char
	   *p<0x80 || // ascii char
	   *p=='\0')  // end of file
	  break;
	*q++=*p++; // copy rest of the bytes
      }
    }
  }
  *q='\0';

#ifdef DEBUG30
  fprintf(stdout,"%s: utf8getcharacter:",procname);
  fprintf(stdout," string: %s",string);
  fprintf(stdout,", n: %d",n);
  fprintf(stdout,", character: %s",buf);
  fprintf(stdout,", characterlengths: %d",characterlengths);
  fprintf(stdout,"\n");
#endif
}

static void utf8getcharacter1(int size, unsigned char *buf, int n, unsigned char *string)
{
  unsigned char *p,*q;
  
  p=string;
  q=buf;

  // find first byte of character

  p+=n;

  // copy first byte and rest
  // of character
  
  if(*p!='\0') {
    *q++=*p; // copy first byte
    if(*p>0xbf) { // if first is utf8 char
      p++;
      for(;;) {
	if(*p>0xbf || // first utf8 char
	   *p<0x80 || // ascii char
	   *p=='\0')  // end of file
	  break;
	*q++=*p++; // copy rest of the bytes
      }
    }
  }
  *q='\0';

#ifdef DEBUG30
  fprintf(stdout,"%s: utf8getcharacter:",procname);
  fprintf(stdout," string: %s",string);
  fprintf(stdout,", n: %d",n);
  fprintf(stdout,", character: %s",buf);
  fprintf(stdout,", characterlengths: %d",characterlengths);
  fprintf(stdout,"\n");
#endif
}

#define aDEBUG45 2

int digitscount=10;

static void out_word(int size, unsigned char *buf, unsigned char *digits, unsigned long word2) // 8.5.2021 JariK
{
  int c, d, len;
  unsigned long word;
  unsigned char string[132], character[32];

  //digitscount = utf8characters(digits);
  word=word2;
  len=0;
  string[0]='\0';

  if(word==0 || digitscount<2) {
    // zero
    utf8getcharacter(sizeof(character),character,0,digits);
    if(len+strlen(character)<sizeof(string)) {
      strcat(string,character);
      len+=strlen(character);
    }
  } else {
    // non zero
    while(word>0) {
      utf8getcharacter(sizeof(character),character,word%digitscount,digits);
      if(len+strlen(character)<sizeof(string)) {
	strcat(string,character);
	len+=strlen(character);
      }
      word/=digitscount;
    }
  }

  // reverse string
  
  *buf='\0';
  len=0;
  d=utf8characters(string);
  for(c=d-1;c>=0;c--) {
    utf8getcharacter(sizeof(character),character,c,string);
    if(len+strlen(character)<size) {
      strcat(buf,character);
      len+=strlen(character);
    }
  }

#ifdef DEBUG45
  fprintf(stdout,"]\n%s: out_word: ",procname);
  fprintf(stdout," reverse string: %s",string);
  fprintf(stdout,", digits: %s",digits);
  fprintf(stdout,", int: %lu",word2);
  fprintf(stdout,"\n[");
#endif
}

static void out_word_10(int size, unsigned char *buf, unsigned long word2) // 8.5.2021 JariK
{
  int c, d, len;
  unsigned long word;
  unsigned char string[132], character[32];
  unsigned char *digits="0123456789";
  int digitscount=10;
  
  //digitscount = utf8characters(digits);
  word=word2;
  len=0;
  string[0]='\0';

  if(word==0 || digitscount<2) {
    // zero
    utf8getcharacter1(sizeof(character),character,0,digits);
    if(len+strlen(character)<sizeof(string)) {
      strcat(string,character);
      len+=strlen(character);
    }
  } else {
    // non zero
    while(word>0) {
      utf8getcharacter1(sizeof(character),character,word%digitscount,digits);
      if(len+strlen(character)<sizeof(string)) {
	strcat(string,character);
	len+=strlen(character);
      }
      word/=digitscount;
    }
  }

  // reverse string
  
  *buf='\0';
  len=0;
  d=utf8characters(string);
  for(c=d-1;c>=0;c--) {
    utf8getcharacter1(sizeof(character),character,c,string);
    if(len+strlen(character)<size) {
      strcat(buf,character);
      len+=strlen(character);
    }
  }

#ifdef DEBUG45
  fprintf(stdout,"]\n%s: out_word: ",procname);
  fprintf(stdout," reverse string: %s",string);
  fprintf(stdout,", digits: %s",digits);
  fprintf(stdout,", int: %lu",word2);
  fprintf(stdout,"\n[");
#endif
}

#define aDEBUG48 2

static void in_word(unsigned long *word, unsigned char *digits, unsigned char *buf)
{
  int c,d,e,f,ok;
  unsigned char character[32], character2[32];

  *word=0;
  d=utf8characters(buf);
  f=utf8characters(digits);

  for(c=0;c<d;c++) {
    utf8getcharacter(sizeof(character2),character2,c,buf);
    ok=0;
    for(e=0;e<f;e++) {
      utf8getcharacter(sizeof(character),character,e,digits);
      if(!strcmp(character,character2)) {
	ok=1;
	break;
      }
    }
    if(ok) {
      *word=((*word)*f)+e;
    } else {
      fprintf(stdout,"%s: in_word:",procname);
      fprintf(stdout," illegal digit '%s'\n",character2);
      help=1;
    }
  }

#ifdef DEBUG48
  fprintf(stdout,"%s: in_word:",procname);
  fprintf(stdout," word: %lu",*word);
  fprintf(stdout,", digits: %s",digits);
  fprintf(stdout,", string: %s",buf);
  fprintf(stdout,"\n");
#endif
}

static void line_clear(int *len, unsigned char **buf)
{
  if(*len<1) {
    *len=129;
    *buf=realloc(*buf,*len);
  }
  **buf='\0';
}

static int line_add_string_sort(int *len, unsigned char **buf, unsigned char *string)
{
  int cmp,count,add;
  unsigned char *p;

  p=*buf;
  add=1;
  while(*p!='\0') {
    cmp=strncmp(string,p,strlen(string));
    if(cmp>0) {
      while(*p!=' ' && *p!='\0') // find next space
	p++;
      while(*p==' ' && *p!='\0') // find next non space
	p++;
    } else if(cmp==0) {
      add=0;
      break;
    } else {
      break;
    }
  }

  if(add) {
    count=strlen(*buf)+strlen(string)+1+1;
    if(*buf==NULL || count>*len) {
      int diff=p-*buf;
      *len = *len + 128;
      *buf=realloc(*buf,*len);
      p=*buf+diff;
    }
    memmove(p+strlen(string)+1,p,strlen(p)+1);
    memmove(p,string,strlen(string));
    p+=strlen(string);
    *p=' ';
  }

  return(add);
}

static void line_get_string(int len, unsigned char *buf, int n, unsigned char *string)
{
  int e,ok,count;
  unsigned char *p,*q;

  ok=0;
  p=string;
  e=0;

  while(*p!='\0') {
    if(e==n) {
      ok=1;
      break;
    }
    while(*p!=' ' && *p!='\0') // find next space
      p++;
    while(*p==' ' && *p!='\0') // find next non space
      p++;
    e++;
  }
  if(ok) {
    q=buf;
    count=0;
    while(*q!=' ' && *q!='\0') {
      if(++count<len)
	*q++=*p;
      p++;
    }
    *q='\0';
  } else {
    buf[0]='\0';
  }
}

static int zero=1, sspace=0, snewline=0,
  scrlf=1, chars=72, pchars=0, charwidth=1, charspaces=0,
  words=0, pwords=0,
  plinesdigits=5, slineno=1, screen=0,
  quiet=0, sort=0, unique=0, sample=0;
#ifdef DEBUG51
static int limitsize=0,
#endif
static unsigned long long lines=10, plines=0, ptotallines=0;
static unsigned long limit, word;
static unsigned char *digits="0123456789", character[32];
static unsigned char digitstemp[256], *digitsext=NULL;
static unsigned char linenobuf[1024];

#define aDEBUG51 2

static void readword(unsigned char *buf)
{
  int d,e;
  unsigned char temp1024[1024];
  
  if(limit!=0) {
    word=0;
    
    if(zero) {
      word=ressu_gen_limit(limit); // include zeroes
    } else if(limit>=1) {
      while((word=ressu_gen_limit(limit))==0); // skip zeroes
    }
#ifdef DEBUG51
    if(type==2)
      fprintf(stdout,"(%0*lx)",limitsize,word);
    else if(type==8)
      fprintf(stdout,"(%0*lo)",limitsize,word);
    else if(type==10)
      fprintf(stdout,"(%0*lu)",limitsize,word);
    else if(type==16)
      fprintf(stdout,"(%0*lx)",limitsize,word);
    else {
      fprintf(stdout,"(%02lu)",word);
    }
#endif
	  
    out_word(sizeof(temp1024),temp1024,digits,word);
	  
    // fill leading zeroes
    
    buf[0]='\0';
    utf8getcharacter(sizeof(character),character,0,digits);
    for(d=size-utf8characters(temp1024);d>0;d--) {
      strcat(buf,character);
    }
	  
    // rest of the number
	  
    strcat(buf,temp1024);
	  
  } else if(digits!=NULL) {
	  
    buf[0]='\0';
	  
#ifdef DEBUG51
    fprintf(stdout,"(");
#endif
    // fill whole word digit by digit
    for(d=0;d<size;d++) {
      if(digits[0]=='0' && !zero)
	e=ressu_gen_limit(digitscount-1)+1;
      else
	e=ressu_gen_limit(digitscount);
      utf8getcharacter(sizeof(temp1024),temp1024,e,digits);
#ifdef DEBUG51
      fprintf(stdout,"%s",temp1024);
      if(charspaces==1)
	fputc(' ',stdout);
#endif
      strcat(buf,temp1024);
    }
#ifdef DEBUG51
    fprintf(stdout,")");
#endif
  }
}

#ifdef OLD1
static void readword(unsigned char *buf)
{
  int d,e;
  unsigned char temp1024[1024];
  
  if(limit!=0) {
    word=0;
    
    if(zero) {
      word=ressu_gen_limit(limit); // include zeroes
#ifdef DEBUG51
      if(type==2)
	fprintf(stdout,"(%02lx)",word);
      else if(type==8)
	fprintf(stdout,"(%02lo)",word);
      else if(type==10)
	fprintf(stdout,"(%02ld)",word);
      else if(type==16)
	fprintf(stdout,"(%02lx)",word);
      else
	fprintf(stdout,"(%02ld)",word);
#endif
    } else if(limit>=1) {
      while((word=ressu_gen_limit(limit))==0); // skip zeroes
    }
	  
    out_word(sizeof(temp1024),temp1024,digits,word);
	  
    // fill leading zeroes
    
    buf[0]='\0';
    utf8getcharacter(sizeof(character),character,0,digits);
    for(d=size-utf8characters(temp1024);d>0;d--) {
      strcat(buf,character);
    }
	  
    // rest of the number
	  
    strcat(buf,temp1024);
	  
  } else if(digits!=NULL) {
	  
    buf[0]='\0';
    //digitscount=utf8characters(digits);
	  
    // fill whole word digit by digit
	  
    //fprintf(stdout,"[");
    for(d=0;d<size;d++) {
      if(digits[0]=='0' && !zero)
	e=ressu_gen_limit(digitscount-1)+1;
      else
	e=ressu_gen_limit(digitscount);
      utf8getcharacter(sizeof(temp1024),temp1024,e,digits);
      //fprintf(stdout,"%s",temp1024);
      strcat(buf,temp1024);
    }
    //fprintf(stdout,"]");
  }
}

#endif

static int line_number_length()
{
  int c;
  out_word_10(sizeof(linenobuf),linenobuf,lines-1);
  c=strlen(linenobuf);
  if(c<5)
    c=5;
  return(c);
}

static void print_line_number()
{
  unsigned char linenobuf[32];
  
  if(pwords==0 && slineno) {
    sprintf(linenobuf,"%0*llu",plinesdigits,plines);
    fprintf(stdout,"%s",linenobuf);
    fprintf(stdout," ");
  }
}

static int calc_spaces()
{
  int spaces;

  spaces=0;
  
  if(sspace>=2 &&
     // space between word groups
     ( (pwords>0 && pwords%sspace==0) ||
       // space after linenumber
       // are not printed if
       // not printing linenumber
       (slineno && pwords==0) ) )
    spaces++;
    
  if(sspace &&
     // space between words
     ( (pwords>0) ||
       // space after linenumber
       (slineno && pwords==0) ) ) 
    spaces++;

  return(spaces);
}

static void print_spaces()
{
  int sp;

  for(sp=calc_spaces();sp>0;sp--)
    fprintf(stdout," ");
}

static void print_word(unsigned char *buf)
{
  int e;
  
  if(size!=0) {
    if(charspaces==0) {
      fprintf(stdout,"%s",buf);
    } else {
      for(e=0;e<size;e++) {
	unsigned char temp1024[1024];
	utf8getcharacter(sizeof(temp1024),temp1024,e,buf);
	fprintf(stdout,"%s",temp1024);
	fputc(' ',stdout);
      }
    }
  } else {
    fprintf(stdout,"%s",buf);
    if(charspaces==1) {
      fputc(' ',stdout);
    }
  }
}

#ifdef OLD1

static void print_word(unsigned char *buf)
{
  if(charspaces==1) {
    fprintf(stdout,"%*s ",size,buf);
  } else if(size!=0) {
      fprintf(stdout,"%*s",size,buf);
  } else {
    fprintf(stdout,"%s",buf);
  }
}

#endif

#ifdef SHA256

static void newressu_file_digest(char *filename,unsigned char *hash)
{
  int c;
  unsigned char buffer[1024];
  FILE *fp1;
  HashCtx ctx;
  
  HashInit(&ctx);
  if((fp1 = fopen(filename, "rb"))!=NULL) {
    while((c=fread(buffer, 1, sizeof(buffer), fp1)) > 0)
      HashUpdate(&ctx, buffer, c);
    fclose(fp1);
  }
  HashFinal(hash, &ctx);  
}

#endif

#define aDEBUG55 2

void digits_add_string(unsigned char **digits, char *str)
{
  int digitssize;

#ifdef DEBUG55
  fprintf(stdout,"\nolddigits %s",*digits);
  fprintf(stdout,"\nadddigits %s",str);
#endif
  digitssize=0;
  if(*digits!=NULL)
    digitssize+=strlen(*digits);
  digitssize+=strlen(str);
  *digits=realloc(*digits,digitssize+1);
  strcat(*digits,str);
#ifdef DEBUG55
  fprintf(stdout,"\nnewdigits %s",*digits);
  fprintf(stdout,"\n");
#endif
}

void digits_add_limits(unsigned char **digits, int start, int end)
{
  int c, digitssize;
  unsigned char buffer[10];

#ifdef DEBUG55
  fprintf(stdout,"\nolddigits %s",*digits);
  fprintf(stdout,"\nadddigits start:%d, end:%d",start,end);
#endif
  digitssize=0;
  if(*digits!=NULL)
    digitssize+=strlen(*digits);
  
  for(c=start;c<=end;c++) {
    codetoutf8(buffer,c);
    digitssize+=strlen(buffer);
  }
  *digits=realloc(*digits,digitssize+1);
  for(c=start;c<=end;c++) {
    codetoutf8(buffer,c);
    strcat(*digits,buffer);
  }
#ifdef DEBUG55
  fprintf(stdout,"\nnewdigits %s",*digits);
  fprintf(stdout,"\n");
#endif
}

double getseconds()
{
  struct timeval tv;
  gettimeofday(&tv,NULL);
  return((double)tv.tv_sec+(double)tv.tv_usec/1000000);
}

void dump_sample()
{
//sample file size = CLIM*DLIM*BLKSIZE
#define CLIM 8192 // outer loop
#define DLIM 256 // inner loop
#define BLKSIZE 4096 // block size

#define STAT_LINE_READY 2
#define STAT_LINE_NOW 2
#define STAT_LINE_ANIM 2
    
#define TIMEFORMAT "%H:%M %Z"
#define TIMEFORMAT2 "%a %H:%M %Z"
#define DATEFORMAT "%a %d %b %Y"
    
    unsigned int c, d;
    unsigned char buffer[BLKSIZE];
    FILE *fp1;
    time_t secondsstart, secondsnow;
#ifdef STAT_LINE_ANIM
    long int secs, prev_secs=-1;
    int crs=0;
#endif

    if((fp1=fopen(samplefilename,"a")) != NULL) {

      secondsstart=time(NULL);

      for(c=0;c<CLIM;c++) {
	secondsnow=time(NULL);
	
	// print status line:
	// blk 10, written 10MB, 269KB/sec, left 8 h 38 m, ready at Sat 17 Jul 2021 01:57:43 EEST, now Fri 17:19:32 EEST
	
	stat_line_begin();
	stat_line_printf("\rblk %d, written ",c);
	stat_line_readable((unsigned long)c*DLIM*BLKSIZE);
	
	if(c>0) {
	  stat_line_printf(", ");
	  stat_line_readable((unsigned long)((double)c*DLIM*BLKSIZE/(secondsnow-secondsstart)) );
	  stat_line_printf("/sec");

	  char timebuf[128], timebuf2[128];
	  
#ifdef STAT_LINE_NOW

	  // print now
	  
	  stat_line_printf(", now");
	  strftime(timebuf,sizeof(timebuf),TIMEFORMAT2,
		   localtime((time_t *)&secondsnow));
	  stat_line_printf(" %s",timebuf);
#endif

	  // print left
	  
	  long int secondsleft=(int)((((double)secondsnow-secondsstart)/c)*(CLIM-c) );
	  long int secondsleft2;
	  long int temp,timeprinted=0;

	  secondsleft2=secondsleft;
	  stat_line_printf(", left");
	  
	  temp=secondsleft2/(24*3600);
	  if(temp>0) {
	    timeprinted=1;
	    stat_line_printf(" %dd",temp);
	    secondsleft2-=temp*(24*3600);
	  }
	  temp=secondsleft2/3600;
	  if(temp>0) {
	    timeprinted=1;
	    stat_line_printf(" %dh",temp);
	    secondsleft2-=temp*3600;
	  }
	  temp=secondsleft2/60;
	  if(temp>0) {
	    timeprinted=1;
	    stat_line_printf(" %dm",temp);
	    secondsleft2-=temp*60;
	  }
	  temp=secondsleft2;
	  if(!timeprinted) {
	    stat_line_printf(" %d seconds",temp);
	  }

#ifdef STAT_LINE_READY

	  long int secondsend=(int)secondsstart+((((double)secondsnow-secondsstart)/c)*CLIM);

	  // print end date if different7
	  
	  stat_line_printf(", ready at");
	  strftime(timebuf,sizeof(timebuf),DATEFORMAT,
		   localtime((time_t *)&secondsend));
	  strftime(timebuf2,sizeof(timebuf2),DATEFORMAT,
		   localtime((time_t *)&secondsnow));
	  if(strcmp(timebuf,timebuf2)) {
	    stat_line_printf(" %s",timebuf);
	  }

	  // print end time
	  
	  strftime(timebuf,sizeof(timebuf),TIMEFORMAT,
		   localtime((time_t *)&secondsend));
	  stat_line_printf(" %s",timebuf);
#endif

	}

	stat_line_end();
	
	// do the work
	
#ifdef STAT_LINE_ANIM
	unsigned char cursor[4] = { '|', '/', '-', '\\' };

	fprintf(stderr," ");
#endif
	for(d=0;d<DLIM;d++) {
#ifdef STAT_LINE_ANIM
	  secs=time(NULL)%sizeof(cursor);
	  if(prev_secs!=secs) {
	    if(prev_secs!=-1) 
	      crs=(crs+1)%sizeof(cursor);
	    fprintf(stderr,"\b%c",cursor[crs]);
	    fflush(stderr);
	    prev_secs=secs;
	  }
#endif
	  if(input==INPUT_RESSU) // ressu prod
	    ressu_genbytes(sizeof(buffer),buffer);
	  else if(input==INPUT_DEBUG) // ressu debug
	    ressu_genbytes_debug(sizeof(buffer),buffer);
	  else if(input==INPUT_FAST) // ressu fast
	    ressu_genbytes_fast(sizeof(buffer),buffer);
	  else if(input==INPUT_SINGLE) // ressu single
	    ressu_genbytes_single(sizeof(buffer),buffer);
#ifdef FORT
	  else if(input==INPUT_FORT) // ressu fort
	    fort_random_data(sizeof(buffer),buffer);
	  else if(input==INPUT_FORTXOR) // ressu fort
	    fort_random_data_xor(sizeof(buffer),buffer);
#endif
	  else if(input==INPUT_URANDOM) // urandom
	    readfile_xor(sizeof(buffer),buffer,urandomfilename);
#ifdef USE_RANDOM
	  else if(input==INPUT_RANDOM) // random
	    readfile_xor(sizeof(buffer),buffer,randomfilename);
#endif
	  
#ifdef WRITE_SAMPLE
	  fwrite(buffer,1,sizeof(buffer),fp1);
#endif
	} // for(d=0;
#ifdef STAT_LINE_ANIM
	fprintf(stderr,"\b \b");
	prev_secs=-1;
#endif
      }
      fclose(fp1);
    } // if((fp1=fopen

    // remove last status line
    
    stat_line_begin();
    stat_line_printf("Done!");
    stat_line_end();
    fprintf(stdout,"\n");
    fflush(stdout);
}

#include <sys/ioctl.h> // for TIOCGWINSZ

#define aDEBUG50 2

#define aDEBUG71 2

void call_main(char *);

#define aCALL_MAIN 2

#define aDEBUG63 2

#ifdef CALL_MAIN

#define DEBUG99 2

int main2(int argc, char *argv[]);

void call_main(char *cmd)
{
  int size, round, count, chars;
  unsigned char *p, *q, *argmem,*params;
  char **argv;

  size = 0;

  for(round = 0; round < 2; round++) {
    count = 0;
    p = cmd;
    while(*p != '\0') {
      while(*p == ' ' || *p == '\t')
	p++;
      q = p;
      chars = 0;
      while(*p != ' ' &&  *p != '\t' && *p != '\0') {
	p++;
	chars++;
      }
      if(round == 0) // calculate size & alloc
	size += chars + 1 + sizeof(char *);
      else { // move parameters to arg area
	strncpy(params, q, chars);
	*(argv+count) = params;
	params += (chars+1);
      }
      count++;
    }
    if(round == 0) { // allocate
      size += sizeof(char *); // ending NULL
      argmem = malloc(size);
      argv = (char **)argmem;
      params = argmem + sizeof(char *) * (count+1);
    }
  }

  *(argv+count) = NULL; // ending NULL

#ifdef DEBUG99
  
  fprintf(stdout, "size:%d,", size);
  fprintf(stdout, " argmem:");
  for(int c = 0; c < size; c++) {
    if(c > 0 && c%8 == 0)
      fprintf(stdout, "|");
    if(*(argmem+c) == '\\')
      fprintf(stdout, "\\\\");
    if(isprint(*(argmem+c)))
      fprintf(stdout, "%c", *(argmem+c));
    else
      fprintf(stdout, "\\%02x", *(argmem+c));
  }
  fprintf(stdout, "\n");

#endif // #ifdef DEBUG99

  main2(count, argv);
}

int main(int argc, char *argv[])
{
  int first;
  char buffer[1024];

  first=1;
  buffer[0]='\0';
  for(int c=0;c<argc;c++) {
    if(!first)
      strcat(buffer," ");
    strcat(buffer,argv[c]);
    first=0;
  }
#ifdef DEBUG99
  fprintf(stdout,"main: cmd \"%s\"\n",buffer);
#endif
  
  call_main(buffer);
}

#endif // #ifdef CALL_MAIN

#ifdef CALL_MAIN

int main2(int argc, char *argv[])
{
#ifdef DEBUG99
  fprintf(stdout,"main2args:");  
  for(int c=0;c<argc;c++) {
    fprintf(stdout," %d:\"%s\"",c,argv[c]);
  }
  fprintf(stdout,"\n");
#endif // #ifdef DEBUG99

#else // #ifdef CALL_MAIN

int main(int argc, char *argv[])
{
#endif // #ifdef CALL_MAIN
  
  int c, d, status=0;

  procname=argv[0];
  limit=0;

#ifdef NOTUSED
  for(c=0;c<100000000;c++) {
    fprintf(stdout,"%d %f %f\n",c,log10((double)c),log10((double)c)+1);
  }
#endif
  gent_clear();
  ressut_clear();

  clockbytes=0;
  for(d=0;d<1024;d++)
    periods[d]=0;

  
#ifdef DEBUG63
  
  //unsigned long l=(unsigned long)ressu_gen_limit((unsigned long)10001);
  //for(;l<=0x3ffffffffff;l*=2) {
  unsigned long l=1;
  for(;l<=0x3ffffffffff;l*=2) {
    if(l==0x9d || l==0x9e || l==0x9f)
      continue;
    unsigned char buffer[32];
    unsigned long code;
    codetoutf8(buffer, l);
    utf8tocode(&code, buffer);
    if(code!=l) {
      fprintf(stdout,"%s: codetoutf8 and utf8tocode does not match",procname);
      fprintf(stdout,", l:%ld",l);
      fprintf(stdout,", code:%ld",code);
      fprintf(stdout,"\n");
      exit(1);
    }
  }
#endif
  
#ifdef USE_TIMER
  int timer=0;
  double timerstart;
#endif  

  // look thru command line parameters
  
  for(c=1;c<argc;c++) {
    if(!strncmp("-",argv[c],1)) {
      if(!strcmp("--lineno",argv[c])) {
	slineno = !slineno;

      } else if(!strcmp("--crlf",argv[c])) {
	scrlf = !scrlf;
	slineno = 0;

      } else if(!strcmp("--quiet",argv[c])) {
	quiet = !quiet;

      } else if(!strcmp("--stats",argv[c]) ||
	!strcmp("--stat",argv[c])) {
	stats = !stats;

      } else if(!strcmp("--rand",argv[c])) {
	digits = "0123456789";
	sspace = 2;
	snewline = 5;
	slineno = 1;
	words = 10;
	chars = 0;
	limit = 100000;
	//size=5;
	//lines=20000;
	
      } else if(!strncmp("--space",argv[c],7)) {
	if(*(argv[c]+7)!='\0' && atoi(argv[c]+7)>1) {
	  sspace = atoi(argv[c]+7);
	} else if(c+1<argc && atoi(argv[c+1])>1) {
	  sspace = atoi(argv[c+1]);
	  c++;
	} else {
	  sspace = !sspace;
	}

      } else if(!strncmp("--newline",argv[c],9)) {
	if(*(argv[c]+9)!='\0' && atoi(argv[c]+9)>0) {
	  snewline = atoi(argv[c]+9);
	} else if(c+1<argc && atoi(argv[c+1])>0) {
	  snewline = atoi(argv[c+1]);
	  c++;
	}

      } else if(!strcmp("--zero",argv[c])) {
	zero = !zero;

      } else if(!strcmp("--sort",argv[c])) {
	sort = !sort;
	if(sspace == 0)
	  sspace = 1;
		
      } else if(!strcmp("--unique",argv[c])) {
	unique =! unique;
	if(sspace == 0)
	  sspace = 1;
		
      } else if(!strcmp("--lotto",argv[c])) {
	sort = !sort;
	if(sspace==0)
	  sspace = 1;
	//sort = 1;
	//unique = 1;

      } else if(!strcmp("--sample",argv[c])) {
	sample = !sample;
	
      } else if(!strcmp("--copyright",argv[c]) ||
	 !strcmp("--version",argv[c])) {
	newressu_version();
#ifdef SHA256
	unsigned char filedigest[HashLen];
	newressu_file_digest("/proc/self/exe", filedigest);
	fprintf(stderr,"\nsha256: ");
	for(int c = 0;c < HashLen; c++) {
	  fprintf(stderr,"%02x", filedigest[c]);
	}
#endif

	fprintf(stderr,"\n\n");
	help = 1;
	
      } else if(!strncmp("--lim",argv[c],5)) {
	if(*(argv[c]+5)!='\0') {
	  in_word(&limit, digits, argv[c]+5);
	} else if(c+1<argc) {
	  in_word(&limit, digits, argv[c+1]);
	  c++;
	}
	if(sspace< 1 ) // 23.6.2021
	  sspace = 1;

      } else if(!strncmp("-s",argv[c],2)) {
	if(*(argv[c]+2)!='\0') {
	  size = atoi(argv[c]+2);
	} else if(c+1<argc) {
	  size = atoi(argv[c+1]);
	  c++;
	}
	limit = 0; // 23.6.2021

      } else if(!strncmp("--bits",argv[c],6)) {
	if(*(argv[c]+6)!='\0') {
	  ressu_bits1_needed = atoi(argv[c]+6);
	} else if(c+1<argc) {
	  ressu_bits1_needed = atoi(argv[c+1]);
	  c++;
	}	

      } else if(!strncmp("--bytes",argv[c],7)) {
	if(*(argv[c]+7)!='\0') {
	  ressut_bytes = atoi(argv[c]+7);
	} else if(c+1<argc) {
	  ressut_bytes = atoi(argv[c+1]);
	  c++;
	}	

      } else if(!strncmp("-w",argv[c],2)) { // words per line
	if(*(argv[c]+2)!='\0') {
	  words = atoi(argv[c]+2);
	} else if(c+1<argc) {
	  words = atoi(argv[c+1]);
	  c++;
	}
	if(words < 1)
	  words = 1;
	chars = 0;
	screen = 0;
	
      } else if(!strncmp("-c*",argv[c],3)) {
	struct winsize w;
	ioctl(0, TIOCGWINSZ, &w);
	chars = w.ws_col;
	words = 0;
#ifdef DEBUG71
	fprintf(stdout,"screencolumns:%d\n",chars);
#endif

      } else if(!strncmp("-l*",argv[c],3)) {
	struct winsize w;
	ioctl(0, TIOCGWINSZ, &w);
	lines = w.ws_row-1;
#ifdef DEBUG71
	fprintf(stdout,"screenlines:%lld\n",lines);
#endif

      } else if(!strncmp("--screen",argv[c],8)) {
	struct winsize w;
	ioctl(0, TIOCGWINSZ, &w);
	chars = w.ws_col;
	lines = w.ws_row-1;
	words = 0;
	screen = 1;
#ifdef DEBUG71
	fprintf(stdout,"screencolumns:%d",chars);
	fprintf(stdout," screenlines:%lld\n",lines);
#endif
	
      } else if(!strncmp("-c",argv[c],2)) {  // characters per line
	if(*(argv[c]+2)!='\0') {
	  chars = atoi(argv[c]+2);
	} else if(c+1<argc) {
	  chars = atoi(argv[c+1]);
	  c++;
	}
	if(chars < 1)
	  chars = 72;
	words = 0;
	screen = 0;
	
      } else if(!strncmp("-l",argv[c],2)) { // lines
	if(*(argv[c]+2)!='\0') {
	  lines = atoll(argv[c]+2);
	} else if(c+1<argc) {
	  lines = atoll(argv[c+1]);
	  c++;
	}
	screen = 0;
	
      } else if(!strcmp("-x",argv[c])) {
	digits = "0123456789abcdef";
	charspaces = 0;
	charwidth = 1;
	size = 4;
	type = 16;

      } else if(!strcmp("-X",argv[c])) {
	digits = "0123456789ABCDEF";
	charspaces = 0;
	charwidth = 1;
	size = 4;
	type = 16;

      } else if(!strcmp("-d",argv[c])) {
	digits = "0123456789";
	charspaces = 0;
	charwidth = 1;
	size = 5;
	type = 10;

      } else if(!strcmp("-o",argv[c])) {
	digits = "01234567";
	charspaces = 0;
	charwidth = 1;
	size = 3;
	type = 8;

      } else if(!strcmp("-b",argv[c])) {
	digits = "01";
	charspaces = 0;
	charwidth = 1;
	size = 8;
	type = 2;

      } else if(!strcmp("-1",argv[c])) {
	digits=
	  "0123456789" \
	  "ABCDEFGHIJKLMNOPQRSTUVWXYZ" \
	  "abcdefghijklmnopqrstuvwxyz";
	charspaces = 0;
	charwidth = 1;
	size = 1;
	type = 0;

      } else if(!strcmp("-11",argv[c])) {
	digits=
	  "0123456789";
	charspaces = 0;
	charwidth = 1;
	size = 1;
	type = 10;

      } else if(!strcmp("-12",argv[c])) {
	digits=
	  "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
	charspaces = 0;
	charwidth = 1;
	size = 1;

      } else if(!strcmp("-13",argv[c])) {
	digits=
	  "abcdefghijklmnopqrstuvwxyz";
	charspaces = 0;
	charwidth = 1;
	size = 1;
	type = 0;

      } else if(!strcmp("-2",argv[c])) {
	digits=
	  "0123456789" \
	  "ABCDEFGHIJKLMNOPQRSTUVWXYZ" \
	  "abcdefghijklmnopqrstuvwxyz" \
	  "_-";
	charspaces = 0;
	charwidth = 1;
	size = 8;
	type = 0;

      } else if(!strcmp("-3",argv[c])) { // 9.5.2021 JariK
	digits=
	  "!\"#$%&'()*+,-./0123456789:;<=>?@" \
	  "ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`" \
	  "abcdefghijklmnopqrstuvwxyz{|}~";
	charspaces = 0;
	charwidth = 1;
	size = 8;
	type = 0;

      } else if(!strcmp("--dnk",argv[c]) || // Danish alphabet
		!strcmp("--nor",argv[c])) { // Norwegian alphabet
	digits=
	  "ABCDEFGHIJKLMNOPQRSTUVWXYZÆØÅ" \
	  "abcdefghijklmnopqrstuvwxyzæøå";
	charspaces = 0;
	charwidth = 1;
	size = 8;
	type = 0;

      } else if(!strcmp("--fin",argv[c]) || // Finnish alphabet
		!strcmp("--swe",argv[c])) { // Swedish alphabet
	digits=
	  "ABCDEFGHIJKLMNOPQRSTUVWXYZÅÄÖ" \
	  "abcdefghijklmnopqrstuvwxyzåäö";
	charspaces = 0;
	charwidth = 1;
	size = 8;
	type = 0;

      } else if(!strcmp("--rus",argv[c])) { // Russian alphabet
	digits=
	  "АБВГДЕЁЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯ" \
	  "абвгдеёжзийклмнопрстуфхцчшщъыьэюя";
	charspaces = 0;
	charwidth = 1;
	size = 8;
	type = 0;

      } else if(!strcmp("--est",argv[c])) { // Estonian alphabet

	digits=
	  "ABCDEFGHIJKLMNOPQRSŠZŽTUVWÕÄÖÜXY" \
	  "abcdefghijklmnopqrsšzžtuvwõäöüxy";
	charspaces = 0;
	charwidth = 1;
	size = 8;
	type = 0;
  
      } else if(!strcmp("--ltu",argv[c])) { // Lithuanian alphabet
	digits=
	  "AĄBCČDEĘĖFGHIĮYJKLMNOPRSŠTUŲŪVZŽ" \
	  "aąbcčdeęėfghiįyjklmnoprsštuųūvzž";
	charspaces = 0;
	charwidth = 1;
	size = 8;
	type = 0;

      } else if(!strcmp("--lva",argv[c])) { // Latvian alphabet
	digits=
	  "AĀBCČDEĒFGĢHIĪJKĶLĻMNŅOPRSŠTUŪVZŽ" \
	  "aābcčdeēfgģhiījkķlļmnņoprsštuūvzž";
	charspaces = 0;
	charwidth = 1;
	size = 8;
	type = 0;

      } else if(!strcmp("--fra",argv[c]) // French alphabet
		||!strcmp("--gbr",argv[c]) // Great Britain alphabet
		||!strcmp("--usa",argv[c]) // United States alphabet
		||!strcmp("--ita",argv[c]) // Italian alphabet
		||!strcmp("--eng",argv[c]) // English alphabet
		) {
	digits=
	  "ABCDEFGHIJKLMNOPQRSTUVWXYZ" \
	  "abcdefghijklmnopqrstuvwxyz";
	charspaces = 0;
	charwidth = 1;
	size = 8;
	type = 0;

      } else if(!strcmp("--deu",argv[c])) { // Deutsch alphabet
	digits=
	  "ABCDEFGHIJKLMNOPQRSTUVWXYZÄÖÜẞ" \
	  "abcdefghijklmnopqrstuvwxyzäöüß";
	charspaces = 0;
	charwidth = 1;
	size = 8;
	type = 0;

      } else if(!strcmp("--grc",argv[c])) { // Greek alphabet
	digits=
	  "ΑΒΓΔΕΖΗΘΙΚΛΜΝΞΟΠΡΣΤΥΦΧΨΩ" \
	  "αβγδεζηθικλμνξοπρστυφχψω";
	charspaces = 0;
	charwidth = 1;
	size = 8;
	type = 0;
	
      } else if(!strcmp("--jp",argv[c])) { // all Japanese alphabets

	digits = NULL;
	digits_add_string(&digits,
	    "ぁあぃいぅうぇえぉおかがきぎく"
	  "ぐけげこごさざしじすずせぜそぞた"
	  "だちぢっつづてでとどなにぬねのは"
	  "ばぱひびぴふぶぷへべぺほぼぽまみ"
	  "むめもゃやゅゆょよらりるれろゎわ"
	  "ゐゑをんゔゕゖ");
	digits_add_string(&digits,
	  "゠ァアィイゥウェエォオカガキギク"
	  "グケゲコゴサザシジスズセゼソゾタ"
	  "ダチヂッツヅテデトドナニヌネノハ"
	  "バパヒビピフブプヘベペホボポマミ"
	  "ムメモャヤュユョヨラリルレロヮワ"
	  "ヰヱヲンヴヵヶヷヸヹヺ・ーヽヾヿ");
	digits_add_limits(&digits,0x4e00,0x9fef);

	digitsext = digits;
	charspaces = 0;
	charwidth = 2;
	size = 8;
	type = 0;

	
      } else if(!strcmp("--jp1",argv[c]) // Japanese hiragana alphabet
		||!strcmp("--hir",argv[c])) { // Japanese hiragana alphabet
	digits=
	    "ぁあぃいぅうぇえぉおかがきぎく"
	  "ぐけげこごさざしじすずせぜそぞた"
	  "だちぢっつづてでとどなにぬねのは"
	  "ばぱひびぴふぶぷへべぺほぼぽまみ"
	  "むめもゃやゅゆょよらりるれろゎわ"
	  "ゐゑをんゔゕゖ";
	charspaces = 0;
	charwidth = 2;
	size = 8;
	type = 0;

      } else if(!strcmp("--jp2",argv[c]) // Japanese katakana alphabet
		||!strcmp("--kat",argv[c])) {  // Japanese katakana alphabet
	digits=
	  "゠ァアィイゥウェエォオカガキギク"
	  "グケゲコゴサザシジスズセゼソゾタ"
	  "ダチヂッツヅテデトドナニヌネノハ"
	  "バパヒビピフブプヘベペホボポマミ"
	  "ムメモャヤュユョヨラリルレロヮワ"
	  "ヰヱヲンヴヵヶヷヸヹヺ・ーヽヾヿ";
	charspaces = 0;
	charwidth = 2;
	size = 8;
	type = 0;

      } else if(!strcmp("--cn",argv[c]) // Chinese alphabet 
		||!strcmp("--jp3",argv[c]) // Japanese kanji alphabet
		||!strcmp("--kan",argv[c])) { // Japanese kanji alphabet

	digits = NULL;
	digits_add_limits(&digits,0x4e00,0x9fef);

	digitsext = digits;
	charspaces = 0;
	charwidth = 2;
	size = 8;
	type = 0;
	
      } else if(!strcmp("--kor",argv[c])) { // Korean alphabet 

	digits = NULL;
	digits_add_limits(&digits,0xac00,0xd7a3);   // Hangul Syllables (AC00–D7A3)
	//digits_add_limits(&digits,0x1100,0x11ff); // Hangul Jamo (1100–11FF)
	//digits_add_limits(&digits,0x3130,0x318f); // Hangul Compatibility Jamo (3130–318F)
	//digits_add_limits(&digits,0xa960,0xa97f); // Hangul Jamo Extended-A (A960–A97F)
	//digits_add_limits(&digits,0xd7b0,0xd7ff); //Hangul Jamo Extended-B (D7B0–D7FF)

	digitsext = digits;
	charspaces = 0;
	charwidth = 2;
	size = 8;
	type = 0;

      } else if(!strcmp("--got",argv[c])) { // Greek alphabet                                                                                                                          
        digits=
          "𐌰𐌱𐌲𐌳𐌴𐌵𐌶𐌷𐌸𐌹𐌺𐌻𐌼𐌽𐌾𐌿"
          "𐍀𐍁𐍂𐍃𐍄𐍅𐍆𐍇𐍈𐍉𐍊";
	charspaces = 0;
	charwidth = 1;
        size = 8;
	type = 0;

      } else if(!strcmp("--cards",argv[c])) {
	digits=
	  "🂡🂢🂣🂤🂥🂦🂧🂨🂩🂪🂫🂭🂮" \
	  "🂱🂲🂳🂴🂵🂶🂷🂸🂹🂺🂻🂽🂾" \
	  "🃁🃂🃃🃄🃅🃆🃇🃈🃉🃊🃋🃍🃎" \
	  "🃑🃒🃓🃔🃕🃖🃗🃘🃙🃚🃛🃝🃞";
	charspaces = 1;
	charwidth = 2;
	size = 1;
	type = 0;

      } else if(!strcmp("--cardsuits",argv[c])) {
	digits=
	  "♠♡♢♣♤♥♦♧";
	charspaces = 1;
	charwidth = 2;
	size = 1;
	type = 0;

      } else if(!strcmp("--chess",argv[c])) {
	digits=
	  "♔♕♖♗♘♙♚♛♜♝♞♟";
	charspaces = 1;
	charwidth = 2;
	size = 1;
	type = 0;
	
      } else if(!strcmp("--pattern1",argv[c])) {
	digits=
	  "▌▙▄";
	charspaces = 0;
	charwidth = 1;
	size = 1;
	type = 0;

      } else if(!strcmp("--pattern2",argv[c])) {
	digits=
	  "◜◝◞◟";
	charspaces = 0;
	charwidth = 1;
	size = 1;
	type = 0;

      } else if(!strcmp("--pattern3",argv[c])) {
	digits=
	  "\\/";
	charspaces = 0;
	charwidth = 1;
	size = 1;
	type = 0;

      } else if(!strcmp("--pattern4",argv[c])) {
	digits=
	  "◸◹◺◿";
	charspaces = 1;
	charwidth = 2;
	size = 1;
	type = 0;

      } else if(!strcmp("--pattern5",argv[c])) {
	digits=
	  "▧▨";
	charspaces = 1;
	charwidth = 2;
	size = 1;
	type = 0;

      } else if(!strcmp("--isalnum",argv[c]) || // 9.5.2021 JariK
	        !strcmp("--isalpha",argv[c]) ||
	        !strcmp("--isdigit",argv[c]) ||
	        !strcmp("--isgraph",argv[c]) ||
	        !strcmp("--islower",argv[c]) ||
	        !strcmp("--isprint",argv[c]) ||
	        !strcmp("--ispunct",argv[c]) ||
	        !strcmp("--isupper",argv[c]) ||
		!strcmp("--isxdigit",argv[c])) {
	unsigned char *p=digitstemp;
	for(d=0;d<256;d++) {
	  if((!strcmp("--isalnum",argv[c]) && isalnum(d)) ||
	     (!strcmp("--isalpha",argv[c]) && isalpha(d)) ||
	     (!strcmp("--isdigit",argv[c]) && isdigit(d)) ||
	     (!strcmp("--isgraph",argv[c]) && isgraph(d)) ||
	     (!strcmp("--islower",argv[c]) && islower(d)) ||
	     (!strcmp("--isprint",argv[c]) && isprint(d)) ||
	     (!strcmp("--ispunct",argv[c]) && ispunct(d)) ||
	     (!strcmp("--isupper",argv[c]) && isupper(d)) ||
	     (!strcmp("--isxdigit",argv[c]) && isxdigit(d))) {
	    *p++=d;
	  }
	}
	*p='\0';
	digits = digitstemp;
	size = 8;
	type = 0;

      } else if(!strncmp("-i",argv[c],2)) {
	digits=NULL;
	if(*(argv[c]+2)!='\0') {
	  digits = argv[c]+2;
	} else if(c+1 < argc) {
	  digits = argv[c+1];
	  c++;
	}
	if(digits==NULL || utf8characters(digits)<2) {
	  fprintf(stderr,"%s: not enough digits \"%s\"\n",procname,argv[c]);
	  help = 1;
	}
	size = 1;

#ifdef USE_TIMER
      } else if(!strcmp("--timer",argv[c])) {
	timer=1;

#endif
      } else if(!strcmp("--ressu",argv[c])) {
	input = INPUT_RESSU;

      } else if(!strcmp("--debug",argv[c])) {
	input = INPUT_DEBUG;

      } else if(!strcmp("--fast",argv[c])) {
	input = INPUT_FAST;

      } else if(!strcmp("--single",argv[c])) {
	input = INPUT_SINGLE;

#ifdef FORT
      } else if(!strcmp("--fort",argv[c])) {
	input = INPUT_FORT;

      } else if(!strcmp("--fortxor",argv[c])) {
	input = INPUT_FORTXOR;

      } else if(!strcmp("--fortverbose",argv[c])) {
	fort_verbose = !fort_verbose;

      } else if(!strcmp("--fortuseweb",argv[c])) {
	fort_use_web = !fort_use_web;
	
#endif
      } else if(!strcmp("--urandom",argv[c])) {
	input = INPUT_URANDOM;

#ifdef USE_RANDOM
      } else if(!strcmp("--random",argv[c])) {
	input = INPUT_RANDOM;

#endif
      } else {
	fprintf(stderr,"%s: invalid option %s\n",procname,argv[c]);
	status = 1;
	help = 1;
      }
    } else {
      help = 1;

    } // if(!strncmp
  } // for(c=0

  if(size == 0)
    size = 1;
  else if(size > 1024)
    size = 1024;
  if(lines < 1)
    lines = 1;

#ifdef USE_TIMER
  timerstart=getseconds();
#endif
  
  digitscount = utf8characters(digits);
  characterlengths = utf8lengths(digits);

#ifdef FORT
  if(input == INPUT_FORT ||
     input == INPUT_FORTXOR ) {
    strcpy(fort_random_file, "newressufort.rnd");
    //fort_verbose=0;
    fort_init();
  }
#endif
  
  if(sample) {
    dump_sample();
    exit(status);
  } // if(sample)

  // get linenumber length in digits

  plinesdigits = line_number_length();

  // get data length in digits

  if(limit != 0) {
    unsigned char wordbuf[128];
    out_word(sizeof(wordbuf), wordbuf, digits, limit-1);
    size = utf8characters(wordbuf);
  }

  pchars = 0;
  pwords = 0;
  int linew = 0;

  // in beginning of line, count printed line number
      
  if(!quiet && slineno) {
    sprintf(linenobuf,"%0*llu", plinesdigits, plines);
    pchars += strlen(linenobuf);
    pchars++;
  }

  // count words
  
  while((chars > 0 && pchars+size*charwidth+calc_spaces() <= chars) ||
	(words > 0 && pwords < words)) {
    
    linew++;

#ifdef DEBUG50
    fprintf(stdout,"spaces:%d", calc_spaces());
#endif
    
    pchars += calc_spaces();
    pchars += (size*charwidth);
    pwords++;

#ifdef DEBUG50
    fprintf(stdout,", chars:%d", chars);
    fprintf(stdout,", pchars:%d", pchars); 
    fprintf(stdout,", words:%d", words);
    fprintf(stdout,", pwords:%d", pwords);  
    fprintf(stdout,"\n");
#endif
  }

  // one data word needed
  
  if(linew < 1)
    linew = 1;

  unsigned long wordvalues=1, wordvaluesold;

  for(c = 0; c < size; c++) {
    wordvaluesold = wordvalues;
    wordvalues *= digitscount;
    if(wordvalues / digitscount != wordvaluesold) {
      wordvalues = 0;
      break;
    }
  }
  
  if(limit > 0) {
    if(sort==1 && limit-!zero < words) {
      fprintf(stderr,"%s: limit is less than words (zero)", procname);
      fprintf(stderr,", limit:%lu", limit);
      fprintf(stderr,", words:%d", words);
      fprintf(stderr,", zero:%d", zero);
      fprintf(stderr,"\n");
      
      help = 1;
      lines = 0;
    }
  } else {
    if(sort == 1 && size > 0 && wordvalues > 0 && wordvalues < linew) {
      fprintf(stderr,"%s:", procname);
      fprintf(stderr," digits is less than calculated words");
      fprintf(stderr,", digits:%d(%lu)", digitscount, wordvalues);
      fprintf(stderr,", words:%d\n", linew);
      help = 1;
      lines = 0;
    }
  }

  // "small" words as single ressu_gen_limit() call
  
  if(limit == 0 && wordvalues > 0)
    limit = wordvalues;

#ifdef DEBUG51
  unsigned char buffer10[10];
  if(type==2)
    sprintf(buffer10,"%2lx",limit-1);
  else if(type==8)
    sprintf(buffer10,"%2lo",limit-1);
  else if(type==10)
    sprintf(buffer10,"%2ld",limit-1);
  else if(type==16)
    sprintf(buffer10,"%2lx",limit-1);
  else
    sprintf(buffer10,"%2ld",limit-1);
  limitsize=strlen(buffer10);
#endif  
  
  if(stats) {
    fprintf(stdout,"randomsource: %s", randomgen[input]);
    fprintf(stdout,", size: %d", size);
    fprintf(stdout,", linew: %d", linew);
    fprintf(stdout,", pchars: %d", pchars);
    fprintf(stdout,", pwords: %d", pwords);
    fprintf(stdout,", tchars: %llu", (unsigned long long)size*linew*lines);
    fprintf(stdout,", digitscount: %d", digitscount);
    if(wordvalues > 0)
      fprintf(stdout,", wordvalues: %lu", wordvalues);
    if(limit > 0) {
      fprintf(stdout,", limit: %lu", limit);
#ifdef DEBUG51
      fprintf(stdout,", type: %d",type);
      fprintf(stdout,", limitsize%d: %d",type,limitsize);
#endif
    }
    fprintf(stdout,"\n");
  }
  
  if(help) {
    struct helpline {
      char *command;
      char *text;
    } helplines[] = {
      { "newressu -d", "print random decimal digits (default)" },
      { "newressu -o", "print octal digits" },
      { "newressu -x", "print hexadecimal digits" },
      { "newressu -b", "print binary digits" },
      { "newressu -d --space", "print decimal digits, with spaces between \"words\"" },
      { "newressu -b --space", "print binary digits, with spaces between \"words\"" },
      { "newressu -d -l30", "print decimal digits, 30 lines" },
      { "newressu -d -l30 --lineno", "print decimal digits, 30 lines, no linenumbers"  },
      { "newressu --rand", "print numbers in rand style listing"  },
      { "newressu --space 2", "print numbers in 2 number groups"  },
      { "newressu --newline 5", "print numbers in 5 line groups"  },
      { "newressu -l*", "fill all screen lines"  },
      { "newressu -c*", "fill all screen columns"  },
      { "newressu --screen", "fill screen columns and lines"  },
      { "newressu -d -c128", "print decimal digits, 128 characters per line"  },
      { "newressu -d --lim10", "print decimal numbers between 0-9" },
      { "newressu -d --lim10 -x","print hexadecimal numbers with decimal limit" },
      { "newressu -d -s10 --space","print decimal numbers with spaces and wordsize 10" },
      { "newressu -d --space --zero --lim7","print rollings of dice (1-6)" },
      { "newressu -b -s1 --space","print throws of coin (0,1)" },
      { "newressu -d --lim41 -w7 --zero --lotto","print lotto numbers for finnish lotto 7x(1-40)" },
      { "newressu -d -s5 --sort -w16","print 16 sorted decimal numbers from 0 to 99999" },
      { "newressu --isalnum", "print alphanumeric characters" },
      { "newressu --isalpha", "print alphabetic characters" },
      { "newressu --isgraph", "print printables excluding space" },
      { "newressu --islower", "print lowercase characters" },
      { "newressu --ispunct", "print punctuation characters" },
      { "newressu --isupper", "print uppercase characters" },
      { "newressu -1", "print material for passwords" },
      { "newressu --dnk/--nor", "danish/norwegian alphabet" },
      { "newressu --fin/--swe", "finnish/norwegian alphabet" },
      { "newressu --rus", "russian alphabet" },
      { "newressu --est", "estonian alphabet" },
      { "newressu --ltu", "lithuanian alphabet" },
      { "newressu --lva", "latvian alphabet" },
      { "newressu --fra/--gbr/--usa/--ita", "french/gb/us/italian alphabet" },
      { "newressu --deu", "deutsch alphabet" }, 
      { "newressu --grc", "greek alphabet" }, 
      { "newressu --jp", "japan alphabet (hiragana, katakana, kanji) " }, 
      { "newressu --jp1/--hir", "japan alphabet (hiragana) " }, 
      { "newressu --jp2/--kat", "japan alphabet (katakana) " }, 
      { "newressu --jp3/--kan", "japan alphabet (kanji) " }, 
      { "newressu --cn", "chinese alphabet" }, 
      { "newressu --kor", "korean alphabet" }, 
      { "newressu --got", "gothic alphabet" }, 
      { "newressu --cards", "playing cards" }, 
      { "newressu --cardsuits", "playing card suits" }, 
      { "newressu --chess", "chess men" }, 
      { "newressu -i▌▙▄ / --pattern1", "print pattern1" },
      { "newressu -i\\\\/ / --pattern2", "print pattern2" },
      { "newressu --ressu", "use randomness from ressu (default)" },
      { "newressu --debug", "use randomness from debugging ressu" },
      { "newressu --fast", "use randomness from fast ressu" },
      { "newressu --single", "use randomness from single round of ressu" },
#ifdef FORT
      { "newressu --fort", "use randomness from fort" },
#endif
      { "newressu --urandom", "use randomness from /dev/urandom" },
#ifdef USE_RANDOM
      { "newressu --random", "use randomness from /dev/random" },
#endif
    };
    
    for(c = 0; c < sizeof(helplines) / sizeof(helplines[0]); c++) {
      fprintf(stderr,"%-50s", helplines[c].text);
      fprintf(stderr,"%-25s", helplines[c].command);
      fprintf(stderr,"\n");
    }
    for(c = 0; c < chars; c++)
      fprintf(stdout, "*");
    fprintf(stdout, "\n");
    if(lines > 1)
      lines = 1; // print one line below help as a sample
  }

  if(lines == 0)
    exit(status);

  int linecnt = 0;
  unsigned char *line = NULL;
  unsigned char wordbuf[1025];
  
  for(;;) {

    if(!sort) { // no sort, no lotto

      pwords = 0;

      while(pwords < linew) {
	readword(wordbuf);

	if(!quiet) {

	  if(newressu_output) {
	    fprintf(stdout, "\n");
	    newressu_output = 0;
	  }

	  // in beginning of line, print line number

	  print_line_number();
	
	  // want to print spaces between "words"?

	  print_spaces();
	
	  // print word

	  print_word(wordbuf);
	}

	pwords++;
      } // while(pwords<linew) {
    } else { // if(!sort)

      pwords = 0;
      
      line_clear(&linecnt, &line);

      // fetch and save words on this row

      while(pwords < linew) {
	readword(wordbuf);

	if(line_add_string_sort(&linecnt, &line, wordbuf)) {
	  pwords++;
	}
      } // while(pwords<linew) {

      pwords = 0;

      // print words on this row

      while(pwords < linew) {

	line_get_string(sizeof(wordbuf), wordbuf, pwords, line);

	if(!quiet) {

	  if(newressu_output) {
	    fprintf(stdout, "\n");
	    newressu_output = 0;
	  }
	  
	  // in beginning of line, print line number

	  print_line_number();
	
	  // want to print spaces between "words"?
	
	  print_spaces();

	  // print word
	
	  print_word(wordbuf);
	}
	pwords++;
      } // while(pwords<linew) {
    } // if(!sort)

    if(!quiet) {
      fprintf(stdout, "\n");
    }

    plines++;
    ptotallines++;

    // print empty line

    if(!quiet &&
       snewline > 0 &&
       plines%snewline == 0) {
      // if screenfull printed, use
      // total lines (contains also
      // empty lines), if not
      // screenfull use printed
      // lines (without empty lines)
      if((screen && ptotallines < lines) ||
	 (!screen && plines < lines)) {
	fprintf(stdout, "\n");
	ptotallines++;
      }
    }

    newressu_output = 0;
    
    // all needed lines printed?

    if(screen && snewline > 0 &&
       ptotallines >= lines)
      break;
    if(plines >= lines)
      break;

  } // for(;;)

#ifdef USE_TIMER
  if(timer) {
    // run time 1565 seconds, 0.000782 seconds/line (decimal)
    // run time 6538 seconds, 0.003269 seconds/line (--ch)
    // run time 1954 seconds, 0.000977 seconds/line (--ch digitscount)
    // run time 1814 seconds, 0.000907 seconds/line (--ch digitscount)
    // run time 1540 seconds, 0.000770 seconds/line (decimal)
    // run time 2196 seconds, 0.001098 seconds/line (--got)
    // run time 1536 seconds, 0.000768 seconds/line (decimal)   
    // run time 2008 seconds, 0.001004 seconds/line (--jp)
    // run time 2043 seconds, 0.001022 seconds/line (--jp)
    double timertook=getseconds()-timerstart;
    fprintf(stdout,"run time %f seconds",
	    timertook);
    fprintf(stdout,", %lld lines",
	    plines);
    fprintf(stdout,", %f useconds/line",
	    timertook*1000000/plines);
    fprintf(stdout,", %d characters/line",
	    pwords*size);
    fprintf(stdout,", %f useconds/character",
	    (timertook*1000000/plines)/(pwords*size) );
    fprintf(stdout,"\n");
  }
#endif
  fflush(stdout);

  if(digitsext != NULL)
    free(digitsext);
  
#ifdef FORT
  if(input == INPUT_FORT ||
    input == INPUT_FORTXOR) {
    fort_save();
  }
#endif
  exit(status);
}

#endif // MAIN

fort.c

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <ctype.h>

#include <sys/time.h>
#include <errno.h>

#include <openssl/ssl.h>

#include "sha256.h"
#include "newressu.h"

extern unsigned char *procname;
static unsigned char *programname = "fort version 0.52 ©";
static unsigned char *copyright = "Copyright (c) 2020-2022 Jari Kuivaniemi, Helsinki, Finland. Kaikki oikeudet pidätetään!";

#define FORT_INTERNAL_EVENTS 2

#define aDEBUG10 2
#define aDEBUG18 2

#define FORT_XOR_VERSION 2
#define FORT_ORIGINAL_VERSION 2

#include "fort.h"

int fort_events = 1;
int fort_verbose = 0;
int fort_use_web=0;

#define DEBUG 2
#define FORT_MIN_POOL_SIZE 64
static unsigned int fort_internal_events = 1;
static unsigned int fort_internal_event_mode = 1;

#define FORT_USE_WEB 2
#define FORT_USE_URANDOM 2
#define aFORT_USE_RANDOM 2
#define FORT_USE_NEWRESSU_COMMAND 2

unsigned char fort_random_file[128] = "fort.rnd";

#ifdef DEBUG10
static int event_id = 0;
static char fort_events_file[128] = "fortevents.deb";
#endif

// Additional secrets to fort
// (Adversary must guess these too)

#define ADDITIONAL_SECRETS 2
#ifdef ADDITIONAL_SECRETS
static char fort_secret_file[128] = "fortsecret.rnd";
unsigned char *programsecret = "OHUwiVmwm8HlqNhKxPi9rdt_8lm4jXI8hi-FCntPAQN_UXOyt4s6zQnRo__ySAd1";  
#endif

#define FORT_64_POOLS 2

#ifdef FORT_64_POOLS
#define FORT_POOLS 64
typedef unsigned long FORT_COUNTER;
#else
#define FORT_POOLS 32
typedef unsigned int FORT_COUNTER;
#endif

void fort_mix();

#define aDEBUG6 2

unsigned char cvar[16];
int cvarsize=0;

void inccvar()
{
  int c;

  /* 16 bytes, LSB first */
  for(c=0;++cvar[c] == 0 && c < sizeof(cvar)-1;c++);

#ifdef OLD1
  c=0;
  while(++cvar[c] == 0 && c < sizeof(cvar)-1)
    c++;
#endif
  
  if(cvarsize<c)
    cvarsize=c;

#ifdef DEBUG6
  if(newressu_output==1)
    fprintf(stdout,"\n");
  fprintf(stdout,"cvar      ");
  for(int d=cvarsize;d>=0;d--) // in reverse
    fprintf(stdout,"%02x",cvar[d]);
  newressu_output=1;
#endif
}

void clearcvar()
{
  int c;

  for(c = 0; c < sizeof(cvar); c++)
    cvar[c] = 0;
}

void hash_update_cvar(HashCtx *hash)
{
  hash_update(hash, (unsigned char *)&cvar,
	      cvarsize+1);

  inccvar();  
}

static IUTIME gettenths()
{
  struct timeval tv;

  gettimeofday(&tv, NULL);

  return((IUTIME)tv.tv_sec*10 +
      (int)tv.tv_usec/100000);
}

static IUTIME getmicroseconds()
{
  struct timeval tv;

  gettimeofday(&tv, NULL);

  return((IUTIME)tv.tv_sec*1000000 +
      tv.tv_usec);
}

static IUTIME getseconds()
{
  struct timeval tv;

  gettimeofday(&tv, NULL);

  return((IUTIME)tv.tv_sec);
}

struct fort_pool {
  unsigned long length;
  HashCtx pool;
};
static struct fort_pool fort_pools[FORT_POOLS];

void fort_add_random_event(int *pool, int source, int mode, int len, unsigned char *buf)
{
  while(len>1 && buf[len-1]==0)
    len--;

  HashUpdate(&fort_pools[*pool].pool, buf, len);
  fort_pools[*pool].length+=len; // (unsigned long)2097152*16384;

#ifdef DEBUG10
  if(event_id < 65536) {
    FILE *fp1;
    if((fp1=fopen(fort_events_file, "a"))!=NULL) {
      fprintf(fp1,"id=%d", event_id);
      fprintf(fp1,", source=%02d", source);
      fprintf(fp1,", pool=%02d", *pool);
      fprintf(fp1,", mode=%d", mode);
      fprintf(fp1,", len=%d", len);
      fprintf(fp1,", data=");
      for(int c=0;c<len;c++)
        fprintf(fp1,"%02x", buf[c]);
      fprintf(fp1,"\n");
      fflush(fp1);
      fclose(fp1);
      event_id++;
    }
  }
#endif

  switch(mode) {

  case 1:
    (*pool) = ((*pool)+1) % FORT_POOLS;
    break;

  case 3:
    break; // caller decides next pool

  }
}

void fort_add_random_event_timer_start(IUTIME *micros)
{
  *micros = getmicroseconds();
}

void fort_add_random_event_timer_do(int *pool, int source, int mode, IUTIME *micros)
{
  unsigned char temp[2];
  IUTIME t;

  t = getmicroseconds()-*micros;
  temp[0] = t & 0xff;
  temp[1] = (t>>8) & 0xff;

  fort_add_random_event(pool, source, mode,
			sizeof(temp), temp);
}

void fort_add_random_event_time(int *pool, int source, int mode)
{
  int len;
  unsigned char temp[2];
  IUTIME t;
  static int prev_second=-1;

  t = getmicroseconds();
  temp[0] = t & 0xff;
  temp[1] = (t>>8) & 0xff;
  len=2;

  if(prev_second==temp[1]) {
    len--;
  } else {
    prev_second=temp[1];
  }

  fort_add_random_event(pool, source, mode,
	       len, temp);
}

void fort_add_random_event_split(int *pool, int source, int mode, int len, unsigned char *buf, int size)
{
  int n;

  while(len != 0) {
    n = (size<len)? size:len;
    fort_add_random_event(pool, source,
        mode, n, buf);
    buf += n;
    len -= n;
  }
}

#define aDEBUG18 2

void hash_init(HashCtx *hash)
{
  FORT_INTERNAL_EVENTS_START(10)

  HashInit(hash);

#ifdef DEBUG18
  fprintf(stdout,"init\n");
#endif
  
  FORT_INTERNAL_EVENTS_END(11)
}

void hash_update(HashCtx *hash, unsigned char *data, int len)
{
  FORT_INTERNAL_EVENTS_START(12)

  HashUpdate(hash, data, len);

#ifdef DEBUG18
  fprintf(stdout,"data   ");
  for(int d=0;d<len;d++)
    fprintf(stdout,"%02x",data[d]);
  fprintf(stdout,"\n");
#endif
  
  FORT_INTERNAL_EVENTS_END(13)
}

void hash_final(unsigned char digest[HashLen], HashCtx *hash)
{
  FORT_INTERNAL_EVENTS_START(14)

  HashFinal(digest, hash);

#ifdef DEBUG18
  fprintf(stdout,"digest ");
  for(int d=0;d<HashLen;d++)
    fprintf(stdout,"%02x",digest[d]);
  fprintf(stdout,"\n");
#endif
  
  FORT_INTERNAL_EVENTS_END(15)
}

static unsigned char fort_key[HashLen];

void fort_rekey(unsigned char *digest)
{
  HashCtx hash;

  FORT_INTERNAL_EVENTS_START(16)

  hash_init(&hash);
  hash_update(&hash, fort_key, sizeof(fort_key));
  hash_update_cvar(&hash);
  hash_final(digest, &hash);

  // Forget hash

  memset(&hash, 0, sizeof(hash));

  FORT_INTERNAL_EVENTS_END(17)
}

#define FORT_PSEUDO_LIMIT 1048576

// use 
// $ ./newressu --fort -x -w32 -s2 -l2000 --space | more
// to debug...

// choose one of
//     60 (1 minute)
//     300 (5 minutes)
//     600 (10 minutes)
//     900 (15 minutes)
//     1200 (20 minutes)
//     1800 (30 minutes)
//     3600 (hour)
//     7200 (2 hours)
//     10800 (3 hours)
//     14400 (4 hours)
//     21600 (6 hours)
//     28800 (8 hours)
//     43200 (12 hours)
//     86400 (24 hours)
// to get readable report..

#define FORT_SECONDS_BETWEEN_SAVES 10*60
static IUTIME fort_next_save = 0;

#define TIMEFORMAT "%Z%Y%m%d%H%M%S"

void fort_save();

static char current_timezone[10];

#define aDEBUG22 2

void fort_reseed(int len, unsigned char *buf)
{
  HashCtx hash;

  FORT_INTERNAL_EVENTS_START(22)

    
  hash_init(&hash);
  hash_update(&hash, fort_key, sizeof(fort_key));
  hash_update_cvar(&hash);
  hash_update(&hash, buf, len);

#ifdef DEBUG22
  fprintf(stdout,"\nprevkey   ");
  for(int d=0;d<sizeof(fort_key);d++)
    fprintf(stdout,"%02x",fort_key[d]);
  fprintf(stdout,"\ncvar      ");
  for(int d=0;d<cvarsize+1;d++)
    fprintf(stdout,"%02x",cvar[d]);
  fprintf(stdout,"\ndata      ");
  for(int d=0;d<HashLen;d++)
    fprintf(stdout,"%02x",buf[d]);
  fprintf(stdout,"\ndata asc  ");
  for(int d=0;d<len;d++) {
    if(isprint(buf[d]))
      fprintf(stdout,"%c",buf[d]);
    else
      fprintf(stdout,"\\%02x",buf[d]);
  }
#endif
  
  hash_final(fort_key, &hash);

#ifdef DEBUG22
  fprintf(stdout,"\nnewkey    ");
  for(int d=0;d<sizeof(fort_key);d++)
    fprintf(stdout,"%02x",fort_key[d]);
  fprintf(stdout,"\n");
#endif
  
  memset(&hash, 0, sizeof(hash));

  if(fort_next_save != 0) {
    IUTIME seconds;
    seconds = getseconds();
    
    char timezone[10];
    strftime(timezone, sizeof(timezone), "%Z",
             localtime((time_t *)&seconds) );
    if(strcmp(current_timezone,timezone)) {
      fort_next_save=1;
      strcpy(current_timezone,timezone);
    }
    
    if(fort_next_save != 0 &&
       seconds >= fort_next_save) {
      
      IUTIME diff=
        timegm(localtime((time_t *)&seconds))-seconds;
      
      fort_next_save = seconds -
        ((seconds+diff) %
         FORT_SECONDS_BETWEEN_SAVES) +
        FORT_SECONDS_BETWEEN_SAVES;
      
      fort_save();
    }
  }

  FORT_INTERNAL_EVENTS_END(23)
}

static FORT_COUNTER fort_reseed_count = 0;
static IUTIME fort_next_reseed = 0;

#define aDEBUG28 2

#ifdef FORT_ORIGINAL_VERSION

void fort_pseudo_random_data(int len, 
    unsigned char *buf)
{
  unsigned char digest[HashLen];
  unsigned int n, blockbytes;
#ifdef DEBUG28
  int d=0;
#endif

  FORT_INTERNAL_EVENTS_START(18)

  blockbytes = 0;

  while(len != 0) {
    FORT_INTERNAL_EVENTS_START(19)

    fort_rekey(digest);
    n = (len<HashLen) ? len : HashLen;

#ifdef DEBUG28
    
    fprintf(stdout,"\nbuf(%02x):  ",d++);
    for(int c=0;c<n;c++)
      fprintf(stdout,"%02x",buf[c]);
    fprintf(stdout,"\ndigest:   ");
    for(int c=0;c<n;c++)
      fprintf(stdout,"%02x",digest[c]);
    fprintf(stdout,"\nsum:      ");
    for(int c=0;c<n;c++)
      fprintf(stdout,"%02x",buf[c]^digest[c]);
    fprintf(stdout,"\n");

#endif // #ifdef DEBUG18

    memcpy(buf, digest, n);

    buf += n;
    len -= n;
    blockbytes += n;

    // rekey every 1048576 bytes if data left

    if(blockbytes >= FORT_PSEUDO_LIMIT &&
        len > 0) {                                                                                                              
      fort_rekey(fort_key);
      blockbytes = 0;
    }

    FORT_INTERNAL_EVENTS_END(20)
  }

  fort_rekey(fort_key);

  // Forget last bytes

  memset(digest, 0, sizeof(digest));

  FORT_INTERNAL_EVENTS_END(21)
}

#define aDEBUG34 2

void fort_random_data(int len, unsigned char *buf)
{
  int c;
  IUTIME tenths;
  HashCtx hash;
  unsigned char digest[HashLen];

  FORT_INTERNAL_EVENTS_START(24)

  tenths=gettenths();

  if( (fort_next_reseed == 0) ||
      (fort_next_reseed <= tenths &&
      fort_pools[0].length >=
      FORT_MIN_POOL_SIZE) ) {

    fort_mix();
    
    // next tenth of a second

    fort_next_reseed = tenths + 1;
    fort_reseed_count++;

    hash_init(&hash);
    c=0;

    while(c < FORT_POOLS && (fort_reseed_count
        % (1<<c)) == 0) {

      FORT_INTERNAL_EVENTS_START(25)

      hash_final(digest, &fort_pools[c].pool);

#ifdef DEBUG34
      fprintf(stdout,"\ndata   %2d ",c);
      for(int d=0;d<HashLen;d++)
	fprintf(stdout,"%02x",digest[d]);
#endif

      hash_update(&hash, digest, sizeof(digest));
      fort_pools[c].length = 0;
      HashInit(&fort_pools[c].pool);

      // save earlier pool to new one

      hash_update(&fort_pools[c].pool,
        digest, sizeof(digest));
      c++;

      FORT_INTERNAL_EVENTS_END(26)
    }
    hash_update_cvar(&hash);
    hash_final(digest, &hash);

#ifdef DEBUG34
    fprintf(stdout,"\ndigest    ");
    for(int d=0;d<HashLen;d++)
      fprintf(stdout,"%02x",digest[d]);
    fprintf(stdout,"\n");
#endif

    fort_reseed(sizeof(digest), digest);

    // Forget hash context

    memset(&hash, 0, sizeof(hash));

    // Forget reseed key

    memset(digest, 0, sizeof(digest));
  }

  fort_pseudo_random_data(len, buf);

  FORT_INTERNAL_EVENTS_END(27)
}

#endif // #ifdef FORT_ORIGINAL_VERSION

#ifdef FORT_XOR_VERSION

void fort_pseudo_random_data_xor(int len, 
    unsigned char *buf)
{
  unsigned char digest[HashLen];
  unsigned int n, blockbytes;
#ifdef DEBUG28
  int d=0;
#endif

  FORT_INTERNAL_EVENTS_START(18)

  blockbytes = 0;

  while(len != 0) {
    FORT_INTERNAL_EVENTS_START(19)
      
    fort_rekey(digest);
    n = (len<HashLen) ? len : HashLen;

#ifdef DEBUG28

    fprintf(stdout,"\nbuf(%02x):  ",d++);
    for(int c=0;c<n;c++)
      fprintf(stdout,"%02x",buf[c]);
    fprintf(stdout,"\ndigest:   ");
    for(int c=0;c<n;c++)
      fprintf(stdout,"%02x",digest[c]);
    fprintf(stdout,"\nsum:      ");
    for(int c=0;c<n;c++)
      fprintf(stdout,"%02x",buf[c]^digest[c]);
    fprintf(stdout,"\n");

#endif
    
    for(int c=0;c<n;c++)
      buf[c]^=digest[c];

    buf += n;
    len -= n;
    blockbytes += n;

    // rekey every 1048576 bytes if data left

    if(blockbytes >= FORT_PSEUDO_LIMIT &&
        len > 0) {                                                                                                              
      fort_rekey(fort_key);
      blockbytes = 0;
    }

    FORT_INTERNAL_EVENTS_END(20)
  }

  fort_rekey(fort_key);

  // Forget last bytes

  memset(digest, 0, sizeof(digest));

  FORT_INTERNAL_EVENTS_END(21)
}

void fort_random_data_xor(int len, unsigned char *buf)
{
  int c;
  IUTIME tenths;
  HashCtx hash;
  unsigned char digest[HashLen];

  FORT_INTERNAL_EVENTS_START(24)

  tenths=gettenths();

  if( (fort_next_reseed == 0) ||
      (fort_next_reseed <= tenths &&
      fort_pools[0].length >=
      FORT_MIN_POOL_SIZE) ) {

    fort_mix();

    // next tenth of a second

    fort_next_reseed = tenths + 1;
    fort_reseed_count++;

    hash_init(&hash);
    c=0;

    while(c < FORT_POOLS && (fort_reseed_count
        % (1<<c)) == 0) {

      FORT_INTERNAL_EVENTS_START(25)

      hash_final(digest, &fort_pools[c].pool);

#ifdef DEBUG34
      fprintf(stdout,"\ndata   %2d ",c);
      for(int d=0;d<HashLen;d++)
	fprintf(stdout,"%02x",digest[d]);
#endif
      
      hash_update(&hash, digest, sizeof(digest));
      fort_pools[c].length = 0;
      HashInit(&fort_pools[c].pool);

      // save earlier pool to new one

      hash_update(&fort_pools[c].pool,
        digest, sizeof(digest));
      c++;

      FORT_INTERNAL_EVENTS_END(26)
    }
    hash_update_cvar(&hash);
    hash_final(digest, &hash);

#ifdef DEBUG34
    fprintf(stdout,"\ndigest    ");
    for(int d=0;d<HashLen;d++)
      fprintf(stdout,"%02x",digest[d]);
    fprintf(stdout,"\n");
#endif
    
    fort_reseed(sizeof(digest), digest);

    // Forget hash context

    memset(&hash, 0, sizeof(hash));

    // Forget reseed key

    memset(digest, 0, sizeof(digest));
  }

  fort_pseudo_random_data_xor(len, buf);

  FORT_INTERNAL_EVENTS_END(27)
}

#endif // #ifdef FORT_XOR_VERSION

#define FORTCNT 128

static unsigned int fort_cnt = FORTCNT;
static unsigned char fort_bytes[FORTCNT];
static int fort_byte = 999999999;

int fort_random_data_byte()
{
  if(fort_byte >= fort_cnt) {
    fort_random_data(fort_cnt, fort_bytes);
    fort_byte = 0;
  }
  return(fort_bytes[fort_byte++]);
}

void fort_clear()
{
  memset(fort_bytes, 0, fort_cnt);
  fort_byte = 999999998;
}

int fort_random_data_byte_limit(int limit)
{
  int c;

  while((c = fort_random_data_byte())>=
      (256/limit)*limit);

  return(c % limit);
}

void fort_random_data_buffer(int size,
    unsigned char *buffer)
{
  int c;

  for(c=0; c<size; c++)
    buffer[c] ^= fort_random_data_byte();
}

#define aDEBUG53 2

void fort_reseed_file(unsigned char *filename)
{
  int c, cnt, bytes, characters;
#ifdef DEBUG53
  unsigned char *p;
#endif
  FILE *fp1;
  unsigned char buffer[1024], digest[HashLen];

  HashCtx hash;

  bytes=0;
  characters=0;
  
  if((fp1=fopen(filename, "r"))!=NULL) {
    HashInit(&hash);
    while(fgets(buffer,sizeof(buffer),fp1)!=NULL) {
      cnt=strlen(buffer);
      HashUpdate(&hash, buffer, cnt);
      bytes+=cnt;
      for(c=0;c<cnt;c++) {
	if(buffer[c]<0x80 || buffer[c]>0xbf)
	  characters++;
      }
#ifdef DEBUG53
      p=buffer;
      while(*p!='\0') {
	if(*p=='\\')
	  fprintf(stdout,"\\\\");
	else if(isprint(*p) || *p=='\n')
	  fputc(*p,stdout);
	else
	  fprintf(stdout,"\\%02x",*p);
	p++;
      }
#endif
    }
    hash_update_cvar(&hash);
    HashFinal(digest, &hash);

    fort_reseed(sizeof(digest), digest);

    fclose(fp1);
  }
#ifdef DEBUG53
  //if(fort_verbose) {
  fprintf(stdout,"fort_reseed_file %s",filename);
  fprintf(stdout,", %d bytes read",bytes);
  fprintf(stdout,", %d characters read",characters);
  fprintf(stdout,", sha256: ");
  for(int c = 0;c < HashLen; c++) {
    fprintf(stdout,"%02x", digest[c]);
  }
  fprintf(stdout,"\n");
  //}
#endif
}

#define FORT_SAVE_SIZE 1024

#define aDEBUG57

void fort_save()
{
  FILE *fp1;
  unsigned char buffer[FORT_SAVE_SIZE];

  memset(buffer,0,sizeof(buffer));

  if((fp1 = fopen(fort_random_file, "w")) != NULL) {
    fort_pseudo_random_data(sizeof(buffer), buffer);

#ifdef DEBUG57
    for(int c=0;c<sizeof(buffer);c++) {
      if(c%32==0) {
	if(c!=0)
	  fprintf(stdout,"\n");
	fprintf(stdout,"save      %05d ",c);
      }
      fprintf(stdout," %02x",buffer[c]);
    }
    fprintf(stdout,"\n");
#endif
    fwrite(buffer, 1, sizeof(buffer), fp1);
    memset(buffer, 0, sizeof(buffer));
    fclose(fp1);
  }
}

void fort_restore()
{
  int d;
#ifdef DEBUG57
  int random;
#endif
  FILE *fp1;
  unsigned char buffer[FORT_SAVE_SIZE];

  memset(buffer,0,sizeof(buffer));
  
  if((fp1 = fopen(fort_random_file, "r"))
      != NULL) {
    d = fread(buffer, 1, sizeof(buffer), fp1);
    fclose(fp1);
#ifdef DEBUG57
    random=0;
#endif
  } else {
    fort_pseudo_random_data(sizeof(buffer), buffer);
    ressu_genbytes(sizeof(buffer), buffer);
    d = sizeof(buffer);
#ifdef DEBUG57
    random=1;
#endif
  }
#ifdef DEBUG57
  for(int c=0;c<sizeof(buffer);c++) {
    if(c%32==0) {
      if(c!=0)
	fprintf(stdout,"\n");
      fprintf(stdout,"restore");
      if(random)
	fprintf(stdout,"*");
      else
	fprintf(stdout," ");
      fprintf(stdout,"  %05d ",c);
    }
    fprintf(stdout," %02x",buffer[c]);
  }
  fprintf(stdout,"\n");
#endif
  fort_reseed(d, buffer);
  memset(buffer, 0, sizeof(buffer));

  fort_save();
}

#if defined FORT_USE_URANDOM || \
    defined FORT_USE_RANDOM

static void fort_readfile_xor(int len,
    unsigned char *buf,
    unsigned char *filename)
{
  int c, n, n2;
  unsigned char temp[64];
  FILE *fp1;

  if((fp1 = fopen(filename, "rb"))
      != NULL) {
    while(len != 0) {
      n = (len < sizeof(temp)) ?
          len : sizeof(temp);
      n2=fread(temp, 1, n, fp1);
      for(c = 0; c < n2; c++)
        buf[c] ^= temp[c];
      len -= n2;
      buf += n2;
    }
    fclose(fp1);
  }
}

#endif

#ifdef FORT_USE_WEB

static void parse_string(unsigned char *string, int size, unsigned char **p2)
{
  int count;
  unsigned char *p, *q;

  p=*p2;
  q=string;
  count=0;

  // uppercase & lowercase letters, '.'
  // or utf-8

  while(isalnum(*p)||*p=='.'||*p>0x80) {
    if(++count<size)
      *q++=*p;
    p++;
  }
  *q='\0';
  *p2=p;
}

#endif // #ifdef FORT_USE_WEB

#ifdef FORT_USE_WEB

static int check_string(unsigned char *string, unsigned char *p)
{
  int ok;

  ok=0;
  if(!strncmp(string,p,strlen(string))) {
    ok=1;
  }

  return(ok);
}

#endif // #ifdef FORT_USE_WEB

void fort_internal_random_data_1(int size, char *buf)
{
  ressu_genbytes(size, buf);
#ifdef FORT_XOR_VERSION
  fort_pseudo_random_data_xor(size, buf);
#endif
}

void fort_internal_random_data_2(int size, char *buf)
{
#ifdef FORT_XOR_VERSION
  fort_pseudo_random_data_xor(size, buf);
#else
  fort_pseudo_random_data(size, buf);
#endif
  ressu_genbytes(size, buf);
}

void fort_internal_random_data_3(int size, char *buf)
{
#ifdef FORT_XOR_VERSION
  fort_random_data_xor(size, buf);
#else
  fort_random_data(size, buf);
#endif
}

static IUTIME fort_next_localmix = 0;
//#define FORT_SECONDS_BETWEEN_LOCALMIXES 60*60
#define FORT_SECONDS_BETWEEN_LOCALMIXES 60*60
static IUTIME fort_next_webmix = 0;
//#define FORT_SECONDS_BETWEEN_WEBMIXES 12*3600
#define FORT_SECONDS_BETWEEN_WEBMIXES 12*3600

#define RANDOMNESS_IN_LANGUAGES 2

void fort_mix()
{
  int webmix=0, localmix=0;
  unsigned char temp[64];

  IUTIME seconds;

  seconds = getseconds();
  
  webmix=0;
  localmix=0;

  if(fort_next_webmix == 0 ||
     fort_next_webmix <= seconds) {
    fort_next_webmix=seconds+FORT_SECONDS_BETWEEN_WEBMIXES;
    fort_next_localmix=seconds+FORT_SECONDS_BETWEEN_LOCALMIXES;
    webmix=1;
    localmix=1;
  }

  if(fort_next_localmix == 0 ||
     fort_next_localmix <= seconds) {
    fort_next_localmix=seconds+FORT_SECONDS_BETWEEN_LOCALMIXES;
    localmix=1;
  }

  if(!webmix && !localmix)
    return;
  
  if(fort_verbose) {  
    char timebuf[128];
    strftime(timebuf, sizeof(timebuf), TIMEFORMAT,
	     localtime((time_t *)&seconds));
    fprintf(stdout,"Fort mix time:      %s\n",timebuf);
    strftime(timebuf, sizeof(timebuf), TIMEFORMAT,
	     localtime((time_t *)&fort_next_webmix));
    fprintf(stdout,"Next fort webmix:   %s\n",timebuf);
    strftime(timebuf, sizeof(timebuf), TIMEFORMAT,
	     localtime((time_t *)&fort_next_localmix));
    fprintf(stdout,"Next fort localmix: %s\n",timebuf);
  }
  
  fort_internal_random_data_1(sizeof(temp), temp);
  fort_reseed(sizeof(temp), temp);
  
#if defined FORT_USE_WEB || \
  defined FORT_USE_RDRAND || \
  defined FORT_USE_RDSEED || \
  defined FORT_USE_NEWRESSU_COMMAND
  unsigned char digest[HashLen];
#endif    
  
#ifdef FORT_USE_WEB
  if(webmix && fort_use_web) {
    char *webpages[] = {
      "https://moijari.com:5001/",
      "https://moijari.com:5005/",
      "https://moijari.com:5006/",
    };

    for(int c=0;c<sizeof(webpages)/sizeof(webpages[0]);c++) {
      unsigned char *p;
      
      unsigned char scheme[32];
      unsigned char host[32];
      unsigned char port[10];
      unsigned char rest[128];
      
      p=webpages[c];
      parse_string(scheme,sizeof(scheme),&p);
      
      if(check_string("://",p)) {
	p+=3;
	parse_string(host,sizeof(host),&p);
      } else {
	strcpy(host,scheme);
	strcpy(scheme,"http");
      }
      
      if(check_string(":",p)) {
	p++;
	parse_string(port,sizeof(port),&p);
      } else {
	strcpy(port,"80");
      }
      
      if(*p!='/') 
	strcpy(rest,"/");
      else
	strcpy(rest,p);
      
      if(fort_verbose) {    
	fprintf(stdout,"URL:%s ",webpages[c]);
	fprintf(stdout,"[scheme:%s]",scheme);
	fprintf(stdout,"[host:%s]",host);
	fprintf(stdout,"[port:%s]",port);
	fprintf(stdout,"[rest:%s]",p);
	fflush(stdout);
      }
      
      if(!strcmp(scheme,"http")) {
	fort_hash_http_page(host, port, p, digest);
      } else if(!strcmp(scheme,"https")) {
	fort_hash_https_page(host, port, p, digest);
      }
      if(fort_verbose) {
	fprintf(stdout,"\n");
	fflush(stdout);
      }
      fort_reseed(sizeof(digest), digest);
    }
  }
#endif // #ifdef FORT_USE_WEB
    
  if(localmix) {    
#ifdef FORT_USE_URANDOM
    memset(temp, 0, sizeof(temp));
    fort_readfile_xor(sizeof(temp), temp,
		      "/dev/urandom");
    fort_reseed(sizeof(temp), temp);
#endif
  
#ifdef FORT_USE_RANDOM
    memset(temp, 0, sizeof(temp));
    fort_readfile_xor(sizeof(temp), temp,
		      "/dev/random");
    fort_reseed(sizeof(temp), temp);
#endif

#if defined FORT_USE_RDRAND || \
  defined FORT_USE_RDSEED
    HashCtx hash;
    unsigned char digest[HashLen];
#endif
    
#ifdef FORT_USE_RDRAND

    memset(temp,0,sizeof(temp));
    if(rdrand_bytes(sizeof(temp),temp)) {
      
      HashInit(&hash);
      
      hash_update_cvar(&hash);

      HashUpdate(&hash, temp, sizeof(temp));
      HashFinal(digest, &hash);
      
      if(fort_verbose) {
	fprintf(stdout,", sha256: ");
	for(int c = 0;c < HashLen; c++) {
	  fprintf(stdout,"%02x", digest[c]);
	}
	fprintf(stdout,"\n");
	fflush(stdout);
      }
      
      fort_reseed(sizeof(digest), digest);
    }  
    
#endif // #ifdef FORT_USE_RDRAND
  
#ifdef FORT_USE_RDSEED
  
    memset(temp,0,sizeof(temp));
    if(rdseed_bytes(sizeof(temp),temp)) {
      
      HashInit(&hash);

      hash_update_cvar(&hash);

      HashUpdate(&hash, temp, sizeof(temp));
      HashFinal(digest, &hash);
      
      if(fort_verbose) {
	fprintf(stdout,", sha256: ");
	for(int c = 0;c < HashLen; c++) {
	  fprintf(stdout,"%02x", digest[c]);
	}
	fprintf(stdout,"\n");
	fflush(stdout);
      }
      
      fort_reseed(sizeof(digest), digest);
    }

#endif // #ifdef FORT_USE_RDSEED

#ifdef FORT_USE_NEWRESSU_COMMAND

    char *commands[] = {
      "/bin/newressu -2 -s8 -c64 -l1 --lineno",
      "/bin/newressu -2 -s8 -c64 -l1 --lineno --fast",
      "/bin/newressu -2 -s8 -c64 -l1 --lineno --urandom",
#ifdef RANDOMNESS_IN_LANGUAGES
      "/bin/newressu --cn -s8 -c64 -l1 --single --lineno",
      "/bin/newressu --deu -s8 -c64 -l1 --single --lineno",
      "/bin/newressu --dnk -s8 -c64 -l1 --single --lineno",
      "/bin/newressu --eng -s8 -c64 -l1 --single --lineno",
      "/bin/newressu --est -s8 -c64 -l1 --single --lineno",
      "/bin/newressu --fin -s8 -c64 -l1 --single --lineno",
      "/bin/newressu --fra -s8 -c64 -l1 --single --lineno",
      "/bin/newressu --gbr -s8 -c64 -l1 --single --lineno",
      "/bin/newressu --got -s8 -c64 -l1 --single --lineno",
      "/bin/newressu --grc -s8 -c64 -l1 --single --lineno",
      "/bin/newressu --ita -s8 -c64 -l1 --single --lineno",
      "/bin/newressu --jp -s8 -c64 -l1 --single --lineno",
      "/bin/newressu --jp1 -s8 -c64 -l1 --single --lineno",
      "/bin/newressu --jp2 -s8 -c64 -l1 --single --lineno",
      "/bin/newressu --jp3 -s8 -c64 -l1 --single --lineno",
      "/bin/newressu --kor -s8 -c64 -l1 --single --lineno",
      "/bin/newressu --ltu -s8 -c64 -l1 --single --lineno",
      "/bin/newressu --lva -s8 -c64 -l1 --single --lineno",
      "/bin/newressu --nor -s8 -c64 -l1 --single --lineno",
      "/bin/newressu --rus -s8 -c64 -l1 --single --lineno",
      "/bin/newressu --swe -s8 -c64 -l1 --single --lineno",
#endif
    };

    for(int c=0;c<sizeof(commands)/sizeof(commands[0]);c++) {
      if(strstr(commands[c], "--fort")) {
	fprintf(stderr,"%s: fort_mix(): cannot call fort recursively \"%s\"\n",
		procname,commands[c]);
      } else {
	fort_hash_command(commands[c], digest);
	fort_reseed(sizeof(digest), digest);
      }
    }
#endif // #ifdef FORT_USE_NEWRESSU_COMMAND
  }
}

void file_digest(char *filename,unsigned char temp[HashLen])
{
  int c;
  unsigned char buffer[1024];
  FILE *fp1;
  HashCtx ctx;
  
  HashInit(&ctx);
  if((fp1=fopen(filename,"rb"))!=NULL) {
    while((c=fread(buffer,1,sizeof(buffer),fp1))>0)
      HashUpdate(&ctx,buffer,c);
    fclose(fp1);
  }
  HashFinal(temp,&ctx);
}

#define DEBUG88

void fort_init()
{
  int c;
  unsigned char temp32[32];

  memset(temp32,0,sizeof(temp32));
  memset(fort_bytes,0,sizeof(fort_bytes));
  memset(fort_key,0,sizeof(fort_key));
  
  if(fort_verbose) {
    fprintf(stdout,"hash: %s",
	    HashName);
    fprintf(stdout,", pools: %d*%ld", FORT_POOLS,
	    sizeof(struct fort_pool));
    fprintf(stdout,", HashCtx: %ld",
	    sizeof(HashCtx));
    fprintf(stdout,", hashsize: %d",
	    HashLen);
    fprintf(stdout,"\n");
  }
  
  unsigned int save_fort_internal_events;
  save_fort_internal_events=fort_internal_events;
  fort_internal_events=1;

  fort_next_save = 0;
  
  clearcvar();

  // first key to fort_key
  
  fort_internal_random_data_1(sizeof(fort_key), fort_key);

#ifdef ADDITIONAL_SECRETS  

  // additional constant randomness from program

  fort_reseed(strlen(copyright), copyright);
  fort_reseed(strlen(programname), programname);

  unsigned char filedigest[HashLen];
  file_digest("/proc/self/exe",filedigest);
  fort_reseed(strlen(filedigest), filedigest);
  
  fort_reseed(strlen(programsecret), programsecret);

  // additional constant randomness
  // from you (one more secret adversary
  // has to guess)

  FILE *fp1;
  if((fp1 = fopen(fort_secret_file, "r")) != NULL) {
    fclose(fp1);
  } else {
    if((fp1 = fopen(fort_secret_file, "w")) != NULL) {
      fprintf(fp1,"Your secret additional constant data to fort:\n");
      fclose(fp1);
      unsigned char temp2[160];
      sprintf(temp2,"%s -2 -l1 >>%s",procname,fort_secret_file);
      system(temp2);
      fprintf(stdout,"File %s written\n",fort_secret_file);
    }
  }
  fort_reseed_file(fort_secret_file);

#endif
  
  // Initialize buffers

  for(c=0; c<FORT_POOLS; c++) {
    fort_pools[c].length = 0;
    HashInit(&fort_pools[c].pool);
  }

#ifdef DEBUG10

  FILE *fp1;
  
  // Empty events file

  if((fp1 = fopen(fort_events_file, "w"))!=NULL)
    fclose(fp1);
  event_id = 0;

#endif // #ifdef DEBUG10

  // Mix fort key with web + local
  // random numbers
  
  fort_mix();

  for(c=0; c<FORT_POOLS; c++) {
    FORT_INTERNAL_EVENTS_START(31)
    fort_internal_random_data_2(sizeof(temp32), temp32);
    hash_update(&fort_pools[c].pool,
      temp32, sizeof(temp32));
    FORT_INTERNAL_EVENTS_END(32)
  }

#ifdef FORT_INTERNAL_EVENTS

  if(fort_internal_events) {

    // Create some internal events

    for(c=0; c<32; c++) {
      FORT_INTERNAL_EVENTS_START(34)
      fort_internal_random_data_3(sizeof(temp32), temp32);
      FORT_INTERNAL_EVENTS_END(35)
    }
  }

#endif // #ifdef FORT_INTERNAL_EVENTS

  fort_reseed_count = 0;
  fort_next_reseed = 0;

  // Reseed fort_key with new events

  fort_internal_random_data_3(sizeof(temp32), temp32);
  fort_reseed(sizeof(temp32), temp32);

  fort_restore();

  // Forget temp

  memset(temp32,0,sizeof(temp32));

  fort_internal_events = save_fort_internal_events;

  //fort_reseed_count = 0;
  //fort_next_reseed = 0;

  fort_next_save = 1;
}

void fort_version()
{
  fprintf(stderr,"%s",programname); // touch these outside MAIN
  fprintf(stderr,", %s\n",copyright);
}

#define aMAIN 2
#ifdef MAIN

unsigned char *procname;

int main(int argc, char *argv[])
{
  procname=argv[0];
  fort_version();
  fort_init();
  return(0);
}

#endif // #ifdef MAIN

sha256.c

/* Written from SHA256 documents by Jari Kuivaniemi, read "http://en.wikipedia.org/wiki/SHA-2" */
#include <stdio.h>
#include <memory.h>
#include <string.h>

#include "sha256.h"

extern unsigned char *procname;

//#ifdef MAIN // in Makefile

unsigned char *sha_name="SHA256 v1.0";

void SHA256Init(SHA256_CONTEXT *sha256)
{
  sha256->state[0] = 0x6a09e667;
  sha256->state[1] = 0xbb67ae85;
  sha256->state[2] = 0x3c6ef372;
  sha256->state[3] = 0xa54ff53a;
  sha256->state[4] = 0x510e527f;
  sha256->state[5] = 0x9b05688c;
  sha256->state[6] = 0x1f83d9ab;
  sha256->state[7] = 0x5be0cd19;
  
  sha256->count = 0;
}

IUWORD k256[64] = {
  0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,
  0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,
  0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
  0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967,
  0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,
  0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
  0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,
  0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2
};

#define RR32(word,bits) ( ((word) >> (bits)) | ((word) << (32 - (bits))) )
#define RS32(word,bits) ( ((word) >> (bits)) )

void SHA256Transform(IUWORD state[8], IUBYTE buffer[64])
{
  int i;
  
  IUWORD w[64], s0;
  IUWORD a, b, c, d, e, f, g, h;
  IUWORD maj, t2, s1;
  IUWORD ch, t1;
  
  for(i=0;i<16;i++) {
    w[i] =
      (IUWORD)buffer[i*4+0] << 24 |
      (IUWORD)buffer[i*4+1] << 16 |
      (IUWORD)buffer[i*4+2] << 8  |
      (IUWORD)buffer[i*4+3];
  }
  
  for(i=16;i<64;i++) {
    s0 = (RR32(w[i-15],7)) ^ (RR32(w[i-15],18)) ^ (RS32(w[i-15],3));
    s1 = (RR32(w[i-2],17)) ^ (RR32(w[i-2],19)) ^ (RS32(w[i-2],10));
    w[i] = w[i-16] + s0 + w[i-7] + s1;
  }
  
  a = state[0];
  b = state[1];
  c = state[2];
  d = state[3];
  e = state[4];
  f = state[5];
  g = state[6];
  h = state[7];
  
  for(i=0;i<64;i++) {
    s0 = (RR32(a,2)) ^ (RR32(a,13)) ^ (RR32(a,22));
    maj = (a & b) ^ (a & c) ^ (b & c);
    t2 = s0 + maj;
    s1 = (RR32(e,6)) ^ (RR32(e,11)) ^ (RR32(e,25));
    ch = (e & f) ^ ((~ e) & g);
    t1 = h + s1 + ch + k256[i] + w[i];
    
    h = g;
    g = f;
    f = e;
    e = d + t1;
    d = c;
    c = b;
    b = a;
    a = t1 + t2;
  }
  
  state[0] = state[0] + a;
  state[1] = state[1] + b;
  state[2] = state[2] + c;
  state[3] = state[3] + d;
  state[4] = state[4] + e;
  state[5] = state[5] + f;
  state[6] = state[6] + g;
  state[7] = state[7] + h;
}

void SHA256Update(SHA256_CONTEXT *sha256, unsigned char *data, int len)
{
  int i,j;
  
  j = (int)sha256->count & 63;
  
  sha256->count+=len;
  
  if((j+len)>63) {
    memcpy(&sha256->buffer[j],data,64-j); /* last bytes of next block */
    
    SHA256Transform(sha256->state, sha256->buffer);
    for (i = 64 - j ; i + 63 < len; i += 64) {
      SHA256Transform(sha256->state, &data[i]);
    }
    j = 0;
  } else
    i=0;
  
  memcpy(&sha256->buffer[j],&data[i],len-i);
}

void SHA256Final(unsigned char digest[32], SHA256_CONTEXT *sha256)
{
  int i,j;
  unsigned char filelenght[8];
  IULONG count;
  
  count=sha256->count << 3;
  SHA256Update(sha256,"\200",1);
  
  while((sha256->count & 63) != 56)
    SHA256Update(sha256,"\0",1);
  
  filelenght[0]=(unsigned char)(count >> 56)&0xff;
  filelenght[1]=(unsigned char)(count >> 48)&0xff;
  filelenght[2]=(unsigned char)(count >> 40)&0xff;
  filelenght[3]=(unsigned char)(count >> 32)&0xff;
  filelenght[4]=(unsigned char)(count >> 24)&0xff;
  filelenght[5]=(unsigned char)(count >> 16)&0xff;
  filelenght[6]=(unsigned char)(count >> 8 )&0xff;
  filelenght[7]=(unsigned char)(count&0xff);
  
  SHA256Update(sha256,filelenght,sizeof(filelenght));
  
  for(i=0,j=0;i<8;i++) {
    digest[j++]=(unsigned char) (sha256->state[i] >> 24)&0xff;
    digest[j++]=(unsigned char) (sha256->state[i] >> 16)&0xff;
    digest[j++]=(unsigned char) (sha256->state[i] >> 8)&0xff;
    digest[j++]=(unsigned char) (sha256->state[i] )&0xff;
  }
}

#ifdef MAIN

void printhex(char *name, unsigned char *digest, int len)
{
  int c;

  fprintf(stdout,"%s=",name);
  for(c=0;c<len;c++) {
    fprintf(stdout,"%02x",digest[c]);
  }
  fflush(stdout);
}

int shahexdigit(int c)
{
  if(c>='0' && c<='9') return(c-'0');
  else if(c>='a' && c<='f') return(c-'a'+10);
  else if(c>='A' && c<='F') return(c-'A'+10);
  return(0);
}

void sha_test()
{
  int c,d,e,ok,allok;
  SHA256_CONTEXT sha256;
  unsigned char result[32],*p;
  
  fprintf(stdout,"%s",sha_name);
  fprintf(stdout,", Context size: %ld", sizeof(SHA256_CONTEXT));
  fprintf(stdout,", Hash size: 32");
  fprintf(stdout,", IUBYTE size: %ld", sizeof(IUBYTE));
  fprintf(stdout,", IUWORD size: %ld", sizeof(IUWORD));
  fprintf(stdout,", IULONG size: %ld", sizeof(IULONG));

  struct test {
    unsigned char *string;
    int count;
    unsigned char *result;
  } tests[] = {
    { "abc",1,"ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad" },
    { "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq",1,"248d6a61d20638b8e5c026930c3e6039a33ce45964ff2167f6ecedd419db06c1" },
    { "a",1000000,"cdc76e5c9914fb9281a1c7e284d73e67f1809a48a497200e046d39ccc7112cd0" },
    { "The quick brown fox jumps over the lazy dog",1,"d7a8fbb307d7809469ca9abcb0082e4f8d5651e46d3cdb762d02d0bf37c9e592" },
  };

  allok=1;
  for(c=0;c<sizeof(tests)/sizeof(tests[0]);c++) {
    SHA256Init(&sha256);
    for(d=0;d<tests[c].count;d++)
      SHA256Update(&sha256,tests[c].string,strlen(tests[c].string));
    SHA256Final(result,&sha256);
    p=tests[c].result;
    d=0;
    ok=1;
    while(*p!='\0') {
      if(*p!='\0')
	e=shahexdigit(*p++);
      if(*p!='\0')
	e=e*16+shahexdigit(*p++);
      if(e!=result[d])
	ok=0;
      d++;
    }
    if(ok) {
      fprintf(stdout,"\nsha256 test ");
      fprintf(stdout,"string: %s",tests[c].string);
      fprintf(stdout,", count: %d, ",tests[c].count);
      printhex("tmp32",result,sizeof(result));
      fprintf(stdout,", result: %s",tests[c].result);
      fprintf(stdout," ok!!!!");
      fflush(stdout);
    } else {
      fprintf(stdout,"\nsha256 test ");
      fprintf(stdout,"string: %s",tests[c].string);
      fprintf(stdout,", count: %d, ",tests[c].count);
      printhex("tmp32",result,sizeof(result));
      fprintf(stdout,", result: %s",tests[c].result);
      fprintf(stdout," failed!!!!");
      fflush(stdout);
      allok=0;
    }
  }
  if(allok) {
    fprintf(stdout,", sha256 tests ok!!!!\n");
  } else {
    fprintf(stdout,", sha256 tests failed!!!!\n");
  }
  fflush(stdout);
}

int main(int argc, char *argv[])
{
  sha_test();
}

#endif

intelrandom.c

#include <stdio.h>
#include <memory.h>

#include "fort.h"
#include "newressu.h"

#if defined FORT_USE_RDRAND ||			\
    defined FORT_USE_RDSEED

// see: https://software.intel.com/content/www/us/en/develop/articles/intel-digital-random-number-generator-drng-software-implementation-guide.html

void _cpuid(unsigned int leaf, unsigned int subleaf,
	    unsigned int *a, unsigned int *b, unsigned int *c, unsigned int *d)
{
  asm volatile("cpuid"
	       : "=a" (*a), "=b" (*b), "=c" (*c), "=d" (*d)
	       : "a" (leaf), "c" (subleaf) );
}

int _is_cpu_vendor(unsigned char *cpuvendor)
{
  int ok=0;
  unsigned int a, b, c, d;

  _cpuid(0, 0, &a, &b, &c, &d);

  if(memcmp((char *)(&b), cpuvendor,4)==0 &&
     memcmp((char *)(&d), cpuvendor+4,4)==0 &&
     memcmp((char *)(&c), cpuvendor+8,4)==0)
    ok=1;

  return(ok);
}

#endif

#ifdef FORT_USE_RDRAND

int _has_rdrand()
{
  int ok=0;
  unsigned int a, b, c, d;

  _cpuid(1, 0, &a, &b, &c, &d);
  if((c & 0x40000000) == 0x40000000) {
    ok=1;
  }

  return(ok);
}

int _rdrand_long(unsigned long *therand)
{
  unsigned char ret;

  asm volatile("rdrand %0; setc %1"
	       : "=r" (*therand), "=qm" (ret) );

  return(int) ret;
}

int rdrand_bytes(int buflen, unsigned char *buf)
{
  int n, ret = 0;
  unsigned long l;

  if(_is_cpu_vendor("GenuineIntel") && _has_rdrand()) {
    if(fort_verbose)
      fprintf(stdout,"Intel rdrand");
    ret=1;
  } else if(_is_cpu_vendor("AuthenticAMD") && _has_rdrand()) {
    if(fort_verbose)
      fprintf(stdout,"AMD rdrand");
    ret=1;
  }
  
  if(ret) {
    while(buflen > 0) {
      if((ret = _rdrand_long(&l)) == 0) // 1 ok, 0 fail
	break;
      if(fort_verbose)
	fprintf(stdout," %016lx",l);
      n = (buflen < sizeof(l) ? buflen : sizeof(l));
      memcpy(buf, (unsigned char *)&l, n);
      buf+=n;
      buflen-=n;
    }
  }
  return(ret);
}

#endif // #ifdef FORT_USE_RDRAND

#ifdef FORT_USE_RDSEED

int _has_rdseed()
{
  int ok=0;
  unsigned int a, b, c, d;

  _cpuid(7, 0, &a, &b, &c, &d);
  if((b & 0x40000) == 0x40000) {
    ok=1;
  }

  return(ok);
}

int _rdseed_long(unsigned long *therand)
{
  unsigned char ret;

  asm volatile("rdseed %0; setc %1"
	       : "=r" (*therand), "=qm" (ret) );

  return(int) ret;
}

int rdseed_bytes(int buflen, unsigned char *buf)
{
  int n, ret = 0;
  unsigned long l;

  if(_is_cpu_vendor("GenuineIntel") && _has_rdseed()) {
    if(fort_verbose)
      fprintf(stdout,"Intel rdseed");
    ret=1;
  } else if(_is_cpu_vendor("AuthenticAMD") && _has_rdseed()) {
    if(fort_verbose)
      fprintf(stdout,"AMD rdseed");
    ret=1;
  }

  if(ret) {
    while(buflen > 0) {
      int tries=0;
      while(++tries < 100) {
	if((ret = _rdseed_long(&l)) == 1) { // 1 ok, 0 fail
	  break;
	}
      }
      if(ret==0)
	break;
      if(fort_verbose) {
	fprintf(stdout," %016lx",l);
	newressu_output=1;
      }
      n = (buflen < sizeof(l) ? buflen : sizeof(l));
      memcpy(buf, (unsigned char *)&l, n);
      buf+=n;
      buflen-=n;
    }
  }
  return(ret);
}

#endif // #ifdef FORT_USE_RDSEED

webrandom.c

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <memory.h>
#include <errno.h>

#include <openssl/ssl.h>
#include <openssl/err.h>

#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <sys/types.h>
#include <sys/socket.h>

#include "sha256.h"
#include "fort.h"

extern unsigned char *procname;
extern int fort_verbose;

#include <stdarg.h>

void dbs_printf(unsigned char **buf, size_t *buf_length, const unsigned char *format, ...)
{
  int count;
  va_list args;;
  
  va_start(args, format);
  count = vsnprintf(*buf, *buf_length, format, args) + 1;
  va_end(args);
  if(*buf_length < count) {
    *buf_length = count;
    *buf = realloc(*buf, *buf_length);
    va_start(args, format);
    count = vsnprintf(*buf, *buf_length, format, args) + 1;
    va_end(args);
  }
}

int fort_connect(unsigned char *host, unsigned char *port)
{
  struct addrinfo hints, *res, *resp;
  int s, status;
  
  memset(&hints, 0, sizeof(hints));
  hints.ai_family = AF_UNSPEC;
  hints.ai_socktype = SOCK_STREAM;
  hints.ai_flags = AI_PASSIVE;
  
  if((status = getaddrinfo(host, port, &hints, &res)) != 0) {
    fprintf(stderr,"\n%s: getaddrinfo", procname);
    fprintf(stderr,", status %d", status);
    fprintf(stderr,", gai_strerror(): %s", gai_strerror(status));
    fprintf(stderr,", errno %d\n", errno);
    fflush(stderr);
  }
  
  for(resp=res; resp!=NULL; resp = resp->ai_next) {
    if((s = socket(resp->ai_family, resp->ai_socktype, resp->ai_protocol))<0)
      continue;
    if(connect(s, resp->ai_addr, resp->ai_addrlen) == 0)
      break;
    close(s);
  }

  freeaddrinfo(res);

  return(s);
}

#define aDEBUG27 2

void fort_hash_http_page(unsigned char *host,unsigned char *port, unsigned char *page, unsigned char *hash) // 202011 JariK
{
  int c, cnt, s, status, bytes, characters;

  if((s = fort_connect(host, port))<0) {
    fprintf(stderr,"\n%s: cannot fort_connect()", procname);
    fprintf(stderr,", status: %d", s);
    fprintf(stderr,", errno: %d" , errno);
    perror("fort_connect");
    fflush(stderr);
  }

  unsigned char *format =
    "GET %s HTTP/1.0\r\n"
    "Host: %s:%s\r\n";
  static unsigned char *msg = NULL;
  static size_t msg_length=0;

  dbs_printf(&msg, &msg_length, format, page, host, port);
  
  if((status=write(s, msg, strlen(msg)))<0) {
    fprintf(stderr, "\n%s: write(), error: %d\n", procname, errno);
    perror("write");
    fflush(stderr);
  }

  HashCtx ctx;
  unsigned char buffer[1024];

  HashInit(&ctx);

  bytes=0;
  characters=0;

  while((cnt = read(s, buffer, sizeof(buffer)))>0) {
#ifdef DEBUG27
    write(1,buffer,cnt);
    fflush(stdout);
#endif
    HashUpdate(&ctx, buffer, cnt);
    bytes+=cnt;
    for(c=0;c<cnt;c++) {
      if(buffer[c]<0x80 || buffer[c]>0xbf)
	characters++;
    }
  }

  hash_update_cvar(&ctx);
  HashFinal(hash, &ctx);

  if(fort_verbose) {
    fprintf(stdout,"fort_hash_http_page:");
    fprintf(stdout," %d bytes read", bytes);
    fprintf(stdout,", %d characters read", characters);
    fprintf(stdout,", sha256: ");
    for(int c = 0;c < HashLen; c++) {
      fprintf(stdout,"%02x", hash[c]);
    }
    fprintf(stdout,"\n");
  }

  close(s);
}

#define aDEBUG49 2
#define aDEBUG50 2

void fort_hash_https_page(unsigned char *host,unsigned char *port, unsigned char *page, unsigned char *hash) // 202011 JariK
{
  int c, cnt, s, status, bytes, characters;

  SSL_METHOD *method=NULL;
  SSL_CTX *ctx=NULL;
  SSL *ssl;

  SSL_library_init(); //see: http://h30266.www3.hpe.com/odl/axpos/opsys/vmsos84/BA554_90007/ch04s03.html
  OpenSSL_add_ssl_algorithms();
  SSL_load_error_strings();

#ifdef DEBUG49
  fprintf(stdout,"SSLv23_client_method()\n");
#endif
  if((method = (SSL_METHOD *)    
      SSLv23_client_method()) == NULL) {
    fprintf(stderr,"\n%s: cannot SSLv3_server_method()", procname);
    fflush(stderr);
  }

#ifdef DEBUG49
  fprintf(stdout,"SSL_CTX_new()\n");
#endif
  if((ctx=SSL_CTX_new(method)) == NULL) {
    fprintf(stderr,"\n%s: cannot SSL_CTX_new()", procname);
    fflush(stderr);
  }

#ifdef DEBUG49
  fprintf(stdout,"SSL_new()\n");
#endif
  if((ssl=SSL_new(ctx)) == NULL) {
    fprintf(stderr,"\n%s: cannot SSL_new()", procname);
    fflush(stderr);
  }

#ifdef DEBUG49
  fprintf(stdout,"fort_connect()\n");
#endif 
 if((s = fort_connect(host, port))<0) {
    fprintf(stderr,"\n%s: cannot fort_connect()", procname);
    fprintf(stderr,", status: %d", s);
    fprintf(stderr,", errno: %d" , errno);
    perror("fort_connect");
    fflush(stderr);
  }

  SSL_set_fd(ssl,s);

#ifdef DEBUG49
  fprintf(stdout,"SSL_connect(ssl)\n");
#endif 
  if((status=SSL_connect(ssl))<=0) {
    fprintf(stderr,"\n%s: cannot SSL_connect()", procname);
    fprintf(stderr,", status: %d", status);
    fprintf(stderr,", errno: %d" , errno);
    fprintf(stderr,", SSL_get_error(): %d\n", SSL_get_error(ssl,status));
    perror("SSL_connect");
    fflush(stderr);
  }

  unsigned char *format =
    "GET %s HTTP/1.0\r\n"
    "Host: %s:%s\r\n";
  static unsigned char *msg = NULL;
  static size_t msg_length=0;

  dbs_printf(&msg, &msg_length, format, page, host, port);

#ifdef DEBUG49
  fprintf(stdout,"SSL_write(), msg_length:%ld, msg=\"%s\"\n",msg_length,msg);
#endif 
  if((status=SSL_write(ssl, msg, strlen(msg)))<0) {
    fprintf(stderr,"\n%s: SSL_write()", procname);
    fprintf(stderr,", status: %d", status);
    fprintf(stderr,", errno: %d", errno);
    fprintf(stderr,", SSL_get_error(): %d", SSL_get_error(ssl,status));
    perror("SSL_write");
    fflush(stderr);
  }
  fflush(stdout);
  
  HashCtx hashctx;
  unsigned char buffer[2048];

  HashInit(&hashctx);

  bytes=0;
  characters=0;

#ifdef DEBUG49
  fprintf(stdout,"SSL_read()\n");
#endif
  int bytesneeded=0, bytesheader=0, bytescontent=0;
  
  do {
    cnt=SSL_read(ssl, buffer, sizeof(buffer));
    if(cnt<0) {
      int err, err2;
      err=SSL_get_error(ssl,cnt);
      err2=ERR_get_error();

      fprintf(stderr, "\n%s: cannot SSL_read()", procname);
      fprintf(stderr, ", retval: %d", cnt);
      fprintf(stderr, ", errno: %d", errno);
      fprintf(stderr,", SSL_get_error() %d", err);
      fprintf(stderr,", ERR_get_error() %d\n", err2);
      perror("SSL_read");
      fflush(stderr);
      break;
    }

#ifdef DEBUG50
    write(1,buffer,cnt);
#endif
    HashUpdate(&hashctx, buffer, cnt);
    bytes+=cnt;

    for(c=0;c<cnt;c++) {
      if(buffer[c]<0x80 || buffer[c]>0xbf)
	characters++;
    }
    if(bytesneeded==0) {
      char *p;
      p=buffer;
      int count=0;
      while(*p!='\0') {
	if(!strncmp(p,"\r\nContent-Length: ",18)) {
	  bytescontent=atoi(p+18);
	}
	if(!strncmp(p,"\r\n\r\n",4)) {
	  bytesheader=count;
	}
	p++;
	count++;
      }
      bytesneeded=bytescontent+bytesheader+4;
    }
  } while(SSL_pending(ssl) || bytes<bytesneeded);

  fprintf(stdout,"bytescontent:%d",bytescontent);
  fprintf(stdout,", bytesheader:%d",bytesheader);
  fprintf(stdout,", bytesneeded:%d\n",bytesneeded);
  fflush(stdout);
  
#ifdef OLD1

#ifdef DEBUG49
  fprintf(stdout,"SSL_read()\n");
#endif 
  while((cnt=SSL_read(ssl, buffer, sizeof(buffer)))>0) {
#ifdef DEBUG49
    fprintf(stdout,"SSL_read() round\n");
#endif 
    
#ifdef DEBUG50
    write(1,buffer,cnt);
    fflush(stdout);
#endif
    HashUpdate(&hashctx, buffer, cnt);
    bytes+=cnt;
    for(c=0;c<cnt;c++) {
      if(buffer[c]<0x80 || buffer[c]>0xbf)
	characters++;
    }
  }
  fflush(stdout);
  if(cnt<0) {
    fprintf(stderr, "\n%s: SSL_read()", procname);
    fprintf(stderr, ", status: %d", status);
    fprintf(stderr, ", errno: %d", errno);
    fprintf(stderr,", SSL_get_error(): %d", SSL_get_error(ssl,status));
    perror("SSL_read");
    fflush(stderr);
  }
  
#endif
  
  fflush(stdout);

  hash_update_cvar(&hashctx);
  HashFinal(hash, &hashctx);

  fprintf(stdout,"fort_hash_https_page:");
  fprintf(stdout," %d bytes read", bytes);
  fprintf(stdout,", %d characters read", characters);
  fprintf(stdout,", sha256: ");
  for(int c = 0;c < HashLen; c++) {
    fprintf(stdout,"%02x", hash[c]);
  }
  fprintf(stdout,"\n");
#ifdef NOTUSED
  
#ifdef DEBUG49
  fprintf(stdout,"SSL_shutdown()\n");
#endif 
  SSL_shutdown(ssl);
#endif
  
#ifdef DEBUG49
  fprintf(stdout,"SSL_free()\n");
#endif 
  SSL_free(ssl);
#ifdef DEBUG49
  fprintf(stdout,"SSL_CTX_free()\n");
#endif 
  SSL_CTX_free(ctx);
  close(s);
}

commandrandom.c

#include <stdio.h>
#include <stdlib.h>

#include "sha256.h"
#include "fort.h"

#define DEBUG6 2 // display random data

void fort_hash_command(unsigned char *command, unsigned char *hash)
{
  int c, cnt, bytes, chars;
  FILE *fp1;
  unsigned char buffer[1024];

  HashCtx hashctx;

  bytes=0;
  chars=0;
  
  if((fp1=popen(command, "r"))!=NULL) {
    HashInit(&hashctx);

    if(fort_verbose) {
      fprintf(stdout,"fort_hash_command: %s\n",command);
      fflush(stdout);
    }

    while((cnt=fread(buffer,1,sizeof(buffer),fp1))>0) {
#ifdef DEBUG6
      if(fort_verbose)
	fwrite(buffer,1,cnt,stdout);
#endif
      HashUpdate(&hashctx, buffer, cnt);
      bytes+=cnt;
      for(c=0;c<cnt;c++) {
	if(buffer[c]<0x80 || buffer[c]>0xbf)
	  chars++;
      }
    }
    pclose(fp1);
    
    if(fort_verbose) {
      fprintf(stdout,", %d bytes read",bytes);
      fprintf(stdout,", %d characters read",chars);
    }
    
    hash_update_cvar(&hashctx);
    
    HashFinal(hash, &hashctx);

    if(fort_verbose) {
      fprintf(stdout,", sha256: ");
      for(int c = 0;c < HashLen; c++) {
	fprintf(stdout,"%02x", hash[c]);
      }
    
      fprintf(stdout,"\n");
      fflush(stdout);
    }
  }
}

ressu4.c

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>

#include "html.h"
#include "dbs.h"
#include "sha256.h"

unsigned char htmldigest[HashLen*2+1];

static char *programname = "Ressu4 version 0.2 ©";
static unsigned char *copyright = "Copyright (c) 2013-2022 Jari Kuivaniemi, Helsinki, Finland. Kaikki oikeudet pidätetään!";
char *myport = "5006";
char *procheader = "Ressu random numbers (3rd edition)";
char *proctitle = "Ressu random numbers";

extern char *procname;
extern char filenamehead[64];
extern unsigned char htmlfilename[64];
extern unsigned char htmlfileextension[10];
extern unsigned char htmltime[32];
extern unsigned char htmltimeshort[32];

extern unsigned char useragent;
extern unsigned char safari;

int firstrun=1;

#define aDEBUG8

void ressu4_app()
{
  unsigned char *p;
  unsigned char command[128];
  unsigned char buffer[1024];
  unsigned char script_file[128]="ressu4script.html";
  FILE *fp1,*fp2;
  
  if((fp1=fopen(script_file,"r"))!=NULL) {
    fclose(fp1);
  } else {
    if((fp1=fopen(script_file,"w"))!=NULL) {

      fprintf(fp1,";\n");
      fprintf(fp1,"; Script for ressu4 ©\n");
      fprintf(fp1,";\n");
      fprintf(fp1,"<h1>%s</h1>\n",procheader);
      fprintf(fp1,";\n");
      fprintf(fp1,"<p>The next chapter consists of characters that\n");
      fprintf(fp1," try to resemble throws of a 64 sided dice as closely as possible.\n");
      fprintf(fp1," Characters have numbers from '0' to '9' (10 entries),\n");
      fprintf(fp1," uppercase letters from 'A' to 'Z' (26 entries), lowercase letters\n");
      fprintf(fp1," 'a' to 'z' (26 entries), '-' and '_' (2 entries).\n");
      fprintf(fp1," Total is 10+26+26+2 = 64 values.\n");
      fprintf(fp1," Characters are grouped into sets of 8 each. Throws\n");
      fprintf(fp1," are random, so you cannot deduce value from\n");
      fprintf(fp1," previous or next value(s).</p>\n");
#ifdef KOK
      fprintf(fp1,"<p>Always have more than one random number generator.\n");
      fprintf(fp1," Preferably one of them in your own program. If you have\n");
      fprintf(fp1," to use these characters as is, add something\n");
      fprintf(fp1," (and change something).</p>\n");
#endif
      fprintf(fp1,"<h3>Newressu random numbers</h3>\n");
      fprintf(fp1,"/bin/newressu -2 -s8 -l1 -c5120 --space --lineno\n");
      fprintf(fp1,";\n");
      fprintf(fp1,"<h3>Random digits</h3>\n");
      fprintf(fp1,"/bin/newressu -11 -s8 -l1 -c1792 --space --lineno\n");
      fprintf(fp1,";\n");
      fprintf(fp1,"<h3>Random uppercase letters</h3>\n");
      fprintf(fp1,"/bin/newressu -12 -s8 -l1 -c1792 --space --lineno\n");
      fprintf(fp1,";\n");
      fprintf(fp1,"<h3>Random lowercase letters</h3>\n");
      fprintf(fp1,"/bin/newressu -13 -s8 -l1 -c1792 --space --lineno\n");
      fprintf(fp1,";\n");
      fprintf(fp1,"<h2>Random characters in number systems</h2>\n");
      fprintf(fp1,";\n");
      fprintf(fp1,"<h3>Random binary digits</h3>\n");
      fprintf(fp1,"<p>Following binary numbers are eight bits from 0 to 255 decimal.\n");
      fprintf(fp1," From right to left the bit multipliers are 1, 2, 4, 8, 16, 32, 64 and 128 (2^b) in decimal.\n");
      fprintf(fp1," So 10000000b is 128d, 11111111b is 255d, 00000010b is 2d, 00000011b is 3d etc.\n");
      fprintf(fp1," Here d after number means of course decimal. Digit numbers, b in 2^b, vary from 0 to 7.</p>\n");
      fprintf(fp1,"/bin/newressu -b -s8 -l1 -c1792 --space --lineno\n");
      fprintf(fp1,";\n");
      fprintf(fp1,"<h3>Random octal digits</h3>\n");
      fprintf(fp1,"<p>These octal numbers are also from 0 to 255 decimal (0 to 377 octal).\n");
      fprintf(fp1," From right to left octal digit multipliers are 1, 8, 64 (8^o) in decimal.\n");
      fprintf(fp1," Here 377o is 255d, 010o is 8d, 100o is 64d.\n");
      fprintf(fp1," Each octal digit contains 3 binary bits, and 377o can be grouped\n");
      fprintf(fp1," in binary like this 011 111 111.</p>\n");
      fprintf(fp1,"/bin/newressu -o --lim400 -l1 -c1792 --lineno\n");
      fprintf(fp1,";\n");
      fprintf(fp1,"<h3>Random decimal digits</h3>\n");
      fprintf(fp1,"<p>These decimal numbers are from 0 to 99999. From right\n");
      fprintf(fp1," to left decimal digit multipliers are 1, 10, 100, 1000 and 10000 (10^d).</p>\n");
      fprintf(fp1,"/bin/newressu -d -s5 -l1 -c1792 --space --lineno\n");
      fprintf(fp1,";\n");
      fprintf(fp1,"<h3>Random hexadecimal digits</h3>\n");
      fprintf(fp1,"<p>Next hexadecimal numbers are from 0000h to ffffh meaning 0 to 65535 decimal.\n");
      fprintf(fp1," Hexadecimal digit has numbers from 0 to 9 and letters a(10),\n");
      fprintf(fp1," b(11), c(12), d(13), e(14) and f(15). From right to left hexadecimal multipliers\n");
      fprintf(fp1," are 1, 16, 256, 4096 decimal (16^h). Each hexadecimal digit contains 4 bits so ffffh can be\n");
      fprintf(fp1," grouped in binary like this 1111 1111 1111 1111.</p>\n");
      fprintf(fp1,"/bin/newressu -x -s4 -l1 -c1792 --space --lineno\n");
      fprintf(fp1,";\n");
      fprintf(fp1,"<h2>Random characters in languages</h2>\n");
      fprintf(fp1,";\n");
      fprintf(fp1,"<p>The next chapters consists of random characters in various\n");
      fprintf(fp1," languages. Most randomness is in chinese, japanese and\n");
      fprintf(fp1," korean characters. Chinese has 20976 values per character,\n");
      fprintf(fp1," japanese has 21158 values per character and korean has\n");
      fprintf(fp1," 11172 values per character.</p>\n");
      fprintf(fp1,"<p>Latin (or roman) based alphabets have characters as follows:\n");
      fprintf(fp1," danish alphabet has 58 characters,\n");
      fprintf(fp1," deutsch alphabet has 60 characters,\n");
      fprintf(fp1," english has 52 characters,\n");
      fprintf(fp1," estonian has 64 characters,\n");
      fprintf(fp1," finnish alphabet has 58 characters,\n");
      fprintf(fp1," french character set has 52 characters,\n");
      fprintf(fp1," italian character set has 52 characters,\n");
      fprintf(fp1," latvian has 66 characters,\n");
      fprintf(fp1," lithuanian has 64 characters,\n");
      fprintf(fp1," norwegian has 58 characters,\n");
      fprintf(fp1," swedish has 58 characters.\n");
      fprintf(fp1," </p>\n");
      fprintf(fp1,";\n");
      fprintf(fp1,"<h3>Chinese random characters</h3>\n");
      fprintf(fp1,"/bin/newressu --cn -s8 -l1 -c1792 --lineno\n");
      fprintf(fp1,";\n");
      fprintf(fp1,"<h3>Danish random characters</h3>\n");
#ifdef KOK
      fprintf(fp1,"<p>Danish has latin letters 'a' to 'z' ('A' to 'Z')\n");
      fprintf(fp1,"and 'æ', 'ø', and 'å' ('Æ', 'Ø', 'Å').</p>\n");
#endif
      fprintf(fp1,";ABCDEFGHIJKLMNOPQRSTUVWXYZÆØÅ\n");
      fprintf(fp1,";abcdefghijklmnopqrstuvwxyzæøå\n");
      fprintf(fp1,"/bin/newressu --dnk -s8 -l1 -c1792 --space --lineno\n");
      fprintf(fp1,";\n");
      fprintf(fp1,"<h3>Deutsch random characters</h3>\n");
      fprintf(fp1,";ABCDEFGHIJKLMNOPQRSTUVWXYZÄÖÜẞ\n");
      fprintf(fp1,";abcdefghijklmnopqrstuvwxyzäöüß\n");
      fprintf(fp1,"/bin/newressu --deu -s8 -l1 -c1792 --space --lineno\n");
      fprintf(fp1,";\n");
      fprintf(fp1,"<h3>English random characters</h3>\n");
      fprintf(fp1,";ABCDEFGHIJKLMNOPQRSTUVWXYZ\n");
      fprintf(fp1,";abcdefghijklmnopqrstuvwxyz\n");
      fprintf(fp1,"/bin/newressu --eng -s8 -l1 -c1792 --space --lineno\n");
      fprintf(fp1,";\n");
      fprintf(fp1,"<h3>Estonian random characters</h3>\n");
      fprintf(fp1,";ABCDEFGHIJKLMNOPQRSŠZŽTUVWÕÄÖÜXY\n");
      fprintf(fp1,";abcdefghijklmnopqrsšzžtuvwõäöüxy\n");
      fprintf(fp1,"/bin/newressu --est -s8 -l1 -c1792 --space --lineno\n");
      fprintf(fp1,";\n");
      fprintf(fp1,"<h3>Finnish random characters</h3>\n");
      fprintf(fp1,";ABCDEFGHIJKLMNOPQRSTUVWXYZÅÄÖ\n");
      fprintf(fp1,";abcdefghijklmnopqrstuvwxyzåäö\n");
      fprintf(fp1,"/bin/newressu --fin -s8 -l1 -c1792 --space --lineno\n");
      fprintf(fp1,";\n");
      fprintf(fp1,"<h3>French random characters</h3>\n");
      fprintf(fp1,";ABCDEFGHIJKLMNOPQRSTUVWXYZ\n");
      fprintf(fp1,";abcdefghijklmnopqrstuvwxyz\n");
      fprintf(fp1,"/bin/newressu --fra -s8 -l1 -c1792 --space --lineno\n");
      fprintf(fp1,";\n");
      fprintf(fp1,"<h3>Gothic random characters</h3>\n");
      fprintf(fp1,"/bin/newressu --got -s8 -l1 -c1792 --space --lineno\n");
      fprintf(fp1,";\n");
      fprintf(fp1,"<h3>Greek random characters</h3>\n");
      fprintf(fp1,";ΑΒΓΔΕΖΗΘΙΚΛΜΝΞΟΠΡΣΤΥΦΧΨΩ\n");
      fprintf(fp1,";αβγδεζηθικλμνξοπρστυφχψω\n");
      fprintf(fp1,"/bin/newressu --grc -s8 -l1 -c1792 --space --lineno\n");
      fprintf(fp1,";\n");
      fprintf(fp1,"<h3>Italian random characters</h3>\n");
      fprintf(fp1,";ABCDEFGHIJKLMNOPQRSTUVWXYZ\n");
      fprintf(fp1,";abcdefghijklmnopqrstuvwxyz\n");
      fprintf(fp1,"/bin/newressu --ita -s8 -l1 -c1792 --space --lineno\n");
      fprintf(fp1,";\n");
      fprintf(fp1,"<h3>Japanese random characters</h3>\n");
      fprintf(fp1,"/bin/newressu --jp -s8 -l1 -c1792 --lineno\n");
      fprintf(fp1,";\n");
      fprintf(fp1,"<h3>Korean random characters</h3>\n");
      fprintf(fp1,"/bin/newressu --kor -s8 -l1 -c1792 --lineno\n");
      fprintf(fp1,";\n");
      fprintf(fp1,"<h3>Latvian random characters</h3>\n");
      fprintf(fp1,";AĀBCČDEĒFGĢHIĪJKĶLĻMNŅOPRSŠTUŪVZŽ\n");
      fprintf(fp1,";aābcčdeēfgģhiījkķlļmnņoprsštuūvzž\n");
      fprintf(fp1,"/bin/newressu --lva -s8 -l1 -c1792 --space --lineno\n");
      fprintf(fp1,";\n");
      fprintf(fp1,"<h3>Lithuanian random characters</h3>\n");
      fprintf(fp1,";AĄBCČDEĘĖFGHIĮYJKLMNOPRSŠTUŲŪVZŽ\n");
      fprintf(fp1,";aąbcčdeęėfghiįyjklmnoprsštuųūvzž\n");
      fprintf(fp1,"/bin/newressu --ltu -s8 -l1 -c1792 --space --lineno\n");
      fprintf(fp1,";\n");
      fprintf(fp1,"<h3>Norwegian random characters</h3>\n");
      fprintf(fp1,";ABCDEFGHIJKLMNOPQRSTUVWXYZÆØÅ\n");
      fprintf(fp1,";abcdefghijklmnopqrstuvwxyzæøå\n");
      fprintf(fp1,"/bin/newressu --nor -s8 -l1 -c1792 --space --lineno\n");
      fprintf(fp1,";\n");
      fprintf(fp1,"<h3>Russian random characters</h3>\n");
      fprintf(fp1,";АБВГДЕЁЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯ\n");
      fprintf(fp1,";абвгдеёжзийклмнопрстуфхцчшщъыьэюя\n");
      fprintf(fp1,"/bin/newressu --rus -s8 -l1 -c1792 --space --lineno\n");
      fprintf(fp1,";\n");
      fprintf(fp1,"<h3>Swedish random characters</h3>\n");
      fprintf(fp1,";ABCDEFGHIJKLMNOPQRSTUVWXYZÅÄÖ\n");
      fprintf(fp1,";abcdefghijklmnopqrstuvwxyzåäö\n");
      fprintf(fp1,"/bin/newressu --swe -s8 -l1 -c1792 --space --lineno\n");
      fprintf(fp1,";\n");
      fprintf(fp1,"<h2>Technical</h2>\n");
      fprintf(fp1,"<p>This version runs newressu new for all of the previous\n");
      fprintf(fp1," random number chapters (25 runs), so the buffer is empty in\n");
      fprintf(fp1," the beginning of the chapter runs.\n");
      fprintf(fp1," This whole page is created (including randomness) after your\n");
      fprintf(fp1," network query is received,\n");
      fprintf(fp1," so time newressu runs is quite reasonable.</p>\n");
      fprintf(fp1,"<p>This version does random skips on clock material,\n");
      fprintf(fp1," which makes it harder to guess it. Ressu skips\n");
      fprintf(fp1," 0-255 bytes every ~1000 bytes.\n");
      fprintf(fp1," This version also is ressu only, there is no whitening\n");
      fprintf(fp1," or combining of other generators.</p>\n");
      fclose(fp1);
    }
  } // if((fp1=fopen
  if((fp1=fopen(script_file,"r"))!=NULL) {    
    while(fgets(command,sizeof(command),fp1)!=NULL) {
      if(command[0]==';')
	continue;
      else if(!strncmp(command,"/bin/newressu ",14)) {
	if((fp2=popen(command, "r"))!=NULL) {
	  dbs_html_printf("<code>");
	  while(fgets(buffer,sizeof(buffer),fp2)!=NULL) {
#ifdef DEBUG8
	    fprintf(stdout,"\"%s\"",buffer);
#endif
	    p=buffer;
	    while(*p!='\0') {
	      if(*p!='-') 
		dbs_html_printf("%c",*p);
	      else {
		if(safari)
		  dbs_html_printf("&#8209;");
		//dbs_html_printf("&minus;");
		//dbs_html_printf("&ndash;");
		//dbs_html_printf("&hyphen;");
		//dbs_html_printf("&#45;");
		else
		  dbs_html_printf("&minus;");
	      }
	      p++;
	    } // while(*p!='\0') {
	    //dbs_html_printf(" ");
	    //dbs_html_printf("\n");
	    //dbs_html_printf("<br>");
	  } // while(fgets(
	  dbs_html_printf("</code>");
	  fclose(fp2);
	} // if((fp2
      } else { // if(!strncmp(command
	if(useragent)
	  dbs_html_printf("%s",command);
	else if(strstr(command,"<h1>")!=NULL ||
		strstr(command,"<h2>")!=NULL ||
		strstr(command,"<h3>")!=NULL ||
		strstr(command,"<h4>")!=NULL )
	  dbs_html_printf("%s",command);
      } // if(strncmp
    } // while(fgets
    fclose(fp1);
  } // if((fp1=fopen
  if((fp1=fopen("ressuoriginal.html","r"))!=NULL) {
    while(fgets(buffer,sizeof(buffer),fp1)!=NULL)
      if(buffer[0]!=';')
	dbs_html_printf("%s",buffer);
    fclose(fp1);
  }
}

void dba_loop()
{
  html_clear_all();
  if(!strcmp(htmlfileextension,"ico") ||
     !strcmp(htmlfileextension,"png")) {
    dbs_html_set(0);
    dbs_html_printf("HTTP/1.0 404 Not Found\r\n");
    //dbs_html_printf("Location: \r\n");
    //dbs_html_printf("Server: %s\r\n", programname);
  } else {  
    dbs_html_set(0);
    dbs_html_printf("HTTP/1.0 200 OK\r\n");
    dbs_html_printf("Location: \r\n");
    dbs_html_printf("Server: %s\r\n", programname);
    dbs_html_printf("Date: %s\r\n", htmltime);
    
    dbs_html_set(1);
    
    dbs_html_printf("<!doctype html>\r\n");
    dbs_html_printf("<html lang=\"fi\">");
    
    dbs_html_printf("<head>");
    dbs_html_printf("<meta charset=\"utf-8\">");
    dbs_html_printf("<title>%s</title>",proctitle);
    dbs_html_printf("<meta name=\"author\" content=\"Jari Kuivaniemi\">");
    dbs_html_printf("<meta name=\"copyright\" content=\"Jari Kuivaniemi\">");
    dbs_html_printf("<meta name=\"format-detection\" content=\"telephone=no\">"); // Safari
    dbs_html_printf("<meta name=\"format-detection\" content=\"telephone=no\"/>"); // Safari
    dbs_html_printf("<meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">");
    dbs_html_printf("</head>");
    
    dbs_html_printf("<body>");
    
    ressu4_app();

    dbs_html_printf("<p>%s", programname);
    dbs_html_printf(",  sha256(%s)", htmldigest);
    dbs_html_printf("</p>");

    dbs_html_printf("</body>");
  
    dbs_html_printf("</html>");
  }
}

void dba_loop2()
{
  int len;

  dbs_html_set(0);

  len=strlen(html_get_string(1)) +
    strlen(html_get_string(2)) +
    strlen(html_get_string(3)) +
    strlen(html_get_string(4)) +
    strlen(html_get_string(5)) +
    strlen(html_get_string(6)) +
    strlen(html_get_string(7)) +
    strlen(html_get_string(8));
  log_printf("Content-Length: %d\n",len);
  dbs_html_printf("Content-Length: %d", len);
  dbs_html_printf("\r\n\r\n");
}

void ressu4_version()
{
  fprintf(stdout,"\n%s", programname);
  fprintf(stdout," %s\n", copyright);
  fflush(stdout);
}

void dba_main(int argc, char *argv[])
{
  strcat(filenamehead,procname);
  strcat(filenamehead,myport);

  ressu4_version();
}

html.c

#include <stdio.h>
#include <malloc.h>
#include <string.h>
#include <ctype.h>

#include <stdarg.h>

#include "html.h"

int html_now = 0;
unsigned char *html[] = { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL };
int html_size[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0 };

void html_set(int bufno)
{
  html_now=bufno;
  if(html[bufno]==NULL) {
    html_size[bufno] = 10;
    html[bufno]=malloc(html_size[bufno]);
  }
}

int html_get()
{
  return(html_now);
}

unsigned char *html_get_string(int bufno)
{
  return(html[bufno]);
}

void html_clear()
{
  html_set(html_now);
  html[html_now][0]='\0';
}

void html_clear_all()
{
  int c;
  for(c=0;c<HTML_BUFFERS;c++) {
    html_set(c);
    html_clear();
  }
}

static void html_printf_valist(const char *format, va_list ap)
{
  int count;
  static char *printbuf=NULL;
  static int printbuf_len=0;

  va_list ap2;
  va_copy(ap2,ap);

  count=vsnprintf(printbuf, printbuf_len, format, ap) + 1;
  if(printbuf_len < count) {
    printbuf_len = count;
    printbuf=realloc(printbuf, printbuf_len);
    count=vsnprintf(printbuf, printbuf_len, format, ap2) + 1;
  }

  if(html_size[html_now] <
     strlen(html[html_now]) +
     strlen(printbuf) + 1) {
    html_size[html_now] =
     strlen(html[html_now]) +
     strlen(printbuf) + 1;
    html[html_now] = realloc(html[html_now], html_size[html_now]);
  }
  
  strcpy(html[html_now]+strlen(html[html_now]), printbuf);
}


void html_printf(const char *format, ...)
{
  va_list args;

  va_start(args, format);
  html_printf_valist(format, args);
  //fprintf(stdout,format, args);
  va_end(args);
}

void html_buf_printf(int bufno, const char *format, ...)
{
  int save_html;
  va_list args;

  save_html=html_get();
  html_set(bufno);
  va_start(args, format);
  html_printf_valist(format, args);
  va_end(args);
  html_set(save_html);
}

int indent;
int printedchars=0;

#define aDEBUG28

void html_out_crlf()
{
  if(printedchars) {
#ifdef DEBUG28
    fprintf(stdout,"(%d)",indent*8+printedchars);
#endif
    html_printf("\n");
#ifdef DEBUG28
    fprintf(stdout,"\n");
#endif
    for(int c=0;c<indent;c++) {
      html_printf("\t");
#ifdef DEBUG28
      fprintf(stdout,"\t");
#endif
    }
    printedchars=0;
  }
}

#define aDEBUG31 2

void html_parse_name(int size, unsigned char *name, unsigned char **p2)
{
  int count;
  unsigned char *p,*n;

  p = *p2;
  count = 0;
  n = name;
  while(isalpha(*p) || isdigit(*p) || *p=='!') {
    if(++count < size)
      *n++ = *p;
    p++;
    count++;
  }
  *n = '\0';

#ifdef DEBUG31
  fprintf(stdout,"[name:%s]",name);
#endif
}

#define aDEBUG36 2
#define aDEBUG37 2

void html_indent(unsigned char *p2)
{
  int space, ch, tags, tagfound, intag, inchar;
  unsigned char *p,*q,*q2,name[32],tag[48];

  p=p2;
  ch=0;
  indent=0;
  inchar=0;
  while(*p!='\0') {
    space = 0;
    while(*p=='\r' || *p=='\n' || *p=='\t' || *p==' ') {
      p++;
      space = 1;
    }
    if(!strncmp(p,"<br>",4)) {
      p+=4;
      html_printf("<br>");
#ifdef DEBUG36
      fprintf(stdout,"<br>");
#endif
      printedchars+=4;
      
      while(*p=='\r' || *p=='\n' || *p=='\t' || *p==' ')
	p++;
#ifdef DEBUG36
      fprintf(stdout,"[nextchar:%c]",*p);
#endif
      if(strncmp(p,"</",2))
	html_out_crlf();
    }

    if(!strncmp(p,"</",2)) { // Check for end tag

      q2 = p;
      p += 2;
      q = p;
      html_parse_name(sizeof(name), name, &q);
      q = q2 - 1;
      tags = 0;
      tagfound = 0;

      // Search for start tag backward
      sprintf(tag,"<%s", name);
      while(q >= p2) {
        if(*q == '<') {
          if(!strncmp(tag, q, strlen(tag))) {
#ifdef DEBUG36    
            fprintf(stdout,"[tag:%s]", tag);
#endif
            tagfound = 1;
            break;
          } else
            tags++;
        }
        q--;
      }
      if(tags && indent > 0) {
        indent--;
#ifdef DEBUG36
        fprintf(stdout,"[indent:%d]",indent);
        fprintf(stdout,"[tagfound:%d]",tagfound);
#endif
        html_out_crlf();
      }
      html_printf("</");
#ifdef DEBUG36
      fprintf(stdout,"</");
#endif
      space = 0;
      intag = 1;
      inchar = 0;
#ifdef DEBUG36
      fprintf(stdout,"[inchar:%d]",inchar);
#endif
      printedchars+=2;

    } else if(*p=='<') { // Check for start tag

      p++;
      q = p;
      html_parse_name(sizeof(name),name,&q);
      tags = 0;
      tagfound = 0;

      // Search for end tag forward
      sprintf(tag,"</%s",name);
      while(*q!='\0') {
        if(*q=='<') {
          if(!strncmp(tag, q, strlen(tag))) {
#ifdef DEBUG36
            fprintf(stdout,"[tag:%s]",tag);
#endif
            tagfound = 1;
            break;
          } else
            tags++;
        }
        q++;
      }
      html_out_crlf();
      if(tags && tagfound) {
        indent++;
#ifdef DEBUG36
        fprintf(stdout,"[indent:%d]",indent);
        fprintf(stdout,"[tagfound:%d]",tagfound);
#endif
      }
      html_printf("<");
#ifdef DEBUG36
      fprintf(stdout,"<");
#endif
      space = 0;
      intag = 1;
      inchar = 0;
#ifdef DEBUG36
      fprintf(stdout,"[inchar:%d]",inchar);
#endif
      printedchars++;
    } else if((isprint(*p) || *p>=128) && *p!='\0') {
      if(!inchar && !intag) {
	inchar=1;
#ifdef DEBUG36
	fprintf(stdout,"[inchar:%d]",inchar);
#endif
	//html_out_crlf();
      }
      int count=0;
      for(q=p;(isprint(*q) || *q>=128) && *q!='\0';q++) {
	if(*q=='\r' || *q=='\n' || *q=='\t' || *q==' ')
	  break;
#ifdef DEBUG36
	fprintf(stdout,"%c",*q);
#endif
	count++;
      }
#ifdef DEBUG36
      fprintf(stdout,"(%d)",count);
#endif
    }

    int chars = 0;

    // calculate number of chars
    q = p;
    while((*q!='<' && (isprint(*q) || *q>=128)) && *q!='\0') {
      if(*q=='\r' || *q=='\n' || *q=='\t' || *q==' ')
        break;
      if(*q<0x80 || *q>0xbf) // utf8 too
        chars++;
      if(*q=='>')
	break;
      q++;
    }

    // print line break if needed
    if(indent*8+printedchars+chars > 100 && !intag) {
      html_out_crlf(); // print nl+indent
      space = 0;
    }
    
    // print space if needed
    if(ch != '>' && // no space after tag
       *p != '<' && // no space before tag
       printedchars > 0 &&
       space) {
      html_printf(" ");
#ifdef DEBUG36
      fprintf(stdout," ");
#endif
      space = 0;
    }

    //print the string
    while((*p != '<' && (isprint(*p) || *p >= 128)) && *p != '\0') {
      if(*p == '>') {
        intag = 0;
      }
      if(*p == '\r' || *p == '\n' || *p == '\t' || *p == ' ')
        break;
      ch = *p;
      html_printf("%c", *p);
#ifdef DEBUG36
      fprintf(stdout,"%c",*p);
#endif
      printedchars++;
      if(*p=='>') {
	p++;
	break;
      }
      p++;
    }
#ifdef DEBUG36
    fprintf(stdout,"(%d)",chars);
#endif
  } //while(*p!='\0')
#ifdef DEBUG37
  fprintf(stdout,"%s",html[html_now]);
#endif
}

dbs.c

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <poll.h>
#include <time.h>
#include <ctype.h>

#include <sys/time.h>
//#include "db2.h"
#include "sha256.h"

#include "dbs.h"

#ifdef RESSU
#include "ressugen.h"
#endif

#ifdef FORT
#define aFORT_EVENTS 2
static int fort_events = 0;
static unsigned int fort_event_mode = 1;
#endif
#include "fort.h"

#include "html.h"

static unsigned char *copyright = "Copyright (c) 2016-2022 Jari Kuivaniemi, Helsinki, Finland. Kaikki oikeudet pidätetään!";
static char *programname = "DBS version 0.15 ©";

#define html_printf dbs_html_printf
#define IUTIME unsigned long long
unsigned char *procname = "dbs";
int callid=-1;

unsigned char filenamehead[16];

unsigned char *htmlin;
int htmlinlen=2048;

unsigned char htmlrecvheaderlen=0;
unsigned char *htmlrecvheader=NULL;
unsigned char htmlrecvpayloadlen=0;
unsigned char *htmlrecvpayload=NULL;
unsigned char htmlsentheaderlen=0;
unsigned char *htmlsentheader=NULL;
unsigned char htmlsentpayloadlen=0;
unsigned char *htmlsentpayload=NULL;
unsigned char htmlmethod[10];
unsigned char htmlpath[128];
unsigned char htmlversion[32];
unsigned char htmlfilename[64];
unsigned char htmlfileextension[10];
unsigned char htmlhost[32];
unsigned char htmluseragent[1024];
unsigned char htmlcookie[1024];
unsigned char htmlsessionid[33];
unsigned char htmltimeshort[32];
unsigned char htmltime[32];
unsigned char *htmlparams=NULL;
unsigned char htmldigest[HashLen*2+1];
unsigned char htmlmode[10];
unsigned char htmlip[32];
unsigned char htmlsslcipher[64];
unsigned char htmlhostname[64];
unsigned char htmlport[10];
unsigned char htmllanguage[10];
unsigned char htmluseconds[10];
unsigned char htmlprevminutes[32];
unsigned char useragent=0;
unsigned char chrome=0;
unsigned char edg=0;
unsigned char firefox=0;
unsigned char ipad=0;
unsigned char iphone=0;
unsigned char flaglinux=0;
unsigned char safari=0;

#define USE_SEMAPHORES 2

void dump_string(FILE *fp1, unsigned char *p)
{
  fprintf(stdout,"{");
  while(*p != '\0') {
    if(*p == '\\')
      fprintf(fp1,"\\\\");
    else if(isprint(*p))
      fprintf(fp1,"%c", *p);
    else
      fprintf(fp1,"\\%02x", *p);
    p++;
  }
  fprintf(stdout,"}");
}

static int dbs_parse_hex1(unsigned char **str) /* 20131003 JariK */
{
  unsigned char *p;
  int digit;

  p=*str;
  digit=0;
  if(*p >= 'a' && *p <= 'f')
    digit = *p - 'a' + 10, p++;
  else if(*p >= 'A' && *p <= 'F')
    digit = *p - 'A' + 10, p++;
  else if(*p >= '0' && *p <= '9')
    digit = *p - '0', p++;
  else digit = -1;

  *str = p;
  return(digit);
}

static int dbs_parse_html_string(int stringlen, unsigned char *string, unsigned char **html)
{
  int c,d, count, ok;
  unsigned char *s=string;
  unsigned char *h=*html;

  ok = 0;
  count = 0;
  
  while(isalnum(*h) || *h=='%' || *h=='+'
	|| *h == '-' || *h == '_' || *h == '.'
	|| *h==',' || *h == '*') {
    ok = 1;
    if(*h == '%') {
      h++;
      if((c=dbs_parse_hex1(&h)) >= 0) {
	if((d=dbs_parse_hex1(&h)) >= 0) {
	  c = c * 16 + d;
	} else
	  c = c;
      } else
	c = 64;
      if(++count < stringlen) {
	if(c == 0x22)
	  *s++ = '\'';
	else
	  *s++ = c;
      }
    } else if(*h == '+') {
      if(++count < stringlen)
	*s++ = ' ';
      h++;
    } else {
      if(++count < stringlen)
	*s++ = *h;
      h++;
    }
  }
  *s = '\0';
  *html = h;

  return(ok);
}

#include <stdarg.h>

int dbs_html_get_string(unsigned char *string,unsigned char **str,int len)
{
  int c, d, ok, count;
  unsigned char *p, *n;

  n = string;
  p = *str;
  ok = 0;

  count = 0;
  while(isalnum(*p) || *p == '%'|| *p == '+'
	|| *p == '-' || *p == '_' || *p == '='
	|| *p=='&' || *p=='.' || *p=='*') {
    ok = 1;
    if(*p == '%') {
      p++;
      if((c = dbs_parse_hex1(&p)) >= 0) {
	if((d = dbs_parse_hex1(&p)) >= 0) {
	  c = c * 16 + d;
	} else
	  c = c;
      } else
	c = 64;
      if(count++ < len)
	*n++ = c;
    } else if(*p == '+') {
      if(count++ < len)
	*n++ = ' ';
      p++;
    } else {
      if(count++ < len)
	*n++ = *p++;
      else
	p++;
    }
  }
  *n = '\0';
  *str = p;

  return(ok);
}

int dbs_parse_html_parameter(int namelen, unsigned char *name, int valuelen,unsigned char *value, unsigned char **s)
{
  if(dbs_parse_html_string(namelen, name, s) == 0)
    return(0);
  if((**s) == '=')
    (*s)++;
  dbs_parse_html_string(valuelen, value, s);
#ifdef OLD1
  if(dbs_parse_html_string(valuelen, value, s) == 0)
    return(0);
#endif
  if(**s == '&')
    (*s)++;
  
  return(1);
}

int dbs_get_parameter(char *name, int valuelen, unsigned char *value)
{
  int ok;
  unsigned char name2[32];
  unsigned char *h=htmlparams;

  value[0] = '\0';
  ok = 0;

  while(*h != '\0') {
    dbs_parse_html_parameter(sizeof(name2), name2, valuelen, value, &h);
    if(!strcmp(name,name2)) {
      ok = 1;
      break;
    }
  }

  if(ok == 0)
    value[0] = '\0';
  
  return(ok);
}

static unsigned long dbs_getseconds()
{
  struct timeval tv;

  gettimeofday(&tv, NULL);

  return((IUTIME)tv.tv_sec);
}

#define aDEBUG11 2

static unsigned char *dbs_html_get_request_line(unsigned char *name, int lenbuffer, unsigned char *buffer)
{
  int len;
  unsigned char *p, *q, tag[32];

  p = htmlin;

#ifdef DEBUG11
  fprintf(stdout,"Data:");
  dump_string(stdout,p);
  fprintf(stdout,"\n");
#endif
  
  sprintf(tag,"\r\n%s:",name);
  while(*p != '\0') {
    if(!strncmp(p, tag, strlen(tag))) {
      p += strlen(tag);
      while(isblank(*p))
	p++;
      q = buffer;
      len = 0;
      while(*p != '\r' && *p != '\n' && *p != '\0') {
	if(++len < lenbuffer)
	  *q++ = *p;
	p++;
      }
      *q = '\0';
      return(buffer);
    }
    if(*p != '\0')
      p++;
  }
  return(NULL);
}

static void dbs_html_get_request_line_num(unsigned char *name, int lenbuffer, unsigned char *buffer)
{
  unsigned char *p;

  if((p = dbs_html_get_request_line(name,lenbuffer,buffer)) == NULL)
    sprintf(buffer,"0");
#ifdef OLD1
  else {
    int len = 0;
    unsigned char *n = buffer;
    while(isdigit(*p)) {
      if(++len < lenbuffer)
        *n++ = *p;
      p++;
    }
    *n = '\0';
  }
#endif
}

void dbs_get_cookie(unsigned char *name, int valuelen, unsigned char *value)
{
  int len;
  unsigned char *p, *n;

  value[0] = '\0';
  
  p = htmlcookie;
  
  while(*p != '\0') {
    while(isblank(*p))
      p++;
    if(!strncmp(p,name,strlen(name))) {
      p += strlen(name);
      while(isblank(*p))
        p++;
      if(*p == '=')
        p++;
      while(isblank(*p))
        p++;
      n = value;
      len = 0;
      while(*p != ';' && isprint(*p)) {
        if(++len < valuelen)
          *n++ = *p;
        p++;
      }
      *n = '\0';
      return;
    }
    while(*p != ';' && *p != '\n' && *p != '\0')
      p++;
    if(*p == ';')
      p++;
    while(isblank(*p))
      p++;
  }
}

static void dbs_html_parse_string(int buflen, char *buf, unsigned char **p2)
{
  int len;
  unsigned char *p;

  p=*p2;
  len=0;
  while(*p!='\0' && !isblank(*p) && *p!='\n' && *p!='\r') {
    if(++len < buflen) {
      *buf++ = *p;
    }
    p++;
  }
  *buf='\0';

  while(isblank(*p))
    p++;

  *p2 = p;
}

static void dbs_html_parse_filename(int buflen, char *buf, unsigned char *p)
{
  int len;
  unsigned char *n;

  len = 0;
  n = buf;

  while(*p != '\0') {
    if(*p == '/') {
      n = buf;
      len = 0;
    } else {
      if(++len < buflen)
        *n++ = *p;
    }
    p++;
  }
  *n = '\0';
}

static void dbs_html_parse_extension(int buflen, char *buf, unsigned char *p)
{
  int len;
  unsigned char *n;

  len = 0;
  n = buf;

  while(*p != '\0') {
    if(*p == '.') {
      n = buf;
      len = 0;
    } else {
      if(++len < buflen)
        *n++ = *p;
    }
    p++;
  }
  *n = '\0';
}

static unsigned char *dbs_html_get_params()
{
  int ok = 0;
  unsigned char *p = htmlin;

  while(*p != '\0') {
    if(!strncmp(p,"\r\n\r\n",4)) {
      p += 4;
      ok = 1;
      break;
    }
    p++;
  }

  if(ok)
    return(p);
  else
    return(NULL);
}

#include <stdarg.h>

unsigned char *logbuf=NULL;
int logbuf_len=0;

void log_clear()
{
  if(logbuf != NULL)
    logbuf[0] = '\0';
}

void log_free()
{
  if(logbuf != NULL) {
    free(logbuf);
    logbuf_len = 0;
    logbuf = NULL;
  }
}

#define aDEBUG20 2
#define aDEBUG21 2

void log_printf(const char *format, ...)
{
  int count,size;
  va_list args;
  static char *printbuf=NULL;
  static int printbuf_len=0;

  va_start(args, format);
  count=vsnprintf(printbuf, printbuf_len, format, args) + 1;
  va_end(args);

  if(printbuf_len < count) {
    printbuf_len = count;
    printbuf=realloc(printbuf, printbuf_len);
    va_start(args, format);
    count=vsnprintf(printbuf, printbuf_len, format, args) + 1;
    va_end(args);
  }

#ifdef DEBUG20
  fprintf(stdout,"\n%p %d %s %p %d",
	  printbuf, printbuf_len, printbuf, logbuf, logbuf_len);
#endif

  size=(logbuf==NULL? 0:strlen(logbuf))+count;
  if(logbuf_len<size) {
    unsigned char *temp=logbuf;
    logbuf_len = size;
    logbuf = realloc(logbuf, logbuf_len);
    if(temp == NULL)
      logbuf[0] = '\0';
  }

#ifdef DEBUG21
  fprintf(stdout,"\n%p %d %s",
	  logbuf, logbuf_len, logbuf);
#endif
  strcat(logbuf, printbuf);
}

void log_dump_string(unsigned char *p)
{
  while(*p != '\0') {
    if(*p == '\\')
      log_printf("\\\\");
    else if(isprint(*p) || *p == '\r' || *p == '\n')
      log_printf("%c",*p);
    else
      log_printf("\\%02x",*p);
    p++;
  }
}

static void dbs_add_end_new_str(char *filename, char *string)
{
  int ok;
  char buffer[256];
  FILE *fp1;

  ok = 0;
  if((fp1 = fopen(filename,"r")) != NULL) {
    while(fgets(buffer,sizeof(buffer),fp1) != NULL) {
      buffer[strlen(buffer)-1] = '\0';
      if(!strcmp(buffer,string)) {
	ok = 1;
	break;
      }
    }
    fclose(fp1);
  }
  if(!ok) {
    if((fp1 = fopen(filename,"a")) != NULL) {
      fprintf(fp1,"%s\n", string);
      fclose(fp1);
    }
  }
}

#define aDEBUG25 2

void dba_loop();
void dba_loop2();

static void dbs_run_loop()
{  
  unsigned char *p;

  p=htmlin;
  dbs_html_parse_string(sizeof(htmlmethod), htmlmethod,&p);
  dbs_html_parse_string(sizeof(htmlpath), htmlpath, &p);
  dbs_html_parse_string(sizeof(htmlversion), htmlversion, &p);
  dbs_html_parse_filename(sizeof(htmlfilename), htmlfilename, htmlpath);
  dbs_html_parse_extension(sizeof(htmlfileextension), htmlfileextension, htmlfilename);
  
  htmlparams = dbs_html_get_params();
  if(htmlparams == NULL)
    htmlparams = "";

  if(dbs_html_get_request_line("Host", sizeof(htmlhost), htmlhost) == NULL)
    htmlhost[0] = '\0';
  
  if(dbs_html_get_request_line("User-Agent", sizeof(htmluseragent), htmluseragent) == NULL)
    htmluseragent[0] = '\0';

  if(dbs_html_get_request_line("Cookie", sizeof(htmlcookie), htmlcookie)==NULL)
    htmlcookie[0] = '\0';
  
  chrome = 0;
  edg = 0;
  firefox = 0;
  ipad = 0;
  iphone = 0;
  flaglinux = 0;
  safari = 0;

  useragent=0;

  if(htmluseragent[0] != '\0')
    useragent = 1;

  unsigned char *p2 = htmluseragent;

  log_printf(", useragent");

  p2=p;
  while(*p2 != '\r' && *p2 != '\n') {
    if(!strncmp(p2,"Chrome",6)) {
      chrome = 1;
      log_printf(", chrome");
    }
    if(!strncmp(p2,"Edg",6)) {
      edg = 1;
      log_printf(", Edg");
    }
    if(!strncmp(p2,"Firefox",6)) {
      firefox = 1;
      log_printf(", firefox");
    }
    if(!strncmp(p2,"iPad",4)) {
      ipad = 1;
      log_printf(", ipad");
    }
    if(iphone==0 && !strncmp(p2,"iPhone",6)) {
      iphone = 1;
      log_printf(", iphone");
    }
    if(!strncmp(p2,"Linux",5)) {
      flaglinux = 1;
      log_printf(", linux");
    }
    if(!strncmp(p2,"Safari",6)) {
      safari = 1;
      log_printf(", safari");
    }
    p2++;
  }

  log_printf("\n");

  html_clear_all();
  
  dba_loop();

#ifdef DEBUG25
  log_printf("\nhtml prettyprinter");
#endif
  
#ifdef DEBUG25
  log_printf("\nbuffers1:");
  for(int c = 0; c < HTML_BUFFERS; c++) { 
    log_printf(" %d:%ld", c, strlen(html_get_string(c)));
  }
  log_printf("\n");  
#endif
  
  for(int c = 1; c < HTML_BUFFERS-2; c++) {
    p = html_get_string(c);
    dbs_html_set(HTML_BUFFERS - 2);
    html_printf("%s", p);
    dbs_html_set(c);
    html_clear();
  }
  
#ifdef DEBUG25
  log_printf("\nbuffers2:");
  for(int c = 0; c < HTML_BUFFERS; c++) { 
    log_printf(" %d:%ld",c,strlen(html_get_string(c)));
  }
  log_printf("\n");  
#endif
  
  p = html_get_string(HTML_BUFFERS-2);
  dbs_html_set(HTML_BUFFERS - 1);
  html_indent(p);
  dbs_html_set(HTML_BUFFERS - 2);
  html_clear();
  
#ifdef DEBUG25
  log_printf("\nbuffers3:");
  for(int c = 0; c < HTML_BUFFERS; c++) { 
    log_printf(" %d:%ld",c, strlen(html_get_string(c)));
  }
  log_printf("\n");  
#endif
  
#ifdef DEBUG25
  log_printf("html prettyprinter done.\n");
#endif
  
  dba_loop2();
}

#define aDEBUG34 2
#define aDEBUG31 2

static void dbs_run_critical_port()
{
  FILE *fp1;
  char filename[128];
  char filename2[128];

  sprintf(filename,"%stimelog.log", filenamehead);
#ifdef DEBUG34
  fprintf(stdout,"Writing %s\n", filename);
#endif
  if((fp1 = fopen(filename,"a")) != NULL) {
    fprintf(fp1,"%s, ip=\"%s\"\n", htmltimeshort, htmlip);
    fclose(fp1);
  }
  
  sprintf(filename,"%sips.log",filenamehead);
#ifdef DEBUG34
  fprintf(stdout,"Writing %s\n",filename);
#endif
  dbs_add_end_new_str(filename, htmlip);

  sprintf(filename,"%shostname.log",filenamehead);
#ifdef DEBUG34
  fprintf(stdout,"Writing %s\n",filename);
#endif
  dbs_add_end_new_str(filename, htmlhostname);

  if(htmlsslcipher[0] != '\0') {
    sprintf(filename,"%sciphers.log",filenamehead);
#ifdef DEBUG34
    fprintf(stdout,"Writing %s\n",filename);
#endif
    dbs_add_end_new_str(filename, htmlsslcipher);
  }

  if(htmluseragent[0] != '\0') {
    sprintf(filename,"%suseragent.log",filenamehead);
#ifdef DEBUG34
    fprintf(stdout,"Writing %s\n", filename);
#endif
    dbs_add_end_new_str(filename,htmluseragent);
  }

  sprintf(filename2,"%scallid.dat", filenamehead);
#ifdef DEBUG34
  fprintf(stdout,"Reading %s\n", filename2);
#endif
  if((fp1 = fopen(filename2, "r")) != NULL) {
    unsigned char buffer16[16];
    fgets(buffer16, sizeof(buffer16), fp1);
    callid = atoi(buffer16);
    fclose(fp1);
  } else {
    callid = 0;
  }
  
  log_printf("callid:%d\n",callid);
  sprintf(filename,"%shtml.log",filenamehead);
#ifdef DEBUG34
  fprintf(stdout,"Writing %s\n",filename);
#endif
  if((fp1 = fopen(filename, "a")) != NULL) {
    fprintf(fp1,"htmltime: \"%s\", htmltimeshort: \"%s\", ip=\"%s\", callid=\"%d\"\n",
	    htmltime, htmltimeshort, htmlip, callid);
    fprintf(fp1,"%s\n", htmlin);
    for(int c = 0; c < HTML_BUFFERS; c++) {
#ifdef DEBUG31
      fprintf(stdout,"%d", c);
      fprintf(stdout," %p", html_get_string(c));
      if(html_get_string(c) != NULL)
	fprintf(stdout,"%s", html_get_string(c));
#endif
      if(html_get_string(c) != NULL &&
	 strlen(html_get_string(c)) > 0) {
	fprintf(fp1,"%d: %s\n", c, html_get_string(c));
      }
    }
    fclose(fp1);
  }
  
  callid++; // next call id
#ifdef DEBUG34
  fprintf(stdout,"Writing %s\n",filename2);
#endif
  if((fp1=fopen(filename2, "w")) != NULL) {
    fprintf(fp1,"%d\n", callid);
    fclose(fp1);
  }
}

struct lfield {
  unsigned char *name;
  int valuetype;
  unsigned char *value;
  int size;
} lfields[] = {
  { "procname", 1, (unsigned char *)&procname, 32 },
  { "timeshort", 0, htmltimeshort, sizeof(htmltimeshort) },
  { "time", 0, htmltime, sizeof(htmltime) },
  { "hostname", 0, htmlhostname, sizeof(htmlhostname) },
  { "host", 0, htmlhost, sizeof(htmlhost) },
  { "useragent", 0, htmluseragent, sizeof(htmluseragent) },
  { "method", 0, htmlmethod, sizeof(htmlmethod) },
  { "path", 0, htmlpath, sizeof(htmlpath) },
  { "version", 0, htmlversion, sizeof(htmlversion) },
  { "filename", 0, htmlfilename, sizeof(htmlfilename) },
  { "fileextension", 0, htmlfileextension, sizeof(htmlfileextension) },
  { "cookie", 0, htmlcookie, sizeof(htmlcookie) },
  { "sessionid", 0, htmlsessionid, sizeof(htmlsessionid) },
  { "params", 1, (unsigned char *)&htmlparams, 0 },
  { "recvheader", 1, (unsigned char *)&htmlrecvheader, sizeof(htmlrecvheader) },
  { "recvpayload", 1, (unsigned char *)&htmlrecvpayload, sizeof(htmlrecvpayload) },
  { "sentheader", 1, (unsigned char *)&htmlsentheader, sizeof(htmlsentheader) },
  { "sentpayload", 1, (unsigned char *)&htmlsentpayload, sizeof(htmlsentpayload) },
  { "digest", 0, htmldigest, sizeof(htmldigest) },
  { "mode", 0, htmlmode, sizeof(htmlmode) },
  { "ip", 0, htmlip, sizeof(htmlip) },
  { "sslcipher", 0, htmlsslcipher, sizeof(htmlsslcipher) },
  { "port", 0, htmlport, sizeof(htmlport) },
  { "language", 0, htmllanguage, sizeof(htmllanguage) },
  { "useconds", 0, htmluseconds, sizeof(htmluseconds) },
  { "prevminutes", 0, htmlprevminutes, sizeof(htmlprevminutes) },
};

struct lfile {
  unsigned char *query;
} lfiles[] = {
  { "" },
};

#define aDEBUG35 2
#define VALUEUTF8 2

int db4_compile_field(int buflength, unsigned char *buf, unsigned char *name)
{
  int size=0;
  unsigned char *value=NULL;

  for(int c = 0; c < sizeof(lfields) / sizeof(struct lfield); c++) {
    if(!strcmp(name, lfields[c].name)) {
      if(lfields[c].valuetype == 0) {
	value = lfields[c].value;
	break;
      } else if(lfields[c].valuetype == 1) {
	value = *((unsigned char **)lfields[c].value);
	break;
      }

    }
  }
  size = 7 + strlen(name);
  if(value != NULL) {
    unsigned char *p;
    p = value;
    while(*p != '\0') {
      if(*p == '"')
	size+=2;
      else if(*p=='\\')
	size+=2;
#ifdef VALUEUTF8
      else if(isprint(*p) || *p>=0x80)
#else
      else if(isprint(*p))
#endif
	size++;
      else
	size+=3;
      p++;
    }
  }
  if(size < buflength) {
    strcat(buf,"'");
    strcat(buf,name);
    strcat(buf,"' = \"");
    if(value != NULL) {
      unsigned char *p;
      p=value;
      while(*p != '\0') {
	if(*p == '"') {
	  unsigned char char3[3];
	  sprintf(char3,"\\\"");
	  strcat(buf,char3);
	} else if(*p == '\\') {
	  strcat(buf,"\\\\");
#ifdef VALUEUTF8
	} else if(isprint(*p) || *p >= 0x80) {
#else
	} else if(isprint(*p)) {
#endif
	  unsigned char char2[2];
	  sprintf(char2,"%c",*p);
	  strcat(buf, char2);
	} else {
	  unsigned char char4[4];
	  sprintf(char4,"\\%02x",*p);
	  strcat(buf, char4);
	}
	p++;
      }
#ifdef DEBUG35
      unsigned char *q=buf;
      while(*q != '\0') {
	if(isprint(*q))
	  fprintf(stdout,"%c",*q);
	else
	  fprintf(stdout,"\\%02x",*q);
	q++;
      }
#endif
    }
    strcat(buf,"\"");
  }
  return(size);
}

int db4_compile_set(int buflen, unsigned char *buf2)
{
  int size, count, first=1;
  unsigned char *buf = buf2;
  size=0;
  if(buflen > 0)
    buf[0]='\0';
  
  for(int c = 0; c < sizeof(lfields) / sizeof(struct lfield); c++) {
    count = 0;
    if(!first) {
      if(2 < buflen)
	strcat(buf,", ");
      count += 2;
    }
    count += db4_compile_field(buflen,buf,lfields[c].name);
    buf += count;
    buflen -= count;
    size += count;
    first = 0;
  }
  
  return(size);
}

#define DEBUG39

static void dbs_run_critical_all() {
  int count, buflen=0;
  unsigned char *buf=NULL;

#ifdef DEBUG39
  fprintf(stdout,"db4_compile_set() %d\n",buflen);
  fflush(stdout);
#endif
  count = db4_compile_set(buflen,buf) + 1;
    
  if(buflen < count) {
    buflen = count;
    buf = realloc(buf,buflen);
#ifdef DEBUG39
    fprintf(stdout,"db4_compile_set() %d\n",buflen);
    fflush(stdout);
#endif
    count = db4_compile_set(buflen,buf)+1;
  }
  FILE *fp1;
  if((fp1 = fopen("dbs.skk","a")) != NULL) {
    fprintf(fp1,"%s\n",buf);
    fclose(fp1);
  }
  fprintf(stdout,"%s(%ld)\n",buf,strlen(buf));
  fflush(stdout);
  //for(int c=0;c<sizeof(lfiles)/sizeof(struct lfile);c++) {
  //fprintf(stdout,"%s",lfiles[c].filename);
  //}
}

#include <errno.h>
#include <semaphore.h>
#include <fcntl.h>

unsigned char semname[32], sem2name[32];  
sem_t *mutex, *mutex2;
extern char *myport;

void dbs_open_semaphores()
{
  // semaphore for critical_port
      
  sprintf(semname,"dbssem%s", myport);
  
  if(sem_unlink(semname) == 0) {
    fprintf(stdout,"%s: previous semaphore %s removed\n", procname, semname);
  }
#ifdef DEBUG42
  fprintf(stdout,"sem_open()\n");
#endif
  if((mutex = sem_open(semname, O_CREAT | O_EXCL, 0644, 1)) == SEM_FAILED) {
    fprintf(stderr,"\n%s: cannot sem_open()", procname);
    fprintf(stderr," errno %d", errno);
    fprintf(stderr, "(%s)", strerror(errno));
    fprintf(stderr,"\n");
    perror("sem_open");
  }
  
  // semaphore for critical_all
  
  sprintf(sem2name,"dbssem");
  
  if(sem_unlink(sem2name) == 0) {
    fprintf(stdout,"%s: previous semaphore %s removed\n", procname, sem2name);
  }
#ifdef DEBUG42
  fprintf(stdout,"sem_open()\n");
#endif
  if((mutex2 = sem_open(sem2name, O_CREAT | O_EXCL, 0644, 1)) == SEM_FAILED) {
    fprintf(stderr,"\n%s: cannot sem_open()", procname);
    fprintf(stderr," errno %d", errno);
    fprintf(stderr, "(%s)", strerror(errno));
    fprintf(stderr,"\n");
    perror("sem_open");
  }
}

void dbs_close_semaphores()
{
  sem_unlink(semname);
  sem_close(mutex);
}

void dbs_run_critical_sections()
{
#ifdef USE_SEMAPHORES
      
  fprintf(stdout,"locking port semaphore(child)");
  fprintf(stdout,"\n");
  fflush(stdout);
  
#ifdef DEBUG42
  fprintf(stdout,"sem_wait()\n");
  fflush(stdout);
#endif
  if(sem_wait(mutex) == -1) {
    fprintf(stderr, "%s: cannot sem_wait()", procname);
    fprintf(stderr, ", errno: %d", errno);
    fprintf(stderr, "(%s)", strerror(errno));
    fprintf(stderr,"\n");
    perror("sem_wait");
  }
  
  fprintf(stdout,"critical section (child)");
  fprintf(stdout,"\n");
  fflush(stdout);
#endif
  
#ifdef DEBUG42
  fprintf(stdout,"dbs_run_critical_port()\n");
  fflush(stdout);
#endif
  dbs_run_critical_port();
  
#ifdef USE_SEMAPHORES
  
  fprintf(stdout,"end critical section (child)");
  fprintf(stdout,"\n");
  fflush(stdout);
  
#ifdef DEBUG42
  fprintf(stdout,"sem_post()\n");
#endif
  if(sem_post(mutex) == -1) {
    fprintf(stderr, "%s: cannot sem_post()", procname);
    fprintf(stderr, ", errno: %d\n", errno);
    fprintf(stderr, "(%s)", strerror(errno));
    perror("sem_post");
  }
  
  fprintf(stdout,"release port semaphore(child)");
  fprintf(stdout,"\n");
  fflush(stdout);
  
  fprintf(stdout,"locking all semaphore(child)");
  fprintf(stdout,"\n");
  fflush(stdout);
  
#ifdef DEBUG42
  fprintf(stdout,"sem_wait()\n");
  fflush(stdout);
#endif
  if(sem_wait(mutex2) == -1) {
    fprintf(stderr, "%s: cannot sem_wait()", procname);
    fprintf(stderr, ", errno: %d", errno);
    fprintf(stderr, "(%s)", strerror(errno));
    fprintf(stderr,"\n");
    perror("sem_wait");
  }
  
  fprintf(stdout,"critical section (child)");
  fprintf(stdout,"\n");
  fflush(stdout);
#endif
  
#ifdef DEBUG42
  fprintf(stdout,"dbs_run_critical_all()\n");
  fflush(stdout);
#endif
  dbs_run_critical_all();
  
#ifdef USE_SEMAPHORES
  
  fprintf(stdout,"end critical section (child)");
  fprintf(stdout,"\n");
  fflush(stdout);
  
#ifdef DEBUG42
  fprintf(stdout,"sem_post()\n");
#endif
  if(sem_post(mutex2) == -1) {
    fprintf(stderr, "%s: cannot sem_post()", procname);
    fprintf(stderr, ", errno: %d\n", errno);
    fprintf(stderr, "(%s)", strerror(errno));
    perror("sem_post");
  }
  
  fprintf(stdout,"release all semaphore(child)");
  fprintf(stdout,"\n");
  fflush(stdout);
}

#include <openssl/ssl.h>
#include <openssl/err.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <signal.h>
#include <netinet/in.h>
#include <arpa/inet.h>
/* See: http://h41379.www4.hpe.com/doc/83final/ba554_90007/ch04s03.html */

#include <netdb.h>

#define backlog 64

int s,news;
char cert_file[128] = "fullchain.pem";
char privatekey_file[128] = "privkey.pem";

#define DEBUG42 2

static int server_getaddrinfo(unsigned char *myport, struct addrinfo **res)
{
  int status;
  struct addrinfo hints;

  memset(&hints, 0, sizeof(hints));
  hints.ai_family = AF_UNSPEC;                   
  hints.ai_socktype = SOCK_STREAM;
  hints.ai_flags = AI_PASSIVE;

#ifdef DEBUG42
  fprintf(stdout,"getaddrinfo()\n");
#endif
  if ((status = getaddrinfo(NULL, myport, &hints, res)) != 0) {
    fprintf(stderr, "\n%s: getaddrinfo error: %s",
            procname, gai_strerror(status));
    fprintf(stderr, ", error code %d\n", status);
    //fflush(stderr);
  }
  return(status);
}

static int server_socket(struct addrinfo *res)
{
  int s;

#ifdef DEBUG42
  fprintf(stdout,"socket()\n");
#endif
  if((s = socket(res->ai_family, res->ai_socktype, res->ai_protocol)) == -1) {
    fprintf(stderr, "%s: socket()", procname);
    fprintf(stderr, ", errno: %d", errno);
    fprintf(stderr, "(%s)", strerror(errno));
    fprintf(stderr,"\n");
    perror("socket");
    //fflush(stderr);
  }
  return(s);
}

static void server_bind(int s, struct addrinfo *res)
{
#ifdef DEBUG42
  fprintf(stdout,"bind()\n");
#endif
  if(bind(s, res->ai_addr, res->ai_addrlen) == -1) {
    int errerrno = errno;
    if(errerrno == 98) {
      fprintf(stdout,"%s cannot bind, waiting to bind", procname);
      while(errerrno == 98) {
	sleep(10);
	fprintf(stdout,".");
	fflush(stdout);
	bind(s, res->ai_addr, res->ai_addrlen);
	errerrno = errno;
      }
      fprintf(stdout,"bind done!\n");
      //fflush(stdout);
    } else {
      int errerrno = errno;
      fprintf(stderr,"\n%s: cannot bind()", procname);
      fprintf(stderr,", errno: %d", errerrno);
      fprintf(stderr, "(%s)", strerror(errerrno));
      fprintf(stderr,"\n");
      perror("bind");
      //fflush(stderr);
    }
  }
}

static int server_listen(int s)
{
  int retval;
  
#ifdef DEBUG42
  fprintf(stdout,"listen()\n");
#endif
  if((retval = listen(s,backlog)) == -1) { // ==!
    int errerrno = errno;
    fprintf(stderr,"\n%s: cannot listen()", procname);
    fprintf(stderr,", errno %d", errerrno);
    fprintf(stderr, "(%s)", strerror(errerrno));
    fprintf(stderr,"\n");
    perror("listen");
    //fflush(stderr);
  }
  
  return(retval);
}

static void server_close(int s)
{
#ifdef DEBUG42
  fprintf(stdout,"close(s)\n");
#endif
  if(close(s) == -1) {
    int errerrno=errno;
    fprintf(stderr,"\n%s: cannot close()", procname);
    fprintf(stderr,", errno %d", errerrno);
    fprintf(stderr, "(%s)", strerror(errerrno));
    fprintf(stderr,"\n");
    perror("close");
    //fflush(stderr);
  }
}

static int server_basic_socket()
{
  int s;
  struct addrinfo *res;

  server_getaddrinfo(myport, &res);
  s = server_socket(res);
  server_bind(s, res);
  freeaddrinfo(res);
  server_listen(s);

  return(s);
}

#define TIMEFORMAT "%Z%Y%m%d%H%M%S"
#define HTMLTIMEFORMAT "%a, %d %b %Y %H:%M:%S %Z"

// statistics for the previous minutes

unsigned long prevhtmlseconds=0, htmlseconds;
unsigned int callstats[15] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };

static void dbs_time_vars()
{
  htmlseconds = dbs_getseconds();

  strftime(htmltimeshort, sizeof(htmltimeshort), TIMEFORMAT,
	   localtime((time_t *)&htmlseconds));
  strftime(htmltime, sizeof(htmltime), HTMLTIMEFORMAT,
	   localtime((time_t *)&htmlseconds));

  int c, d;
  
  unsigned long prevminute = prevhtmlseconds / 60 * 60;
  unsigned long minute = htmlseconds / 60 * 60;
  unsigned long diff = (minute - prevminute) / 60;

  // statistics for the previous 10 minutes
  
  if(diff != 0) {
    for(c = 15, d = 15 - diff; d >= 0; c--, d--) {
      callstats[c] = callstats[d];
    }
    for(; c >= 0; c--)
      callstats[c] = 0;
  }
  callstats[0]++;

  fprintf(stdout,"previous minutes");
  fprintf(stdout," prevmin:%10lu", prevminute);
  fprintf(stdout," min:%10lu", minute);
  fprintf(stdout," diff:%2lu", diff);
  fprintf(stdout," stat:");
  htmlprevminutes[0]='\0';
  for(c=0;c<15;c++) {
    fprintf(stdout," %d", callstats[c]);
    unsigned char buffer[10];
    sprintf(buffer,"%d", callstats[c]);
    if(strlen(htmlprevminutes) + 1 + strlen(buffer) < sizeof(htmlprevminutes)) {
      if(strlen(htmlprevminutes) > 0)
	strcat(htmlprevminutes, " ");
      strcat(htmlprevminutes, buffer);
    }
  }
  fprintf(stdout,"\n");
  
  prevhtmlseconds = htmlseconds;
}

unsigned long long dbs_get_useconds()
{
  struct timeval tv;
  gettimeofday(&tv, NULL);
  return(tv.tv_usec + 1000000 * tv.tv_sec);
}

#include <sys/socket.h>

static void dbs_server_vars(struct sockaddr_in sa_cli, int addr_size, char *name)
{
  strcpy(htmlip, inet_ntoa(sa_cli.sin_addr));
  sprintf(htmlport,"%d", sa_cli.sin_port);
  htmlsslcipher[0] = '\0';
  htmlhostname[0] = '\0';
  
  log_printf("\n%s, Connection(%s) from %x", procname, name, sa_cli.sin_addr.s_addr); 
  log_printf(", ip %s", htmlip);
  log_printf(", port %s", htmlport);
  log_printf(", at %s", htmltime);
  
  char host[NI_MAXHOST], serv[NI_MAXSERV];
  
  host[0] = '\0';
  serv[0] = '\0';
  if(getnameinfo((struct sockaddr *)&sa_cli, addr_size, host, NI_MAXHOST, serv, NI_MAXSERV, NI_NUMERICHOST | NI_NUMERICSERV) == 0) {
    log_printf(", numeric hostname:%s", host);
    log_printf(", numeric service:%s", serv);
  } else {
    log_printf(", numeric hostname:????");
    log_printf(", numeric service:????");
  }
  host[0] = '\0';
  serv[0] = '\0';
  if(getnameinfo((struct sockaddr *)&sa_cli, addr_size, host, NI_MAXHOST, serv, NI_MAXSERV, NI_NUMERICSERV) == 0) {
    log_printf(", name hostname:%s", host);
    log_printf(", service:%s", serv);
    strncpy(htmlhostname, host, sizeof(htmlhostname));
  } else {
    log_printf(", name hostname:????");
    log_printf(", service:????");
  }
  log_printf("\n");

}

#define DEBUG61 2

static void dbs_get_header(int *len, unsigned char **buf, unsigned char *text)
{
  int count;
  unsigned char *p;

  if(text == NULL)
    text = "";
#ifdef DEBUG61
  fprintf(stdout,"get_header(): text:%s(%ld)\n", text, strlen(text));
  fflush(stdout);
#endif
  p = text;
  count = 0;
  while(*p != '\0' &&
	strncmp(p,"\r\n\r\n",4) ) {
    fprintf(stdout," %c", *p);
    fflush(stdout);
    p++;
    count++;
  }
  if(!strncmp(p,"\r\n", 2))
    count += 2; // include one cr-lf pair
  count++; // and '\0'
  if(*len < count) {
    *len = count;
    *buf = realloc(*buf,*len);
  }
  strncpy(*buf, text, count - 1);
  *(*buf + count - 1) = '\0';
}

static void dbs_get_payload(int *len, unsigned char **buf, unsigned char *text)
{
  int count;
  unsigned char *p;

  if(text == NULL)
    text = "";

#ifdef DEBUG61
  fprintf(stdout,"get_payload(), text:%s(%ld)\n", text, strlen(text));
  fflush(stdout);
#endif
  
  p = text;
  count = 0;
  while(*p != '\0' &&
	strncmp(p,"\r\n\r\n",4) ) {
    fprintf(stdout," %c",*p);
    fflush(stdout);
    p++;
  }
  if(!strncmp(p,"\r\n\r\n",4))
    p+=4; // include one cr-lf pair

  count = strlen(p) + 1;

  if(*len < count) {
    *len = count;
    *buf = realloc(*buf, *len);
  }
  strncpy(*buf, p, count);
  *(*buf + count - 1) = '\0';
}

#ifdef SENT_HTML_LOG

static void dbs_get_payload2(int *len, unsigned char **buf, unsigned char *text)
{
  int count;
  unsigned char *p;

  if(text == NULL)
    text = "";

#ifdef DEBUG61
  fprintf(stdout,"get_payload(), text:%s(%ld)\n",text,strlen(text));
  fflush(stdout);
#endif
  
  p = text;
  count = strlen(text) + 1;

  if(*len < count) {
    *len = count;
    *buf = realloc(*buf,*len);
  }
  strcpy(*buf, p);
}

#endif

#define aSENT_HTML_LOG 2

static void dbs_query_vars()
{
  dbs_get_header((int *)&htmlrecvheaderlen, &htmlrecvheader, htmlin);
  dbs_get_payload((int *)&htmlrecvpayloadlen, &htmlrecvpayload, htmlin);
  dbs_get_header((int *)&htmlsentheaderlen, &htmlsentheader, html_get_string(0));
#ifdef SENT_HTML_LOG
  dbs_get_payload2((int *)&htmlsentpayloadlen, &htmlsentpayload, html_get_string(HTML_BUFFERS-1));
#endif
}

#define DEBUG38 2

static void http_client(int news, struct sockaddr_in sa_cli, int addr_size, char *name)
{
  int clen = 0;
  int reads = 0;
  int first = 1;
  int bytes, totalbytes = 0;
  unsigned char buffer10[10];

  unsigned long long useconds;

  useconds = dbs_get_useconds();
  
  htmlparams = NULL;
  htmlin[0] = '\0';

  dbs_server_vars(sa_cli, addr_size, name);

  while(htmlparams == NULL ||
	clen-strlen(htmlparams) > 0) {
    if(!first) {
      log_printf(", ");
    }

    struct pollfd fds;
    fds.fd = news;
    fds.events = POLLIN;
    bytes = 0;
    int retval = poll(&fds,1,1024*1024);
    log_printf("******poll: %d\n",retval);
    if(retval > 0) { // -1 err, 0 expire
#ifdef DEBUG42
      fprintf(stdout,"read()\n");
#endif
      if((bytes = read(news, htmlin + totalbytes, htmlinlen - totalbytes)) < 0) {
	fprintf(stderr,"\n%s: cannot read()\n", procname);
	perror("read");
	//fflush(stderr);
      }
      if(retval > 0)
	reads++;
    } 

    log_printf("(%d bytes)", bytes);
    if(bytes == 0)
      break;
    if(bytes > 3 &&
       !isprint(htmlin[0]) &&
       !isprint(htmlin[1]) &&
       !isprint(htmlin[2])) {
      log_printf("https packet?\n");
      htmlin[0] = '\0';
      totalbytes = 0;
      bytes = 0;
      break;
    }
    *(htmlin + totalbytes + bytes) = '\0';

    totalbytes += bytes;
    if(totalbytes >= htmlinlen) {
      // plus space for '\0'
      htmlin=realloc(htmlin, htmlinlen*2+1);
      htmlinlen *= 2;
    }
    
    htmlparams = dbs_html_get_params();
    unsigned char *p = htmlin;
    dbs_html_parse_string(sizeof(htmlmethod), htmlmethod,&p);
    if(!strcmp(htmlmethod, "GET"))
      break;
    dbs_html_get_request_line_num("Content-Length", sizeof(buffer10), buffer10);
    clen = atoi(buffer10);
    first = 0;
  }

  if(totalbytes != 0) {
    
    log_printf("\n%d reads", reads);
    log_printf(", received %d chars", totalbytes);
    log_printf(", read %d total bytes", totalbytes);
    log_printf(", input buffer size %d chars", htmlinlen);
    log_printf(", data=\"");
    log_dump_string(htmlin);
    log_printf("\"\n");
    
    dbs_run_loop();
    
    log_printf("buffers(html):");
    for(int c = 0; c < HTML_BUFFERS; c++) { 
      log_printf(" %d:%ld", c, strlen(html_get_string(c)));
      if(strlen(html_get_string(c)) > 0) {
	if((bytes = write(news, html_get_string(c), strlen(html_get_string(c)))) == -1) {
	  fprintf(stderr,"\n%s: cannot write() dbs_html[%d]\n", procname, c);
	  perror("write");
	  //fflush(stderr);
	}
      }
    }
    log_printf("\n");
  }
  dbs_query_vars();
  useconds = dbs_get_useconds() - useconds;
  sprintf(htmluseconds,"%lld", useconds);
}

int beepaccept=1;

#define DEBUG45 2
#define DEBUG57 2

static void http_server()
{
  int quit, reset, addr_size;

  struct sockaddr_in sa_cli;

  signal(SIGPIPE, SIG_IGN);
  signal(SIGCHLD, SIG_IGN);

  dbs_open_semaphores();
  
  // plus space for '\0'
  htmlin = malloc(htmlinlen+1);
  
  reset = 1;
  quit = 0;
  
  for(;;) {

    if(quit) {
      break;
    }

    if(reset) {
      s = server_basic_socket();
      reset = 0;
    }
  
    fprintf(stdout,"\n");
    fflush(stdout);
    
    addr_size = sizeof(sa_cli);
#ifdef DEBUG42
    fprintf(stdout,"accept()\n");
#endif
    if((news = accept(s, (struct sockaddr *)&sa_cli, &addr_size)) == -1) {
      fprintf(stderr,"\n%s: cannot accept()\n", procname);
      perror("accept");
      //fflush(stderr);
    }

    dbs_time_vars();
    
    if(beepaccept) {
      fprintf(stderr,"\a");
      fflush(stderr);
    }
    
    pid_t pid;
#ifdef DEBUG45
    fprintf(stdout,"Fork start (parent)");
    fprintf(stdout," getpid:%d getppid:%d", getpid(), getppid());
    fprintf(stdout,"\n");
    fflush(stdout);
#endif
#ifdef DEBUG42
    fprintf(stdout,"fork()\n");
#endif
    if((pid = fork()) < 0) {
      dbs_close_semaphores();

      fprintf(stderr,"\n%s: cannot fork()", procname);
      fprintf(stderr,", errno %d", errno);
      fprintf(stderr, "(%s)", strerror(errno));
      fprintf(stderr, "\n");
      perror("close");
      //fflush(stderr);
      exit(1);
    } else if(pid == 0) { // child
#ifdef DEBUG42
      fprintf(stdout,"log_clear()\n");
#endif
      log_clear();

#ifdef DEBUG42
      fprintf(stdout,"log_printf()\n");
#endif
      log_printf("==========\n");

#ifdef DEBUG45
      fprintf(stdout,"Fork start (child)");
      fprintf(stdout," pid:%d getpid:%d getppid:%d", pid, getpid(), getppid());
      fprintf(stdout,"\n");
      fflush(stdout);
#endif
      close(s);

#ifdef DEBUG42
      fprintf(stdout,"http_client()\n");
#endif
      http_client(news, sa_cli, addr_size, "http");

#ifdef DEBUG57
      fprintf(stdout,"%s", logbuf);
      fflush(stdout);
#ifdef DEBUG42
      fprintf(stdout,"log_clear()\n");
#endif
      log_clear();
#endif

      dbs_run_critical_sections(); 
     
#ifdef DEBUG42
      fprintf(stdout,"server_close(news)\n");
#endif
      server_close(news);

      fprintf(stdout,"%s", logbuf);
      fflush(stdout);
#ifdef DEBUG42
      fprintf(stdout,"log_clear()\n");
#endif
      log_clear();
      
#ifdef DEBUG45
      fprintf(stdout,"Fork end (child)");
      fprintf(stdout," pid:%d getpid:%d getppid:%d", pid, getpid(), getppid());
      fprintf(stdout,"\n");
      fflush(stdout);
#endif
      exit(0);
    }
#ifdef DEBUG45
    fprintf(stdout,"Fork end (parent)");
    fprintf(stdout," pid:%d getpid:%d getppid:%d", pid, getpid(), getppid());
    fprintf(stdout,"\n");
    fflush(stdout);
#endif
#ifdef DEBUG42
      fprintf(stdout,"server_close(news)\n");
#endif
    server_close(news);
  } // for(;;)
  dbs_close_semaphores();
}

static void https_client(int news, SSL_CTX *ctx, struct sockaddr_in sa_cli, int addr_size, char *name)
{
  int status, ok;
  unsigned char buffer10[10];

  SSL *ssl;
  X509 *peer_cert;

  unsigned long long useconds;

  useconds = dbs_get_useconds();
  
  ok = 1;

  dbs_server_vars(sa_cli, addr_size, name);
  
#ifdef DEBUG42
  fprintf(stdout,"SSL_new()\n");
#endif
  if((ssl = SSL_new(ctx)) == NULL) {
    fprintf(stdout,"\n%s: cannot SSL_new()", procname);
  }
  
#ifdef DEBUG42
  fprintf(stdout,"SSL_set_fd()\n");
#endif
  if(SSL_set_fd(ssl,news) != 1) {
    fprintf(stdout,"\n%s: cannot SSL_set_fd()\n", procname);
  }
  
#ifdef DEBUG42
  fprintf(stdout,"SSL_accept()\n");
#endif
  if((status = SSL_accept(ssl)) < 0) {
    fprintf(stdout,"\n%s: cannot SSL_accept(), retval: %d\n", procname,status);
  }
  
#ifdef DEBUG42
  fprintf(stdout,"SSL_get_peer_certificate()\n");
#endif
  peer_cert = SSL_get_peer_certificate(ssl);
  if(peer_cert == NULL) {
    log_printf(", No peer certificate");
  }
  
  log_printf("\n");
  
  int clen = 0;
  int reads = 0;
  int first = 1;
  int bytes, totalbytes = 0;

  htmlparams = NULL;

  htmlin[0] = '\0';
  while(htmlparams == NULL || clen-strlen(htmlparams) > 0) {
    if(!first) {
      log_printf(", ");
    } 
    int tries = 0;
    for(;;) {
      bytes = SSL_read(ssl, htmlin+totalbytes, htmlinlen-totalbytes);

      int errerrno, err, err2;

      errerrno = errno;
      err = SSL_get_error(ssl, bytes);
      err2 = ERR_get_error();

      log_printf("\nSSL_read()");
      log_printf(", retval %d", bytes);
      log_printf(", errno: %d", errerrno);
      log_printf(", SSL_get_error(): %d", err);
      log_printf(", ERR_get_error(): %d", err2);

      
      while((err2 = ERR_get_error()) != 0)
	log_printf(", %d",err2);
      if(bytes >= 0) {
	reads++;
	break;
      }
      if(bytes < 0) {
	if(++tries < 5 && (err == 1 || err == 5)) {
	  usleep(1024 * 512 / 5);
	  log_printf(" try:%d", tries);
	  continue;
	}
	log_printf("cannot SSL_read()\n");
	ok = 0;
	break;
      } // if(bytes
      break;
    } // for(;;)
    log_printf("(%d bytes)", bytes);
    if(!ok)
      break;

    *(htmlin + totalbytes + bytes) = '\0';
    if(bytes == 0)
      break;

    totalbytes += bytes;
    if(totalbytes >= htmlinlen) {
      // plus space for '\0'
      htmlin=realloc(htmlin, htmlinlen * 2 + 1);
      htmlinlen *= 2;
    }
    
    htmlparams = dbs_html_get_params();
    unsigned char *p=htmlin;
    dbs_html_parse_string(sizeof(htmlmethod), htmlmethod,&p);
    if(!strcmp(htmlmethod,"GET"))
      break;
    dbs_html_get_request_line_num("Content-Length",
				  sizeof(buffer10), buffer10);
    clen = atoi(buffer10);
    first = 0;
  }

  log_printf("\n%d reads", reads);
  log_printf(", received %d chars", totalbytes);
  log_printf(", read %d total bytes", totalbytes);
  log_printf(", input buffer size %d chars", htmlinlen);
  log_printf(", data=\"");
  log_dump_string(htmlin);
  log_printf("\"\n");
  
  strncpy(htmlsslcipher, SSL_get_cipher(ssl), sizeof(htmlsslcipher));
  
  if(ok) 
    dbs_run_loop();
  
  if(ok) {
    log_printf("buffers(ssl):");
    for(int c = 0; c < HTML_BUFFERS; c++) {
      log_printf(" %d:%ld", c, strlen(html_get_string(c)));
      if(strlen(html_get_string(c)) > 0) {
#ifdef DEBUG42
	fprintf(stdout,"SSL_write()\n");
#endif
	if((status = SSL_write(ssl, html_get_string(c), strlen(html_get_string(c)))) < 1) {
	  fprintf(stdout,"\n%s: cannot SSL_write(), buffer %d, status: %d, SSL error: %d",
		  procname, c, status, SSL_get_error(ssl, status));
	}
      }
    }
  }
  log_printf("\n");
  log_printf("\nSSL connection using %s", htmlsslcipher);
  log_printf("\n");

#ifdef DEBUG42
  fprintf(stdout,"dbs_query_vars()\n");
#endif
  dbs_query_vars();
  useconds = dbs_get_useconds() - useconds;
  sprintf(htmluseconds,"%lld", useconds);
  
#ifdef DEBUG42
  fprintf(stdout,"SSL_free()\n");
#endif
  SSL_free(ssl);
}

static SSL_CTX *server_https_init()
{
  SSL_METHOD *method=NULL;
  SSL_CTX *ctx=NULL;
  
#ifdef DEBUG42
  fprintf(stdout,"SSL_library_init()\n");
#endif
  SSL_library_init();
  
#ifdef DEBUG42
  fprintf(stdout,"OpenSSL_add_ssl_algorithms()\n");
#endif
  OpenSSL_add_ssl_algorithms();
  
#ifdef DEBUG42
  fprintf(stdout,"OpenSSL_add_ciphers()\n");
#endif
  OpenSSL_add_all_ciphers();
  
#ifdef DEBUG42
  fprintf(stdout,"OpenSSL_load_error_strings()\n");
#endif
  SSL_load_error_strings();
  
#ifdef DEBUG42
  fprintf(stdout,"SSLv23_server_method()\n");
#endif
  if((method = (SSL_METHOD *)    
      SSLv23_server_method()) == NULL) {
    fprintf(stderr,"\n%s: cannot SSLv3_server_method()\n", procname);
    //fflush(stderr);
  }
  
#ifdef DEBUG42
  fprintf(stdout,"SSL_CTX_new()\n");
#endif
  if((ctx=SSL_CTX_new(method)) == NULL) {
    fprintf(stderr,"\n%s: cannot SSL_CTX_new()\n", procname);
  }
  
#ifdef DEBUG42
  fprintf(stdout,"SSL_CTX_use_certificate_file()\n");
#endif
  if(SSL_CTX_use_certificate_file(ctx, cert_file, SSL_FILETYPE_PEM) != 1) {
    int err2;
    err2=ERR_get_error();
    fprintf(stderr,"\n%s: cannot SSL_CTX_use_certificate_file()", procname);
    fprintf(stderr,", ERR_get_error(): %d", err2);
    while((err2 = ERR_get_error()) != 0)
      fprintf(stderr,", %d", err2);
    fprintf(stderr,"\n");
    fflush(stderr);
  }
  
#ifdef DEBUG42
  fprintf(stdout,"SSL_CTX_use_PrivateKey_file()\n");
#endif
  if(SSL_CTX_use_PrivateKey_file(ctx, privatekey_file, SSL_FILETYPE_PEM) != 1) {
    int err2;
    err2=ERR_get_error();
    fprintf(stderr,"\n%s: cannot SSL_CTX_use_PrivateKey_file()", procname);
    fprintf(stderr,", ERR_get_error(): %d", err2);
    while((err2 = ERR_get_error()) != 0)
      fprintf(stderr,", %d", err2);
    fprintf(stderr,"\n");
    fflush(stderr);
  }
  
#ifdef DEBUG42
  fprintf(stdout,"SSL_CTX_load_verify_locations()\n");
#endif
  if(SSL_CTX_load_verify_locations(ctx, cert_file, NULL) != 1) {
    int err2;
    err2 = ERR_get_error();
    fprintf(stderr,"\n%s: cannot SSL_CTX_load_verify_locations()", procname);
    fprintf(stderr,", ERR_get_error(): %d", err2);
    while((err2 = ERR_get_error()) != 0)
      fprintf(stderr,", %d", err2);
  }
  return(ctx);
}

#define DEBUG59 2
#define DEBUG81 2

static void https_server()
{
  int quit, reset, addr_size;
  
  //SSL_METHOD *method=NULL;
  SSL_CTX *ctx=NULL;

  struct sockaddr_in sa_cli;

  signal(SIGPIPE, SIG_IGN);
  signal(SIGCHLD, SIG_IGN);

  // plus space for '\0'  
  htmlin = malloc(htmlinlen+1);

  reset = 1;
  quit = 0;
  
  for(;;) {

    if(quit) {
      if(ctx != NULL)
	SSL_CTX_free(ctx);
      break;
    }

    if(reset) {
      if(ctx != NULL) {
#ifdef DEBUG42
	fprintf(stdout,"SSL_CTX_free()\n");
#endif
	SSL_CTX_free(ctx);  
      }

      ctx = server_https_init();
      s = server_basic_socket();

      dbs_open_semaphores();
      reset = 0;
    } // if(reset)

    fprintf(stdout,"\n");
    fflush(stdout);
    
    addr_size = sizeof(sa_cli);
#ifdef DEBUG42
    fprintf(stdout,"accept()\n");
#endif
    if((news = accept(s, (struct sockaddr *)&sa_cli, &addr_size)) == -1) {
      fprintf(stderr,"\n%s: cannot accept()\n", procname);
      perror("accept");
    }

    dbs_time_vars();
    
    if(beepaccept) {
      fprintf(stderr,"\a");
      fflush(stderr);
    }

    pid_t pid;
#ifdef DEBUG59
    fprintf(stdout,"Fork start (parent)");
    fprintf(stdout," getpid:%d getppid:%d", getpid(), getppid()); 
    fprintf(stdout,"\n");
    fflush(stdout);
#endif
#ifdef DEBUG42
    fprintf(stdout,"fork()\n");
#endif

    if((pid = fork()) < 0) {
      dbs_close_semaphores();
      
      fprintf(stderr,"\n%s: cannot fork()", procname);
      fprintf(stderr,", errno %d", errno);
      fprintf(stderr, "(%s)", strerror(errno));
      fprintf(stderr,"\n");
      perror("fork");
      exit(1);

    } else if(pid == 0) {

#ifdef DEBUG42
      fprintf(stdout,"close(s)\n");
      fflush(stdout);
#endif
      close(s);
      
#ifdef DEBUG42
      fprintf(stdout,"log_clear()\n");
      fflush(stdout);
#endif
      log_clear();

#ifdef DEBUG42
      fprintf(stdout,"log_printf()\n");
      fflush(stdout);
#endif
      fprintf(stdout,"log");
      fflush(stdout);
      log_printf("==========\n");
      fprintf(stdout," done");
      fflush(stdout);
      
#ifdef DEBUG59
      fprintf(stdout,"Fork start (child)");
      fprintf(stdout," pid:%d getpid:%d getppid:%d", pid, getpid(), getppid());
      fprintf(stdout,"\n");
      fflush(stdout);
#endif

#ifdef DEBUG42
      fprintf(stdout,"https_client()\n");
      fflush(stdout);
#endif
      https_client(news, ctx, sa_cli, addr_size, "https");
      
#ifdef DEBUG81
      fprintf(stdout,"%s",logbuf);
      fflush(stdout);
#ifdef DEBUG42
      fprintf(stdout,"log_clear()\n");
      fflush(stdout);
#endif
      log_clear();
#endif

      dbs_run_critical_sections();
      
#endif
      
#ifdef DEBUG42
      fprintf(stdout,"server_close(news)\n");
      fflush(stdout);
#endif
      server_close(news);

      fprintf(stdout,"%s", logbuf);
      fflush(stdout);
#ifdef DEBUG42
      fprintf(stdout,"log_clear()\n");
      fflush(stdout);
#endif
      log_clear();
      
#ifdef DEBUG59
      fprintf(stdout,"Fork end (child)");
      fprintf(stdout," pid:%d getpid:%d getppid:%d", pid, getpid(), getppid());
      fprintf(stdout,"\n");
      fflush(stdout);
#endif
      exit(0);
    } // if(pid == 0)
#ifdef DEBUG42
    fprintf(stdout,"server_close(news)\n");
    fflush(stdout);
#endif
    server_close(news);

#ifdef DEBUG59
    fprintf(stdout,"Fork end (parent)");
    fprintf(stdout," pid:%d getpid:%d getppid:%d", pid, getpid(), getppid());
    fprintf(stdout,"\n");
    fflush(stdout);
#endif
  } // for(;;)
  SSL_CTX_free(ctx);  

  dbs_close_semaphores();
}

static unsigned char *dbs_save_string(unsigned char *string)
{
  unsigned char *temp = malloc(strlen(string) + 1);
  strcpy(temp, string);
  return(temp);
}

static void dbs_file_digest(char *filename, unsigned char *hash)
{
  int c;
  unsigned char buffer[1024];
  FILE *fp1;
  HashCtx ctx;
  
  HashInit(&ctx);
  if((fp1 = fopen(filename, "rb")) != NULL) {
    while((c = fread(buffer, 1, sizeof(buffer), fp1)) > 0)
      HashUpdate(&ctx, buffer, c);
    fclose(fp1);
  }
  HashFinal(hash, &ctx);  
}

int dba_main(int argc,char *argv[]);

static void dbs_version()
{
  fprintf(stdout,"%s, ", programname);
  fprintf(stdout,"%s\n", copyright);
  fflush(stdout);
}

int https=1;

int dbs_main(int argc,char *argv[])
{
  int c;
  for(c = 1; c < argc; c++) {
    if(!strncmp(argv[c], "--https", 7))
      https = 1;
    else if(!strncmp(argv[c], "--http", 6))
      https = 0;
    else if(!strncmp(argv[c], "--port", 6)) {
      if(argv[c][6] != '\0')
        myport = dbs_save_string(&argv[c][6]);
      else
        myport = dbs_save_string(argv[++c]);
    } else if(!strncmp(argv[c], "-p", 2)) {
      if(argv[c][2] != '\0')
        myport = dbs_save_string(&argv[c][2]);
      else
        myport = dbs_save_string(argv[++c]);
    } else if(!strncmp(argv[c], "--version", 9)) {
      dbs_version();
    } else if(!strncmp(argv[c], "-v", 2)) {
      dbs_version();
    }
  }
  return(0);
}

int main(int argc,char *argv[])
{
  unsigned char filedigest[HashLen];
  
  procname = argv[0];

  dbs_file_digest("/proc/self/exe", filedigest);
  htmldigest[0] = '\0';
  for(int c = 0; c < HashLen; c++) {
    char twodigits[3];
    sprintf(twodigits,"%02x", filedigest[c]);
    strcat(htmldigest, twodigits);
  }

  filenamehead[0] = '\0';
  
  dbs_main(argc,argv);
  dba_main(argc,argv);
  //db2_main(argc,argv);

  fprintf(stdout,"%s", programname);
  fflush(stdout);
  if(https)
    fprintf(stdout,", https");
  else
    fprintf(stdout,", http");

  fprintf(stdout,", port %s", myport);

  fprintf(stdout,",  sha256(%s)\n", htmldigest);
  fflush(stdout);

  FILE *fp1;
  unsigned char filename[64];
    
  snprintf(filename, sizeof(filename), "%spid.deb", filenamehead);
  if((fp1 = fopen(filename,"w")) != NULL) {
    fprintf(fp1,"%d\n", getpid());
    fclose(fp1);
  }

#define aDEBUG_FORT
  
#ifdef DEBUG_FORT
  unsigned char buffer64[64];
  fprintf(stdout,"dbs: for(;;)\n");
  fflush(stdout);
  for(;;) {
    fort_random_data(sizeof(buffer64),buffer64);
  }
#endif
  
  if(https)
    https_server();
  else
    http_server();

  exit(0);
}

newressu.h

void ressu_genbytes(int size, unsigned char *buffer);
unsigned long ressu_gen_limit(unsigned long limit);

#define INPUT_RESSU 0
#define INPUT_DEBUG 1
#define INPUT_FAST 2
#define INPUT_SINGLE 3
#define INPUT_FORT 6
#define INPUT_FORTXOR 7
#define INPUT_URANDOM 8
#define INPUT_RANDOM 9

extern int input;
extern int newressu_output;
extern char *randomgen[];

fort.h

/* Perustuu Bruce Schneierin kirjassa esittämään fortuna järjestelmään.
 * Written by Jari Kuivaniemi
 */

#ifndef SHA256_H
#include "sha256.h"
#endif

#define aFORT_USE_RDRAND 2
#define aFORT_USE_RDSEED 2

typedef unsigned long long IUTIME;

extern int fort_verbose;
extern int fort_partial_line;
extern int fort_use_web;

extern unsigned char fort_random_file[128];
extern unsigned char fort_pools_file[128];
#ifdef DEBUG10
static char fort_events_file[128] = "fortevents.deb";
#endif
unsigned char cvar[16];
int cvarsize;

void inccvar();
void clearcvar();
void hash_update_cvar(HashCtx *hash);

void fort_add_random_event(int *pool, int source, int mode, int len, unsigned char *buf);
void fort_add_random_event_timer_start(IUTIME *micros);
void fort_add_random_event_timer_do(int *pool, int source, int mode, IUTIME *millis);
void fort_add_random_event_split(int *pool, int source, int mode, int len, unsigned char *buf,int size);
void fort_add_random_event_time(int *pool, int source, int mode);
void fort_rekey(unsigned char *buf);
void fort_pseudo_random_data(int len,unsigned char *buf);
void fort_pseudo_random_data_xor(int len,unsigned char *buf);
void fort_reseed(int len,unsigned char *buf);
void fort_random_data(int len,unsigned char *buf);
void fort_random_data_xor(int len,unsigned char *buf);
int fort_random_data_byte();
void fort_clear();
int fort_random_data_byte_limit(int limit);
void fort_random_data_buffer(int size, unsigned char *buffer);
void fort_save();
void fort_read_file();
void fort_mix();
void fort_init();
void hash_init(HashCtx *hash);
void hash_update(HashCtx *hash, unsigned char *data, int len);
void hash_final(unsigned char digest[HashLen], HashCtx *hash);

void fort_hash_http_page(unsigned char *host,unsigned char *port, unsigned char *page, unsigned char *hash);
void fort_hash_https_page(unsigned char *host,unsigned char *port, unsigned char *page, unsigned char *hash);

void fort_hash_command(unsigned char *command, unsigned char *hash);

int rdrand_bytes(int buflen, unsigned char *buf);
int rdseed_bytes(int buflen, unsigned char *buf);

#ifdef FORT_INTERNAL_EVENTS
#define FORT_INTERNAL_EVENTS_START(source) \
  IUTIME micros;                           \
  static int \
    pool=0, pool2=0; \
  if(fort_internal_events) { \
    fort_add_random_event_time(&pool, \
    source, fort_internal_event_mode); \
    fort_add_random_event_timer_start(&micros); \
  }
#else
#define FORT_INTERNAL_EVENTS_START(source)
#endif

#ifdef FORT_INTERNAL_EVENTS
#define FORT_INTERNAL_EVENTS_END(source) \
  if(fort_internal_events) \
    fort_add_random_event_timer_do(&pool2, \
      source, fort_internal_event_mode, \
      &micros);
#else
#define FORT_INTERNAL_EVENTS_END(source)
#endif

#ifdef FORT_EVENTS
#define FORT_EVENTS_START(source) \
  IUTIME micros;                           \
  static int \
    pool=0, pool2=0; \
  if(fort_events) { \
    fort_add_random_event_time(&pool, \
    source, fort_event_mode); \
    fort_add_random_event_timer_start(&micros); \
  }
#else
#define FORT_EVENTS_START(source)
#endif

#ifdef FORT_EVENTS
#define FORT_EVENTS_END(source) \
  if(fort_events) \
    fort_add_random_event_timer_do(&pool2, \
      source, fort_event_mode, \
      &micros);
#else
#define FORT_EVENTS_END(source)
#endif

sha256.h

#ifndef SHA256_H
#define SHA256_H

#define HashName   "SHA256"
#define HashInit   SHA256Init
#define HashUpdate SHA256Update
#define HashFinal  SHA256Final
#define HashLen    32
#define HashCtx    SHA256_CONTEXT

typedef unsigned char IUBYTE;
typedef unsigned int IUWORD;
typedef unsigned long long IULONG;

typedef struct {
    IUWORD state[8];
    IULONG count;
    IUBYTE buffer[64];
} SHA256_CONTEXT;

void SHA256Init(SHA256_CONTEXT *sha256);
void SHA256Update(SHA256_CONTEXT* sha256, unsigned char *data, int len);
void SHA256Final(unsigned char digest[32], SHA256_CONTEXT *sha256);

void sha_test();

#endif

dbs.h

#define aRESSU 2
#define aFORT 2

#define HTML_LAST_BUFFER 4

int dbs_get_parameter(char *name, int valuelen, unsigned char *value);
void dbs_get_cookie(unsigned char *name, int valuelen, unsigned char *value);
int dbs_html_get_string(unsigned char *string,unsigned char **str,int len);
int dbs_parse_html_parameter(int namelen, unsigned char *name, int valuelen,unsigned char *value, unsigned char **s);

void log_clear();
void log_free();
void log_printf(const char *format, ...);

/*
int dbs_parse_hex1(unsigned char **str);
int dbs_parse_html_string(int stringlen, unsigned char *string, unsigned char **html);
unsigned long dbs_getseconds();
unsigned char *dbs_html_get_request_line(unsigned char *name);
void dbs_html_get_request_line_num(unsigned char *name, int lenbuffer, unsigned char *buffer);
void dbs_html_parse_string(int buflen, char *buf, unsigned char **p2);
void dbs_html_parse_filename(int buflen, char *buf, unsigned char *p);
unsigned char *dbs_html_get_params();
void dbs_version();
*/

html.h

unsigned char *html[9];

void html_set(int html);
int html_get();
unsigned char *html_get_string(int bufno);
void html_clear();
void html_clear_all();
void html_printf(const char *format, ...);
void html_buf_printf(int bufno, const char *format, ...);
void html_start();
void html_indent(unsigned char *p);

#define dbs_html_set html_set
#define dbs_html_get html_get
#define dbs_html_clear html_clear
#define dbs_html_printf_valist html_printf_valist
#define dbs_html_printf html_printf
#define dbs_html_buf_printf html_buf_printf

#define HTML_BUFFERS 9