DBS versio 0.08

DBS on tertun palvelinohjelma, joka vastaanottaa asiakkaan selaimelta sivupyyntöjä, kutsuu sovellusohjelmaa (DBA), joka muotostaa sivupyynnön pohjalta vastauksen. Vastaus palautetaan DBS:lle, joka lähettää tuloksen asiakkaalle.

Edit: muutoksia julkaisun jälkeen:

Palvelimissa on vielä ongelmaa Safari-selaimen kanssa, safari menee “luuppiin”, jos haetaan sekä portillista ja portitonta URL:ää vuorotellen (moijari.com ja moijari.com:5005).

.ico (favicon.ico) tiedostopyyntöjen ohittamista varten lisätty muuttuja htmlextension muuttuja, sille hakurutiini dbs_html_parse_extension ja kutsu edelliselle rutiinille. Ei korjannut safari ongelmaa. Seuraavana ressu3 (moijari.com:5005) koodi:

void dba_loop()
{
  html_clear_all();
  if(!strcmp(htmlextension,"ico")) {
    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("\n<!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("</head>");

    dbs_html_printf("<body>");

    ressu3_app();

    dbs_html_printf("<br><br>%s,  sha256(%s)<br><br>", programname,
                    htmldigest);
    dbs_html_printf("\t\toriginal url: <a href=\"https://moijari.com:5001\">https://moijari.com:5005</a>\n");
    dbs_html_printf("\t\t or <a href=\"https://moijari.com:5005\">https://moijari.com:5005</a><br>\n");

    dbs_html_printf("</body>");

    dbs_html_printf("</html>");

    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));
    dbs_html_printf("Content-Length: %d", len);
    dbs_html_printf("\r\n\r\n");

  }
}

End of muutokset.

Ohjelman käyttämiä muuttujia:

unsigned char *htmlin;
int htmlinlen=2048;

unsigned char htmlmethod[10];
unsigned char htmlpath[128];
unsigned char htmlversion[32];
unsigned char htmlfilename[64];
unsigned char htmlextension[10];
unsigned char htmlsessionid[33];
unsigned char htmltime[32];
unsigned char htmltimeshort[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[33];
unsigned char htmlport[10];
unsigned char htmllanguage[10];

Rutiini muuttaa html-scriptin hexana esitetyn yksi numeroisen luvun int:iksi.

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);
}

Tämä rutiini muodostaa html parametristä UTF8-merkkinonon.

Tässä versiossa on lisätty satunnaisuuden keräysrutiineja fort:lle (FORT_EVENTS_START ja FORT_EVENT_END), kuten muissakin myöhemmissä rutiineissa.

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;

  FORT_EVENTS_START(300)

  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)
        *s++=c;
    } else if(*h=='+') {
      if(++count<stringlen)
        *s++=' ';
      h++;
    } else {
      if(++count<stringlen)
        *s++=*h;
      h++;
    }
  }
  *s='\0';
  *html=h;

  FORT_EVENTS_END(301)

  return(ok);
}

Seuraavassa rutiinit, joita käytetään satunnaisuuden keräämiseen edellisessä ja seuraavissa funktioissa. Olen lisännyt sen sellaisiin rutiineihin jotka sisältävät suorituspituutensa puolesta suoritusajan vaihtelua. Jos et halua käyttää näitä lisää pikku-a FORT_EVENTS määritykseen. Voit tarkastella tapahtumien satunnaisuutta “grep source=300 fortevents.deb” komennolla, jossa 300 on halutun lähteen numero.

#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

dbs_html_get_string muuntaa koko merkkijonon, ei pelkästään parametrejä UTF8 muotoon(se sisältää myös parametrierottimen ‘&’).

#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;

  FORT_EVENTS_START(302)

  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;

  FORT_EVENTS_END(303)

  return(ok);
}

Seuraava rutiini palauttaa seuraavan parametrin nimen ja arvon. Merkkijonon parsiminen aloitetaan s osoitteesta ja suorituksen jälkeen uusi merkkijonon kohta talletetaan takaisin s muuttujaan (**):

