1 #ifndef NETSTORAGE_HANDLER__HPP
2 #define NETSTORAGE_HANDLER__HPP
3 
4 /*  $Id: nst_handler.hpp 515877 2016-10-06 14:29:20Z satskyse $
5  * ===========================================================================
6  *
7  *                            PUBLIC DOMAIN NOTICE
8  *               National Center for Biotechnology Information
9  *
10  *  This software/database is a "United States Government Work" under the
11  *  terms of the United States Copyright Act.  It was written as part of
12  *  the author's official duties as a United States Government employee and
13  *  thus cannot be copyrighted.  This software/database is freely available
14  *  to the public for use. The National Library of Medicine and the U.S.
15  *  Government have not placed any restriction on its use or reproduction.
16  *
17  *  Although all reasonable efforts have been taken to ensure the accuracy
18  *  and reliability of the software and data, the NLM and the U.S.
19  *  Government do not and cannot warrant the performance or results that
20  *  may be obtained by using this software or data. The NLM and the U.S.
21  *  Government disclaim all warranties, express or implied, including
22  *  warranties of performance, merchantability or fitness for any particular
23  *  purpose.
24  *
25  *  Please cite the author in any work or product based on this material.
26  *
27  * ===========================================================================
28  *
29  * Authors:  Denis Vakatov
30  *
31  * File Description: NetStorage commands handler
32  *
33  */
34 
35 #include <string>
36 #include <connect/services/json_over_uttp.hpp>
37 #include <corelib/ncbitime.hpp>
38 #include <corelib/request_ctx.hpp>
39 #include <connect/server.hpp>
40 #include <misc/netstorage/netstorage.hpp>
41 
42 #include "nst_clients.hpp"
43 #include "nst_users.hpp"
44 #include "nst_metadata_options.hpp"
45 #include "nst_database.hpp"
46 #include "nst_service_parameters.hpp"
47 #include "nst_timing.hpp"
48 
49 
50 BEGIN_NCBI_SCOPE
51 
52 // Forward declarations
53 class CNetStorageServer;
54 struct SCommonRequestArguments;
55 struct SStorageFlags;
56 struct SICacheSettings;
57 struct SUserKey;
58 
59 
60 // Helper class to make sure the current request context is reset at the end of
61 // the scope
62 class CRequestContextResetter
63 {
64     public:
65         CRequestContextResetter();
66         ~CRequestContextResetter();
67 };
68 
69 
70 // Helper class to make sure the pushed IMessageListener is popped
71 // approprietely at the end of the scope
72 class CMessageListenerResetter
73 {
74     public:
75         CMessageListenerResetter();
76         ~CMessageListenerResetter();
77 };
78 
79 
80 // The CRelocateCallback is used to provide a callback during the RELOCATE
81 // message processing. The NetStorageAPI Relocate call is synchronous so
82 // it may take a long time within which the client socket could time out.
83 // The callback is called after each portion of data is relocated so it is
84 // a good suitable point to send a heartbeat message to the client. The
85 // heartbeat - in addition to the keeping the connection active - sends some
86 // progress information, notably the number of the relocated bytes.
87 class CNetStorageHandler;
88 class CRelocateCallback
89 {
90     public:
91         CRelocateCallback(CNetStorageHandler &  handler,
92                           const SCommonRequestArguments &  common_args,
93                           CDirectNetStorageObject &  object,
94                           bool  need_progress_report);
95 
96     public:
97         // Should match TNetStorageProgressCb prototype
98         void  Callback(CJsonNode  info);
99 
100     private:
101         CNetStorageHandler &                m_Handler;
102         const SCommonRequestArguments &     m_CommonArgs;
103         CDirectNetStorageObject &           m_Object;
104         bool                                m_NeedProgressReport;
105 };
106 
107 
108 class CNetStorageHandler : public IServer_ConnectionHandler
109 {
110 public:
111 
112     CNetStorageHandler(CNetStorageServer *  server);
113     ~CNetStorageHandler();
114 
115     // IServer_ConnectionHandler protocol
116     virtual EIO_Event GetEventsToPollFor(const CTime** alarm_time) const;
117     virtual void      OnOpen(void);
118     virtual void      OnRead(void);
119     virtual void      OnWrite(void);
120     virtual void      OnClose(IServer_ConnectionHandler::EClosePeer peer);
121     virtual void      OnTimeout(void);
122     virtual void      OnOverflow(EOverflowReason reason);
123 
124     // Statuses of commands to be set in diagnostics' request context
125     // Additional statuses can be taken from
126     // http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html
127     enum EHTTPStatus {
128         eStatus_OK                  = 200, // Command is ok and execution
129                                            // is good
130 
131         eStatus_BadRequest          = 400, // Command is incorrect
132         eStatus_NotFound            = 404, // Object is not found
133         eStatus_Inactive            = 408, // Connection was closed due to
134                                            // inactivity timeout
135         eStatus_Probe               = 444, // Routine test from systems
136         eStatus_SocketIOError       = 499, // Error writing to socket
137 
138         eStatus_ServerError         = 500, // Internal server error
139         eStatus_NotImplemented      = 501, // Command is not implemented
140         eStatus_ShuttingDown        = 503  // Server is shutting down
141     };
142 
143     // In most of the case a socket timeout is considered as an error however
144     // there could be a case -- e.g. candidate is the relocate progress message
145     // -- when a timeout needs to be ignored. So there is an enumeration below.
146     enum ESocketTimeoutTreat {
147         eTimeoutIsError,
148         eTimeoutIsOK
149     };
150 
151 private:
152     // Application specific part
153     bool  x_ReadRawData();
154     void  x_OnMessage(const CJsonNode &  message);
155     void  x_OnData(const void *  data, size_t  data_size);
156     void  x_SendWriteConfirmation();
157 
158     // It closes the connection if there were socket writing errors
159     EIO_Status  x_SendSyncMessage(
160                         const CJsonNode &  message,
161                         ESocketTimeoutTreat  timeout_treat = eTimeoutIsError);
162     EIO_Status  x_SendOutputBuffer(ESocketTimeoutTreat  timeout_treat);
163     void  x_OnSocketWriteError(EIO_Status  status, size_t  bytes_written,
164                                const char *  output_buffer,
165                                size_t  output_buffer_size);
166     void  x_PrintMessageRequestStart(const CJsonNode &  message);
167     void  x_PrintMessageRequestStop(void);
168 
169     // Future versions may send the messages asynchronously
170     void  x_SendAsyncMessage(const CJsonNode &  message);
171 
172 private:
173     void x_SetQuickAcknowledge(void);
x_SetCmdRequestStatus(unsigned int status)174     void x_SetCmdRequestStatus(unsigned int  status)
175     { if (m_CmdContext.NotNull())
176         m_CmdContext->SetRequestStatus(status); }
x_SetConnRequestStatus(unsigned int status)177     void x_SetConnRequestStatus(unsigned int  status)
178     { if (m_ConnContext.NotNull())
179         m_ConnContext->SetRequestStatus(status); }
180 
181 private:
182     void x_CreateConnContext(void);
183     unsigned int  x_GetPeerAddress(void);
184 
185     CNetStorageServer *         m_Server;
186 
187     // Diagnostics context for the current connection
188     CRef<CRequestContext>       m_ConnContext;
189     // Diagnostics context for the currently executed command
190     CRef<CRequestContext>       m_CmdContext;
191 
192     // The client identification. It appears after HELLO.
193     string                      m_Service;
194     string                      m_Client;
195 
196 private:
197     enum EReadMode {
198         eReadMessages,
199         eReadRawData
200     };
201 
202     char *                  m_ReadBuffer;
203     EReadMode               m_ReadMode;
204     CUTTPReader             m_UTTPReader;
205     CJsonOverUTTPReader     m_JSONReader;
206 
207     char *                  m_WriteBuffer;
208     CUTTPWriter             m_UTTPWriter;
209     CJsonOverUTTPWriter     m_JSONWriter;
210 
211     CFastMutex              m_OutputQueueMutex;
212     vector<CJsonNode>       m_OutputQueue;
213 
214 private:
215     // Asynchronous write support
216     CDirectNetStorageObject m_ObjectBeingWritten;
217     Int8                    m_DataMessageSN;
218     EMetadataOption         m_MetadataOption;
219     bool                    m_CreateRequest;
220     TNSTDBValue<CTimeSpan>  m_CreateTTL;
221     Int8                    m_DBClientID;
222     Int8                    m_DBUserID;
223     Int8                    m_ObjectSize;
224     CNSTServiceProperties   m_WriteServiceProps;
225 
226 private:
227     bool                    m_ByeReceived;
228     bool                    m_FirstMessage;
229     bool                    m_WriteCreateNeedMetaDBUpdate;
230 
231     CNSTTiming              m_Timing;
232 
233     typedef void (CNetStorageHandler::*FProcessor)(
234                                 const CJsonNode &,
235                                 const SCommonRequestArguments &);
236     struct SProcessorMap
237     {
238         string      m_MessageType;
239         FProcessor  m_Processor;
240     };
241     static SProcessorMap    sm_Processors[];
242     FProcessor  x_FindProcessor(const SCommonRequestArguments &  common_args);
243 
244     // Individual message processors
245     // The return value is how many bytes are expected as raw data
246     void x_ProcessBye(const CJsonNode &                message,
247                       const SCommonRequestArguments &  common_args);
248     void x_ProcessHello(const CJsonNode &                message,
249                         const SCommonRequestArguments &  common_args);
250     void x_ProcessInfo(const CJsonNode &                message,
251                        const SCommonRequestArguments &  common_args);
252     void x_ProcessConfiguration(const CJsonNode &                message,
253                                 const SCommonRequestArguments &  common_args);
254     void x_ProcessHealth(const CJsonNode &                message,
255                          const SCommonRequestArguments &  common_args);
256     void x_ProcessAckAlert(const CJsonNode &                message,
257                            const SCommonRequestArguments &  common_args);
258     void x_ProcessReconfigure(const CJsonNode &                message,
259                               const SCommonRequestArguments &  common_args);
260     void x_ProcessShutdown(const CJsonNode &                message,
261                            const SCommonRequestArguments &  common_args);
262     void x_ProcessGetClientsInfo(const CJsonNode &                message,
263                                  const SCommonRequestArguments &  common_args);
264     void x_ProcessGetUsersInfo(const CJsonNode &                message,
265                                const SCommonRequestArguments &  common_args);
266     void x_ProcessGetMetadataInfo(const CJsonNode &                message,
267                                   const SCommonRequestArguments &  common_args);
268     void x_ProcessGetObjectInfo(const CJsonNode &                message,
269                                 const SCommonRequestArguments &  common_args);
270     void x_ProcessGetAttrList(const CJsonNode &                message,
271                               const SCommonRequestArguments &  common_args);
272     void x_ProcessGetClientObjects(const CJsonNode &                message,
273                                    const SCommonRequestArguments &  comm_args);
274     void x_ProcessGetUserObjects(const CJsonNode &                message,
275                                  const SCommonRequestArguments &  comm_args);
276     void x_ProcessGetAttr(const CJsonNode &                message,
277                           const SCommonRequestArguments &  common_args);
278     void x_ProcessSetAttr(const CJsonNode &                message,
279                           const SCommonRequestArguments &  common_args);
280     void x_ProcessDelAttr(const CJsonNode &                message,
281                           const SCommonRequestArguments &  common_args);
282     void x_ProcessRead(const CJsonNode &                message,
283                        const SCommonRequestArguments &  common_args);
284     void x_ProcessCreate(const CJsonNode &                message,
285                          const SCommonRequestArguments &  common_args);
286     void x_ProcessWrite(const CJsonNode &                message,
287                         const SCommonRequestArguments &  common_args);
288     void x_ProcessDelete(const CJsonNode &                message,
289                          const SCommonRequestArguments &  common_args);
290     void x_ProcessRelocate(const CJsonNode &                message,
291                            const SCommonRequestArguments &  common_args);
292     void x_ProcessExists(const CJsonNode &                message,
293                          const SCommonRequestArguments &  common_args);
294     void x_ProcessGetSize(const CJsonNode &                message,
295                           const SCommonRequestArguments &  common_args);
296     void x_ProcessSetExpTime(const CJsonNode &                message,
297                              const SCommonRequestArguments &  common_args);
298     void x_ProcessLockFTPath(const CJsonNode &                message,
299                              const SCommonRequestArguments &  common_args);
300 
301 private:
302     CDirectNetStorageObject x_GetObject(const CJsonNode &  message,
303                                         bool  need_fake_write = false);
304     void x_CheckObjectLoc(const string &  object_loc) const;
305     void x_CheckICacheSettings(const SICacheSettings &  icache_settings);
306     void x_CheckUserKey(const SUserKey &  user_key);
307     void x_GetStorageParams(const CJsonNode &   message,
308                             SICacheSettings *   icache_settings,
309                             SUserKey *          user_key,
310                             TNetStorageFlags *  flags);
311     CDirectNetStorageObject x_CreateObjectStream(
312                     const SICacheSettings &  icache_settings,
313                     TNetStorageFlags         flags);
314     EIO_Status x_SendOverUTTP();
315     EMetadataOption x_ConvertMetadataArgument(const CJsonNode &  message) const;
316     void x_ValidateWriteMetaDBAccess(const CJsonNode &  message,
317                                      bool  expect_object = true) const;
318     bool x_DetectMetaDBNeedUpdate(const CJsonNode &  message,
319                                   CNSTServiceProperties &  props) const;
320     bool x_DetectMetaDBNeedOnCreate(TNetStorageFlags  flags);
321     bool x_DetectMetaDBNeedOnGetObjectInfo(
322                                         const CJsonNode & message,
323                                         CNSTServiceProperties &  props) const;
324     void x_CreateClient(void);
325     Int8 x_GetClientID(const string &  client);
326     void x_CreateUser(void);
327     Int8 x_GetUserID(const CNSTUserID &  user);
328     void x_FillObjectInfo(CJsonNode &  reply, const string &  val);
329     void x_SetObjectInfoReply(CJsonNode &  reply, const string &  name,
330                               const TNSTDBValue<CTime> &  value);
331     void x_SetObjectInfoReply(CJsonNode &  reply, const string &  name,
332                               const TNSTDBValue<Int8> &  value);
333     void x_SetObjectInfoReply(CJsonNode &  reply, const string &  name,
334                               const TNSTDBValue<string> &  value);
335 
336     void x_OptionalExpirationUpdate(CDirectNetStorageObject &  object,
337                                     CJsonNode &  reply,
338                                     const string &  user_message);
339     void x_CheckExistanceStatus(int  status);
340     void x_CheckExpirationStatus(int  status);
341     void x_CheckNonAnonymousClient(const string &  op) const;
342     string x_GetConnRef(void);
343 
344 private:
345     enum EOp {
346         eReadOp,
347         eWriteOp,
348         eRelocateOp
349     };
350     void x_ProlongObjectOnFailure(EOp  operation,
351                                   const string &  object_key,
352                                   const CNSTServiceProperties &  service_props);
353 
354     friend class CRelocateCallback;
355 }; // CNetStorageHandler
356 
357 
358 END_NCBI_SCOPE
359 
360 #endif
361 
362