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