int dbs_parse_html_parameter(int namelen, unsigned char *name, 
    int valuelen,unsigned char *value,
    unsigned char **s)
{
  FORT_EVENTS_START(304)

  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)++;

  FORT_EVENTS_END(305)

  return(1);
}

Seuraava rutiini palauttaa halutun nimisen parametrin html sivun parametreista: Parametrit alkavat kohdasta htmlparams.

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

  FORT_EVENTS_START(306)

  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;
    }
  }

  FORT_EVENTS_END(307)

  return(ok);
}

Tässä vanha tuttu sekuntien haku:

static unsigned long dbs_getseconds()
{
  struct timeval tv;

  gettimeofday(&tv, NULL);

  return((IUTIME)tv.tv_sec);
}

Seuraavalla rutiinilla palautetaan html-otsakkeen rivi, joka alkaa tietyllä merkkijonolla: (tällä haetaan ainakin Cookie ja Content-Length -rivit: (sessionid kenttää (+ ip:tä) ei vielä tarkasteta, ip:t poistettu, sessionid poistettu)

EET20201211183424, ip="x.x.x.x", callid="1826"
POST /app HTTP/1.1^M
Host: x.x.x.x:5004^M
User-Agent: Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:83.0) Gecko/20100101 Firefox/83.0^M
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8^M
Accept-Language: en-US,en;q=0.5^M
Accept-Encoding: gzip, deflate, br^M
Content-Type: application/x-www-form-urlencoded^M
Content-Length: 230^M
Origin: https://x.x.x.x:5004^M
Connection: keep-alive^M
Referer: https://x.x.x.x:5004/logon^M
Cookie: sessionid=012345678901234567890123456789012; mode=Display; language=fi^M
Upgrade-Insecure-Requests: 1^M
static unsigned char *dbs_html_get_request_line(unsigned char *name)
{
  unsigned char *p;

  FORT_EVENTS_START(308)

  p=htmlin;
  while(*p!='\0') {
    if(!strncmp(p,"\r\n",2)) {
      p+=2;
      if(!strncmp(p,name,strlen(name))) {
        p+=strlen(name);
	if(*p==':') {
          p++;
          while(isblank(*p))
            p++;
          return(p);
        }
      }
    }
    p++;
  }
  FORT_EVENTS_END(309)

  return(NULL);
}

Tällä haetaan numeerinen html-otsakkeen rivi: (käytetään Content-Length haussa)

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

  FORT_EVENTS_START(310)

  if((p=dbs_html_get_request_line(name))==NULL)
    sprintf(buffer,"0");
  else {
    len=0;
    n=buffer;
    while(isdigit(*p)) {
      if(++len<lenbuffer)
        *n++=*p;
      p++;
    }
    *n='\0';
  }
  FORT_EVENTS_END(311)
}

Tällä haetaan nimetty cookie:

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

  FORT_EVENTS_START(312)

  if((p=dbs_html_get_request_line("Cookie"))==NULL) {
    return;
  }

  while(*p!='\n' && *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<sizeof(htmlsessionid))
          *n++=*p;
        p++;
      }
      *n='\0';
      return;
    }
    while(*p!=';' && *p!='\n' && *p!='\0')
      p++;
    if(*p==';')
      p++;
    while(isblank(*p))
      p++;
  }

  FORT_EVENTS_END(313)
}

Tätä käytetään välilyönneillä erotellun cr-lf loppuisen merkkijonon parsimiseen: Se on lähinnä käytössä html-otsakkeen ensimmäisellä rivillä (POST /app HTTP/1.1^M)

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

  FORT_EVENTS_START(314)

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

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

  *p2=p;

  FORT_EVENTS_END(315)
}

Tätä käytetään välilyönneillä erotellun cr-lf loppuisen merkkijoon parsimiseen. Se parsii tiedostopolun tiedostonimen: Se on käytössä html-otsakkeen ensimmäisellä rivillä (POST /app HTTP/1.1^M). Tiedostonimi on tietenkin tiedostopolun viimeisen kauttaviivan jälkeinen osa.

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

  FORT_EVENTS_START(316)

  len=0;
  n=buf;

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

  FORT_EVENTS_END(317)
}

