Example #1
0
int read_some_events(struct thread_info *t) {
    struct io_unit *event_io;
    struct io_event *event;
    int nr;
    int i; 
    int min_nr = io_iter;
    struct timeval stop_time;

    if (t->num_global_pending < io_iter)
        min_nr = t->num_global_pending;

#ifdef NEW_GETEVENTS
    nr = io_getevents(t->io_ctx, min_nr, t->num_global_events, t->events,NULL);
#else
    nr = io_getevents(t->io_ctx, t->num_global_events, t->events, NULL);
#endif
    if (nr <= 0)
        return nr;

    gettimeofday(&stop_time, NULL);
    for (i = 0 ; i < nr ; i++) {
	event = t->events + i;
	event_io = (struct io_unit *)((unsigned long)event->obj); 
	finish_io(t, event_io, event->res, &stop_time);
    }
    return nr;
}
Example #2
0
/*
 * wait for all pending requests for this io operation to finish
 */
static int io_oper_wait(struct thread_info *t, struct io_oper *oper) {
    struct io_event event;
    struct io_unit *event_io;

    if (oper == NULL) {
        return 0;
    }

    if (oper->num_pending == 0)
        goto done;

    /* this func is not speed sensitive, no need to go wild reading
     * more than one event at a time
     */
#ifdef NEW_GETEVENTS
    while(io_getevents(t->io_ctx, 1, 1, &event, NULL) > 0) {
#else
    while(io_getevents(t->io_ctx, 1, &event, NULL) > 0) {
#endif
	struct timeval tv_now;
        event_io = (struct io_unit *)((unsigned long)event.obj); 

	gettimeofday(&tv_now, NULL);
	finish_io(t, event_io, event.res, &tv_now);

	if (oper->num_pending == 0)
	    break;
    }
done:
    if (oper->num_err) {
        fprintf(stderr, "%u errors on oper, last %u\n", 
	        oper->num_err, oper->last_err);
    }
    return 0;
}

off_t random_byte_offset(struct io_oper *oper) {
    off_t num;
    off_t rand_byte = oper->start;
    off_t range;
    off_t offset = 1;

    range = (oper->end - oper->start) / (1024 * 1024);
    if ((page_size_mask+1) > (1024 * 1024))
        offset = (page_size_mask+1) / (1024 * 1024);
    if (range < offset)
        range = 0;
    else
        range -= offset;

    /* find a random mb offset */
    num = 1 + (int)((double)range * rand() / (RAND_MAX + 1.0 ));
    rand_byte += num * 1024 * 1024;
    
    /* find a random byte offset */
    num = 1 + (int)((double)(1024 * 1024) * rand() / (RAND_MAX + 1.0));

    /* page align */
    num = (num + page_size_mask) & ~page_size_mask;
    rand_byte += num;

    if (rand_byte + oper->reclen > oper->end) {
	rand_byte -= oper->reclen;
    }
    return rand_byte;
}
Example #3
0
int main(int argc,char **argv)
{
 URL *Url;
 URL **list,*refresh;
 int j;

 if(argc==1)
   {fprintf(stderr,"usage: test-doc URL < contents-of-url\n");return(1);}

 StderrLevel=ExtraDebug;

 InitErrorHandler("test-doc",0,1);

 InitConfigurationFile("./wwwoffle.conf");

 init_io(STDERR_FILENO);

 if(ReadConfigurationFile(STDERR_FILENO))
    PrintMessage(Fatal,"Error in configuration file 'wwwoffle.conf'.");

 finish_io(STDERR_FILENO);

 Url=SplitURL(argv[1]);

 init_io(0);

 ParseDocument(0,Url,1);

 if((refresh=GetReference(RefMetaRefresh)))
    printf("Refresh = %s\n",refresh->file);

 if((list=GetReferences(RefStyleSheet)))
    for(j=0;list[j];j++)
       printf("StyleSheet = %s\n",list[j]->file);

 if((list=GetReferences(RefImage)))
    for(j=0;list[j];j++)
       printf("Image = %s\n",list[j]->file);

 if((list=GetReferences(RefFrame)))
    for(j=0;list[j];j++)
       printf("Frame = %s\n",list[j]->file);

 if((list=GetReferences(RefScript)))
    for(j=0;list[j];j++)
       printf("Script = %s\n",list[j]->file);

 if((list=GetReferences(RefObject)))
    for(j=0;list[j];j++)
       printf("Object = %s\n",list[j]->file);

 if((list=GetReferences(RefInlineObject)))
    for(j=0;list[j];j++)
       printf("InlineObject = %s\n",list[j]->file);

 if((list=GetReferences(RefLink)))
    for(j=0;list[j];j++)
       printf("Link = %s\n",list[j]->file);

 FreeURL(Url);

 finish_io(0);

 return(0);
}
Example #4
0
void RequestMonitoredPages(void)
{
 DIR *dir;
 struct dirent* ent;

 /* Open the monitor subdirectory. */

 if(chdir("monitor"))
   {PrintMessage(Warning,"Cannot change to directory 'monitor'; [%!s] no files monitored.");return;}

 dir=opendir(".");
 if(!dir)
   {PrintMessage(Warning,"Cannot open directory 'monitor'; [%!s] no files monitored.");ChangeBackToSpoolDir();return;}

 ent=readdir(dir);
 if(!ent)
   {PrintMessage(Warning,"Cannot read directory 'monitor'; [%!s] no files monitored.");closedir(dir);ChangeBackToSpoolDir();return;}

 /* Scan through all of the files. */

 do
   {
    struct stat buf;

    if(ent->d_name[0]=='.' && (ent->d_name[1]==0 || (ent->d_name[1]=='.' && ent->d_name[2]==0)))
       continue; /* skip . & .. */

    if(stat(ent->d_name,&buf))
      {PrintMessage(Inform,"Cannot stat file 'monitor/%s'; [%!s] race condition?",ent->d_name);return;}
    else if(S_ISREG(buf.st_mode) && *ent->d_name=='O')
      {
       URL *Url=FileNameToURL(ent->d_name);
       int last,next;

       ChangeBackToSpoolDir();

       if(!Url)
          continue;

       MonitorTimes(Url,&last,&next);

       PrintMessage(Debug,"Monitoring '%s' last=%dh next=%dh => %s",Url->name,last,next,next?"No":"Yes");

       chdir("monitor");

       if(next==0)
         {
          int ifd=open(ent->d_name,O_RDONLY|O_BINARY);

          if(ifd==-1)
             PrintMessage(Warning,"Cannot open monitored file 'monitor/%s' to read; [%!s].",ent->d_name);
          else
            {
             int ofd;

             init_io(ifd);

             ChangeBackToSpoolDir();

             ofd=OpenNewOutgoingSpoolFile();

             if(ofd==-1)
                PrintMessage(Warning,"Cannot open outgoing spool file for monitored URL '%s'; [%!s].",Url->name);
             else
               {
                char *contents=(char*)malloc(buf.st_size+1);

                init_io(ofd);

                read_data(ifd,contents,buf.st_size);
                if(write_data(ofd,contents,buf.st_size)==-1)
                   PrintMessage(Warning,"Cannot write to outgoing file; disk full?");

                finish_io(ofd);
                CloseNewOutgoingSpoolFile(ofd,Url);

                free(contents);
               }

             chdir("monitor");

             finish_io(ifd);
             close(ifd);

             if(utime(URLToFileName(Url,'M',0),NULL))
                PrintMessage(Warning,"Cannot change timestamp of monitored file 'monitor/%s'; [%!s].",URLToFileName(Url,'M',0));
            }
         }

       FreeURL(Url);
      }
   }
 while((ent=readdir(dir)));

 ChangeBackToSpoolDir();

 closedir(dir);
}
Example #5
0
static void MonitorFormParse(int fd,URL *Url,char *request_args,Body *request_body)
{
 int i,mfd=-1;
 char **args,*url=NULL;
 URL *monUrl;
 char mofy[13]="NNNNNNNNNNNN",*dofm=NULL,dofw[8]="NNNNNNN",*hofd=NULL;
 char MofY[13],DofM[32],DofW[8],HofD[25];

 if(!request_args && !request_body)
   {
    HTMLMessage(fd,404,"WWWOFFLE Monitor Form Error",NULL,"MonitorFormError",
                "body",NULL,
                NULL);
    return;
   }

 if(request_body)
   {
    char *form=URLRecodeFormArgs(request_body->content);
    args=SplitFormArgs(form);
    free(form);
   }
 else
    args=SplitFormArgs(request_args);

 for(i=0;args[i];i++)
   {
    if(!strncmp("url=",args[i],(size_t)4))
       url=TrimArgs(URLDecodeFormArgs(args[i]+4));
    else if(!strncmp("mofy1=",args[i],(size_t)6))
       mofy[0]=args[i][6];
    else if(!strncmp("mofy2=",args[i],(size_t)6))
       mofy[1]=args[i][6];
    else if(!strncmp("mofy3=",args[i],(size_t)6))
       mofy[2]=args[i][6];
    else if(!strncmp("mofy4=",args[i],6))
       mofy[3]=args[i][6];
    else if(!strncmp("mofy5=",args[i],(size_t)6))
       mofy[4]=args[i][6];
    else if(!strncmp("mofy6=",args[i],(size_t)6))
       mofy[5]=args[i][6];
    else if(!strncmp("mofy7=",args[i],(size_t)6))
       mofy[6]=args[i][6];
    else if(!strncmp("mofy8=",args[i],(size_t)6))
       mofy[7]=args[i][6];
    else if(!strncmp("mofy9=",args[i],(size_t)6))
       mofy[8]=args[i][6];
    else if(!strncmp("mofy10=",args[i],(size_t)7))
       mofy[9]=args[i][7];
    else if(!strncmp("mofy11=",args[i],(size_t)7))
       mofy[10]=args[i][7];
    else if(!strncmp("mofy12=",args[i],(size_t)7))
       mofy[11]=args[i][7];
    else if(!strncmp("dofm=",args[i],(size_t)5))
       dofm=args[i]+5;
    else if(!strncmp("dofw0=",args[i],(size_t)6))
       dofw[0]=args[i][6];
    else if(!strncmp("dofw1=",args[i],(size_t)6))
       dofw[1]=args[i][6];
    else if(!strncmp("dofw2=",args[i],(size_t)6))
       dofw[2]=args[i][6];
    else if(!strncmp("dofw3=",args[i],(size_t)6))
       dofw[3]=args[i][6];
    else if(!strncmp("dofw4=",args[i],(size_t)6))
       dofw[4]=args[i][6];
    else if(!strncmp("dofw5=",args[i],(size_t)6))
       dofw[5]=args[i][6];
    else if(!strncmp("dofw6=",args[i],(size_t)6))
       dofw[6]=args[i][6];
    else if(!strncmp("hofd=",args[i],(size_t)5))
       hofd=args[i]+5;
    else
       PrintMessage(Warning,"Unexpected argument '%s' seen decoding form data for URL '%s'.",args[i],Url->name);
   }

 if(url==NULL || *url==0)
   {
    HTMLMessage(fd,404,"WWWOFFLE Monitor Form Error",NULL,"MonitorFormError",
                "body",request_body?request_body->content:request_args,
                NULL);
    if(url) free(url);
    free(args[0]);
    free(args);
    return;
   }

 monUrl=SplitURL(url);
 free(url);

 /* Parse the requested time */

 strcpy(MofY,"000000000000");
 for(i=0;i<12;i++)
    if(mofy[i]=='Y')
       MofY[i]='1';

 if(!dofm || !*dofm)
    strcpy(DofM,"1111111111111111111111111111111");
 else
   {
    int d,any=0,range=0,lastd=0;
    char *p=dofm;
    strcpy(DofM,"0000000000000000000000000000000");

    while(*p)
      {
       while(*p && !isdigit(*p))
         {
          if(*p=='*')
            {
             strcpy(DofM,"1111111111111111111111111111111");
             any=1;
            }
          if(*p=='-')
             range=1;
          p++;
         }
       if(!*p)
          break;
       d=atoi(p)-1;
       if(range)
         {
          if(d>30)
             d=30;
          for(;lastd<=d;lastd++)
             DofM[lastd]='1';
          range=0;
          any++;
         }
       else if(d>=0 && d<31)
         {
          DofM[d]='1';
          any++;
          lastd=d;
         }
       while(isdigit(*p))
          p++;
      }

    if(range)
       for(;lastd<=30;lastd++)
          DofM[lastd]='1';
    else
       if(!any)
          strcpy(DofM,"1111111111111111111111111111111");
   }

 strcpy(DofW,"0000000");
 for(i=0;i<7;i++)
    if(dofw[i]=='Y')
       DofW[i]='1';

 if(!hofd || !*hofd)
    strcpy(HofD,"100000000000000000000000");
 else
   {
    int h,any=0,range=0,lasth=0;
    char *p=hofd;
    strcpy(HofD,"000000000000000000000000");

    while(*p)
      {
       while(*p && !isdigit(*p))
         {
          if(*p=='*')
            {
             strcpy(HofD,"111111111111111111111111");
             any=1;
            }
          if(*p=='-')
             range=1;
          p++;
         }
       if(!*p)
          break;
       h=atoi(p);
       if(range)
         {
          if(h>23)
             h=23;
          for(;lasth<=h;lasth++)
             HofD[lasth]='1';
          range=0;
          any++;
         }
       else if(h>=0 && h<24)
         {
          HofD[h]='1';
          any++;
          lasth=h;
         }
       while(isdigit(*p))
          p++;
      }

    if(range)
       for(;lasth<=23;lasth++)
          HofD[lasth]='1';
    else
       if(!any)
          strcpy(HofD,"100000000000000000000000");
   }

 mfd=CreateMonitorSpoolFile(monUrl,MofY,DofM,DofW,HofD);

 if(mfd==-1)
    HTMLMessage(fd,500,"WWWOFFLE Server Error",NULL,"ServerError",
                "error","Cannot open file to store monitor request",
                NULL);
 else
   {
    Header *new_request_head=RequestURL(monUrl,NULL);
    char *head=HeaderString(new_request_head);

    init_io(mfd);

    write_string(mfd,head);

    finish_io(mfd);
    close(mfd);

    HTMLMessage(fd,200,"WWWOFFLE Monitor Will Get",NULL,"MonitorWillGet",
                "url",monUrl->name,
                NULL);

    free(head);
    FreeHeader(new_request_head);
   }

 free(args[0]);
 free(args);

 FreeURL(monUrl);
}
Example #6
0
int main(int argc, char** argv)
{
 int i;
 int err;
 struct stat buf;
 int uid,gid;

 /* Parse the command line options */

 for(i=1;i<argc;i++)
   {
    if(!strcmp(argv[i],"-h") || !strcmp(argv[i],"--help"))
       usage(1);

    if(!strcmp(argv[i],"--version"))
       usage(2);

    if(!strcmp(argv[i],"-d"))
      {
       detached=0;

       if(i<(argc-1) && isdigit(argv[i+1][0]))
         {
          StderrLevel=Fatal+1-atoi(argv[++i]);

          if(StderrLevel<0 || StderrLevel>Fatal)
            {fprintf(stderr,"wwwoffled: The '-d' option requires a number between 0 and %d.\n",Fatal+1); exit(1);}
         }

       continue;
      }

    if(!strcmp(argv[i],"-l"))
      {
       if(++i>=argc)
         {fprintf(stderr,"wwwoffled: The '-l' option requires a filename.\n"); exit(1);}
       if(argv[i][0]!='/')
         {fprintf(stderr,"wwwoffled: The '-l' option requires an absolute pathname.\n"); exit(1);}

       log_file=argv[i];
       continue;
      }

    if(!strcmp(argv[i],"-p"))
      {
       print_pid=1;
       continue;
      }

    if(!strcmp(argv[i],"-f"))
      {
       nofork=1;
       detached=0;
       continue;
      }

    if(!strcmp(argv[i],"-c"))
      {
       if(++i>=argc)
         {fprintf(stderr,"wwwoffled: The '-c' option requires a filename.\n"); exit(1);}

       config_file=argv[i];
       continue;
      }

    fprintf(stderr,"wwwoffled: Unknown option '%s'.\n",argv[i]); exit(1);
   }

 /* Combination options */

 if(log_file)
   {
    if(nofork)
       log_file=NULL;           /* -f overrides -l */
    else
       detached=1;              /* -l overrides -d */

    if(StderrLevel==-1)
       StderrLevel=Inform;      /* -l sets log level if no -d */
   }

 /* Initialise things. */

 for(i=0;i<MAX_FETCH_SERVERS;i++)
    fetch_pids[i]=0;

 for(i=0;i<MAX_SERVERS;i++)
    server_pids[i]=0;

 if(log_file)
    OpenErrorLog(log_file);

 InitErrorHandler("wwwoffled",0,1); /* use stderr and not syslog to start with. */

 /* Read the configuration file. */

 InitConfigurationFile(config_file);

 init_io(STDERR_FILENO);

 if(ReadConfigurationFile(STDERR_FILENO))
    PrintMessage(Fatal,"Error in configuration file '%s'.",ConfigurationFileName());

 finish_io(STDERR_FILENO);

 InitErrorHandler("wwwoffled",ConfigInteger(UseSyslog),1); /* enable syslog if requested. */

 /* Print a startup message. */

#if USE_IPV6
#define IPV6_STRING "with ipv6"
#else
#define IPV6_STRING "without ipv6"
#endif

#define ZLIB_STRING "with zlib"

#define GNUTLS_STRING "with gnutls"

 PrintMessage(Important,"WWWOFFLE Demon Version %s (%s,%s,%s) started.",WWWOFFLE_VERSION,IPV6_STRING,ZLIB_STRING,GNUTLS_STRING);
 PrintMessage(Inform,"WWWOFFLE Read Configuration File '%s'.",ConfigurationFileName());

 /* Change the user and group. */

 gid=ConfigInteger(WWWOFFLE_Gid);
 uid=ConfigInteger(WWWOFFLE_Uid);

 if(uid!=-1)
    seteuid(0);

 if(log_file && (uid!=-1 || gid!=-1))
    chown(log_file,(uid_t)uid,(gid_t)gid);

 if(gid!=-1)
   {
#if HAVE_SETGROUPS
    if(getuid()==0 || geteuid()==0)
       if(setgroups(0,NULL)<0)
          PrintMessage(Fatal,"Cannot clear supplementary group list [%!s].");
#endif

#if HAVE_SETRESGID
    if(setresgid((gid_t)gid,(gid_t)gid,(gid_t)gid)<0)
       PrintMessage(Fatal,"Cannot set real/effective/saved group id to %d [%!s].",gid);
#else
    if(geteuid()==0)
      {
       if(setgid((gid_t)gid)<0)
          PrintMessage(Fatal,"Cannot set group id to %d [%!s].",gid);
      }
    else
      {
#if HAVE_SETREGID
       if(setregid(getegid(),(gid_t)gid)<0)
          PrintMessage(Fatal,"Cannot set effective group id to %d [%!s].",gid);
       if(setregid((gid_t)gid,(gid_t)~1)<0)
          PrintMessage(Fatal,"Cannot set real group id to %d [%!s].",gid);
#else
       PrintMessage(Fatal,"Must be root to totally change group id.");
#endif
      }
#endif
   }

 if(uid!=-1)
   {
#if HAVE_SETRESUID
    if(setresuid((uid_t)uid,(uid_t)uid,(uid_t)uid)<0)
       PrintMessage(Fatal,"Cannot set real/effective/saved user id to %d [%!s].",uid);
#else
    if(geteuid()==0)
      {
       if(setuid((uid_t)uid)<0)
          PrintMessage(Fatal,"Cannot set user id to %d [%!s].",uid);
      }
    else
      {
#if HAVE_SETREUID
       if(setreuid(geteuid(),(uid_t)uid)<0)
          PrintMessage(Fatal,"Cannot set effective user id to %d [%!s].",uid);
       if(setreuid((uid_t)uid,(uid_t)~1)<0)
          PrintMessage(Fatal,"Cannot set real user id to %d [%!s].",uid);
#else
       PrintMessage(Fatal,"Must be root to totally change user id.");
#endif
      }
#endif
   }

 if(uid!=-1 || gid!=-1)
    PrintMessage(Inform,"Running with uid=%d, gid=%d.",geteuid(),getegid());

 if(geteuid()==0 || getegid()==0)
    PrintMessage(Warning,"Running with root user or group privileges is not recommended.");

 /* Create, Change to and open the spool directory. */

 umask(0);

 if(stat(ConfigString(SpoolDir),&buf))
   {
    err=mkdir(ConfigString(SpoolDir),(mode_t)ConfigInteger(DirPerm));
    if(err==-1 && errno!=EEXIST)
       PrintMessage(Fatal,"Cannot create spool directory %s [%!s].",ConfigString(SpoolDir));
    stat(ConfigString(SpoolDir),&buf);
   }

 if(!S_ISDIR(buf.st_mode))
    PrintMessage(Fatal,"The spool directory %s is not a directory.",SpoolDir);

 err=ChangeToSpoolDir(ConfigString(SpoolDir));
 if(err==-1)
    PrintMessage(Fatal,"Cannot change to spool directory %s [%!s].",ConfigString(SpoolDir));

 /* Bind the HTTP proxy socket(s). */

#if USE_IPV6
 if(ConfigString(Bind_IPv6))
   {
    http_fd[1]=OpenServerSocket(ConfigString(Bind_IPv6),ConfigInteger(HTTP_Port));
    if(http_fd[1]==-1)
       PrintMessage(Fatal,"Cannot create HTTP IPv6 server socket.");
   }
#endif

 if(ConfigString(Bind_IPv4))
   {
    http_fd[0]=OpenServerSocket(ConfigString(Bind_IPv4),ConfigInteger(HTTP_Port));
    if(http_fd[0]==-1)
      {
#if USE_IPV6
       if(http_fd[1]!=-1 && /* PS 2003-01-13 redundant? If IPv6 is listening to 0 then it doesn't matter what address IPv4 is listening to... (at least on linux?) */
                            /* ConfigString(Bind_IPv4) && !strcmp(ConfigString(Bind_IPv4),"0.0.0.0") && */
                            ConfigString(Bind_IPv6) && !strcmp(ConfigString(Bind_IPv6),"[0:0:0:0:0:0:0:0]"))
          PrintMessage(Warning,"Cannot create HTTP IPv4 server socket (but the IPv6 one might accept IPv4 connections).");
       else
          PrintMessage(Fatal,"Cannot create HTTP IPv4 server socket.");
#else
       PrintMessage(Fatal,"Cannot create HTTP server socket.");
#endif
      }
   }

 if(http_fd[0]==-1 && http_fd[1]==-1)
   {
#if USE_IPV6
    PrintMessage(Fatal,"The IPv4 and IPv6 HTTP sockets were not bound; are they disabled in the config file?");
#else
    PrintMessage(Fatal,"The HTTP socket was not bound; is it disabled in the config file?");
#endif
   }

 /* Bind the HTTPS socket(s). */

 if(LoadRootCredentials())
   {
    PrintMessage(Warning,"Failed to read (or create if needed) the WWWOFFLE root certificates.");
   }

 if(LoadTrustedCertificates())
   {
    PrintMessage(Warning,"Failed to read in any trusted certificates.");
   }

#if USE_IPV6
 if(ConfigString(Bind_IPv6))
   {
    https_fd[1]=OpenServerSocket(ConfigString(Bind_IPv6),ConfigInteger(HTTPS_Port));
    if(https_fd[1]==-1)
       PrintMessage(Fatal,"Cannot create HTTPS IPv6 server socket.");
   }
#endif

 if(ConfigString(Bind_IPv4))
   {
    https_fd[0]=OpenServerSocket(ConfigString(Bind_IPv4),ConfigInteger(HTTPS_Port));
    if(https_fd[0]==-1)
      {
#if USE_IPV6
       if(https_fd[1]!=-1 && ConfigString(Bind_IPv4) && !strcmp(ConfigString(Bind_IPv4),"0.0.0.0") &&
                             ConfigString(Bind_IPv6) && !strcmp(ConfigString(Bind_IPv6),"[0:0:0:0:0:0:0:0]"))
          PrintMessage(Warning,"Cannot create HTTPS IPv4 server socket (but the IPv6 one might accept IPv4 connections).");
       else
          PrintMessage(Fatal,"Cannot create HTTPS IPv4 server socket.");
#else
       PrintMessage(Fatal,"Cannot create HTTPS server socket.");
#endif
      }
   }

 if(https_fd[0]==-1 && https_fd[1]==-1)
   {
#if USE_IPV6
    PrintMessage(Fatal,"The IPv4 and IPv6 HTTPS sockets were not bound; are they disabled in the config file?");
#else
    PrintMessage(Fatal,"The HTTPS socket was not bound; is it disabled in the config file?");
#endif
   }

 /* Bind the WWWOFFLE control socket(s). */

#if USE_IPV6
 if(ConfigString(Bind_IPv6))
   {
    wwwoffle_fd[1]=OpenServerSocket(ConfigString(Bind_IPv6),ConfigInteger(WWWOFFLE_Port));
    if(wwwoffle_fd[1]==-1)
       PrintMessage(Fatal,"Cannot create WWWOFFLE IPv6 server socket.");
   }
#endif

 if(ConfigString(Bind_IPv4))
   {
    wwwoffle_fd[0]=OpenServerSocket(ConfigString(Bind_IPv4),ConfigInteger(WWWOFFLE_Port));
    if(wwwoffle_fd[0]==-1)
      {
#if USE_IPV6
       if(wwwoffle_fd[1]!=-1 && ConfigString(Bind_IPv4) && !strcmp(ConfigString(Bind_IPv4),"0.0.0.0") &&
                                ConfigString(Bind_IPv6) && !strcmp(ConfigString(Bind_IPv6),"[0:0:0:0:0:0:0:0]")) {
          PrintMessage(Warning,"Cannot create WWWOFFLE IPv4 server socket (but the IPv6 one might accept IPv4 connections).");
          PrintMessage(Warning,"Consider adding \"bind-ipv4 = none\" to wwwoffle.conf if using IPv6.");
       }
       else
          PrintMessage(Fatal,"Cannot create WWWOFFLE IPv4 server socket.");
#else
       PrintMessage(Fatal,"Cannot create WWWOFFLE server socket.");
#endif
      }
   }

 if(wwwoffle_fd[0]==-1 && wwwoffle_fd[1]==-1)
   {
#if USE_IPV6
    PrintMessage(Fatal,"The IPv4 and IPv6 WWWOFFLE sockets were not bound; are they disabled in the config file?");
#else
    PrintMessage(Fatal,"The WWWOFFLE socket was not bound; is it disabled in the config file?");
#endif
   }

 /* Detach from terminal */

 if(detached)
   {
    demoninit();

    PrintMessage(Important,"Detached from terminal and changed pid to %d.",getpid());

    if(log_file)
       InitErrorHandler("wwwoffled",-1,-1); /* pid changes after detaching, keep stderr as was. */
    else
       InitErrorHandler("wwwoffled",-1, 0); /* pid changes after detaching, disable stderr. */

    if(!log_file)
       close(STDERR_FILENO);
   }

 close(STDIN_FILENO);
 close(STDOUT_FILENO);

 install_sighandlers();

 max_servers=ConfigInteger(MaxServers);
 max_fetch_servers=ConfigInteger(MaxFetchServers);

 /* Loop around waiting for connections. */

 PrintMessage(Inform,"WWWOFFLE Ready to accept connections.");

 do
   {
    struct timeval tv;
    fd_set readfd;
    int nfds=0,nfd=0;

    FD_ZERO(&readfd);

#if USE_IPV6
       for(nfd=0;nfd<=1;nfd++)
         {
#endif
          if(http_fd[nfd]>=nfds)
             nfds=http_fd[nfd]+1;
          if(https_fd[nfd]>=nfds)
             nfds=https_fd[nfd]+1;
          if(wwwoffle_fd[nfd]>=nfds)
             nfds=wwwoffle_fd[nfd]+1;

          if(n_servers<max_servers)
            {
             if(http_fd[nfd]!=-1)
                FD_SET(http_fd[nfd],&readfd);
             if(https_fd[nfd]!=-1)
                FD_SET(https_fd[nfd],&readfd);
            }

          if(wwwoffle_fd[nfd]!=-1)
             FD_SET(wwwoffle_fd[nfd],&readfd);
#if USE_IPV6
         }
#endif

    tv.tv_sec=10;
    tv.tv_usec=0;

    if(select(nfds,&readfd,NULL,NULL,&tv)!=-1)
      {
#if USE_IPV6
       for(nfd=0;nfd<=1;nfd++)
         {
#endif
          if(wwwoffle_fd[nfd]!=-1 && FD_ISSET(wwwoffle_fd[nfd],&readfd))
            {
             char *host,*ip;
             int port,client;

             client=AcceptConnect(wwwoffle_fd[nfd]);

             if(client>=0)
               {
                init_io(client);
                configure_io_timeout(client,ConfigInteger(SocketTimeout),ConfigInteger(SocketTimeout));

                if(SocketRemoteName(client,&host,&ip,&port))
                  {
                   finish_io(client);
                   CloseSocket(client);
                  }
                else
                  {
                   char *canonical_ip=CanonicaliseHost(ip);

                   if(IsAllowedConnectHost(host) || IsAllowedConnectHost(canonical_ip))
                     {
                      PrintMessage(Important,"WWWOFFLE Connection from host %s (%s).",host,canonical_ip); /* Used in audit-usage.pl */

                      CommandConnect(client);

                      if(fetch_fd!=client)
                        {
                         finish_io(client);
                         CloseSocket(client);
                        }
                     }
                   else
                     {
                      PrintMessage(Warning,"WWWOFFLE Connection rejected from host %s (%s).",host,canonical_ip); /* Used in audit-usage.pl */
                      finish_io(client);
                      CloseSocket(client);
                     }

                   free(canonical_ip);
                  }
               }
            }

          if(http_fd[nfd]!=-1 && FD_ISSET(http_fd[nfd],&readfd))
            {
             char *host,*ip;
             int port,client;

             client=AcceptConnect(http_fd[nfd]);

             if(client>=0)
               {
                init_io(client);
                configure_io_timeout(client,ConfigInteger(SocketTimeout),ConfigInteger(SocketTimeout));

                if(!SocketRemoteName(client,&host,&ip,&port))
                  {
                   char *canonical_ip=CanonicaliseHost(ip);

                   if(IsAllowedConnectHost(host) || IsAllowedConnectHost(canonical_ip))
                     {
                      PrintMessage(Inform,"HTTP Proxy connection from host %s (%s).",host,canonical_ip); /* Used in audit-usage.pl */
                      ForkServer(client);
                     }
                   else
                      PrintMessage(Warning,"HTTP Proxy connection rejected from host %s (%s).",host,canonical_ip); /* Used in audit-usage.pl */

                   free(canonical_ip);
                  }

                if(nofork)
                   got_sigexit=1;

                if(!nofork)
                  {
                   finish_io(client);
                   CloseSocket(client);
                  }
               }
            }

          if(https_fd[nfd]!=-1 && FD_ISSET(https_fd[nfd],&readfd))
            {
             char *host,*ip;
             int port,client;

             client=AcceptConnect(https_fd[nfd]);

             if(client>=0)
               {
                init_io(client);
                configure_io_timeout(client,ConfigInteger(SocketTimeout),ConfigInteger(SocketTimeout));

                if(!SocketRemoteName(client,&host,&ip,&port))
                  {
                   char *canonical_ip=CanonicaliseHost(ip);

                   if(IsAllowedConnectHost(host) || IsAllowedConnectHost(canonical_ip))
                     {
                      PrintMessage(Inform,"HTTPS Proxy connection from host %s (%s).",host,canonical_ip); /* Used in audit-usage.pl */
                      ForkServer(client);
                     }
                   else
                      PrintMessage(Warning,"HTTPS Proxy connection rejected from host %s (%s).",host,canonical_ip); /* Used in audit-usage.pl */

                   free(canonical_ip);
                  }

                if(nofork)
                   got_sigexit=1;

                if(!nofork)
                  {
                   finish_io(client);
                   CloseSocket(client);
                  }
               }
            }

#if USE_IPV6
         }
#endif
      }

    if(got_sighup)
      {
       got_sighup=0;

       PrintMessage(Important,"SIGHUP signalled.");

       if(log_file)
         {
          PrintMessage(Important,"Closing and opening log file.");

          OpenErrorLog(log_file);
         }

       PrintMessage(Important,"WWWOFFLE Re-reading Configuration File.");

       if(ReadConfigurationFile(-1))
          PrintMessage(Warning,"Error in configuration file; keeping old values.");

       PrintMessage(Important,"WWWOFFLE Finished Re-reading Configuration File.");
      }

    if(got_sigchld)
      {
       int pid, status;
       int isserver=0;

       /* To avoid race conditions, reset the flag before fetching the status */

       got_sigchld=0;

       while((pid=waitpid(-1,&status,WNOHANG))>0)
         {
          int i;
          int exitval=0;

          if(WIFEXITED(status))
             exitval=WEXITSTATUS(status);
          else if(WIFSIGNALED(status))
             exitval=-WTERMSIG(status);

          if(purging)
             if(purge_pid==pid)
               {
                if(exitval>=0)
                   PrintMessage(Inform,"Purge process exited with status %d (pid=%d).",exitval,pid);
                else
                   PrintMessage(Important,"Purge process terminated by signal %d (pid=%d).",-exitval,pid);

                purging=0;
               }

          for(i=0;i<max_servers;i++)
             if(server_pids[i]==pid)
               {
                n_servers--;
                server_pids[i]=0;
                isserver=1;

                if(exitval>=0)
                   PrintMessage(Inform,"Child wwwoffles exited with status %d (pid=%d).",exitval,pid);
                else
                   PrintMessage(Important,"Child wwwoffles terminated by signal %d (pid=%d).",-exitval,pid);

                break;
               }

          /* Check if the child that terminated is one of the fetching wwwoffles */

          for(i=0;i<max_fetch_servers;i++)
             if(fetch_pids[i]==pid)
               {
                n_fetch_servers--;
                fetch_pids[i]=0;
                break;
               }

          if(exitval==3)
             fetching=0;

          if(exitval==4 && online!=0)
             fetching=1;

          if(online==0)
             fetching=0;
         }

       if(isserver)
          PrintMessage(Debug,"Currently running: %d servers total, %d fetchers.",n_servers,n_fetch_servers);
      }

    /* The select timed out or we got a signal. If we are currently fetching,
       start fetch servers to look for jobs in the spool directory. */

    while(fetching && n_fetch_servers<max_fetch_servers && n_servers<max_servers)
       ForkServer(fetch_fd);

    if(fetch_fd!=-1 && !fetching && n_fetch_servers==0)
      {
       write_string(fetch_fd,"WWWOFFLE No more to fetch.\n");

       finish_io(fetch_fd);
       CloseSocket(fetch_fd);
       fetch_fd=-1;

       PrintMessage(Important,"WWWOFFLE Fetch finished.");

       ForkRunModeScript(ConfigString(RunFetch),"fetch","stop",-1);
      }
   }
 while(!got_sigexit);

 /* Close down and exit. */

 /* These four sockets don't need finish_io() calling because they never
    had init_io() called, they are just bound to a port listening. */

 if(http_fd[0]!=-1) CloseSocket(http_fd[0]);
 if(http_fd[1]!=-1) CloseSocket(http_fd[1]);
 if(wwwoffle_fd[0]!=-1) CloseSocket(wwwoffle_fd[0]);
 if(wwwoffle_fd[1]!=-1) CloseSocket(wwwoffle_fd[1]);

 if(!nofork)
   {
    if(n_servers)
       PrintMessage(Important,"Exit signalled - waiting for %d child wwwoffles servers.",n_servers);
    else
       PrintMessage(Important,"Exit signalled.");
   }

 while(n_servers)
   {
    int i;
    int pid,status,exitval=0;

    while((pid=waitpid(-1,&status,0))>0)
      {
       if(WIFEXITED(status))
          exitval=WEXITSTATUS(status);
       else if(WIFSIGNALED(status))
          exitval=-WTERMSIG(status);

       for(i=0;i<max_servers;i++)
          if(server_pids[i]==pid)
            {
             n_servers--;
             server_pids[i]=0;

             if(exitval>=0)
                PrintMessage(Inform,"Child wwwoffles exited with status %d (pid=%d).",exitval,pid);
             else
                PrintMessage(Important,"Child wwwoffles terminated by signal %d (pid=%d).",-exitval,pid);

             break;
            }

       if(purging)
          if(purge_pid==pid)
            {
             if(exitval>=0)
                PrintMessage(Inform,"Purge process exited with status %d (pid=%d).",exitval,pid);
             else
                PrintMessage(Important,"Purge process terminated by signal %d (pid=%d).",-exitval,pid);

             purging=0;
            }
      }
   }

 PrintMessage(Important,"Exiting.");

 FinishConfigurationFile();

 FreeLoadedCredentials();

 return(0);
}