source: box/trunk/bin/bbstored/BackupStoreDaemon.cpp @ 3049

Revision 3049, 9.5 KB checked in by chris, 5 months ago (diff)

Add remote host and port to post-login login message, requested by Pete Jalajas.

  • Property svn:eol-style set to native
Line 
1// --------------------------------------------------------------------------
2//
3// File
4//              Name:    BackupStoreDaemon.cpp
5//              Purpose: Backup store daemon
6//              Created: 2003/08/20
7//
8// --------------------------------------------------------------------------
9
10#include "Box.h"
11
12#include <stdlib.h>
13#include <stdio.h>
14#include <signal.h>
15
16#ifdef HAVE_SYSLOG_H
17        #include <syslog.h>
18#endif
19
20#include "BackupStoreContext.h"
21#include "BackupStoreDaemon.h"
22#include "BackupStoreConfigVerify.h"
23#include "autogen_BackupProtocol.h"
24#include "RaidFileController.h"
25#include "BackupStoreAccountDatabase.h"
26#include "BackupStoreAccounts.h"
27#include "BannerText.h"
28
29#include "MemLeakFindOn.h"
30
31// --------------------------------------------------------------------------
32//
33// Function
34//              Name:    BackupStoreDaemon::BackupStoreDaemon()
35//              Purpose: Constructor
36//              Created: 2003/08/20
37//
38// --------------------------------------------------------------------------
39BackupStoreDaemon::BackupStoreDaemon()
40        : mpAccountDatabase(0),
41          mpAccounts(0),
42          mExtendedLogging(false),
43          mHaveForkedHousekeeping(false),
44          mIsHousekeepingProcess(false),
45          mHousekeepingInited(false),
46          mInterProcessComms(mInterProcessCommsSocket),
47          mpTestHook(NULL)
48{
49}
50
51// --------------------------------------------------------------------------
52//
53// Function
54//              Name:    BackupStoreDaemon::~BackupStoreDaemon()
55//              Purpose: Destructor
56//              Created: 2003/08/20
57//
58// --------------------------------------------------------------------------
59BackupStoreDaemon::~BackupStoreDaemon()
60{
61        // Must delete this one before the database ...
62        if(mpAccounts != 0)
63        {
64                delete mpAccounts;
65                mpAccounts = 0;
66        }
67        // ... as the mpAccounts object has a reference to it
68        if(mpAccountDatabase != 0)
69        {
70                delete mpAccountDatabase;
71                mpAccountDatabase = 0;
72        }
73}
74
75// --------------------------------------------------------------------------
76//
77// Function
78//              Name:    BackupStoreDaemon::DaemonName()
79//              Purpose: Name of daemon
80//              Created: 2003/08/20
81//
82// --------------------------------------------------------------------------
83const char *BackupStoreDaemon::DaemonName() const
84{
85        return "bbstored";
86}
87
88
89// --------------------------------------------------------------------------
90//
91// Function
92//              Name:    BackupStoreDaemon::DaemonBanner()
93//              Purpose: Daemon banner
94//              Created: 1/1/04
95//
96// --------------------------------------------------------------------------
97std::string BackupStoreDaemon::DaemonBanner() const
98{
99        return BANNER_TEXT("Backup Store Server");
100}
101
102
103// --------------------------------------------------------------------------
104//
105// Function
106//              Name:    BackupStoreDaemon::GetConfigVerify()
107//              Purpose: Configuration definition
108//              Created: 2003/08/20
109//
110// --------------------------------------------------------------------------
111const ConfigurationVerify *BackupStoreDaemon::GetConfigVerify() const
112{
113        return &BackupConfigFileVerify;
114}
115
116
117// --------------------------------------------------------------------------
118//
119// Function
120//              Name:    BackupStoreDaemon::SetupInInitialProcess()
121//              Purpose: Setup before we fork -- get raid file controller going
122//              Created: 2003/08/20
123//
124// --------------------------------------------------------------------------
125void BackupStoreDaemon::SetupInInitialProcess()
126{
127        const Configuration &config(GetConfiguration());
128       
129        // Initialise the raid files controller
130        RaidFileController &rcontroller = RaidFileController::GetController();
131
132        std::string raidFileConfig;
133
134        #ifdef WIN32
135                if (!config.KeyExists("RaidFileConf"))
136                {
137                        raidFileConfig = BOX_GET_DEFAULT_RAIDFILE_CONFIG_FILE;
138                }
139                else
140                {
141                        raidFileConfig = config.GetKeyValue("RaidFileConf");
142                }
143        #else
144                raidFileConfig = config.GetKeyValue("RaidFileConf");
145        #endif
146
147        rcontroller.Initialise(raidFileConfig);
148       
149        // Load the account database
150        std::auto_ptr<BackupStoreAccountDatabase> pdb(BackupStoreAccountDatabase::Read(config.GetKeyValue("AccountDatabase").c_str()));
151        mpAccountDatabase = pdb.release();
152       
153        // Create a accounts object
154        mpAccounts = new BackupStoreAccounts(*mpAccountDatabase);
155       
156        // Ready to go!
157}
158
159
160// --------------------------------------------------------------------------
161//
162// Function
163//              Name:    BackupStoreDaemon::Run()
164//              Purpose: Run shim for the store daemon -- read some config details
165//              Created: 2003/10/24
166//
167// --------------------------------------------------------------------------
168void BackupStoreDaemon::Run()
169{
170        // Get extended logging flag
171        mExtendedLogging = false;
172        const Configuration &config(GetConfiguration());
173        mExtendedLogging = config.GetKeyValueBool("ExtendedLogging");
174       
175        // Fork off housekeeping daemon -- must only do this the first
176        // time Run() is called.  Housekeeping runs synchronously on Win32
177        // because IsSingleProcess() is always true
178       
179#ifndef WIN32
180        if(!IsSingleProcess() && !mHaveForkedHousekeeping)
181        {
182                // Open a socket pair for communication
183                int sv[2] = {-1,-1};
184                if(::socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, sv) != 0)
185                {
186                        THROW_EXCEPTION(ServerException, SocketPairFailed)
187                }
188                int whichSocket = 0;
189               
190                // Fork
191                switch(::fork())
192                {
193                case -1:
194                        {
195                                // Error
196                                THROW_EXCEPTION(ServerException, ServerForkError)
197                        }
198                        break;
199                case 0:
200                        {
201                                // In child process
202                                mIsHousekeepingProcess = true;
203                                SetProcessTitle("housekeeping, idle");
204                                whichSocket = 1;
205                                // Change the log name
206                                ::openlog("bbstored/hk", LOG_PID, LOG_LOCAL6);
207                                // Log that housekeeping started
208                                BOX_INFO("Housekeeping process started");
209                                // Ignore term and hup
210                                // Parent will handle these and alert the
211                                // child via the socket, don't want to
212                                // randomly die!
213                                ::signal(SIGHUP, SIG_IGN);
214                                ::signal(SIGTERM, SIG_IGN);
215                        }
216                        break;
217                default:
218                        {
219                                // Parent process
220                                whichSocket = 0;
221                        }
222                        break;
223                }
224               
225                // Mark that this has been, so -HUP doesn't try and do this again
226                mHaveForkedHousekeeping = true;
227               
228                // Attach the comms thing to the right socket, and close the other one
229                mInterProcessCommsSocket.Attach(sv[whichSocket]);
230               
231                if(::close(sv[(whichSocket == 0)?1:0]) != 0)
232                {
233                        THROW_EXCEPTION(ServerException, SocketCloseError)
234                }
235        }
236#endif // WIN32
237
238        if(mIsHousekeepingProcess)
239        {
240                // Housekeeping process -- do other stuff
241                HousekeepingProcess();
242        }
243        else
244        {
245                // In server process -- use the base class to do the magic
246                ServerTLS<BOX_PORT_BBSTORED>::Run();
247
248                if (!mInterProcessCommsSocket.IsOpened())
249                {
250                        return;
251                }
252
253                // Why did it stop? Tell the housekeeping process to do the same
254                if(IsReloadConfigWanted())
255                {
256                        mInterProcessCommsSocket.Write("h\n", 2);
257                }
258
259                if(IsTerminateWanted())
260                {
261                        mInterProcessCommsSocket.Write("t\n", 2);
262                }
263        }
264}
265
266// --------------------------------------------------------------------------
267//
268// Function
269//              Name:    BackupStoreDaemon::Connection(SocketStreamTLS &)
270//              Purpose: Handles a connection, by catching exceptions and
271//                       delegating to Connection2
272//              Created: 2003/08/20
273//
274// --------------------------------------------------------------------------
275void BackupStoreDaemon::Connection(SocketStreamTLS &rStream)
276{
277        try
278        {
279                Connection2(rStream);
280        }
281        catch(BoxException &e)
282        {
283                BOX_ERROR("Error in child process, terminating connection: " <<
284                        e.what() << " (" << e.GetType() << "/" << 
285                        e.GetSubType() << ")");
286        }
287        catch(std::exception &e)
288        {
289                BOX_ERROR("Error in child process, terminating connection: " <<
290                        e.what());
291        }
292        catch(...)
293        {
294                BOX_ERROR("Error in child process, terminating connection: " <<
295                        "unknown exception");
296        }
297}
298       
299// --------------------------------------------------------------------------
300//
301// Function
302//              Name:    BackupStoreDaemon::Connection2(SocketStreamTLS &)
303//              Purpose: Handles a connection from bbackupd
304//              Created: 2006/11/12
305//
306// --------------------------------------------------------------------------
307void BackupStoreDaemon::Connection2(SocketStreamTLS &rStream)
308{
309        // Get the common name from the certificate
310        std::string clientCommonName(rStream.GetPeerCommonName());
311       
312        // Log the name
313        BOX_INFO("Client certificate CN: " << clientCommonName);
314       
315        // Check it
316        int32_t id;
317        if(::sscanf(clientCommonName.c_str(), "BACKUP-%x", &id) != 1)
318        {
319                // Bad! Disconnect immediately
320                BOX_WARNING("Failed login: invalid client common name: " <<
321                        clientCommonName);
322                return;
323        }
324
325        // Make ps listings clearer
326        std::ostringstream tag;
327        tag << "client=" << BOX_FORMAT_ACCOUNT(id);
328        SetProcessTitle(tag.str().c_str());
329        Logging::Tagger tagWithClientID(tag.str());
330
331        // Create a context, using this ID
332        BackupStoreContext context(id, *this, GetConnectionDetails());
333
334        if (mpTestHook)
335        {
336                context.SetTestHook(*mpTestHook);
337        }
338       
339        // See if the client has an account?
340        if(mpAccounts && mpAccounts->AccountExists(id))
341        {
342                std::string root;
343                int discSet;
344                mpAccounts->GetAccountRoot(id, root, discSet);
345                context.SetClientHasAccount(root, discSet);
346        }
347
348        // Handle a connection with the backup protocol
349        BackupProtocolServer server(rStream);
350        server.SetLogToSysLog(mExtendedLogging);
351        server.SetTimeout(BACKUP_STORE_TIMEOUT);
352        try
353        {
354                server.DoServer(context);
355        }
356        catch(...)
357        {
358                LogConnectionStats(id, context.GetAccountName(), rStream);
359                throw;
360        }
361        LogConnectionStats(id, context.GetAccountName(), rStream);
362        context.CleanUp();
363}
364
365void BackupStoreDaemon::LogConnectionStats(uint32_t accountId,
366        const std::string& accountName, const SocketStreamTLS &s)
367{
368        // Log the amount of data transferred
369        BOX_NOTICE("Connection statistics for " << 
370                BOX_FORMAT_ACCOUNT(accountId) << " "
371                "(name=" << accountName << "):"
372                " IN="  << s.GetBytesRead() <<
373                " OUT=" << s.GetBytesWritten() <<
374                " NET_IN=" << (s.GetBytesRead() - s.GetBytesWritten()) <<
375                " TOTAL=" << (s.GetBytesRead() + s.GetBytesWritten()));
376}
Note: See TracBrowser for help on using the repository browser.