Tämä rutiini hakee tiedoston nimen jatkeen (extension) edellisen kappaleen palauttamasta tiedostonimestä:

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

  FORT_EVENTS_START(330)

  len=0;
  n=buf;

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

Seuraavaa käytetään html-otsakkeen “payload” kentän hakuun. Se sisältää pyynnöstä riippuen joko parametrien arvot tai asiakkaalle palautetun html-sivun rivit. Payload kenttä löytyy html-otsakkeen ensimmäisen “\r\n\r\n”-merkkijonon jälkeen.

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

  FORT_EVENTS_START(318)

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

  FORT_EVENTS_END(319)

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

Aliohjelmaa käytetään lähinnä ohjelman lokien talletuksessa.

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);
    }
  }
}

Tätä rutiinia käytetään https- ja http-palvelimien jälkeen ja se hakee yhteyden ja html-otsakkeen tiedot lokien ja asiakasohjelman käyttämiin kenttiin. Lisäksi tämä kerää lokitietoja edellisistä.

void dba_loop();

static void dbs_run_loop()
{
  unsigned char *p;

  FORT_EVENTS_START(320)

  p=htmlin;
  dbs_html_parse_string(sizeof(htmlmethod), htmlmethod,&p);
  fprintf(stdout,"htmlmethod: \"%s\"", htmlmethod);
  fflush(stdout);

  dbs_html_parse_string(sizeof(htmlpath), htmlpath, &p);
  fprintf(stdout,", htmlpath: \"%s\"", htmlpath);
  fflush(stdout);

  dbs_html_parse_string(sizeof(htmlversion), htmlversion, &p);
  fprintf(stdout,", htmlversion: \"%s\"", htmlversion);
  fflush(stdout);

  dbs_html_parse_filename(sizeof(htmlfilename), htmlfilename, htmlpath);
  fprintf(stdout,", htmlfilename: \"%s\"", htmlfilename);
  fflush(stdout);

  dbs_html_parse_extension(sizeof(htmlextension), htmlextension, htmlfilename);
  fprintf(stdout,", htmlextension: \"%s\"", htmlextension);
  fflush(stdout);

  htmlparams=dbs_html_get_params();
  if(htmlparams==NULL)
    htmlparams="";
  fprintf(stdout,", htmlparamslen: \"%ld\"", strlen(htmlparams));

  html_clear_all();

  dba_loop();

  FILE *fp1;
  char filename[64];

  sprintf(filename,"%stimelog.deb",filenamehead);
  if((fp1=fopen(filename,"a"))!=NULL) {
    fprintf(fp1,"%s, ip=\"%s\"\n",htmltime, htmlip);
    fclose(fp1);
  }

  sprintf(filename,"%sips.deb",filenamehead);
  dbs_add_end_new_str(filename, htmlip);

  sprintf(filename,"%shostname.deb",filenamehead);
  dbs_add_end_new_str(filename, htmlhostname);

  if(htmlsslcipher[0]!='\0') {
    sprintf(filename,"%sciphers.deb",filenamehead);
    dbs_add_end_new_str(filename,htmlsslcipher);
  }
  sprintf(filename,"%shtml.deb",filenamehead);
  if((fp1 = fopen(filename,"a")) != NULL) {
    fprintf(fp1,"%s, ip=\"%s\", callid=\"%d\"\n",htmltime, htmlip, callid);
    fprintf(fp1,"%s\n",htmlin);
    for(int c=0;c<HTML_BUFFERS;c++) {
      if(strlen(html_get_string(c))>0) {
        fprintf(fp1,"%d: %s\n",c,html_get_string(c));
      }
    }
    fclose(fp1);
  }
  fprintf(stdout,"\ncallid: %d\n", callid++);
  sprintf(filename,"%scallid.deb",filenamehead);
  if((fp1 = fopen(filename,"w")) != NULL) {
    fprintf(fp1,"%d\n", callid);
    fclose(fp1);
  }
  FORT_EVENTS_END(321)
}

Seuraavana lopun palvelinohjelmien osat, joita käytetään sekä https- että http-palvelimissa.

#include <errno.h>
#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 5

int s,news;
char *cert_file = "cert.pem";
char *privatekey_file = "key.pem";

