ec28e53b71c12c61921bdd6c465568daff65b713
[jarrpa/prequel.git] / src / daemon / PrequelD.c
1 /* ========================================================================== **
2  *                                 PrequelD.c
3  *
4  * Copyright:
5  *  Copyright (C) 2012 by Christopher R. Hertel
6  *
7  * Email: crh@ubiqx.mn.org
8  *
9  * $Id: PrequelD.c; 2014-09-22 17:14:11 -0500; Christopher R. Hertel$
10  *
11  * -------------------------------------------------------------------------- **
12  *
13  * Description:
14  *  PeerDist protocol server daemon.
15  *
16  * -------------------------------------------------------------------------- **
17  *
18  * License:
19  *
20  *  This program is free software: you can redistribute it and/or modify
21  *  it under the terms of the GNU General Public License as published by
22  *  the Free Software Foundation, either version 3 of the License, or
23  *  (at your option) any later version.
24  *
25  *  This program is distributed in the hope that it will be useful,
26  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
27  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
28  *  GNU General Public License for more details.
29  *
30  *  You should have received a copy of the GNU General Public License
31  *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
32  *
33  * -------------------------------------------------------------------------- **
34  *               This code was developed in participation with
35  *                the Protocol Freedom Information Foundation.
36  *         See http://www.protocolfreedom.org/ for more information.
37  * -------------------------------------------------------------------------- **
38  *
39  * Notes:
40  *
41  *  The Prequel Project website is http://www.ubiqx.org/proj/Prequel/
42  *
43  *  Terminology:
44  *
45  *    PeerDist  - The protocol and/or encoding format used by Microsoft's
46  *                BranchCacheTM distributed caching system.
47  *
48  *    Prequel   - The name of an Open Source project aimed at implementing
49  *                PeerDist for use with Linux, *BSD, and other Unix-like
50  *                OSes.
51  *
52  *  References:
53  *    [BCOVIEW]:    MS W2K8R2 BranchCache Overview
54  *                  http://technet.microsoft.com/en-us/library/dd637832.aspx
55  *
56  *    [MS-CCRSOD]:  Content Caching and Retrieval System Overview
57  *                  http://msdn.microsoft.com/en-us/library/ff632262.aspx
58  *
59  *    [MS-PCCRC]:   Peer Content Caching and Retrieval: Content Identification
60  *                  http://msdn.microsoft.com/en-us/library/dd303704.aspx
61  *
62  *  To Compile:
63  *    cc -I.. -D_FILE_OFFSET_BITS=64 -o PrequelD PrequelD.c \
64  *      PD_peerdist1.c PD_read_config.c PD_sha2_oSSL.c PD_utils.c Gstr.c \
65  *      ../ubi_sLinkList.c -lcrypto -lpthread
66  *
67  *  ToDo:
68  *    + Add support for Unicode pathnames.
69  *
70  *    + The background thread should traverse source directories and generate
71  *      hash caches for any file that meets criteria and does not have an
72  *      up-to-date hash cache file.
73  *
74  *    + The background thread should traverse cache directories and delete
75  *      any cache files that are out-of-date or which map back to a source
76  *      file that no longer exists (or has been truncated to a size that is
77  *      smaller than the minimum).
78  *
79  *    + Add PeerDist v2 support.
80  *
81  *    + Add signal handling:
82  *      - HUP:  Lock the mutex and re-read the config file.  Update directory
83  *              traversal state.
84  *      - TERM: Exit cleanly.
85  *
86  *    + Long-term:  Collect interesting statistics and log them on SIGHUP,
87  *                  SIGTERM, or SIGUSR1.
88  *
89  *    + Add a -s <socket> option to override the socket path in the config
90  *      file.
91  *
92  *    + More consideration should be given to the handling of the "Server
93  *      Secret", which is used to sign the "Segment Hash of Data" to create
94  *      the "Segment Secret".  At present, we just read the "Server Secret"
95  *      from a file.  See the <ReadKeys()> function, below.
96  *
97  *      Two ideas on this:
98  *      - Each sourcedir *may* have its own keyfile.  One of the options for
99  *        the keyfile (possibly the default?) would be to generate a Server
100  *        Secret on the fly.  In that case, the Server Secret would be
101  *        different every time PrequelD is run (which wouldn't be all bad,
102  *        assuming PrequelD is really stable).  It would mean that caches
103  *        would be invalidated every time PrequelD restarts, and that the
104  *        key could not be shared by multiple servers.  Providing this option
105  *        would further require that we allow for an empty keyfile value in
106  *        the config file (which might change the syntax).
107  *      - Server Secrets could be stored AES encrypted, to match the format
108  *        of Server Secrets extracted from Windows servers.  The problem
109  *        with this option is that PrequelD would still need to have access
110  *        to the passphrase used to decrypt the AES-encrypted secrets, so
111  *        we would still have an exposed password.
112  *
113  * FIX:
114  *
115  *  + The 'exclude' configuration command doesn't yet work.
116  *
117  *  + Need to detect whether we are running already or not.  We can run
118  *    multiple daemons at once, as long as their src directories don't
119  *    overlap and they are using different sockets.  Add a PID file path
120  *    to the configuration, default to /var/run/prequel.pid
121  *
122  *  + We implement a QUERY command over the Unix domain socket.  Its purpose
123  *    is to return the pathname of a cache file given the pathname of the
124  *    source file.  Cool.
125  *
126  *    Problem is, the current implementation of the QUERY does not include
127  *    the PeerDist major/minor numbers, so we can only return the least
128  *    common denominator (1.0).  The QUERY command needs to be changed to
129  *    pass version numbers, or to *optionally* pass version numbers when
130  *    the least common denominator is not being requested.
131  *
132  * ========================================================================== **
133  */
134
135 #include <time.h>           /* For nanosleep(2).                        */
136 #include <stdlib.h>         /* Standard Library.                        */
137 #include <stdbool.h>        /* Standard boolean type.                   */
138 #include <stdint.h>         /* Standard extended integer types.         */
139 #include <unistd.h>         /* For getopt(3), close(2), unlink(2), etc. */
140 #include <string.h>         /* For strerror(3), strchr(3).              */
141 #include <stdarg.h>         /* Standard variable argument lists.        */
142 #include <ctype.h>          /* For isspace(3) and iscntrl(3).           */
143 #include <sys/types.h>      /* For the pid_t and DIR* types.            */
144 #include <dirent.h>         /* For reading directory entries.           */
145 #include <pthread.h>        /* For POSIX Threads.                       */
146 #include <poll.h>           /* For ppoll(2) and struct pollfd.          */
147 #include <sys/socket.h>     /* Socket(7) interface header.              */
148 #include <sys/un.h>         /* Unix(7) domain sockets.                  */
149 #include <sys/time.h>       /* The timeval struct and gettimeofday(2).  */
150
151 #include "PD_peerdist1.h"   /* PeerDist v1 protocol support.  */
152 #include "PD_read_config.h" /* Read the configuration file.   */
153 #include "PD_utils.h"       /* General PrequelD utilities.    */
154 #include "ubi_sLinkList.h"  /* Linked List module.            */
155 #include "Gstr.h"           /* Growable string buffers.       */
156
157
158 /* -------------------------------------------------------------------------- **
159  * Defined Constants:
160  *
161  *  DEFAULT_CONFIG_FILE - Default pathname of the configuration file to read
162  *                        on startup.  This value can be overridden at
163  *                        compile time.
164  *
165  *  SYSLOG_NAME         - The name used to identify this program in Syslog
166  *                        logs.
167  *
168  *  RECV_TIMEOUT        - Number of seconds and microseconds to listen on
169  *                        an input socket while receiving data.  Formated
170  *                        as an initialization pair: { <sec>, <usec> }.
171  *                        1usec = 1/1000000sec (10^-6, or 1/1000msec)
172  *
173  *  POLL_TIMEOUT        - Number of milliseconds to wait when poll(2)ing
174  *                        an input socket.  1msec = 1/1000sec == 1000usec.
175  *
176  *  bSIZE               - A buffer size used to allocate the read buffer
177  *                        included in the <RecvBufr> structure.
178  */
179
180 #ifndef DEFAULT_CONFIG_FILE
181 #define DEFAULT_CONFIG_FILE "/etc/prequeld/pd.conf"
182 #endif
183
184 #define SYSLOG_NAME "prequeld"
185
186 #define RECV_TIMEOUT { 2, 0 }     /*  2 seconds.  */
187 #define POLL_TIMEOUT 30000        /* 30 seconds.  */
188
189 #define bSIZE 1024
190
191
192 /* -------------------------------------------------------------------------- **
193  * Macros:
194  *
195  *  forEach( V, L ) - A macro for traversing a linked list of <pd_ConfigRec>
196  *                    records. This is just a simplified way of expressing a
197  *                    linked-list traversal using a "for" loop.  Think of it
198  *                    as "for each <V> in <L>".
199  *                    V - The variable that will point to each node in the
200  *                        list.  <V> must be substituted with a pointer to a
201  *                        <pd_ConfigRec> structure.
202  *                    L - The list to be traversed.
203  *
204  */
205
206 #define forEach( V, L ) \
207         for( (V) = (pd_ConfigRec *)ubi_slFirst( (L) ); \
208              NULL != (V); \
209              (V) = (pd_ConfigRec *)ubi_slNext( (V) ) )
210
211
212 /* -------------------------------------------------------------------------- **
213  * Typedefs:
214  *
215  *  RangeVal  - Used to read and interpret the value of the Range: option,
216  *              which may be sent by the client.  If <given> is false, the
217  *              we know that the client did not provide a value.  If <given>
218  *              is true, then the client did provide a value and that value
219  *              is stored in the <val> field.
220  *
221  *  WorkItem  - A queue entry and a string pointer pointing to the pathname
222  *              of a source file that is in need of hashing.
223  *
224  */
225
226 typedef struct
227   {
228   bool      given;        /* Was a value given. */
229   uint64_t  val;          /* The given value.   */
230   } RangeVal;
231
232 typedef struct
233   {
234   ubi_slNode  node;       /* Linked list node.  */
235   char       *srcPath;    /* Source file path.  */
236   } WorkItem;
237
238
239 /* -------------------------------------------------------------------------- **
240  * Global Constants:
241  *
242  *  Copyright   - Copyright information.
243  *  License     - License information string.
244  *  Revision    - Revision string, generated by revision control.
245  *  Id          - Longer revision string.
246  *
247  *  HelpMsg     - The program help message.
248  *  VerboseMsg  - Verbose help message.
249  */
250
251 static const char *Copyright =
252                     "Copyright (c) 2012 by Christopher R. Hertel";
253 static const char *License =
254                     "License: GNU General Public License version 3 (GPLv3)\n"
255                     "         http://www.gnu.org/licenses/gpl-3.0.html";
256 static const char *Revision =
257                     "$Revision$";
258 static const char *Id =
259                     "$Id: PrequelD.c; 2014-09-22 17:14:11 -0500; Christopher R. Hertel$";
260
261 static const char *HelpMsg[] =
262   {
263   "  Available Options:",
264   "  -c <file> Specify the configuration file to use.",
265   "  -f        Run in the foreground, not as a daemon.",
266   "  -h        Produce this useful help message, then exit (-hv == more help).",
267   "  -l <file> Send log messages to <file>.",
268   "  -q        Be quiet.  Set the verbosity level to zero.",
269   "  -t        Test-parse the configuration file, then exit.",
270   "  -v        Be verbose.  Add more -v's for more verbosity.",
271   "  -V        Output version information.",
272   NULL
273   };
274
275 static const char *VerboseMsg[] =
276   {
277   "The Options Available to You:",
278   "  -c <file> Specify the configuration file to use.",
279   "            Default: \"" DEFAULT_CONFIG_FILE "\".",
280   "  -f        Run in the foreground, not as a daemon.",
281   "            Default: Run as a daemon.",
282   "  -h        Produce a useful help message, then exit.",
283   "            Default: Don't produce a useful help message.  Run normally.",
284   "  -l <file> Send log messages to <file>.",
285   "            Default:  When running in the foreground, log messages are sent",
286   "                      to <stderr>.  When running in the background, log",
287   "                      messages are sent to syslog.  All initial messages",
288   "                      (as the program starts up) are sent to <stdout> or",
289   "                      <stderr>.",
290   "  -q        Be quiet.  Set the verbosity level to zero (0) and produce only",
291   "            the minimum set of diagnostic messages.  Default verbosity: 1.",
292   "  -t        Parse the configuration file and report any errors to <stderr>.",
293   "            The program will exit once parsing is complete.",
294   "            Use -tv to dump the contents of a successfully parsed",
295   "            configuration file.",
296   "  -v        Be verbose.  Add more -v's for more verbosity.",
297   "            Use of -q or -v overrides the config file verbosity settings.",
298   "            Default verbosity: 1.",
299   "  -V        Output version information.",
300   "            Increased verbosity provides copyright and license information.",
301   NULL
302   };
303
304
305 /* -------------------------------------------------------------------------- **
306  * Global Variables:
307  *
308  *  Verbosity     - Controls the level of diagnostic messages that are
309  *                  produced.  The minimum value is 0.  Anything above 10
310  *                  is ridiculous.  Default: 1.  A maximum value of 255
311  *                  is enforced both in the PD_read_config module and in
312  *                  <ReadOpts()> function, below.
313  *
314  *  Daemonize     - By default PrequelD will run as a daemon, but this
315  *                  default behavior can be overridden with a command-line
316  *                  option.  There is no configuration file option for this,
317  *                  so we use a global variable to represent this attribute.
318  *
319  *  Cfg           - Pointer used to retrieve the configuration information
320  *                  from the configuration file.
321  *
322  *  WorkerThread  - The thread ID of the background thread that is doing all
323  *                  of the real work (that is, generating and maintaining
324  *                  hash files).  The "foreground" thread communicates with
325  *                  clients.
326  *
327  *  GlobalMutex   - A global mutex attribute.  The worker thread needs brief
328  *                  access to the <Cfg> list and other state attribues.
329  *                  This allows the foreground and background to share.
330  *
331  *  Shutdown      - Used to let the worker process know when it is time to
332  *                  shut down and return.
333  *
334  *  WorkQueue     - A queue of source file names that are waiting to be
335  *                  hashed.  The queue is filled when a request is made
336  *                  and no hash cache file is found.  It is emptied by
337  *                  the worker thread.  Queued entries have priority over
338  *                  source files found during directory traversal.
339  */
340
341 static unsigned int     Verbosity     = 1;
342 static bool             Daemonize     = true;
343 static pd_Config       *Cfg           = NULL;
344 static pthread_t        WorkerThread;
345 static pthread_mutex_t  GlobalMutex   = PTHREAD_MUTEX_INITIALIZER;
346 static bool             Shutdown      = false;
347 static ubi_slList       WorkQueue[1];
348
349
350 /* -------------------------------------------------------------------------- **
351  * Static Functions:
352  */
353
354 static void Usage( const char *progname, int status )
355   /* ------------------------------------------------------------------------ **
356    * Provide usage information, then exit.
357    *
358    *  Input:  progname  - Pointer to a string containing the program name.
359    *          status    - Exit status to return.
360    *
361    *  Output: <none>
362    *
363    *  Notes:  Output is sent to <stdout> so that it can be piped through
364    *          'more' or 'less' or something else.
365    *
366    * ------------------------------------------------------------------------ **
367    */
368   {
369   int          i;
370   const char **msg = (Verbosity > 1) ? VerboseMsg : HelpMsg;
371
372   Say( "Usage: %s [options]\n", progname );
373   for( i = 0; NULL != msg[i]; i++ )
374     Say( "%s\n", msg[i] );
375
376   exit( status );
377   } /* Usage */
378
379
380 static void LockLog( char *fmt, ... )
381   /* ------------------------------------------------------------------------ **
382    * Lock/unlock the global mutex to safely write a log message.
383    *
384    *  Input:  fmt - Format string, as used in printf(), etc.
385    *          ... - Variable parameter list.
386    *
387    *  Output: <none>
388    *
389    *  Notes:  A simple wrapper around <vLog()> in PD_utils.
390    *
391    *  See:    <PD_utils.vLog()>
392    *
393    * ------------------------------------------------------------------------ **
394    */
395   {
396   va_list ap;
397
398   if( 0 == pthread_mutex_lock( &GlobalMutex ) )
399     {
400     va_start( ap, fmt );
401     vLog( fmt, ap );
402     va_end( ap );
403     (void)pthread_mutex_unlock( &GlobalMutex );
404     }
405   } /* LockLog */
406
407
408 static void deltaTval( struct timeval *tval )
409   /* ------------------------------------------------------------------------ **
410    * Calculate the difference between then and now.
411    *
412    *  Input:  tval  - A pointer to a timeval structure containing an initial
413    *                  time (start time).  The contents of <tval> will be
414    *                  updated to indicate the difference in time between
415    *                  the initial time and the current time.
416    *
417    *  Output: <none>
418    *
419    *  Notes:  If the contents of <tval> are all zero or <tval> is ahead of
420    *          the current time, the input is considered to be invalid and
421    *          <tval> will be returned with all zeros to indicate the error.
422    *
423    *  See:    gettimeofday(2)
424    *
425    * ------------------------------------------------------------------------ **
426    */
427   {
428   struct timeval now_tv[1];
429   struct timeval result = { 0, 0 };
430
431   /* Is the input valid?  */
432   if( (0 != tval->tv_sec) || (0 != tval->tv_usec) )
433     {
434     /* Attempt to get the current time. */
435     if( 0 == gettimeofday( now_tv, NULL ) )
436       {
437       /* <now_tv> must be greater than <tval>.  */
438       if( (now_tv->tv_sec > tval->tv_sec)
439        || ((now_tv->tv_sec == tval->tv_sec)
440         && (now_tv->tv_usec > tval->tv_usec)) )
441         {
442         result.tv_sec = now_tv->tv_sec - tval->tv_sec;
443         if( now_tv->tv_usec > tval->tv_usec )
444           result.tv_usec = now_tv->tv_usec - tval->tv_usec;
445         else
446           {
447           result.tv_sec--;
448           result.tv_usec = (1000000 - tval->tv_usec) + now_tv->tv_usec;
449           }
450         }
451       }
452     }
453
454   *tval = result;
455   return;
456   } /* deltaTval */
457
458
459 FIX: HERE!
460
461
462 static void *Responder( void *sockptr )
463   /* ------------------------------------------------------------------------ **
464    * Respond to requests from a client.
465    *
466    *  Input:  sockptr - A pointer to an integer, which is the open
467    *                    communications socket.
468    *
469    *  Output: <none>
470    *
471    *  Notes:  This is, essentially, the mainline of a thread that is
472    *          spawned to deal with a single client connection.  It
473    *          handles requests from the client until the client closes
474    *          the connection.
475    *
476    *  See:    The <Readme.txt> file includes the definition of the simple
477    *          client/server protocol.
478    *
479    * ------------------------------------------------------------------------ **
480    */
481   {
482   int             client_sock = *((int *)thingy);     /* Copy the socked id.  */
483   bool            run   = true;                       /* Ready to run.        */
484   struct timeval  tv[1] = { RECV_TIMEOUT };
485   RecvBufr        Rb[1];
486   struct pollfd   pfd[1];
487   int             result;
488
489   /* Free unused memory and detach the thread so we can just exit when done.  */
490   free( thingy );
491   (void)pthread_detach( pthread_self() );
492
493   /* Log entry to let the world know we're running. */
494   if( Verbosity > 2 )
495     LockLog( "Responder() running to handle a new connection.\n" );
496
497   /* Set a timeout on the i/o socket. */
498   if( setsockopt( client_sock, SOL_SOCKET, SO_RCVTIMEO,
499                   (void *)tv, sizeof( struct timeval ) ) )
500     {
501     /* This should never happen. */
502     LockLog( "Error setting timeout on socket; %s.\n", ErrStr );
503     run = false;
504     }
505
506   /* Read and handle request messages, one at a time.  */
507   while( run )
508     {
509     }
510
511   /* All done.  Close the socket and the thread.  */
512   (void)close( client_sock );
513   return( NULL );
514   } /* Responder */
515
516
517 static void Listener( const int lsock )
518   /* ------------------------------------------------------------------------ **
519    * Listen for incomming connection requests and spawn responder threads.
520    *
521    *  Input:  lsock - Listening socket.
522    *
523    *  Output: <none>
524    *
525    *  Notes:  This function is run within the primary thread, but it is
526    *          started after the worker thread has been spun off so it
527    *          must lock the global mutex before accessing any commonly
528    *          used objects.
529    *
530    *          We allocate an integer from the heap, copy the socket number,
531    *          and pass the pointer to the child.  This is done in part to
532    *          avoid an annoying problem.  On 64-bit systems (it seems) the
533    *          integer type is a different size than the void * type.  Doing
534    *          things the old fashioned way (casting the int to void * and
535    *          then casting back within the child) generates a legitimate
536    *          warning.  Casting between different size types may not work
537    *          as we would expect.
538    *
539    *          As long as we can get the integer from memory, this method is
540    *          more 'correct'... sort of.
541    *
542    *  See Also: <Responder()>
543    *
544    * ------------------------------------------------------------------------ **
545    */
546   {
547   int       newSock;
548   int       result = 0;
549   int      *parptr;
550   pthread_t threadhandle;
551
552   /* Wait for connection requests, then spawn off threads to handle the
553    * incoming connections.
554    */
555   while( (newSock = accept( lsock, NULL, NULL )) >= 0 )
556     {
557     parptr = (int *)malloc( sizeof( int ) );
558     if( NULL != parptr )
559       {
560       *parptr = newSock;
561       result  = pthread_create( &threadhandle, NULL, &Responder, parptr );
562       }
563     if( (NULL == parptr) || result )      /* Check for problems.  */
564       {
565       if( 0 == pthread_mutex_lock( &GlobalMutex ) )
566         {
567         if( NULL == parptr )
568           {
569           LogX( EXIT_FAILURE,
570                 "Failure: Memory allocation failure creating subthread.\n" );
571           }
572         else
573           {
574           /* We free <parptr> here because the subthread was not created.
575            *  Normally, <parptr> would be freed by the subthread.
576            */
577           Log( "Warning: Error creating responder subthread; %s.\n",
578                strerror( result ) );
579           free( parptr );
580           }
581         (void)pthread_mutex_unlock( &GlobalMutex );
582         }
583       (void)close( newSock );
584       }
585     }
586
587   /* Lock the mutex to write the error message to the log.
588    *  To get here, there must have been an error returned by <accept()>.
589    */
590   if( 0 == pthread_mutex_lock( &GlobalMutex ) )
591     {
592     /* The pthread lock does not modify errno, so we don't need to store it.  */
593     Log( "Failure: Error accepting socket connection; %s.\n", ErrStr );
594     (void)pthread_mutex_unlock( &GlobalMutex );
595     }
596   close( lsock );
597   } /* Listener */
598
599
600 static void WorkHash( const char *srcPathName )
601   /* ------------------------------------------------------------------------ **
602    * Create a hash cache file given a source file name.
603    *
604    *  Input:  srcPathName - The pathname of the source file to be hashed.
605    *
606    *  Output: <none>
607    *
608    *  Notes:  Dancing with the mutex.
609    *
610    * ------------------------------------------------------------------------ **
611    */
612   {
613   pd_ConfigRec  *entry;                   /* Configuration record pointer.    */
614   char          *cacheDir;                /* Copy of the cacheDir path.       */
615   int            minBlocks;               /* Minimum source file block size.  */
616   pd_v1HashType  hashType;                /* Type of hash to be used.         */
617   unsigned char  key[PD_V1_KEY_SIZE];     /* SourceDir's Server Secret.       */
618   int            result;                  /* Store function call return val.  */
619   int            syserr;                  /* Store returned system error val. */
620   struct timeval tval[1];                 /* For calculating hash times.      */
621
622   /* Try to grab the mutex.
623    *  If we can't grab the mutex, then something's wrong but we cannot log it
624    *  because we need the mutex in order to (safely) write to the log.  We'll
625    *  have to bail out.
626    */
627   if( 0 != pthread_mutex_lock( &GlobalMutex ) )
628     return;
629
630   /* We have mutex.
631    *  Find the config record that points to the source directory tree in
632    *  which the source file resides.
633    */
634   entry = pd_FindSrcDir( Cfg, srcPathName );
635   if( NULL == entry )
636     {
637     if( Verbosity > 1 )
638       Log( "Queued file is not in scope: %s\n", srcPathName );
639     (void)pthread_mutex_unlock( &GlobalMutex );
640     return;
641     }
642   /* This should be impossible.
643    *  Check PD_read_config if this ever happens.
644    */
645   if( NULL == (entry->cacheDir) )
646     {
647     Log( "Warning: Bad configuration entry; cacheDir is NULL.\n" );
648     (void)pthread_mutex_unlock( &GlobalMutex );
649     return;
650     }
651
652   /* We have mutex and a configuration entry.
653    *  Copy all of the config values so that we can release the mutex.
654    */
655   cacheDir  = strdup( entry->cacheDir );
656   minBlocks = entry->minBlocks;
657   hashType  = entry->v1HashType;
658   syserr    = 0;
659   (void)memcpy( key, entry->userParam, PD_V1_KEY_SIZE );
660   /* Unlock the mutex.  */
661   (void)pthread_mutex_unlock( &GlobalMutex );
662
663   /* Check that the <cacheDir> copy was successfully created. */
664   if( NULL == cacheDir )
665     {
666     if( Verbosity )
667       Log( "Warning: Memory allocation failure in WorkHash().\n" );
668     return;
669     }
670
671   /* If anyone knows any reason why this hash file should not be created,
672    *  speak now...
673    */
674   result = pd_v1ShouldHash( srcPathName, cacheDir, minBlocks );
675   if( pd_Success != result )
676     {
677     if( Verbosity > 1 )
678       {
679       Log( "Won't hash %s; %s.\n", srcPathName,
680            pd_v1StrResult( result ) );
681       }
682     free( cacheDir );
683     return;
684     }
685
686   /* If we're going to output timing, try to get the start time.
687    *  Set the start time to zero if the gettimeofday(2) call fails.
688    */
689   if( (Verbosity > 2) && (0 != gettimeofday( tval, NULL )) )
690     tval->tv_sec = tval->tv_usec = 0;
691
692   /* Now do the hashing.  */
693   result = pd_v1CreateHashCache( srcPathName,
694                                  cacheDir,
695                                  hashType,
696                                  key,
697                                  &syserr );
698   /* Optionally generate the delta time.  */
699   if( Verbosity > 2 )
700     deltaTval( tval );
701   /* Clean up. */
702   free( cacheDir );
703
704   /* If we're not going to (or can't) report anything, we're done.  */
705   if( (Verbosity < 1) || (0 != pthread_mutex_lock( &GlobalMutex )) )
706     return;
707
708   /* Report the results.
709    *  It is not a fatal error to fail to create the cache file, but it should
710    *  probably be logged.  Logging requires the mutex.
711    */
712   if( pd_Success == result )
713     {
714     if( Verbosity > 2 )
715       {
716       if( (0 != tval->tv_sec) || (0 !=tval->tv_usec) )
717         {
718         int m  = ((tval->tv_sec) / 60);
719         int s  = ((tval->tv_sec) - (m * 60));
720         int ms = ((tval->tv_usec) / 1000);
721
722         if( ((tval->tv_usec) - (ms * 1000)) >= 500 )
723           ++ms;
724         Log( "  Hashed: %s in %0dm%0d.%0.3ds.\n", srcPathName, m, s, ms );
725         }
726       else
727         Log( "  Hashed: %s.\n", srcPathName );
728       }
729     }
730   else
731     {
732     if( syserr )
733       Log( "Failure hashing %s; %s; %s.\n", srcPathName,
734            pd_v1StrResult( result ), strerror( syserr ) );
735     else
736       Log( "Failure hashing %s; %s.\n", srcPathName,
737            pd_v1StrResult( result ) );
738     }
739
740   /* And release the mutex again. */
741   (void)pthread_mutex_unlock( &GlobalMutex );
742   } /* WorkHash */
743
744
745 static void *WorkerMain( void *thingy )
746   /* ------------------------------------------------------------------------ **
747    * Worker thread mainline.
748    *
749    *  Input:  thingy  - Pointer to an opaque blob that currently isn't used.
750    *                    This is the <void *arg> parameter to
751    *                    pthread_create(3).
752    *
753    *  Output: Always returns NULL.
754    *
755    *  Notes:  This function is the mainline of a background thread.  It's
756    *          job is to generate the hash cache files.
757    *
758    *  FIX:    The wDir state is designed to allow the worker thread to
759    *          traverse configured source directories and hash files that
760    *          have not been requested yet.  The requested files, listed
761    *          in the <WorkQueue> have higher priority.  Unfortunately,
762    *          directory traversal has not been implemented yet.
763    *
764    *          In addition, we should traverse the cache directories and
765    *          purge cache files that are out of date or for which the
766    *          source file no longer exists.
767    *
768    * ------------------------------------------------------------------------ **
769    */
770   {
771   static enum { wNone, wStop, wQueue, wDir } doState;   /* What shall we do?  */
772   static struct timespec ts = { 0, 500000000 };         /* Half a second.     */
773   WorkItem              *srcEntry = NULL;
774
775   do
776     {
777     /* Start our loop by waiting a half second, just to pace ourselves. */
778     (void)nanosleep( &ts, NULL );
779
780     /* Determine which action to take, and collect any required data.
781      *  This requires locking/unlocking the global mutex.
782      */
783     doState = wNone;      /* Default action.  */
784     if( 0 == pthread_mutex_lock( &GlobalMutex ) )
785       {
786       /* Note:  See pthread_mutex_lock(3).  We do not check for an error
787        *        because none of the listed possibilities are at all likely
788        *        to occurr and, if an error were to occur, we don't have a
789        *        sensible way of handling it (other than to wait and retry).
790        */
791       if( Shutdown )
792         doState = wStop;
793       else
794         {
795         if( 0 == ubi_slCount( WorkQueue ) )
796           doState = wDir;
797         else
798           {
799           srcEntry = (WorkItem *)ubi_slDequeue( WorkQueue );
800           if( (NULL != srcEntry) && (NULL != srcEntry->srcPath) )
801             {
802             doState = wQueue;
803             if( Verbosity > 2 )
804               Log( "Dequeued: %s\n", srcEntry->srcPath );
805             }
806           else
807             Log( "Error: NULL entry in priority queue.\n" );
808           }
809         }
810       (void)pthread_mutex_unlock( &GlobalMutex );
811       }
812
813     /* Now do the thing.  */
814     switch( doState )
815       {
816       case wQueue:
817         /* Hash an entry from the queue, then free the entry as a whole.  */
818         if( srcEntry )
819           {
820           WorkHash( srcEntry->srcPath );
821           free( srcEntry );
822           }
823         break;
824       case wDir:
825         /* Hash an entry from a source directory. */
826         /* FIX: Need directory traversal. */
827         break;
828       default:
829         break;
830       }
831
832     } while( wStop != doState );
833
834   return( NULL );
835   } /* WorkerMain */
836
837
838 static void StartWorker( void )
839   /* ------------------------------------------------------------------------ **
840    * Start a background thread to generate hash cache files.
841    *
842    *  Input:  <none>
843    *  Output: <none>
844    *
845    *  Notes:  The worker thread does the work of creating hash cache files
846    *          from source content.  It runs separately so that it does not
847    *          interfere with communication with our clients.
848    *
849    *          <WorkerThread> is a global variable.
850    *          <WorkerMain()> is is the "mainline" of the worker thread.
851    *
852    * ------------------------------------------------------------------------ **
853    */
854   {
855   int            result;
856   pthread_attr_t attr[1];
857
858   /* Set up the attributes to make the thread joinable, then start it.  */
859   if( (result = pthread_attr_init( attr )) )
860     LogX( EXIT_FAILURE, "Failure initializing worker thread attributes; %s.\n",
861           strerror( result ) );
862
863   if( (result = pthread_attr_setdetachstate( attr, PTHREAD_CREATE_JOINABLE )) )
864     LogX( EXIT_FAILURE,
865           "Failure setting \"joinable\" attribute for worker thread; %s.\n",
866           strerror( result ) );
867
868   if( (result = pthread_create( &WorkerThread, attr, WorkerMain, NULL )) )
869     LogX( EXIT_FAILURE, "Failure spawning worker thread; %s.\n",
870           strerror( result )  );
871   } /* StartWorker */
872
873
874 static int OpenListenSock( const char *sockpath )
875   /* ------------------------------------------------------------------------ **
876    * Open a Unix Domain socket and set it to listen for connection requests.
877    *
878    *  Input:  sockpath  - The pathname of the Unix Domain socket to be
879    *                      opened for listening.
880    *
881    *  Output: The opened and listening socket.
882    *          Only a valid value will be returned.  On error, this function
883    *          will exit the program.
884    *
885    *  Notes:  We call this prior to spinning off any threads, so we can avoid
886    *          locking the global mutex.
887    *
888    * ------------------------------------------------------------------------ **
889    */
890   {
891   struct sockaddr_un laddr[1];
892   int                lsock;
893
894   /* Sanity check.
895    * We must be able to fit the socket path into a Unix Domain socket address.
896    */
897   if( strlen( sockpath ) >= sizeof( laddr->sun_path ) )
898     {
899     LogX( EXIT_FAILURE,
900           "Annoyance: Path '%s' exceeds maximum unix domain address length.\n",
901           sockpath );
902     }
903
904   /* Create a unix domain socket. */
905   lsock = socket( AF_UNIX, SOCK_STREAM, 0 );
906   if( lsock < 0 )
907     {
908     LogX( EXIT_FAILURE,
909           "Failure: Unable to create unix domain socket; %s.\n", ErrStr );
910     }
911
912   /* Bind the socket to the name within the namespace. */
913   (void)unlink( sockpath );
914   (void)memset( laddr, 0, sizeof( struct sockaddr_un ) );
915   laddr->sun_family = AF_UNIX;
916   (void)strcpy( laddr->sun_path, sockpath );
917   if( bind( lsock, (struct sockaddr *)laddr, sizeof( laddr ) ) < 0 )
918     {
919     (void)close( lsock );
920     LogX( EXIT_FAILURE,
921           "Failure: Socket bind() to '%s' failed; %s.\n", sockpath, ErrStr );
922     }
923
924   /* Set the socket to listen. */
925   if( listen( lsock, 32 ) < 0 )
926     {
927     (void)close( lsock );
928     (void)unlink( sockpath );
929     LogX( EXIT_FAILURE,
930           "Failure: Cannot listen on unix domain socket '%s'; %s.\n",
931           sockpath, ErrStr );
932     }
933
934   return( lsock );
935   } /* OpenListenSock */
936
937
938 static void Spawn( void )
939   /* ------------------------------------------------------------------------ **
940    * Spawn a daemon process, which will take over control for us.
941    *
942    *  Input:  <none>
943    *  Output: <none>
944    *
945    *  Notes:  This function causes the program to run in the background.
946    *
947    *          If the child process is created successfully, the parent
948    *          process is terminated using _exit(2).  This bypasses executing
949    *          any functions registered with atexit(3) or on_exit(3).  We
950    *          don't have any such functions but, even so, this is the normal
951    *          way to exit the parent process.
952    *          See: http://www.steve.org.uk/Reference/Unix/faq_2.html#SEC6
953    *
954    * ------------------------------------------------------------------------ **
955    */
956   {
957   pid_t pid = fork();
958
959   if( pid < 0 )   /* Error. */
960     LogX( EXIT_FAILURE, "Cannot spawn child process; %s\n", ErrStr );
961
962   if( pid > 0 )   /* Parent process; just exit. */
963     _exit( EXIT_SUCCESS );
964
965   /* Child process.
966    */
967   if( setsid() < 0 )
968     LogX( EXIT_FAILURE, "Failure: setsid(2) failed in Spawn(); %s.\n", ErrStr );
969   if( Verbosity )
970     Log( "Process %d spawned.\n", getpid() );
971   /* Close standard file descriptors. */
972   close(  STDIN_FILENO );
973   close( STDOUT_FILENO );
974   close( STDERR_FILENO );
975   return;
976   } /* Spawn */
977
978
979 static void ReadKeys( void )
980   /* ------------------------------------------------------------------------ **
981    * Read and store the server secret signing keys from the key files.
982    *
983    *  Input:  <none>
984    *  Output: <none>
985    *
986    *  Notes:  The signing key is officially known as the "Server Secret".
987    *          See the definition of Server Secret in [MS-PCCRC], section 1.1.
988    *
989    *          The "Server Secret" is the SHA-256 hash of "an arbitrary length
990    *          binary string stored on the server”.  [MS-PCCRC] does not give
991    *          a name to this arbitrary binary string.  In Prequel
992    *          documentation, it is referred to as the "Server Passphrase".
993    *          So, the Server Secret is the hash of the Server Passphrase.
994    *
995    *          This function makes one or more passes through the sourcedir
996    *          configuration list.  Each time, it finds the first entry
997    *          that has a NULL <userParam> pointer.  It attempts to read the
998    *          signing key from the keyfile.  If it succeeds, it goes
999    *          through the rest of the list looking for matching keyfile
1000    *          names.  If it finds a match, it points the <userParam> of
1001    *          the matching entry to the already-copied key.
1002    *
1003    *          The userParam pointer could be used for storing a more complex
1004    *          structure or other extended information.  Right now, it's only
1005    *          used for storing the signing key.
1006    *
1007    * ------------------------------------------------------------------------ **
1008    */
1009   {
1010   FILE          *keyF;
1011   pd_ConfigRec  *entry;
1012   char          *kfName;
1013   unsigned char *ss = NULL;
1014   size_t         result;
1015
1016   do
1017     {
1018     kfName = NULL;
1019     forEach( entry, Cfg )   /* Read ConfigRec entries sequentially. */
1020       {
1021       if( NULL == entry->userParam )
1022         {
1023         if( NULL == kfName )
1024           {
1025           kfName = entry->keyFileName;
1026           if( NULL == (ss = (unsigned char *)malloc( PD_V1_KEY_SIZE )) )
1027             LogX( EXIT_FAILURE,
1028                   "Failure: malloc(3) failed in ReadKeys(); %s.\n", ErrStr );
1029           if( NULL == (keyF = fopen( kfName, "r" )) )
1030             LogX( EXIT_FAILURE,
1031                   "Failure: Could not open keyfile %s; %s.\n", kfName, ErrStr );
1032           result = fread( ss, 1, PD_V1_KEY_SIZE, keyF );
1033           if( PD_V1_KEY_SIZE != result )
1034             LogX( EXIT_FAILURE,
1035                   "Failure: Only %d bytes in keyfile %s.\n", result, kfName );
1036           (void)fclose( keyF );
1037           entry->userParam = ss;
1038           }
1039         else
1040           {
1041           if( 0 == strcmp( kfName, entry->keyFileName ) )
1042             entry->userParam = ss;
1043           }
1044         }
1045       }
1046     } while( NULL != kfName );
1047
1048   } /* ReadKeys */
1049
1050
1051 static void ReadConfig( char *fname )
1052   /* ------------------------------------------------------------------------ **
1053    * Open, read, and interpret the configuration file.
1054    *
1055    *  Input:  fname - The name of the file to open, or NULL.
1056    *                  If <fname> is NULL, then the default file name will
1057    *                  be used.
1058    *
1059    *  Output: <none>
1060    *
1061    *  Notes:  The configuration file format was inspired, somewhat, by the
1062    *          format of the ISC dhcpd.conf file.
1063    *
1064    * ------------------------------------------------------------------------ **
1065    */
1066   {
1067   FILE *configF;
1068
1069   /* Ensure that we have a configurage file pathname,
1070    * then attempt to open the file for reading.
1071    */
1072   if( NULL == fname )
1073     fname = DEFAULT_CONFIG_FILE;
1074   if( NULL == (configF = fopen( fname, "r" )) )
1075     Fail( "Unable to open configuration file \"%s\" for input; %s.\n",
1076           fname, ErrStr );
1077
1078   /* Parse it.
1079    *  <Cfg> is a global pointer.
1080    */
1081   Cfg = pd_ParseCfg( configF );
1082
1083   /* Close it.
1084    */
1085   fclose( configF );
1086   } /* ReadConfig */
1087
1088
1089 static void ReadOpts( int argc, char *argv[] )
1090   /* ------------------------------------------------------------------------ **
1091    * Interpret any command-line options, and the configuration file.
1092    *
1093    *  Input:  argc  - Count of arguments.
1094    *          argv  - Array of pointers to argument strings.
1095    *
1096    *  Output: <none>
1097    *
1098    *  Notes:  This function also calls <ReadConfig()>, which reads and
1099    *          interprets the configuration file.
1100    *
1101    *          This is quite a workhorse function.  It handles collecting
1102    *          and validating the configuration of the daemon.
1103    *
1104    * ------------------------------------------------------------------------ **
1105    */
1106   {
1107   int           c;
1108   FILE         *LogF;
1109   extern char  *optarg;
1110   extern int    optind;
1111   char         *ConfigFile  = NULL;
1112   char         *LogFile     = NULL;
1113   bool          VerbSet     = false;
1114   bool          SpewHelp    = false;
1115   bool          SpewVersion = false;
1116   bool          TestConfig  = false;
1117
1118   /* Read the arguments.
1119    */
1120   while( (c = getopt( argc, argv, "c:fhl:qtvV" )) >= 0 )
1121     {
1122     switch( c )
1123       {
1124       case 'c':
1125         ConfigFile  = optarg;
1126         break;
1127       case 'f':
1128         Daemonize   = false;
1129         break;
1130       case 'h':
1131         SpewHelp    = true;
1132         break;
1133       case 'l':
1134         LogFile     = optarg;
1135         break;
1136       case 'q':
1137         Verbosity   = 0;
1138         VerbSet     = true;
1139         break;
1140       case 't':
1141         TestConfig  = true;
1142         break;
1143       case 'v':
1144         if( Verbosity < 0xFF )
1145           Verbosity++;
1146         VerbSet     = true;
1147         break;
1148       case 'V':
1149         SpewVersion = true;
1150         break;
1151       default:
1152         /* Unknown option.  Provide simple help, then exit.
1153          */
1154         Verbosity = 0;
1155         Usage( argv[0], EXIT_FAILURE );
1156         break;
1157       }
1158     }
1159
1160   /* Provide version information (and more) if it was requested.
1161    */
1162   if( SpewVersion )
1163     {
1164     Say( "%s\n", Revision );
1165     if( Verbosity )
1166       {
1167       Say( "%s\n", Id );
1168       if( Verbosity > 1 )
1169         {
1170         Say( "%s\n", Copyright );
1171         if( Verbosity > 2 )
1172           {
1173           Say( "%s\n", License );
1174           if( Verbosity > 3 )
1175             {
1176             Say( "Developed in participation with the " );
1177             Say( "Protocol Freedom Information Foundation.\n" );
1178             }
1179           }
1180         }
1181       }
1182     if( SpewHelp )
1183       {
1184       if( Verbosity )
1185         Say( "\n" );
1186       }
1187     else
1188       exit( EXIT_SUCCESS );
1189     }
1190
1191   /* If help was requested, send help.
1192    */
1193   if( SpewHelp )
1194     {
1195     Usage( argv[0], EXIT_SUCCESS );
1196     }
1197
1198   /* If the user requested a configuration file test, provide it and
1199    *  then exit the program.
1200    */
1201   if( TestConfig )
1202     {
1203     (void)setLogFile( stderr );
1204     if( NULL == ConfigFile )
1205       ConfigFile = DEFAULT_CONFIG_FILE;
1206     ReadConfig( ConfigFile );
1207     if( (Verbosity == 1) && (NULL != Cfg) )
1208       Log( "%s: successfully parsed.\n", ConfigFile );
1209     if( Verbosity > 1)
1210       pd_DumpCfg( Cfg );
1211     exit( EXIT_SUCCESS );
1212     }
1213
1214   /* Enable logging.
1215    *  If a log file name was specified, then all messages from this point
1216    *  on will be directed to the log file.
1217    *  If no log file was specified, and we will run as a daemon, then we
1218    *  start logging to syslog().
1219    *  Otherwise, we log to <stderr> unless/until a log file name is given
1220    *  in the configuration file.
1221    */
1222   if( NULL == LogFile )
1223     {
1224     if( Daemonize )
1225       OpenSyslog( SYSLOG_NAME );
1226     else
1227       (void)setLogFile( stderr );
1228     }
1229   else
1230     {
1231     LogF = fopen( LogFile, "a" );
1232     if( NULL == LogF )
1233       Fail( "Unable to open log file \"%s\" for output; %s.\n",
1234             LogFile, ErrStr );
1235     (void)setLogFile( LogF );
1236     }
1237
1238   /* Open and read the configuration file.
1239    *  Command-line options override configfile options.  This is particularly
1240    *  tricky when dealing with logging, which has already started.
1241    */
1242   ReadConfig( ConfigFile );
1243   if( NULL == Cfg )         /* Parsing returned no configuration.  Exit.  */
1244     LogX( EXIT_FAILURE, "Null configuration.  Exiting.\n" );
1245
1246   if( NULL == LogFile )
1247     {
1248     /* We have already started logging to syslog (background) or stderr
1249      * (foreground).  If a log file was specified in the config file, and
1250      * if we are not running in the foreground, use the specified config
1251      * file.
1252      */
1253     if( (NULL != Cfg->logFileName) && Daemonize )
1254       {
1255       LogF = fopen( Cfg->logFileName, "a" );
1256       if( NULL == LogF )
1257         Fail( "Unable to open log file \"%s\" for output; %s.\n",
1258               Cfg->logFileName, ErrStr );
1259       (void)setLogFile( LogF );
1260       }
1261     else
1262       {
1263       /* When writing to <stderr>, don't print timestamps.  */
1264       (void)setLogTimeStamp( false );
1265       }
1266     }
1267   else
1268     {
1269     /* If we have a command-line specified logfile, store it in the Cfg
1270      *  structure for later use.
1271      */
1272     Cfg->logFileName = replaceStr( LogFile, Cfg->logFileName );
1273     }
1274
1275   /* User-set verbosity overrides config file.  */
1276   if( VerbSet )
1277     {
1278     pd_ConfigRec *entry;
1279
1280     forEach( entry, Cfg )
1281       entry->verbosity = (0xFF & Verbosity);
1282     }
1283
1284   } /* ReadOpts */
1285
1286
1287 /* -------------------------------------------------------------------------- **
1288  * Mainline:
1289  */
1290
1291 int main( int argc, char *argv[] )
1292   /* ------------------------------------------------------------------------ **
1293    * Program mainline.
1294    *
1295    *  Input:  argc  - You know what this is.
1296    *          argv  - You know what to do.
1297    *
1298    *  Output: EXIT_SUCCESS or, on failure, EXIT_FAILURE.
1299    *
1300    * ------------------------------------------------------------------------ **
1301    */
1302   {
1303   int listenSock;
1304
1305   /* Gather working parameters.
1306    *  Note that ReadOpts() also takes care of reading the configuration file.
1307    */
1308   ReadOpts( argc, argv );         /* Get all set up to run. */
1309   ReadKeys();                     /* Find the signing keys. */
1310
1311   /* Become a daemon, unless we were told otherwise.  */
1312   if( Daemonize )
1313     Spawn();
1314
1315   /* Before creating any subthreads, let's try to open the listening socket.  */
1316   listenSock = OpenListenSock( Cfg->sockFileName );
1317
1318   /* Initialize the priority queue and start the worker thread. */
1319   (void)ubi_slInitList( WorkQueue );
1320   StartWorker();
1321
1322   /* Listen for incoming requests on the named Unix Domain socket.  */
1323   Listener( listenSock );
1324
1325   /* When we stop listening, it's time to shut down the worker thread.  */
1326   (void)pthread_mutex_lock( &GlobalMutex );
1327   Shutdown = true;
1328   (void)pthread_mutex_unlock( &GlobalMutex );
1329   (void)pthread_join( WorkerThread, NULL );
1330
1331   /* Clean up and exit. */
1332   if( Verbosity )
1333     Log( "Normal exit.\n" );
1334   return( EXIT_SUCCESS );
1335   } /* main */
1336
1337 /* ========================================================================== */