extern char *myport;

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;

  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;

  if((s = socket(res->ai_family, res->ai_socktype, res->ai_protocol))==-1) {
    fprintf(stderr, "%s: socket(), error: %d\n", procname, errno);
    perror("socket");
    fflush(stderr);
  }
  return(s);
}

static void server_bind(int s, struct addrinfo *res)
{
  if(bind(s, res->ai_addr, res->ai_addrlen)==-1) {
    if(errno == 98) {
      fprintf(stdout,"%s cannot bind, waiting to bind", procname);
      fflush(stdout);
      while(errno == 98) {
        sleep(10);
        fprintf(stdout,".");
        fflush(stdout);
        bind(s, res->ai_addr, res->ai_addrlen);
      }
      fprintf(stdout,"bind done!\n");
      fflush(stdout);
    } else {
      fprintf(stderr,"\n%s: cannot bind(), error: %d\n", procname, errno);
      perror("bind");
      fflush(stderr);
    }
  }
}

static int server_listen(int s)
{
  int listenfd;

  if((listenfd=listen(s,backlog))==-1) {
    fprintf(stderr,"\n%s: cannot listen()\n", procname);
    perror("listen");
    fflush(stderr);
  }

  return(listenfd);
}

static void server_close(int s)
{
  if(close(s)==-1) {
    fprintf(stderr,"\n%s: cannot close()\n", procname);
    perror("close");
    fflush(stderr);
  }
}

Palvelimiin on lisätty metodilla GET ehto, jolloin GET pyynnöt voivat olla yksi blokkisia.

Seuraavassa http-osuus palvelimesta:

#include <sys/socket.h>

#define TIMEFORMAT "%Z%Y%m%d%H%M%S"
#define HTMLTIMEFORMAT "%a, %d %b %Y %H:%M:%S %Z"

static void http_server()
{
  int addr_size;

  struct sockaddr_in sa_cli;
  struct addrinfo *res;

  unsigned char buffer10[10];

  FORT_EVENTS_START(322)

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

  signal(SIGPIPE, SIG_IGN);

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


  for(;;) {
    FORT_EVENTS_START(323)

    addr_size = sizeof(sa_cli);
    news = accept(s, (struct sockaddr *)&sa_cli, &addr_size);

    strcpy(htmlip, inet_ntoa(sa_cli.sin_addr));
    sprintf(htmlport,"%d", sa_cli.sin_port);
    htmlsslcipher[0] = '\0';

    char host[32], serv[32];

    getnameinfo((struct sockaddr *)&sa_cli,addr_size,host,sizeof(host),serv,sizeof(serv),NI_NUMERICHOST|NI_NUMERICSERV);
    fprintf(stdout," numeric hostname:%s",host);
    fprintf(stdout," numeric service:%s",serv);

    getnameinfo((struct sockaddr *)&sa_cli,addr_size,host,sizeof(host),serv,sizeof(serv),NI_NUMERICSERV);
    fprintf(stdout," name hostname:%s",host);
    fprintf(stdout," service:%s",serv);

    htmlhostname[0]='\0';

    unsigned long seconds = dbs_getseconds();
    strftime(htmltimeshort, sizeof(htmltimeshort), TIMEFORMAT,
             localtime((time_t *)&seconds));
    strftime(htmltime, sizeof(htmltime), HTMLTIMEFORMAT,
             localtime((time_t *)&seconds));

    fprintf(stdout,"\nConnection(http) from %x", sa_cli.sin_addr.s_addr);
    fprintf(stdout,", ip %s", htmlip);
    fprintf(stdout,", port %s", htmlport);
    fprintf(stdout,", at %s\n", htmltime);

    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) {
        fprintf(stdout,", ");
      }
      fprintf(stdout,"read %d", reads);
      fflush(stdout);
      if((bytes=read(news, htmlin+totalbytes, htmlinlen-totalbytes))<0) {
        fprintf(stderr,"\n%s: cannot read()\n", procname);
        perror("read");
        fflush(stderr);
      }
      fprintf(stdout,"(%d bytes)", bytes);
      if(bytes==0)
        break;
      if(bytes>3 &&
         !isprint(htmlin[0]) &&
         !isprint(htmlin[1]) &&
         !isprint(htmlin[2])) {
        fprintf(stdout,"https packet?\n");
        htmlin[0]='\0';
        totalbytes=0;
        bytes=0;
        break;
      }
      *(htmlin+totalbytes+bytes) = '\0';
      fprintf(stdout,"%s\n",htmlin);
      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);
      reads++;
      first = 0;
    }
    if(totalbytes==0)
      continue;
    fprintf(stdout,"\n%d reads", reads);
    fprintf(stdout,", received %d chars", totalbytes);
    fprintf(stdout,", read %d total bytes", totalbytes);
    fprintf(stdout,", input buffer size %d chars", htmlinlen);
    fprintf(stdout,", data=\"%s\"\n", htmlin);

    dbs_run_loop();

    for(int c=0;c<HTML_BUFFERS;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);
        }
      }
    }
    server_close(news);
    fflush(stdout);

    FORT_EVENTS_END(324)
  }
  FORT_EVENTS_END(325)
}

Seuraavaksi https-palvelin:

static void https_server()
{
  int status, addr_size;

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

  struct sockaddr_in sa_cli;
  struct addrinfo *res;

  unsigned char buffer10[10];

  FORT_EVENTS_START(326)

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

  signal(SIGPIPE, SIG_IGN);

  SSL_library_init();

  OpenSSL_add_ssl_algorithms();
  OpenSSL_add_all_ciphers();

  SSL_load_error_strings();


  if((method = (SSL_METHOD *)
      SSLv23_server_method()) == NULL) {
    fprintf(stderr,"\n%s: cannot SSLv3_server_method()", procname);
    fflush(stderr);
  }

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

  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);
  }

  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);
  }

  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); // listenfd = server_listen(s);                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                               

  for(;;) {
    FORT_EVENTS_START(327)
    addr_size = sizeof(sa_cli);
    if((news=accept(s, (struct sockaddr *)&sa_cli, &addr_size))==-1) {
      fprintf(stderr,"\n%s: cannot accept()\n", procname);
      perror("accept");
      fflush(stderr);
    }

    strcpy(htmlip, inet_ntoa(sa_cli.sin_addr));
    sprintf(htmlport,"%d", sa_cli.sin_port);

    char host[32], serv[32];

    getnameinfo((struct sockaddr *)&sa_cli,addr_size,host,sizeof(host),serv,sizeof(serv),NI_NUMERICHOST|NI_NUMERICSERV);
    fprintf(stdout," numeric hostname:%s",host);
    fprintf(stdout," numeric service:%s",serv);

    getnameinfo((struct sockaddr *)&sa_cli,addr_size,host,sizeof(host),serv,sizeof(serv),NI_NUMERICSERV);
    fprintf(stdout," name hostname:%s",host);
    fprintf(stdout," service:%s",serv);

    unsigned long seconds = dbs_getseconds();
    strftime(htmltimeshort, sizeof(htmltimeshort), TIMEFORMAT,
             localtime((time_t *)&seconds));
    strftime(htmltime, sizeof(htmltime), HTMLTIMEFORMAT,
             localtime((time_t *)&seconds));


    fprintf(stdout,"\nConnection(https) from %x", sa_cli.sin_addr.s_addr);
    fprintf(stdout,", ip %s", htmlip);
    fprintf(stdout,", port %s", htmlport);
    fprintf(stdout,", at %s\n", htmltime);

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

    if(SSL_set_fd(ssl,news) != 1) {
      fprintf(stderr,"\n%s: cannot SSL_set_fd()", procname);
      fflush(stderr);
    }

    int doreadwrite=1,tries=0;

    for(;;) {
      tries++;

      if(tries>4) {
        doreadwrite=0;
        break;
      }

      status=SSL_accept(ssl);
      if(status==-1) {
        int sslerr=SSL_get_error(ssl,status);
        int saveerrno=errno;
        fprintf(stderr,"\n%s: cannot SSL_accept(), status: %d, SSL error: %d, errno: %d",
                procname, status, sslerr, saveerrno);
        fflush(stderr);

        switch(sslerr) {
        case SSL_ERROR_WANT_READ:
          fprintf(stderr,", sslerr: SSL_ERROR_WANT_READ, retrying");
          continue;
        case SSL_ERROR_WANT_WRITE:
          fprintf(stderr,", sslerr: SSL_ERROR_WANT_WRITE, retrying");
          continue;
        case SSL_ERROR_SYSCALL:
          fprintf(stderr,", sslerr: SSL_ERROR_SYSCALL(5), errno: %d, retrying\n",saveerrno);
          ERR_print_errors_fp(stderr);
          continue;
        }
      } else
        break;
    }

    if(doreadwrite) {
      peer_cert = SSL_get_peer_certificate(ssl);
      if(peer_cert == NULL) {
        fprintf(stdout,", No peer certificate");
        fflush(stdout);
      }

      fprintf(stdout,"\n");

      int clen = 0;
      int reads = 0;
      int first = 1;
      htmlparams = NULL;
      int bytes, totalbytes = 0;
      while(htmlparams==NULL || clen-strlen(htmlparams) > 0) {
        if(!first) {
          fprintf(stdout,", ");
        }
        fprintf(stdout,"read %d", reads);
        fflush(stdout);
        if((bytes = SSL_read(ssl, htmlin+totalbytes, htmlinlen-totalbytes))<0) {
          fprintf(stderr,"\n%s: cannot SSL_read()\n", procname);
          perror("SSL_read");
          fflush(stderr);
        }
        fprintf(stdout,"(%d bytes)", bytes);
        if(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);
        reads++;
        first = 0;
      }

      fprintf(stdout,"\n%d reads", reads);
      fprintf(stdout,", received %d chars", totalbytes);
      fprintf(stdout,", read %d total bytes", totalbytes);
      fprintf(stdout,", input buffer size %d chars", htmlinlen);
      fprintf(stdout,", data=\"%s\"\n", htmlin);

      strncpy(htmlsslcipher, SSL_get_cipher(ssl), sizeof(htmlsslcipher));

      dbs_run_loop();

      for(int c=0;c<HTML_BUFFERS;c++) {
        if(strlen(html_get_string(c))>0) {
          if((status=SSL_write(ssl, html_get_string(c), strlen(html_get_string(c))))<1) {
            fprintf(stderr,"\n%s: cannot SSL_write(), buffer %d, status: %d, SSL error: %d",
                    procname, c, status, SSL_get_error(ssl,status));
            fflush(stderr);
          }
        }
      }
    }
    fprintf(stdout,"\nSSL connection using %s", htmlsslcipher);
    fflush(stderr);
    SSL_free(ssl);
    server_close(news);

    fflush(stdout);
    FORT_EVENTS_END(328)
  } // for(;;)                                                                                                                                                                                                                                                   
  SSL_CTX_free(ctx);
  FORT_EVENTS_END(329)
}

Tässä rutiini merkkijonon tallettamiseen. Käytetään lähinnä ohjelman parametreissa.

static unsigned char *dbs_save_string(unsigned char *string)
{
  unsigned char *temp = malloc(strlen(string)+1);
  strcpy(temp, string);
  return(temp);
}

Tällä lasketaan tiedoston eli tässä ajettavan ohjelman “sormenjälki”.

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);
}

Ja varsin pääohjelma:

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],buffer10[10];

  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);
  }

  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);
  fprintf(stdout,"%s\n\n", copyright);
  fflush(stdout);

  dbs_main(argc,argv);
  dba_main(argc,argv);

  FILE *fp1;
  unsigned char filename[64];

  callid = 0;

  sprintf(filename,"%scallid.deb",filenamehead);
  if((fp1 = fopen(filename,"r")) != NULL) {
    fgets(buffer10, sizeof(buffer10), fp1);
    callid = atoi(buffer10);
    fclose(fp1);
  }

  sprintf(filename,"%spid.deb",filenamehead);
  if((fp1 = fopen(filename,"w")) != NULL) {
    fprintf(fp1,"%d\n", getpid());
    fclose(fp1);
  }

  if(https)
    https_server();
  else
    http_server();

  exit(0);
}