NCBI C++ ToolKit
nst_handler.cpp
Go to the documentation of this file.

Go to the SVN repository for this file.

1 /* $Id: nst_handler.cpp 99345 2023-03-14 14:21:41Z satskyse $
2  * ===========================================================================
3  *
4  * PUBLIC DOMAIN NOTICE
5  * National Center for Biotechnology Information
6  *
7  * This software/database is a "United States Government Work" under the
8  * terms of the United States Copyright Act. It was written as part of
9  * the author's official duties as a United States Government employee and
10  * thus cannot be copyrighted. This software/database is freely available
11  * to the public for use. The National Library of Medicine and the U.S.
12  * Government have not placed any restriction on its use or reproduction.
13  *
14  * Although all reasonable efforts have been taken to ensure the accuracy
15  * and reliability of the software and data, the NLM and the U.S.
16  * Government do not and cannot warrant the performance or results that
17  * may be obtained by using this software or data. The NLM and the U.S.
18  * Government disclaim all warranties, express or implied, including
19  * warranties of performance, merchantability or fitness for any particular
20  * purpose.
21  *
22  * Please cite the author in any work or product based on this material.
23  *
24  * ===========================================================================
25  *
26  * Authors: Denis Vakatov
27  *
28  * File Description: NetStorage commands handler
29  *
30  */
31 
32 #include <ncbi_pch.hpp>
33 
34 #include <sys/types.h>
35 #include <sys/socket.h>
36 #include <netinet/in.h>
37 #include <netinet/tcp.h>
38 #include <signal.h>
39 
42 #include <corelib/ncbi_message.hpp>
44 
45 #include "nst_handler.hpp"
46 #include "nst_server.hpp"
47 #include "nst_protocol_utils.hpp"
48 #include "nst_exception.hpp"
49 #include "nst_version.hpp"
50 #include "nst_application.hpp"
51 #include "nst_warning.hpp"
52 #include "nst_config.hpp"
53 #include "nst_util.hpp"
54 #include "error_codes.hpp"
55 #include "nst_constants.hpp"
56 
57 
59 using namespace std::placeholders;
60 
61 
62 const string kObjectExpired = "NetStorage object has expired";
63 const string kObjectNotFound = "NetStorage object is not found";
64 
65 
67 {
71  { "CONFIGURATION", & CNetStorageHandler::x_ProcessConfiguration },
73  { "ACKALERT", & CNetStorageHandler::x_ProcessAckAlert },
74  { "RECONFIGURE", & CNetStorageHandler::x_ProcessReconfigure },
75  { "SHUTDOWN", & CNetStorageHandler::x_ProcessShutdown },
76  { "GETCLIENTSINFO", & CNetStorageHandler::x_ProcessGetClientsInfo },
77  { "GETUSERSINFO", & CNetStorageHandler::x_ProcessGetUsersInfo },
78  { "GETMETADATAINFO", & CNetStorageHandler::x_ProcessGetMetadataInfo },
79  { "GETOBJECTINFO", & CNetStorageHandler::x_ProcessGetObjectInfo },
80  { "GETATTRLIST", & CNetStorageHandler::x_ProcessGetAttrList },
81  { "GETCLIENTOBJECTS", & CNetStorageHandler::x_ProcessGetClientObjects },
82  { "GETUSEROBJECTS", & CNetStorageHandler::x_ProcessGetUserObjects },
83  { "GETATTR", & CNetStorageHandler::x_ProcessGetAttr },
84  { "SETATTR", & CNetStorageHandler::x_ProcessSetAttr },
85  { "DELATTR", & CNetStorageHandler::x_ProcessDelAttr },
90  { "RELOCATE", & CNetStorageHandler::x_ProcessRelocate },
92  { "GETSIZE", & CNetStorageHandler::x_ProcessGetSize },
93  { "SETEXPTIME", & CNetStorageHandler::x_ProcessSetExpTime },
94  { "LOCKFTPATH", & CNetStorageHandler::x_ProcessLockFTPath },
95  { "", NULL }
96 };
97 
98 
99 
101 {}
102 
104 {
106 }
107 
109 {}
110 
112 {
114 }
115 
116 
117 
120  const SCommonRequestArguments & common_args,
121  CDirectNetStorageObject & object,
122  bool need_progress_report) :
123  m_Handler(handler), m_CommonArgs(common_args), m_Object(object),
124  m_NeedProgressReport(need_progress_report)
125 {}
126 
127 
129 {
131  return;
132 
134  reply.SetByKey("ProgressInfo", info);
135 
136  // The x_SendSyncMessage() call will also close the client socket if
137  // it was an unsucessfull writing.
138  EIO_Status status = m_Handler.x_SendSyncMessage(reply,
140  switch (status) {
141  case eIO_Success:
142  return;
143  #if 0
144  // It is commented out for the time being.
145  // Now it is not clear what to do with the output buffers in case of a
146  // timeout. One of the options is to discard them. Another is to leave
147  // intact. When (and if) it becomes clear that ignoring of the timeout
148  // is really needed then this part should be uncommented. See the
149  // x_SendSyncMessage(...) call above as well.
150  case eIO_Timeout: // It was decided to ignore the timeouts
151  ERR_POST(Warning << "Timeout writing a relocate progress info. "
152  "Client socket: "
154  return;
155  #endif
156  default:
157  break;
158  }
159 
160  // Some other unsuccessfull socket.write() return code
162 }
163 
164 
166  : m_Server(server),
167  m_ReadMode(CNetStorageHandler::eReadMessages),
168  m_JSONWriter(m_UTTPWriter),
169  m_ObjectBeingWritten(eVoid),
170  m_DataMessageSN(-1),
171  m_MetadataOption(eMetadataNotSpecified),
172  m_DBClientID(-1),
173  m_ObjectSize(0),
174  m_ByeReceived(false),
175  m_FirstMessage(true),
176  m_WriteCreateNeedMetaDBUpdate(false)
177 {
179 }
180 
181 
183 {}
184 
185 
186 EIO_Event
187 CNetStorageHandler::GetEventsToPollFor(const CTime** /*alarm_time*/) const
188 {
189  // This implementation is left to simplify the transition to
190  // asynchronous replies. Currently the m_OutputQueue is always
191  // empty so the only eIO_Read will be returned.
192  if (m_OutputQueue.empty())
193  return eIO_Read;
194  return eIO_ReadWrite;
195 }
196 
197 
199 {
200  CSocket & socket = GetSocket();
201  STimeout to = {m_Server->GetNetworkTimeout(), 0};
202 
203  socket.DisableOSSendDelay();
204  socket.SetTimeout(eIO_ReadWrite, &to);
206 
207  if (m_Server->IsLog()) {
208  CRequestContextResetter context_resetter;
210  }
211 }
212 
213 
215 {
216  CRequestContextResetter context_resetter;
217  if (m_ConnContext.NotNull()) {
218  if (m_CmdContext.NotNull())
220  else
222  }
223 
224 
225  size_t n_read;
226  CSocket & socket = GetSocket();
228  EIO_Status status = socket.Read(m_ReadBuffer, kReadBufferSize,
229  &n_read);
231  m_Timing.Append("Client socket read", start);
232 
233  switch (status) {
234  case eIO_Success:
235  break;
236  case eIO_Timeout:
237  this->OnTimeout();
238  return;
239  case eIO_Closed:
241  return;
242  case eIO_Interrupt:
243  ERR_POST(Warning << "Error reading from the client socket ("
244  << socket.GetPeerAddress() + "): "
245  << "(" << static_cast<int>(status) << ")");
246  // Will be repeated again later?
247  return;
248  case eIO_NotSupported:
249  ERR_POST(Warning << "Error reading from the client socket ("
250  << socket.GetPeerAddress() + "): "
251  << "(" << static_cast<int>(status) << ")");
254  return;
255  default:
256  // eIO_InvalidArg, eIO_Unknown
257  ERR_POST(Warning << "Error reading from the client socket ("
258  << socket.GetPeerAddress() + "): "
259  << "(" << static_cast<int>(status) << ")");
262  return;
263  }
264 
266 
267  if (m_ReadMode == eReadMessages || x_ReadRawData()) {
268  try {
270 
271  if (!m_JSONReader.GetMessage().IsObject()) {
272  // All the incoming objects must be dictionaries
275  return;
276  }
277 
278  if (socket.GetStatus(eIO_Open) != eIO_Success) {
279  // while we are in the loop of reading it is possible that
280  // the socket was closed, e.g. by the client side
281  // In this case it makes no sense to continue
282  return;
283  }
284 
286  m_FirstMessage = false;
289  break;
290  }
291  }
292  catch (const CJsonOverUTTPException & e) {
293  // Parsing error
294  if (!m_FirstMessage) {
295  // The systems try to attack all the servers and they send
296  // provocative messages. If the very first unparsable message
297  // received then it does not make sense even to log it to avoid
298  // excessive messages in AppLog.
299  ERR_POST("Incoming message parsing error. " << e <<
300  " The connection will be closed.");
302  } else {
304  }
306  }
307  catch (const exception & ex) {
308  ERR_POST("STL exception while processing incoming message: " <<
309  ex);
312  }
313  catch (...) {
314  ERR_POST("Unknown exception while processing incoming message");
317  }
318  }
319 }
320 
321 
323 {
324  // This implementation is left to simplify the transition to
325  // asynchronous replies. Currently this method will never be called
326  // because the GetEventsToPollFor(...) never returns anything but
327  // eIO_Read
328 
329  for (;;) {
330  CJsonNode message;
331 
332  {
334 
335  if (m_OutputQueue.empty())
336  break;
337 
338  message = m_OutputQueue.front();
339  m_OutputQueue.erase(m_OutputQueue.begin());
340  }
341 
342  if (!m_JSONWriter.WriteMessage(message))
343  do
345  while (!m_JSONWriter.CompleteMessage());
346 
348  }
349 }
350 
351 
353 {
354  // m_ConnContext != NULL also tells that the logging is required
355  if (m_ConnContext.IsNull())
356  return;
357 
358  switch (peer)
359  {
361  // All the places where the server closes the connection make sure
362  // that the conn and cmd request statuses are set approprietly
363  break;
365  // The only non-synchronous commands are WRITE/CREATE and when we
366  // are in the middle of them, the m_ObjectBeingWritten is not null
367  if (m_ObjectBeingWritten) {
369  if (m_CmdContext.NotNull())
371  }
372  break;
373  }
374 
375  // If a command has not finished its logging by some reasons - do it
376  // here as the last chance.
377  if (m_CmdContext.NotNull()) {
379  if (!m_Timing.Empty()) {
380  string timing = m_Timing.Serialize(GetDiagContext().Extra());
381  if (!timing.empty())
382  GetDiagContext().Extra().Print("timing", timing);
383  }
387  }
388 
389  CSocket & socket = GetSocket();
390  TNCBI_BigCount read_count = socket.GetCount(eIO_Read);
391  TNCBI_BigCount write_count = socket.GetCount(eIO_Write);
392 
393  m_ConnContext->SetBytesRd(read_count);
394  m_ConnContext->SetBytesWr(write_count);
395 
396  // Call the socket shutdown only if it was a client close and
397  // there was some data exchange over the connection.
398  // LBSMD - when it checks a connection point - opens and aborts the
399  // connection without any data transferring and in this scenario the
400  // socket.Shutdown() call returns non success.
402  (read_count > 0 || write_count > 0)) {
403 
404  // The socket.Shutdown() call will fail if there is some not delivered
405  // data in the socket or if the connection was not closed properly on
406  // the client side.
408  if (status != EIO_Status::eIO_Success) {
410  ERR_POST(Warning << "Unsuccessful client socket shutdown. "
411  "The socket may have data not delivered to the client. "
412  "Error code: " << status << ": " << IO_StatusStr(status));
413  }
414  }
415 
420 }
421 
422 
424 {
425  if (m_ConnContext.NotNull())
427 }
428 
429 
431 {
432  CRequestContextResetter context_resetter;
433  if (m_ConnContext.NotNull()) {
434  if (m_CmdContext.NotNull())
436  else
438  }
439 
440  switch (reason) {
442  ERR_POST("eCommunicationError:Connection pool full");
443  break;
445  ERR_POST("eCommunicationError:Unpollable connection");
446  break;
448  ERR_POST("eCommunicationError:Request queue full");
449  break;
450  default:
451  ERR_POST("eCommunicationError:Unknown overflow error");
452  }
453 }
454 
455 
457 {
459 
460  while ((uttp_event = m_UTTPReader.GetNextEvent()) == CUTTPReader::eChunk ||
461  uttp_event == CUTTPReader::eChunkPart)
463 
464  switch (uttp_event) {
466  return false;
467 
469  if (m_UTTPReader.GetControlSymbol() == '\n') {
472  return true;
473  }
474  /* FALL THROUGH */
475 
476  default:
477  ERR_POST("Data stream parsing error. The connection will be closed.");
480  return false;
481  }
482 }
483 
484 
485 
486 // x_OnMessage gets control when a command message is received.
488 {
489  // Log all the message parameters
491 
492  // Extract message type and its serial number
493  SCommonRequestArguments common_args;
494  try {
495  common_args = ExtractCommonFields(message);
496  }
497  catch (const CNetStorageServerException & ex) {
498  ERR_POST("Error extracting mandatory fields: " << ex << ". "
499  "The connection will be closed.");
500 
502  common_args.m_SerialNumber,
503  NCBI_ERRCODE_X_NAME(NetStorageServer_ErrorCode),
504  "Error extracting mandatory fields",
505  ex.GetType(),
507 
509  if (x_SendSyncMessage(response) == eIO_Success)
511  return;
512  }
513 
514  // Shutting down analysis is here because it needs the command serial
515  // number to return it in the reply message.
516  if (m_Server->ShutdownRequested()) {
517  ERR_POST(Warning << "Server is shutting down. "
518  "The connection will be closed.");
519 
520  // Send response message with an error
522  common_args.m_SerialNumber,
523  NCBI_ERRCODE_X_NAME(NetStorageServer_ErrorCode),
524  "Server is shutting down",
525  kScopeLogic,
527 
529  if (x_SendSyncMessage(response) == eIO_Success)
531  return;
532  }
533 
534 
535 
536  if (m_ByeReceived) {
537  // BYE message has been received before. Send error response
538  // and close the connection.
539  ERR_POST(Warning << "Received a message after BYE. "
540  "The connection will be closed.");
541 
542  // Send response message with an error
544  common_args.m_SerialNumber,
545  NCBI_ERRCODE_X_NAME(NetStorageServer_ErrorCode),
546  "No messages are allowed after BYE",
547  kScopeLogic,
549 
551  if (x_SendSyncMessage(response) == eIO_Success)
553  return;
554  }
555 
556 
557  bool error = true;
558  unsigned int http_error_code = eStatus_ServerError;
559  Int8 error_code = NCBI_ERRCODE_X_NAME(
560  NetStorageServer_ErrorCode);
561  string error_client_message;
562  unsigned int error_sub_code;
563  string error_scope;
564 
565  try {
566  m_Timing.Clear();
567 
568  // Find the processor
569  FProcessor processor = x_FindProcessor(common_args);
570  if (processor != &CNetStorageHandler::x_ProcessHello)
572 
573  // Call the processor. It returns the number of bytes to expect
574  // after this message. If 0 then another message is expected.
575  (this->*processor)(message, common_args);
576  error = false;
577  }
578  catch (const CNetStorageServerException & ex) {
579  error_sub_code = ex.GetErrCode();
580  if (error_sub_code !=
582  error_sub_code !=
584  // Choke the error printout for these specific cases, see CXX-5818
585  ERR_POST(ex);
586  }
587  http_error_code = ex.ErrCodeToHTTPStatusCode();
588  error_client_message = ex.what();
589  error_scope = ex.GetType();
590 
591  // Note: eAccess alert is set at the point before an exception is
592  // thrown. This is done for a clean alert message.
593  }
594 
595  catch (const CException & ex) {
596  ERR_POST(ex);
597  error_client_message = ex.what();
598  if (GetReplyMessageProperties(ex, &error_scope,
599  &error_code,
600  &error_sub_code) == false) {
601  // The only case here is a CException so error_sub_code needs to be
602  // updated
604  }
605  }
606  catch (const std::exception & ex) {
607  ERR_POST("STL exception: " << ex);
609  error_client_message = ex.what();
610  error_scope = kScopeStdException;
611  }
612  catch (...) {
613  ERR_POST("Unknown exception");
615  error_client_message = "Unknown exception";
616  error_scope = kScopeUnknownException;
617  }
618 
619  if (error) {
620  x_SetCmdRequestStatus(http_error_code);
621 
622  // Send response message with an error
624  common_args.m_SerialNumber,
625  error_code,
626  error_client_message,
627  error_scope, error_sub_code);
628  x_SendSyncMessage(response);
630  }
631 }
632 
633 
634 // x_OnData gets control when raw data are received.
635 void CNetStorageHandler::x_OnData(const void* data, size_t data_size)
636 {
637  if (!m_ObjectBeingWritten) {
638  if (data_size > 0) {
639  ERR_POST("Received " << data_size << " bytes after "
640  "an error has been reported to the client");
641  }
642  return;
643  }
644 
646  try {
647  m_ObjectBeingWritten.Write(data, data_size);
649  m_Timing.Append("NetStorageAPI write (" +
650  NStr::NumericToString(data_size) + ")", start);
651  start = 0.0;
653  m_ObjectSize += data_size;
654 
655  if (m_CmdContext.NotNull())
657  }
658  catch (const exception & ex) {
659  if (double(start) != 0.0 && m_Server->IsLogTimingNSTAPI())
660  m_Timing.Append("NetStorageAPI writing error (" +
661  NStr::NumericToString(data_size) +
662  " bytes to write)", start);
663 
664  string message = "Error writing " + NStr::NumericToString(data_size) +
665  " bytes into " + m_ObjectBeingWritten.GetLoc() +
666  ": " + ex.what();
667 
669  // Prolong makes sense only for the WRITE operation
673  }
674 
676  m_DataMessageSN = -1;
677 
678  ERR_POST(message);
679 
680  string error_scope;
681  Int8 error_code;
682  unsigned int error_sub_code;
683 
684  if (GetReplyMessageProperties(ex, &error_scope,
685  &error_code, &error_sub_code) == false) {
686  // CException or std::exception
688  }
689 
690  // Send response message with an error
693  NCBI_ERRCODE_X_NAME(NetStorageServer_ErrorCode),
694  message, kScopeStdException,
696  x_SendSyncMessage(response);
697 
698  } catch (...) {
699  if (double(start) != 0.0 && m_Server->IsLogTimingNSTAPI())
700  m_Timing.Append("NetStorageAPI writing error (" +
701  NStr::NumericToString(data_size) +
702  " bytes to write)", start);
703 
704  string message = "Unknown exception while writing " +
705  NStr::NumericToString(data_size) +
706  " bytes into " + m_ObjectBeingWritten.GetLoc();
707 
709  // Prolong makes sense only for the WRITE operation
713  }
714 
716  m_DataMessageSN = -1;
717 
718  ERR_POST(message);
719 
720  // Send response message with an error
723  NCBI_ERRCODE_X_NAME(NetStorageServer_ErrorCode),
724  message, kScopeUnknownException,
726  x_SendSyncMessage(response);
727  }
728 }
729 
730 
732 {
733  if (!m_ObjectBeingWritten) {
736  return;
737  }
738 
741  try {
742  if (m_ObjectSize == 0) {
743  // This is the object of zero size i.e. there were no write()
744  // calls. Thus the remote object was not really created.
747  m_Timing.Append("NetStorageAPI writing (0)", start);
748  }
749  start = CNSTPreciseTime::Current();
752  m_Timing.Append("NetStorageAPI closing", start);
753  } catch (const exception & ex) {
755  m_Timing.Append("NetStorageAPI finalizing error", start);
756 
758 
759  string message = "Error while finalizing " +
760  m_ObjectBeingWritten.GetLoc() + ": " + ex.what();
761  ERR_POST(message);
763 
764  string error_scope;
765  Int8 error_code;
766  unsigned int error_sub_code;
767 
768  if (GetReplyMessageProperties(ex, &error_scope, &error_code,
769  &error_sub_code) == false) {
770  // CException or std::exception
772  }
773 
774  AppendError(reply, error_code, message, error_scope, error_sub_code);
775  x_SendSyncMessage(reply);
776 
778  m_DataMessageSN = -1;
779  return;
780  }
781 
783  // Update of the meta DB is required. It differs depending it was an
784  // object creation or writing into an existing one.
785  const CNetStorageObjectLoc & object_loc_struct =
787  string locator = object_loc_struct.GetLocator();
788 
789  if (m_CreateRequest) {
790  // It was creating an object.
791  bool size_was_null = false;
792 
793  try {
795  object_loc_struct.GetUniqueKey(),
797  m_CreateTTL, size_was_null);
798  } catch (const exception & ex) {
800  string message = "Error while updating meta info DB for " +
801  locator + " upon creation: " + ex.what();
802  ERR_POST(message);
803 
804  string error_scope;
805  Int8 error_code;
806  unsigned int error_sub_code;
807 
808  if (GetReplyMessageProperties(ex, &error_scope, &error_code,
809  &error_sub_code) == false) {
810  // CException or std::exception
812  }
813 
814  AppendError(reply, error_code, message, error_scope,
815  error_sub_code, false);
816  } catch (...) {
817  string message = "Unknown error while updating meta info DB "
818  "for " + locator + " upon creation";
819  AppendError(reply,
820  NCBI_ERRCODE_X_NAME(NetStorageServer_ErrorCode),
821  message, kScopeUnknownException,
823  ERR_POST(message);
824  }
825 
826  if (size_was_null)
828  reply, "CREATE");
829  } else {
830  // It was writing into existing object or creating via writing
831  bool size_was_null = false;
832 
833  try {
834  // The object expiration could have been changed while the
835  // object was written so I need to get the expiration right
836  // here. It is not very convenient to calculate the new
837  // expiration time in MS SQL server so it is done in C++ via
838  // two requests which is technically not safe in multiple
839  // access scenario...
840  TNSTDBValue<CTime> object_expiration;
841  TNSTDBValue<Int8> individual_object_ttl;
842  string object_key = object_loc_struct.GetUniqueKey();
844  object_key, object_expiration,
845  individual_object_ttl);
846 
847  // The record will be created if it does not exist
849  object_key, locator, m_ObjectSize,
853  individual_object_ttl),
854  object_expiration, size_was_null);
855  } catch (const exception & ex) {
856  string message = "Error while updating meta info DB for " +
857  locator + " upon writing: " + ex.what();
858  ERR_POST(message);
859 
860  string error_scope;
861  Int8 error_code;
862  unsigned int error_sub_code;
863 
864  if (GetReplyMessageProperties(ex, &error_scope, &error_code,
865  &error_sub_code) == false) {
866  // CException or std::exception
867  error_sub_code = eDatabaseWarning;
868  }
869 
870  AppendError(reply, error_code, message, error_scope,
871  error_sub_code, false);
872  } catch (...) {
873  string message = "Unknown error while updating meta info DB "
874  "for " + locator + " upon writing";
875  AppendError(reply,
876  NCBI_ERRCODE_X_NAME(NetStorageServer_ErrorCode),
877  message, kScopeUnknownException,
879  ERR_POST(message);
880  }
881 
882  if (size_was_null)
884  reply, "WRITE");
885  }
886  }
887 
888  x_SendSyncMessage(reply);
891  m_DataMessageSN = -1;
892 }
893 
894 
897  ESocketTimeoutTreat timeout_treat)
898 {
899  if (!m_JSONWriter.WriteMessage(message))
900  do {
901  EIO_Status status = x_SendOutputBuffer(timeout_treat);
902  if (status != eIO_Success)
903  return status;
904  } while (!m_JSONWriter.CompleteMessage());
905 
906  return x_SendOutputBuffer(timeout_treat);
907 }
908 
909 
910 
912 {
913  // The current implementation does not use this.
914  // The code is left here to simplify transition to the asynchronous
915  // way of communicating.
916 
917  {
919 
920  m_OutputQueue.push_back(par);
921  }
922 
924 }
925 
926 
927 // Log what we can, set the status code and close the connection
929  EIO_Status status, size_t bytes_written,
930  const char * output_buffer, size_t output_buffer_size)
931 {
932  string report =
933  "Error writing message to the client. "
934  "Peer: " + GetSocket().GetPeerAddress() + ". "
935  "Socket write error status: " + IO_StatusStr(status) + ". "
936  "Written bytes: " + NStr::NumericToString(bytes_written) +
937  ". Message begins with: ";
938 
939  if (output_buffer_size > 32) {
940  CTempString buffer_head(output_buffer, 32);
941  report += NStr::PrintableString(buffer_head) + " (TRUNCATED)";
942  }
943  else {
944  CTempString buffer_head(output_buffer, output_buffer_size);
945  report += NStr::PrintableString(buffer_head);
946  }
947 
948  ERR_POST(report);
949 
950  if (m_ConnContext.NotNull()) {
953  if (m_CmdContext.NotNull()) {
956  }
957  }
958 
959  // Register the socket error with the client
961 
962  if (status != eIO_Closed) {
964  }
965 }
966 
967 
970 {
971  const char * output_buffer;
972  size_t output_buffer_size;
973  size_t bytes_written;
974 
975  do {
976  m_JSONWriter.GetOutputBuffer(&output_buffer, &output_buffer_size);
977  while (output_buffer_size > 0) {
979  EIO_Status status = GetSocket().Write(output_buffer,
980  output_buffer_size,
981  &bytes_written);
983  m_Timing.Append("Client socket write (" +
984  NStr::NumericToString(output_buffer_size) + ")",
985  start);
986  if (status != eIO_Success) {
987  if (status == eIO_Timeout && timeout_treat == eTimeoutIsOK) {
988  // It is up to the caller to log a message.
989  // It is not clear what to do with the output buffers:
990  // -- discard
991  // -- leave not touched
992  // So it is not recommended to use the eTimeoutIsOK here
993  // till this is resolved.
994  return status;
995  }
996 
997  // Error writing to the socket. Log what we can and close the
998  // connection.
999  x_OnSocketWriteError(status, bytes_written,
1000  output_buffer, output_buffer_size);
1001  return status;
1002  }
1003 
1004  output_buffer += bytes_written;
1005  output_buffer_size -= bytes_written;
1006  }
1007  } while (m_JSONWriter.NextOutputBuffer());
1008 
1010  return eIO_Success;
1011 }
1012 
1013 
1015 {
1016  int fd = 0;
1017  int val = 1;
1018 
1019  GetSocket().GetOSHandle(&fd, sizeof(fd));
1020  setsockopt(fd, IPPROTO_TCP, TCP_QUICKACK, &val, sizeof(val));
1021 }
1022 
1023 
1025 {
1026  // See CXX-8252
1027  return GetDiagContext().GetStringUID() + "_" +
1029 }
1030 
1031 
1033 {
1036  m_ConnContext->SetClientIP(GetSocket().GetPeerAddress(eSAF_IP));
1037 
1038  // Suppress phid for connections
1039  // It makes no sense to have phid for connections
1040  m_ConnContext->SetHitID("");
1041 
1042  // Set the connection request as the current one and print request start
1045  .Print("_type", "conn")
1046  .Print("conn", x_GetConnRef());
1049 }
1050 
1051 
1053 {
1054  unsigned int peer_addr;
1055 
1056  GetSocket().GetPeerAddress(&peer_addr, 0, eNH_NetworkByteOrder);
1057 
1058  // always use localhost(127.0*) address for clients coming from
1059  // the same net address (sometimes it can be 127.* or full address)
1060  if (peer_addr == m_Server->GetHostNetAddr())
1062  return peer_addr;
1063 }
1064 
1065 
1066 
1069  const SCommonRequestArguments & common_args)
1070 {
1071  for (size_t index = 0; sm_Processors[index].m_Processor != NULL; ++index)
1072  {
1073  if (sm_Processors[index].m_MessageType == common_args.m_MessageType)
1074  return sm_Processors[index].m_Processor;
1075  }
1076  NCBI_THROW(CNetStorageServerException, eInvalidMessageType,
1077  "Message type '" + common_args.m_MessageType +
1078  "' is not supported");
1079 }
1080 
1081 
1082 void
1084 {
1085  if (m_ConnContext.NotNull()) {
1086  if (m_CmdContext.IsNull()) {
1090  }
1092 
1093  // The setting of the client session and IP
1094  // must be done before logging.
1095  SetSessionAndIPAndPHID(message, GetSocket());
1096 
1097  CDiagContext_Extra ctxt_extra =
1099  .Print("_type", "message")
1100  .Print("conn", x_GetConnRef());
1101 
1102  for (CJsonIterator it = message.Iterate(); it; ++it) {
1103  string key = it.GetKey();
1104 
1105  // ncbi_phid has been printed by PrintRequestStart() anyway
1106  if (key == "ncbi_phid")
1107  continue;
1108  // ncbi_context is for serializing into the request context,
1109  // not really for logging
1110  if (key == "ncbi_context")
1111  continue;
1112  if (key == "SessionID" || key == "ClientIP")
1113  continue;
1114 
1115  ctxt_extra.Print(key,
1116  it.GetNode().Repr(CJsonNode::fVerbatimIfString));
1117  }
1118 
1119  ctxt_extra.Flush();
1120 
1121  // Workaround:
1122  // When extra of the GetDiagContext().PrintRequestStart() is destroyed
1123  // or flushed it also resets the status to 0 so I need to set it here
1124  // to 200 though it was previously set to 200 when the request context
1125  // is created.
1127  }
1128 }
1129 
1130 
1131 void
1133 {
1134  if (m_CmdContext.NotNull()) {
1136  if (!m_Timing.Empty()) {
1137  string timing = m_Timing.Serialize(GetDiagContext().Extra());
1138  if (!timing.empty())
1139  GetDiagContext().Extra().Print("timing", timing);
1140  }
1142  m_CmdContext.Reset();
1144  }
1145 }
1146 
1147 
1148 void
1150  const CJsonNode & message,
1151  const SCommonRequestArguments & common_args)
1152 {
1153  m_ByeReceived = true;
1156 }
1157 
1158 
1159 void
1161  const CJsonNode & message,
1162  const SCommonRequestArguments & common_args)
1163 {
1164  string application; // Optional field
1165  string ticket; // Optional field
1166  string protocol_version; // Optional field
1167 
1168  if (!message.HasKey("Client")) {
1169  NCBI_THROW(CNetStorageServerException, eMandatoryFieldsMissed,
1170  "Mandatory field 'Client' is missed");
1171  }
1172 
1173  string client = NStr::TruncateSpaces(message.GetString("Client"));
1174  if (client.empty()) {
1175  NCBI_THROW(CNetStorageServerException, eInvalidArgument,
1176  "Mandatory field 'Client' is empty");
1177  }
1178 
1179  // The following will throw an exception if the limit is broken
1180  SNetStorage::SLimits::Check<SNetStorage::SLimits::SClientName>(client);
1181  m_Client = client;
1182 
1183 
1184  if (message.HasKey("Application"))
1185  application = message.GetString("Application");
1186  if (message.HasKey("Ticket"))
1187  ticket = message.GetString("Ticket");
1188  if (message.HasKey("ProtocolVersion")) {
1189  // Some clients may send the protocol version as an integer
1190  // See CXX-6157
1191  CJsonNode ver = message.GetByKey("ProtocolVersion");
1192  CJsonNode::ENodeType node_type = ver.GetNodeType();
1193  if (node_type == CJsonNode::eString)
1194  protocol_version = ver.AsString();
1195  else if (node_type == CJsonNode::eInteger)
1196  protocol_version = NStr::NumericToString(ver.AsInteger()) +
1197  ".0.0";
1198  else
1199  NCBI_THROW(CNetStorageServerException, eInvalidArgument,
1200  "Invalid type of the 'ProtocolVersion'. "
1201  "String is expected.");
1202  }
1203  if (message.HasKey("Service"))
1204  m_Service = NStr::TruncateSpaces(message.GetString("Service"));
1205  else
1206  m_Service = "";
1208 
1209  // Memorize the client in the registry
1210  m_Server->GetClientRegistry().Touch(m_Client, application,
1211  ticket, m_Service, protocol_version,
1213 
1214  // Send success response
1217 }
1218 
1219 
1220 void
1222  const CJsonNode & message,
1223  const SCommonRequestArguments & common_args)
1224 {
1225  x_CheckNonAnonymousClient("server info request");
1228 
1229  CJsonNode reply = CreateResponseMessage(common_args.m_SerialNumber);
1230  reply.SetString("ServerVersion", NETSTORAGED_VERSION);
1231  reply.SetString("ProtocolVersion", NETSTORAGED_PROTOCOL_VERSION);
1232  reply.SetInteger("PID", CDiagContext::GetPID());
1233  reply.SetString("BuildDate", NETSTORAGED_BUILD_DATE);
1234  reply.SetString("StartDate",
1236  reply.SetString("ServerSession", m_Server->GetSessionID());
1237  reply.SetString("ServerBinaryPath",
1238  CNcbiApplication::Instance()->GetProgramExecutablePath());
1239  reply.SetString("ServerCommandLine", m_Server->GetCommandLine());
1240 
1241  x_SendSyncMessage(reply);
1243 }
1244 
1245 
1246 void
1248  const CJsonNode & message,
1249  const SCommonRequestArguments & common_args)
1250 {
1251  x_CheckNonAnonymousClient("configuration request");
1254 
1255  CNcbiOstrstream conf;
1256  CNcbiOstrstreamToString converter(conf);
1257 
1259 
1260  CJsonNode reply = CreateResponseMessage(common_args.m_SerialNumber);
1261  reply.SetString("Configuration", string(converter));
1262  reply.SetString("ConfigurationFilePath",
1263  CNcbiApplication::Instance()->GetConfigPath());
1264  reply.SetByKey("BackendConfiguration", m_Server->GetBackendConfiguration());
1265  reply.SetDouble("DBExecuteSPTimeout",
1267 
1268  x_SendSyncMessage(reply);
1270 }
1271 
1272 
1273 void
1275  const CJsonNode & message,
1276  const SCommonRequestArguments & common_args)
1277 {
1278  x_CheckNonAnonymousClient("health request");
1279 
1280  // GRID dashboard needs this command to be executed regardless of the
1281  // configuration settings, so the requirement of being an admin is
1282  // removed
1283  // if (!m_Server->IsAdminClientName(m_Client)) {
1284  // string msg = "Only administrators can request server health";
1285  // m_Server->RegisterAlert(eAccess, msg);
1286  // NCBI_THROW(CNetStorageServerException, ePrivileges, msg);
1287  // }
1288 
1291 
1292  CJsonNode reply = CreateResponseMessage(common_args.m_SerialNumber);
1293  reply.SetByKey("Alerts", m_Server->SerializeAlerts());
1294 
1295  // Generic database info
1296  CJsonNode db_stat_node(CJsonNode::NewObjectNode());
1297  bool connected = m_Server->GetDb().IsConnected();
1298 
1299  db_stat_node.SetBoolean("connected", connected);
1300  if (connected) {
1301  try {
1302  map<string, string> db_stat = m_Server->GetDb().
1303  ExecSP_GetGeneralDBInfo();
1304  for (map<string, string>::const_iterator k = db_stat.begin();
1305  k != db_stat.end(); ++k)
1306  db_stat_node.SetString(k->first, k->second);
1307 
1308  db_stat = m_Server->GetDb().ExecSP_GetStatDBInfo();
1309  for (map<string, string>::const_iterator k = db_stat.begin();
1310  k != db_stat.end(); ++k)
1311  db_stat_node.SetString(k->first, k->second);
1312  } catch (const exception & ex) {
1313  // Health must not fail if there is no meta DB connection
1314  AppendWarning(reply, NCBI_ERRCODE_X_NAME(NetStorageServer_ErrorCode),
1315  ex.what(), kScopeStdException, eDatabaseWarning);
1316  } catch (...) {
1317  // Health must not fail if there is no meta DB connection
1318  AppendWarning(reply, NCBI_ERRCODE_X_NAME(NetStorageServer_ErrorCode),
1319  "Unknown metainfo DB access error",
1321  }
1322  }
1323  reply.SetByKey("MetainfoDB", db_stat_node);
1324 
1325  x_SendSyncMessage(reply);
1327 }
1328 
1329 
1330 void
1332  const CJsonNode & message,
1333  const SCommonRequestArguments & common_args)
1334 {
1335  x_CheckNonAnonymousClient("alert acknowledging");
1336 
1338  string msg = "Only administrators can acknowledge alerts";
1340  NCBI_THROW(CNetStorageServerException, ePrivileges, msg);
1341  }
1342 
1343  if (!message.HasKey("Name"))
1344  NCBI_THROW(CNetStorageServerException, eInvalidArgument,
1345  "Mandatory argument Name is not supplied "
1346  "in ACKALERT command");
1347  if (!message.HasKey("User"))
1348  NCBI_THROW(CNetStorageServerException, eInvalidArgument,
1349  "Mandatory argument User is not supplied "
1350  "in ACKALERT command");
1351 
1354 
1356  message.GetString("Name"),
1357  message.GetString("User"));
1358  CJsonNode reply = CreateResponseMessage(common_args.m_SerialNumber);
1359  switch (ack_result) {
1360  case eAcknowledged:
1361  // No warning needed, everything is fine
1362  break;
1363  case eNotFound:
1364  AppendWarning(reply, NCBI_ERRCODE_X_NAME(NetStorageServer_ErrorCode),
1365  "Alert has not been found", kScopeLogic,
1367  break;
1368  case eAlreadyAcknowledged:
1369  AppendWarning(reply, NCBI_ERRCODE_X_NAME(NetStorageServer_ErrorCode),
1370  "Alert has already been acknowledged", kScopeLogic,
1372  break;
1373  default:
1374  AppendWarning(reply, NCBI_ERRCODE_X_NAME(NetStorageServer_ErrorCode),
1375  "Unknown acknowledge result", kScopeLogic,
1377  }
1378  x_SendSyncMessage(reply);
1380 }
1381 
1382 
1383 void
1385  const CJsonNode & message,
1386  const SCommonRequestArguments & common_args)
1387 {
1388  x_CheckNonAnonymousClient("server reconfiguration");
1389 
1390  if (!m_Server->AnybodyCanReconfigure()) {
1392  string msg = "Only administrators can reconfigure server "
1393  "(client: " + m_Client + ")";
1395  NCBI_THROW(CNetStorageServerException, ePrivileges, msg);
1396  }
1397  }
1398 
1401 
1402  // Unconditionally reload the decryptor in case if the key files are
1403  // changed
1405 
1407  common_args.m_SerialNumber);
1409 
1410  // Validate the configuration file first without reloading the application
1411  // config.
1412  string config_path = app->GetConfigPath();
1413  CNcbiIfstream config_stream(config_path.c_str());
1414  CNcbiRegistry candidate_reg(config_stream);
1415  vector<string> config_warnings;
1416  CJsonNode backend_conf;
1417 
1418  NSTValidateConfigFile(candidate_reg, config_warnings,
1419  false); // false -> no exc on bad port
1420  backend_conf = NSTGetBackendConfiguration(candidate_reg, m_Server,
1421  config_warnings);
1422 
1423  if (!config_warnings.empty()) {
1424  string msg;
1425  string alert_msg;
1426  for (vector<string>::const_iterator k = config_warnings.begin();
1427  k != config_warnings.end(); ++k) {
1428  ERR_POST(*k);
1429  if (!msg.empty()) {
1430  msg += "; ";
1431  alert_msg += "\n";
1432  }
1433  msg += *k;
1434  alert_msg += *k;
1435  }
1436  m_Server->RegisterAlert(eReconfigure, alert_msg);
1437  NCBI_THROW(CNetStorageServerException, eInvalidConfig,
1438  "Configuration file is not well formed; " + msg);
1439  }
1440 
1441  // Check that the decryption of the sensitive items works
1443  string decrypt_warning;
1444  params.Read(candidate_reg, "server", decrypt_warning);
1445 
1446  if (!decrypt_warning.empty()) {
1447  ERR_POST(decrypt_warning);
1448  m_Server->RegisterAlert(eDecryptAdminNames, decrypt_warning);
1449  NCBI_THROW(CNetStorageServerException, eInvalidConfig, decrypt_warning);
1450  }
1451 
1452 
1453  // Here: the configuration has been validated and could be loaded
1454 
1455  bool reloaded = app->ReloadConfig(
1457 
1458  // The !m_Server->AnybodyCanReconfigure() part is needed because the
1459  // file might not be changed but the encryption keys could.
1460  if (!reloaded && !m_Server->AnybodyCanReconfigure()) {
1461  AppendWarning(reply, NCBI_ERRCODE_X_NAME(NetStorageServer_ErrorCode),
1462  "Configuration file has not been changed, "
1463  "RECONFIGURE ignored", kScopeLogic,
1465  x_SendSyncMessage(reply);
1467  return;
1468  }
1469 
1470  // Update the config file checksum in memory
1471  vector<string> config_checksum_warnings;
1472  string config_checksum = NST_GetConfigFileChecksum(
1473  app->GetConfigPath(), config_checksum_warnings);
1474  if (config_checksum_warnings.empty()) {
1475  m_Server->SetRAMConfigFileChecksum(config_checksum);
1476  m_Server->SetDiskConfigFileChecksum(config_checksum);
1477  } else {
1478  for (vector<string>::const_iterator
1479  k = config_checksum_warnings.begin();
1480  k != config_checksum_warnings.end(); ++k)
1481  ERR_POST(*k);
1482  }
1483 
1484 
1485  // Reconfigurable at runtime:
1486  // [server]: logging, admin name list, max connections, network timeout
1487  // [metadata_conf]
1488  const CNcbiRegistry & reg = app->GetConfig();
1489 
1490  CJsonNode server_diff = m_Server->SetParameters(params, true);
1491  CJsonNode metadata_diff = m_Server->ReadMetadataConfiguration(reg);
1492  CJsonNode backend_diff = m_Server->GetBackendConfDiff(backend_conf);
1493  CJsonNode db_diff = m_Server->GetDb().SetParameters(reg);
1494 
1495  m_Server->SetBackendConfiguration(backend_conf);
1496 
1497  m_Server->AcknowledgeAlert(eReconfigure, "NSTAcknowledge");
1498  m_Server->AcknowledgeAlert(eStartupConfig, "NSTAcknowledge");
1499  m_Server->AcknowledgeAlert(eConfigOutOfSync, "NSTAcknowledge");
1501 
1502 
1503  if (server_diff.IsNull() &&
1504  metadata_diff.IsNull() &&
1505  backend_diff.IsNull() &&
1506  db_diff.IsNull()) {
1507  if (m_ConnContext.NotNull())
1508  GetDiagContext().Extra().Print("accepted_changes", "none");
1509  AppendWarning(reply, NCBI_ERRCODE_X_NAME(NetStorageServer_ErrorCode),
1510  "No changeable parameters were identified "
1511  "in the new configuration file",
1513  reply.SetByKey("What", CJsonNode::NewObjectNode());
1514  x_SendSyncMessage(reply);
1516  return;
1517  }
1518 
1519  CJsonNode total_changes = CJsonNode::NewObjectNode();
1520  if (!server_diff.IsNull())
1521  total_changes.SetByKey("server", server_diff);
1522  if (!metadata_diff.IsNull())
1523  total_changes.SetByKey("metadata_conf", metadata_diff);
1524  if (!backend_diff.IsNull())
1525  total_changes.SetByKey("backend_conf", backend_diff);
1526  if (!db_diff.IsNull())
1527  total_changes.SetByKey("db_conf", db_diff);
1528 
1529  reply.SetByKey("What", total_changes);
1530  x_SendSyncMessage(reply);
1532 }
1533 
1534 
1535 void
1537  const CJsonNode & message,
1538  const SCommonRequestArguments & common_args)
1539 {
1540  x_CheckNonAnonymousClient("server shutdown");
1541 
1543  string msg = "Only administrators can shutdown server";
1545  NCBI_THROW(CNetStorageServerException, ePrivileges, msg);
1546  }
1547 
1548  if (!message.HasKey("Mode")) {
1549  NCBI_THROW(CNetStorageServerException, eMandatoryFieldsMissed,
1550  "Mandatory field 'Mode' is missed");
1551  }
1552 
1553  string mode;
1554  mode = message.GetString("Mode");
1555  if (mode != "hard" && mode != "soft") {
1556  NCBI_THROW(CNetStorageServerException, eInvalidArgument,
1557  "Allowed 'Mode' values are 'soft' and 'hard'");
1558  }
1559 
1560  if (mode == "hard")
1561  exit(1);
1562 
1563  m_Server->SetShutdownFlag(SIGTERM);
1564 
1565  // Send success response
1568 }
1569 
1570 
1571 void
1573  const CJsonNode & message,
1574  const SCommonRequestArguments & common_args)
1575 {
1576  x_CheckNonAnonymousClient("clients info request");
1579 
1580  // First part is always there: in-memory clients
1581  CJsonNode reply = CreateResponseMessage(common_args.m_SerialNumber);
1582  reply.SetByKey("Clients", m_Server->GetClientRegistry().Serialize());
1583 
1584  // Second part might be here
1585  bool db_access = (m_MetadataOption == eMetadataMonitoring ||
1587  if (db_access) {
1588  try {
1589  vector<string> client_names;
1590  int status = m_Server->GetDb().ExecSP_GetClients(client_names);
1591  if (status != kSPStatusOK) {
1592  reply.SetString("DBClients", "MetadataAccessWarning");
1593  AppendWarning(reply, NCBI_ERRCODE_X_NAME(NetStorageServer_ErrorCode),
1594  "Stored procedure return code is non zero",
1596  } else {
1597  CJsonNode db_clients_node(CJsonNode::NewArrayNode());
1598  for (vector<string>::const_iterator
1599  k = client_names.begin(); k != client_names.end(); ++k) {
1600  db_clients_node.AppendString(*k);
1601  }
1602  reply.SetByKey("DBClients", db_clients_node);
1603  }
1604  } catch (const exception & ex) {
1605  reply.SetString("DBClients", "MetadataAccessWarning");
1606  string error_scope;
1607  Int8 error_code;
1608  unsigned int error_sub_code;
1609 
1610  if (GetReplyMessageProperties(ex, &error_scope, &error_code,
1611  &error_sub_code) == false)
1612  error_sub_code = eDatabaseWarning;
1613 
1614  AppendWarning(reply, error_code,
1615  "Error while getting a list of clients "
1616  "in the metainfo DB: " + string(ex.what()),
1617  error_scope, error_sub_code);
1618  } catch (...) {
1619  reply.SetString("DBClients", "MetadataAccessWarning");
1620  AppendWarning(reply, NCBI_ERRCODE_X_NAME(NetStorageServer_ErrorCode),
1621  "Unknown error while getting a list of clients "
1622  "in the metainfo DB",
1624  }
1625  } else {
1626  reply.SetString("DBClients", "NoMetadataAccess");
1627  }
1628 
1629  x_SendSyncMessage(reply);
1631 }
1632 
1633 
1634 void
1636  const CJsonNode & message,
1637  const SCommonRequestArguments & common_args)
1638 {
1639  x_CheckNonAnonymousClient("users info request");
1642 
1643  CJsonNode reply = CreateResponseMessage(common_args.m_SerialNumber);
1644  try {
1645  vector< pair<string, string> > users;
1646  int status = m_Server->GetDb().ExecSP_GetUsers(users);
1647  if (status != kSPStatusOK) {
1648  AppendError(reply, NCBI_ERRCODE_X_NAME(NetStorageServer_ErrorCode),
1649  "Error executing stored procedure - return code is "
1650  "non zero", kScopeLogic, eDatabaseWarning);
1651  } else {
1653  for (vector< pair<string, string> >::const_iterator
1654  k = users.begin(); k != users.end(); ++k) {
1656  a_user.SetString("Name", (*k).first);
1657  a_user.SetString("Namespace", (*k).second);
1658  u_list.Append(a_user);
1659  }
1660  reply.SetByKey("Users", u_list);
1661  }
1662  } catch (const exception & ex) {
1663  AppendError(reply, NCBI_ERRCODE_X_NAME(NetStorageServer_ErrorCode),
1664  ex.what(), kScopeStdException, eDatabaseWarning);
1665  } catch (...) {
1666  AppendError(reply, NCBI_ERRCODE_X_NAME(NetStorageServer_ErrorCode),
1667  "Unknown error while getting a list of users "
1668  "in the metainfo DB",
1670  }
1671 
1672  x_SendSyncMessage(reply);
1674 }
1675 
1676 
1677 void
1679  const CJsonNode & message,
1680  const SCommonRequestArguments & common_args)
1681 {
1682  x_CheckNonAnonymousClient("metadata configuration request");
1685 
1686  CJsonNode reply = CreateResponseMessage(common_args.m_SerialNumber);
1687 
1688  reply.SetByKey("Services", m_Server->SerializeMetadataInfo());
1689  x_SendSyncMessage(reply);
1691 }
1692 
1693 
1694 void
1696  const CJsonNode & message,
1697  const SCommonRequestArguments & common_args)
1698 {
1699  x_CheckNonAnonymousClient("object info request");
1702 
1703  CJsonNode reply = CreateResponseMessage(common_args.m_SerialNumber);
1704  bool need_db_access = true;
1705  CNSTServiceProperties service_properties; // not used here
1707  need_db_access = x_DetectMetaDBNeedOnGetObjectInfo(message,
1708  service_properties);
1709  CDirectNetStorageObject direct_object = x_GetObject(message);
1710  // First source of data - MS SQL database at hand
1711  TNSTDBValue<string> user_namespace;
1712  TNSTDBValue<string> user_name;
1713  if (need_db_access) {
1714  try {
1715  TNSTDBValue<CTime> expiration;
1716  TNSTDBValue<CTime> creation;
1717  TNSTDBValue<CTime> obj_read;
1718  TNSTDBValue<CTime> obj_write;
1719  TNSTDBValue<CTime> attr_read;
1720  TNSTDBValue<CTime> attr_write;
1721  TNSTDBValue<Int8> read_count;
1722  TNSTDBValue<Int8> write_count;
1723  TNSTDBValue<string> client_name;
1724  TNSTDBValue<Int8> obj_ttl;
1725 
1726  // The parameters are output only (from the SP POV) however the
1727  // integer values should be initialized to avoid valgrind complains
1728  read_count.m_Value = 0;
1729  write_count.m_Value = 0;
1730  int status = m_Server->GetDb().
1731  ExecSP_GetObjectFixedAttributes(
1732  direct_object.Locator().GetUniqueKey(),
1733  expiration, creation,
1734  obj_read, obj_write,
1735  attr_read, attr_write,
1736  read_count, write_count,
1737  client_name,
1738  user_namespace, user_name,
1739  obj_ttl);
1740 
1741  if (status != kSPStatusOK) {
1742  // The record in the meta DB for the object is not found
1743  x_FillObjectInfo(reply, "NoMetadataFound");
1744  } else {
1745  // The record in the meta DB for the object is found
1746  if (expiration.m_IsNull) {
1747  reply.SetString("ExpirationTime", "NotSet");
1748  reply.SetString("Expired", "False");
1749  } else {
1750  reply.SetString("ExpirationTime",
1751  expiration.m_Value.AsString());
1752  if (expiration.m_Value < CurrentTime())
1753  reply.SetString("Expired", "True");
1754  else
1755  reply.SetString("Expired", "False");
1756  }
1757  x_SetObjectInfoReply(reply, "CreationTime", creation);
1758  x_SetObjectInfoReply(reply, "ObjectReadTime", obj_read);
1759  x_SetObjectInfoReply(reply, "ObjectWriteTime", obj_write);
1760  x_SetObjectInfoReply(reply, "AttrReadTime", attr_read);
1761  x_SetObjectInfoReply(reply, "AttrWriteTime", attr_write);
1762  x_SetObjectInfoReply(reply, "ObjectReadCount", read_count);
1763  x_SetObjectInfoReply(reply, "ObjectWriteCount", write_count);
1764  x_SetObjectInfoReply(reply, "ClientName", client_name);
1765  x_SetObjectInfoReply(reply, "UserNamespace", user_namespace);
1766  x_SetObjectInfoReply(reply, "UserName", user_name);
1767 
1768  if (obj_ttl.m_IsNull) {
1769  if (service_properties.GetTTL().m_IsNull)
1770  reply.SetString("TTL", "infinity");
1771  else
1772  reply.SetString("TTL", service_properties.
1773  GetTTL().m_Value.
1774  AsSmartString(kTimeSpanFlags));
1775  } else {
1776  CTimeSpan ttl(static_cast<long>(obj_ttl.m_Value));
1777  reply.SetString("TTL", ttl.AsSmartString(kTimeSpanFlags));
1778  }
1779  }
1780  } catch (const CNetStorageServerException & ex) {
1781  // eDatabaseError => no connection or MS SQL error
1782  x_FillObjectInfo(reply, "MetadataAccessWarning");
1783  AppendWarning(reply, NCBI_ERRCODE_X_NAME(NetStorageServer_ErrorCode),
1784  ex.what(), ex.GetType(), ex.GetErrCode());
1785  } catch (const exception & ex) {
1786  x_FillObjectInfo(reply, "MetadataAccessWarning");
1787  string error_scope;
1788  Int8 error_code;
1789  unsigned int error_sub_code;
1790 
1791  if (GetReplyMessageProperties(ex, &error_scope, &error_code,
1792  &error_sub_code) == false)
1793  error_sub_code = eDatabaseWarning;
1794 
1795  AppendWarning(reply, error_code,
1796  "Error while gettingobject fixed attributes: " +
1797  string(ex.what()), error_scope, error_sub_code);
1798  } catch (...) {
1799  x_FillObjectInfo(reply, "MetadataAccessWarning");
1800  AppendWarning(reply, NCBI_ERRCODE_X_NAME(NetStorageServer_ErrorCode),
1801  "Unknown error while getting object fixed attributes",
1803  }
1804  } else {
1805  x_FillObjectInfo(reply, "NoMetadataAccess");
1806  }
1807 
1808 
1809  // Second source of data - remote object info
1811  bool remote_info_error = true;
1812  try {
1813  CJsonNode object_info = direct_object.GetInfo().ToJSON();
1814  if (m_Server->IsLogTimingNSTAPI())
1815  m_Timing.Append("NetStorageAPI GetInfo", start);
1816  start = 0.0;
1817 
1818  for (CJsonIterator it = object_info.Iterate(); it; ++it) {
1819  string key = it.GetKey();
1820  if (key != "CreationTime")
1821  reply.SetByKey(it.GetKey(), it.GetNode());
1822  }
1823  remote_info_error = false;
1824  } catch (const exception & ex) {
1825  if (double(start) != 0.0 && m_Server->IsLogTimingNSTAPI())
1826  m_Timing.Append("NetStorageAPI GetInfo exception", start);
1827 
1828  ERR_POST(ex);
1829 
1830  string error_scope;
1831  Int8 error_code;
1832  unsigned int error_sub_code;
1833 
1834  if (GetReplyMessageProperties(ex, &error_scope, &error_code,
1835  &error_sub_code) == false)
1836  error_sub_code = eRemoteObjectInfoWarning;
1837 
1838  AppendError(reply, error_code,
1839  "Error while getting remote object info: " +
1840  string(ex.what()), error_scope, error_sub_code);
1841  } catch (...) {
1842  if (double(start) != 0.0 && m_Server->IsLogTimingNSTAPI())
1843  m_Timing.Append("NetStorageAPI GetInfo exception", start);
1844 
1845  string msg = "Unknown error while getting remote object info";
1846 
1847  ERR_POST(msg);
1848  AppendError(reply, NCBI_ERRCODE_X_NAME(NetStorageServer_ErrorCode),
1850  }
1851 
1852  bool need_client_update = false;
1853  CNSTUserID remote_client;
1854  if (need_db_access && user_name.m_IsNull && remote_info_error == false) {
1855  // The object owner is not known in the DB however the
1856  // remote storage may have it. See CXX-8023
1857 
1858  try {
1859  pair<string, string> ns_and_name = direct_object.GetUserInfo();
1860  remote_client.SetNamespace(ns_and_name.first);
1861  remote_client.SetName(ns_and_name.second);
1862 
1863  reply.SetString("UserNamespace", ns_and_name.first);
1864  reply.SetString("UserName", ns_and_name.second);
1865 
1866  need_client_update = true;
1867  } catch (const exception & ex) {
1868  ERR_POST("Error retrieving user name and "
1869  "user namespace from a remote storage: " << ex);
1870  } catch (...) {
1871  ERR_POST("Unknown error retrieving user name and "
1872  "user namespace from a remote storage");
1873  }
1874  }
1875 
1876  x_SendSyncMessage(reply);
1877 
1878  if (need_client_update) {
1879  try {
1880  Int8 user_id = x_GetUserID(remote_client);
1882  direct_object.Locator().GetUniqueKey(),
1883  user_id);
1884  } catch (const exception & ex) {
1885  ERR_POST("Error updating the user ID "
1886  "after getting the object info: " << ex);
1887  } catch (...) {
1888  ERR_POST("Unknown error updating the user ID "
1889  "after getting the object info");
1890  }
1891  }
1892 
1894 }
1895 
1896 
1898  const string & val)
1899 {
1900  reply.SetString("ExpirationTime", val);
1901  reply.SetString("Expired", val);
1902  reply.SetString("CreationTime", val);
1903  reply.SetString("ObjectReadTime", val);
1904  reply.SetString("ObjectWriteTime", val);
1905  reply.SetString("AttrReadTime", val);
1906  reply.SetString("AttrWriteTime", val);
1907  reply.SetString("ObjectReadCount", val);
1908  reply.SetString("ObjectWriteCount", val);
1909  reply.SetString("ClientName", val);
1910  reply.SetString("UserName", val);
1911  reply.SetString("UserNamespace", val);
1912  reply.SetString("TTL", val);
1913 }
1914 
1915 
1916 void
1918  const string & name,
1919  const TNSTDBValue<CTime> & value)
1920 {
1921  if (value.m_IsNull)
1922  reply.SetString(name, "NotSet");
1923  else
1924  reply.SetString(name, value.m_Value.AsString());
1925 }
1926 
1927 
1928 void
1930  const string & name,
1931  const TNSTDBValue<Int8> & value)
1932 {
1933  if (value.m_IsNull)
1934  reply.SetString(name, "NotSet");
1935  else
1936  reply.SetString(name, NStr::NumericToString(value.m_Value));
1937 }
1938 
1939 
1940 void
1942  const string & name,
1943  const TNSTDBValue<string> & value)
1944 {
1945  if (value.m_IsNull)
1946  reply.SetString(name, "NotSet");
1947  else
1948  reply.SetString(name, value.m_Value);
1949 }
1950 
1951 
1952 void
1954  const CJsonNode & message,
1955  const SCommonRequestArguments & common_args)
1956 {
1957  x_CheckNonAnonymousClient("attributes list request");
1960 
1961  if (!message.HasKey("ObjectLoc") && !message.HasKey("UserKey"))
1962  NCBI_THROW(CNetStorageServerException, eMandatoryFieldsMissed,
1963  "GETATTRLIST message must have ObjectLoc or UserKey. "
1964  "None of them was found.");
1965 
1967  NCBI_THROW(CNetStorageServerException, eInvalidMetaInfoRequest,
1968  "DB access is restricted in HELLO");
1969 
1972  x_ValidateWriteMetaDBAccess(message);
1973 
1975  x_CreateClient();
1976 
1977  CJsonNode reply = CreateResponseMessage(common_args.m_SerialNumber);
1978  CDirectNetStorageObject direct_object = x_GetObject(message);
1979  string object_key =
1980  direct_object.Locator().GetUniqueKey();
1981 
1982  // Note: object expiration is checked in a stored procedure
1983  vector<string> attr_names;
1984  int status = m_Server->GetDb().ExecSP_GetAttributeNames(
1985  object_key, attr_names);
1986 
1987  if (status == kSPStatusOK) {
1988  // Everything is fine, the attribute is found
1990  for (vector<string>::const_iterator k = attr_names.begin();
1991  k != attr_names.end(); ++k)
1992  names.AppendString(*k);
1993  reply.SetByKey("AttributeNames", names);
1994  } else {
1995  x_CheckExpirationStatus(status);
1996  x_CheckExistanceStatus(status);
1997  NCBI_THROW(CNetStorageServerException, eInternalError,
1998  "Unknown GetAttributeNames status");
1999  }
2000 
2001  x_SendSyncMessage(reply);
2003 }
2004 
2005 
2006 void
2008  const CJsonNode & message,
2009  const SCommonRequestArguments & common_args)
2010 {
2011  x_CheckNonAnonymousClient("client objects request");
2014 
2015  if (!message.HasKey("ClientName"))
2016  NCBI_THROW(CNetStorageServerException, eMandatoryFieldsMissed,
2017  "GETCLIENTOBJECTS message must have ClientName.");
2018  string client_name = NStr::TruncateSpaces(message.GetString("ClientName"));
2019 
2020  TNSTDBValue<Int8> limit;
2021  limit.m_IsNull = true;
2022  limit.m_Value = 0;
2023  if (message.HasKey("Limit")) {
2024  try {
2025  limit.m_Value = message.GetInteger("Limit");
2026  limit.m_IsNull = false;
2027  } catch (...) {
2028  NCBI_THROW(CNetStorageServerException, eInvalidArgument,
2029  "GETCLIENTOBJECTS message Limit argument "
2030  "must be an integer.");
2031  }
2032  if (limit.m_Value <= 0)
2033  NCBI_THROW(CNetStorageServerException, eInvalidArgument,
2034  "GETCLIENTOBJECTS message Limit argument "
2035  "must be > 0.");
2036  }
2037 
2039  NCBI_THROW(CNetStorageServerException, eInvalidMetaInfoRequest,
2040  "DB access is restricted in HELLO");
2041 
2044  // false => do not expect an object
2045  x_ValidateWriteMetaDBAccess(message, false);
2046  }
2047 
2049  x_CreateClient();
2050 
2051  CJsonNode reply = CreateResponseMessage(common_args.m_SerialNumber);
2052 
2053  vector<string> locators;
2054  Int8 total_client_objects;
2055  int status = m_Server->GetDb().ExecSP_GetClientObjects(
2056  client_name, limit,
2057  total_client_objects, locators);
2058 
2059  if (status == kSPStatusOK) {
2060  // Everything is fine, the object is found
2061  CJsonNode locators_node(CJsonNode::NewArrayNode());
2062  for (vector<string>::const_iterator k = locators.begin();
2063  k != locators.end(); ++k)
2064  locators_node.AppendString(*k);
2065  reply.SetByKey("ObjectLocators", locators_node);
2066  reply.SetInteger("TotalClientObjects", total_client_objects);
2067  } else {
2068  if (status == -1) {
2069  // Client is not found
2070  NCBI_THROW(CNetStorageServerException, eNetStorageClientNotFound,
2071  "NetStorage client '" + client_name + "' is not found");
2072  } else {
2073  // Unknown status
2074  NCBI_THROW(CNetStorageServerException, eInternalError,
2075  "Unknown GetClientObjects status");
2076  }
2077  }
2078 
2079  x_SendSyncMessage(reply);
2081 }
2082 
2083 
2084 void
2086  const CJsonNode & message,
2087  const SCommonRequestArguments & common_args)
2088 {
2089  x_CheckNonAnonymousClient("user objects request");
2092 
2093  if (!message.HasKey("UserName"))
2094  NCBI_THROW(CNetStorageServerException, eMandatoryFieldsMissed,
2095  "GETUSEROBJECTS message must have UserName.");
2096  string user_name = NStr::TruncateSpaces(message.GetString("UserName"));
2097  user_name = NStr::ToLower(user_name);
2098 
2099  if (!message.HasKey("UserNamespace"))
2100  NCBI_THROW(CNetStorageServerException, eMandatoryFieldsMissed,
2101  "GETUSEROBJECTS message must have UserNamespace.");
2102  string user_namespace = NStr::TruncateSpaces(
2103  message.GetString("UserNamespace"));
2104  user_namespace = NStr::ToLower(user_namespace);
2105 
2106  TNSTDBValue<Int8> limit;
2107  limit.m_IsNull = true;
2108  limit.m_Value = 0;
2109  if (message.HasKey("Limit")) {
2110  try {
2111  limit.m_Value = message.GetInteger("Limit");
2112  limit.m_IsNull = false;
2113  } catch (...) {
2114  NCBI_THROW(CNetStorageServerException, eInvalidArgument,
2115  "GETUSEROBJECTS message Limit argument "
2116  "must be an integer.");
2117  }
2118  if (limit.m_Value <= 0)
2119  NCBI_THROW(CNetStorageServerException, eInvalidArgument,
2120  "GETUSEROBJECTS message Limit argument "
2121  "must be > 0.");
2122  }
2123 
2125  NCBI_THROW(CNetStorageServerException, eInvalidMetaInfoRequest,
2126  "DB access is restricted in HELLO");
2127 
2130  // false => do not expect an object
2131  x_ValidateWriteMetaDBAccess(message, false);
2132  }
2133 
2135  x_CreateClient();
2136 
2137  CJsonNode reply = CreateResponseMessage(common_args.m_SerialNumber);
2138 
2139  vector<string> locators;
2140  Int8 total_client_objects;
2141  int status = m_Server->GetDb().ExecSP_GetUserObjects(
2142  user_name, user_namespace, limit,
2143  total_client_objects, locators);
2144 
2145  if (status == kSPStatusOK) {
2146  // Everything is fine, the object is found
2147  CJsonNode locators_node(CJsonNode::NewArrayNode());
2148  for (vector<string>::const_iterator k = locators.begin();
2149  k != locators.end(); ++k)
2150  locators_node.AppendString(*k);
2151  reply.SetByKey("ObjectLocators", locators_node);
2152  reply.SetInteger("TotalUserObjects", total_client_objects);
2153  } else {
2154  if (status == -1) {
2155  // Client is not found
2156  NCBI_THROW(CNetStorageServerException, eNetStorageClientNotFound,
2157  "NetStorage user is not found");
2158  } else {
2159  // Unknown status
2160  NCBI_THROW(CNetStorageServerException, eInternalError,
2161  "Unknown GetUserObjects status");
2162  }
2163  }
2164 
2165  x_SendSyncMessage(reply);
2167 }
2168 
2169 
2170 void
2172  const CJsonNode & message,
2173  const SCommonRequestArguments & common_args)
2174 {
2175  x_CheckNonAnonymousClient("attribute value request");
2178 
2179  if (!message.HasKey("AttrName"))
2180  NCBI_THROW(CNetStorageServerException, eMandatoryFieldsMissed,
2181  "Mandatory field 'AttrName' is missed");
2182 
2183  string attr_name = message.GetString("AttrName");
2184  if (attr_name.empty())
2185  NCBI_THROW(CNetStorageServerException, eInvalidArgument,
2186  "Attribute name must not be empty");
2187 
2188  // CXX-7977: the names are lowercased...
2189  attr_name = NStr::ToLower(attr_name);
2190 
2191  if (!message.HasKey("ObjectLoc") && !message.HasKey("UserKey"))
2192  NCBI_THROW(CNetStorageServerException, eMandatoryFieldsMissed,
2193  "GETATTR message must have ObjectLoc or UserKey. "
2194  "None of them was found.");
2195 
2197  NCBI_THROW(CNetStorageServerException, eInvalidMetaInfoRequest,
2198  "DB access is restricted in HELLO");
2199 
2202  x_ValidateWriteMetaDBAccess(message);
2203 
2204 
2206  x_CreateClient();
2207 
2208  CJsonNode reply = CreateResponseMessage(common_args.m_SerialNumber);
2209  CDirectNetStorageObject direct_object = x_GetObject(message);
2210  string object_key =
2211  direct_object.Locator().GetUniqueKey();
2212 
2213  string value;
2214  int status = m_Server->GetDb().ExecSP_GetAttribute(
2215  object_key, attr_name,
2217  value);
2218 
2219  if (status == kSPStatusOK) {
2220  // Everything is fine, the attribute is found
2221  reply.SetString("AttrValue", value);
2222  } else {
2223  x_CheckExistanceStatus(status);
2224  x_CheckExpirationStatus(status);
2225  if (status == -2) {
2226  // Attribute is not found
2227  NCBI_THROW(CNetStorageServerException, eNetStorageAttributeNotFound,
2228  "NetStorage attribute is not found");
2229  }
2230  if (status == -3) {
2231  // Attribute value is not found
2233  eNetStorageAttributeValueNotFound,
2234  "NetStorage attribute value is not found");
2235  }
2236  // Unknown status
2237  NCBI_THROW(CNetStorageServerException, eInternalError,
2238  "Unknown GetAttributeValue status");
2239  }
2240 
2241  x_SendSyncMessage(reply);
2243 }
2244 
2245 
2246 void
2248  const CJsonNode & message,
2249  const SCommonRequestArguments & common_args)
2250 {
2251  x_CheckNonAnonymousClient("attribute value setting");
2254 
2255  if (!message.HasKey("AttrName"))
2256  NCBI_THROW(CNetStorageServerException, eMandatoryFieldsMissed,
2257  "Mandatory field 'AttrName' is missed");
2258 
2259  string attr_name = message.GetString("AttrName");
2260  SNetStorage::SLimits::Check<SNetStorage::SLimits::SAttrName>(attr_name);
2261 
2262  // CXX-7977: the names are lowercased...
2263  attr_name = NStr::ToLower(attr_name);
2264 
2265  if (!message.HasKey("AttrValue"))
2266  NCBI_THROW(CNetStorageServerException, eMandatoryFieldsMissed,
2267  "Mandatory field 'AttrValue' is missed");
2268 
2269  string value = message.GetString("AttrValue");
2270  SNetStorage::SLimits::Check<SNetStorage::SLimits::SAttrValue>(value);
2271 
2272  if (!message.HasKey("ObjectLoc") && !message.HasKey("UserKey"))
2273  NCBI_THROW(CNetStorageServerException, eMandatoryFieldsMissed,
2274  "SETATTR message must have ObjectLoc or UserKey. "
2275  "None of them was found.");
2276 
2279  NCBI_THROW(CNetStorageServerException, eInvalidMetaInfoRequest,
2280  "State changing operations are restricted in HELLO");
2281 
2282  bool create_if_not_found = true; // default
2283  if (message.HasKey("CreateIfNotFound"))
2284  create_if_not_found = message.GetBoolean("CreateIfNotFound");
2285 
2286 
2287  // The only options left are NotSpecified and Required
2288  x_ValidateWriteMetaDBAccess(message);
2289 
2290  x_CreateClient();
2291 
2292  CJsonNode reply = CreateResponseMessage(common_args.m_SerialNumber);
2293  CDirectNetStorageObject direct_object = x_GetObject(message);
2294  string object_key =
2295  direct_object.Locator().GetUniqueKey();
2296  string object_loc =
2297  direct_object.Locator().GetLocator();
2298 
2301 
2302  // The SP will throw an exception if an error occured
2303  int status = m_Server->GetDb().ExecSP_AddAttribute(
2304  object_key, object_loc,
2305  attr_name, value,
2306  m_DBClientID, create_if_not_found,
2307  ttl);
2308  x_CheckExistanceStatus(status);
2309  x_CheckExpirationStatus(status);
2310  if (status != kSPStatusOK) {
2311  // Unknown status
2312  NCBI_THROW(CNetStorageServerException, eInternalError,
2313  "Unknown AddAttribute status");
2314  }
2315 
2316  x_SendSyncMessage(reply);
2318 }
2319 
2320 
2321 void
2323  const CJsonNode & message,
2324  const SCommonRequestArguments & common_args)
2325 {
2326  x_CheckNonAnonymousClient("attribute deletion");
2329 
2330  if (!message.HasKey("AttrName"))
2331  NCBI_THROW(CNetStorageServerException, eMandatoryFieldsMissed,
2332  "Mandatory field 'AttrName' is missed");
2333 
2334  string attr_name = message.GetString("AttrName");
2335  if (attr_name.empty())
2336  NCBI_THROW(CNetStorageServerException, eInvalidArgument,
2337  "Attribute name must not be empty");
2338 
2339  if (!message.HasKey("ObjectLoc") && !message.HasKey("UserKey"))
2340  NCBI_THROW(CNetStorageServerException, eMandatoryFieldsMissed,
2341  "DELATTR message must have ObjectLoc or UserKey. "
2342  "None of them was found.");
2343 
2346  NCBI_THROW(CNetStorageServerException, eInvalidMetaInfoRequest,
2347  "State changing operations are restricted in HELLO");
2348 
2349  // The only options left are NotSpecified and Required
2350  x_ValidateWriteMetaDBAccess(message);
2351 
2352  x_CreateClient();
2353 
2354  CJsonNode reply = CreateResponseMessage(common_args.m_SerialNumber);
2355  CDirectNetStorageObject direct_object = x_GetObject(message);
2356  string object_key =
2357  direct_object.Locator().GetUniqueKey();
2358 
2359  int status = m_Server->GetDb().ExecSP_DelAttribute(
2360  object_key, attr_name);
2361 
2362  x_CheckExpirationStatus(status);
2363  if (status == kSPObjectNotFound) {
2364  // Object is not found
2365  AppendWarning(reply, NCBI_ERRCODE_X_NAME(NetStorageServer_ErrorCode),
2368  } else if (status == -2) {
2369  // Attribute is not found
2370  AppendWarning(reply, NCBI_ERRCODE_X_NAME(NetStorageServer_ErrorCode),
2371  "NetStorage attribute is not found",
2373  } else if (status == -3) {
2374  // Attribute value is not found
2375  AppendWarning(reply, NCBI_ERRCODE_X_NAME(NetStorageServer_ErrorCode),
2376  "NetStorage attribute value is not found",
2378  } else if (status != kSPStatusOK) {
2379  // Unknown status
2380  NCBI_THROW(CNetStorageServerException, eInternalError,
2381  "Unknown DelAttributeValue status");
2382  }
2383 
2384  x_SendSyncMessage(reply);
2386 }
2387 
2388 
2389 void
2391  const CJsonNode & message,
2392  const SCommonRequestArguments & common_args)
2393 {
2394  x_CheckNonAnonymousClient("object creation");
2397 
2399  NCBI_THROW(CNetStorageServerException, eInvalidMetaInfoRequest,
2400  "State changing operations are restricted in HELLO");
2401 
2403  SICacheSettings icache_settings = ExtractICacheSettings(message);
2404 
2405  x_CheckICacheSettings(icache_settings);
2406 
2407  // The DB update depends on the command flags, on the HELLO
2408  // metadata option and may depend on the HELLO service
2410 
2412  // Meta information is required so check the DB
2413  x_CreateClient();
2414 
2415  // This call will extract the user info from the context and create the
2416  // user in DB if needed
2417  x_CreateUser();
2418  }
2419 
2420  // Create the object stream depending on settings
2421  m_ObjectBeingWritten = x_CreateObjectStream(icache_settings, flags);
2422 
2423  CJsonNode reply = CreateResponseMessage(common_args.m_SerialNumber);
2424  string locator = m_ObjectBeingWritten.GetLoc();
2425 
2426  reply.SetString("ObjectLoc", locator);
2427  x_SendSyncMessage(reply);
2428 
2429  if (m_ConnContext.NotNull() && !message.HasKey("ObjectLoc")) {
2430  GetDiagContext().Extra()
2431  .Print("ObjectLoc", locator)
2432  .Print("ObjectKey", m_ObjectBeingWritten.Locator().GetUniqueKey());
2433  }
2434 
2435  // Inform the message receiving loop that raw data are to follow
2437  m_DataMessageSN = common_args.m_SerialNumber;
2438  m_CreateRequest = true;
2439  m_ObjectSize = 0;
2441 }
2442 
2443 
2444 void
2446  const CJsonNode & message,
2447  const SCommonRequestArguments & common_args)
2448 {
2449  x_CheckNonAnonymousClient("writing into an object");
2452 
2453  if (!message.HasKey("ObjectLoc") && !message.HasKey("UserKey"))
2454  NCBI_THROW(CNetStorageServerException, eMandatoryFieldsMissed,
2455  "WRITE message must have ObjectLoc or UserKey. "
2456  "None of them was found.");
2457 
2459  NCBI_THROW(CNetStorageServerException, eInvalidMetaInfoRequest,
2460  "State changing operations are restricted in HELLO");
2461 
2462  // If it was eMetadataDisabled then updates are not required
2467  message, m_WriteServiceProps);
2468 
2470  // Meta information is required so check the DB
2471  x_CreateClient();
2472  x_CreateUser();
2473  }
2474 
2476  common_args.m_SerialNumber);
2477 
2478  // This will also log the object key and object locator if needed
2479  m_ObjectBeingWritten = x_GetObject(message, true);
2480 
2481  const CNetStorageObjectLoc & object_locator =
2483  string object_key = object_locator.GetUniqueKey();
2484  string locator = object_locator.GetLocator();
2485 
2487  bool create_if_not_found = true; // default
2488  if (message.HasKey("CreateIfNotFound")) {
2489  create_if_not_found = message.GetBoolean("CreateIfNotFound");
2490  }
2491 
2492  if (create_if_not_found == false) {
2493  // The DoesObjectExist procedure will check the object expiration as
2494  // well.
2495  int status = m_Server->GetDb().ExecSP_DoesObjectExist(object_key);
2496  x_CheckExpirationStatus(status);
2497  x_CheckExistanceStatus(status);
2498  }
2499  }
2500 
2501  reply.SetString("ObjectLoc", locator);
2502  x_SendSyncMessage(reply);
2503 
2504  // Inform the message receiving loop that raw data are to follow
2506  m_DataMessageSN = common_args.m_SerialNumber;
2507  m_CreateRequest = false;
2508  m_ObjectSize = 0;
2510 }
2511 
2512 
2513 
2514 void
2516  const CJsonNode & message,
2517  const SCommonRequestArguments & common_args)
2518 {
2519  x_CheckNonAnonymousClient("reading an object");
2520 
2523 
2524  if (!message.HasKey("ObjectLoc") && !message.HasKey("UserKey"))
2525  NCBI_THROW(CNetStorageServerException, eMandatoryFieldsMissed,
2526  "READ message must have ObjectLoc or UserKey. "
2527  "None of them was found.");
2528 
2529  // For eMetadataMonitoring and eMetadataDisabled there must be no updates
2530  // in the meta info DB
2531  bool need_meta_db_update = false;
2532  CNSTServiceProperties service_properties;
2535  need_meta_db_update = x_DetectMetaDBNeedUpdate(message,
2536  service_properties);
2537 
2538 
2540  common_args.m_SerialNumber);
2541  CDirectNetStorageObject direct_object = x_GetObject(message);
2542  const CNetStorageObjectLoc & object_locator = direct_object.Locator();
2543  string object_key = object_locator.GetUniqueKey();
2544  string locator = object_locator.GetLocator();
2545 
2546  bool allow_backend_fallback = true; // default
2547  if (message.HasKey("AllowBackendFallback")) {
2548  allow_backend_fallback = message.GetBoolean("AllowBackendFallback");
2549  }
2550 
2551  if (need_meta_db_update) {
2552  // Meta information is required so check the DB
2553  x_CreateClient();
2554 
2555  // The DoesObjectExist procedure will check the object expiration as
2556  // well.
2557  int status = m_Server->GetDb().ExecSP_DoesObjectExist(object_key);
2558 
2559  x_CheckExpirationStatus(status);
2560  if (status == kSPObjectNotFound) {
2561  // Here: object does not exist
2562  if (allow_backend_fallback == false) {
2564  eNetStorageObjectNotFound, kObjectNotFound);
2565  }
2566  }
2567  }
2568 
2569  x_SendSyncMessage(reply);
2570 
2572 
2573  char buffer[kReadBufferSize];
2574  size_t bytes_read;
2575  Int8 total_bytes = 0;
2576  CNSTPreciseTime start = 0.0;
2577 
2578  try {
2579  while (!direct_object.Eof()) {
2580  start = CNSTPreciseTime::Current();
2581  bytes_read = direct_object.Read(buffer, sizeof(buffer));
2582  if (m_Server->IsLogTimingNSTAPI())
2583  m_Timing.Append("NetStorageAPI read", start);
2584  start = 0.0;
2585 
2586  m_UTTPWriter.SendChunk(buffer, bytes_read, false);
2587 
2588  if (x_SendOverUTTP() != eIO_Success)
2589  return;
2590 
2592  total_bytes += bytes_read;
2593 
2594  if (m_CmdContext.NotNull())
2595  m_CmdContext->SetBytesRd(total_bytes);
2596  }
2597 
2598  start = CNSTPreciseTime::Current();
2599  direct_object.Close();
2600  if (m_Server->IsLogTimingNSTAPI())
2601  m_Timing.Append("NetStorageAPI Close", start);
2602  start = 0.0;
2603 
2604  reply = CreateResponseMessage(common_args.m_SerialNumber);
2605  } catch (const exception & ex) {
2606  if (double(start) != 0.0 && m_Server->IsLogTimingNSTAPI())
2607  m_Timing.Append("NetStorageAPI read (exception)", start);
2608 
2609  string error_scope;
2610  Int8 error_code;
2611  unsigned int error_sub_code;
2612  string message = "Object read error: " + string(ex.what());
2613 
2614  if (GetReplyMessageProperties(ex, &error_scope, &error_code,
2615  &error_sub_code) == false)
2616  error_sub_code = CNetStorageServerException::eReadError;
2617 
2618  reply = CreateErrorResponseMessage(common_args.m_SerialNumber,
2619  error_code, message, error_scope, error_sub_code);
2620  ERR_POST(message);
2621 
2622  if (need_meta_db_update)
2623  x_ProlongObjectOnFailure(eReadOp, object_key, service_properties);
2624 
2625  // Prevent creation of an object in the database if there was none.
2626  // NB: the object TTL will not be updated if there was an object
2627  need_meta_db_update = false;
2628  } catch (...) {
2629  if (double(start) != 0.0 && m_Server->IsLogTimingNSTAPI())
2630  m_Timing.Append("NetStorageAPI read (unknown exception)", start);
2632 
2633  if (need_meta_db_update)
2634  x_ProlongObjectOnFailure(eReadOp, object_key, service_properties);
2635  throw;
2636  }
2637 
2639 
2640  if (x_SendOverUTTP() != eIO_Success)
2641  return;
2642 
2643  if (need_meta_db_update) {
2644  // The errors must not affect the response overall status
2645  bool size_was_null = false;
2646  try {
2647  // The object expiration could have been changed while the object
2648  // was read so I need to get the expiration right here.
2649  // It is not very convenient to calculate the new expiration
2650  // time in MS SQL server so it is done in C++ via two requests
2651  // which is technically not safe in multiple access scenario...
2652  TNSTDBValue<CTime> object_expiration;
2653  TNSTDBValue<Int8> individual_object_ttl;
2655  object_expiration,
2656  individual_object_ttl);
2657 
2659  object_key, locator, total_bytes, m_DBClientID,
2660  service_properties.GetTTL(),
2661  service_properties.GetProlongOnRead(individual_object_ttl),
2662  object_expiration, size_was_null);
2663  } catch (const exception & ex) {
2664  ERR_POST(ex);
2665 
2666  string error_scope;
2667  Int8 error_code;
2668  unsigned int error_sub_code;
2669 
2670  if (GetReplyMessageProperties(ex, &error_scope, &error_code,
2671  &error_sub_code) == false)
2673  // false -> do not change response to ERROR
2674  AppendError(reply, error_code, ex.what(), error_scope,
2675  error_sub_code, false);
2676  } catch (...) {
2677  // Append error however the overall reply must be OK
2678  string msg = "Unknown metainfo DB update error on object read";
2679  ERR_POST(msg);
2680  // false -> do not change response to ERROR
2681  AppendError(reply, NCBI_ERRCODE_X_NAME(NetStorageServer_ErrorCode),
2684  }
2685 
2686  if (size_was_null)
2687  x_OptionalExpirationUpdate(direct_object, reply, "READ");
2688  }
2689 
2690  x_SendSyncMessage(reply);
2692 }
2693 
2694 
2695 void
2697  EOp op,
2698  const string & object_key,
2699  const CNSTServiceProperties & service_props)
2700 {
2701  string operation;
2702  switch (op) {
2703  case eReadOp: operation = "READ"; break;
2704  case eWriteOp: operation = "WRITE"; break;
2705  case eRelocateOp: operation = "RELOCATE"; break;
2706  default:
2707  ERR_POST("Internal error: unknown operation in "
2708  "x_ProlongObjectOnFailure: " << op);
2709  return;
2710  }
2711 
2712  try {
2713  TNSTDBValue<CTime> object_expiration;
2714  TNSTDBValue<Int8> individual_object_ttl;
2716  object_expiration,
2717  individual_object_ttl);
2718 
2719  if (!object_expiration.m_IsNull) {
2720  TNSTDBValue<CTimeSpan> prolong;
2721  switch (op) {
2722  case eReadOp:
2723  prolong = service_props.GetProlongOnRead(individual_object_ttl);
2724  break;
2725  case eWriteOp:
2726  prolong = service_props.GetProlongOnWrite(individual_object_ttl);
2727  break;
2728  case eRelocateOp:
2729  prolong = service_props.GetProlongOnRelocate(individual_object_ttl);
2730  break;
2731  default:
2732  ERR_POST("Internal error: unknown operation in "
2733  "x_ProlongObjectOnFailure: " << op);
2734  return;
2735  }
2736 
2738  object_key, service_props.GetTTL(),
2739  prolong, object_expiration);
2740  }
2741  } catch (const std::exception & ex) {
2742  ERR_POST("Error updating object expiration on " << operation <<
2743  " failure. Ignore and continue. " << ex);
2744  } catch (...) {
2745  ERR_POST("Unknown error updating object expiration on " <<
2746  operation << " failure. Ignore and continue.");
2747  }
2748 }
2749 
2750 
2751 void
2753  const CJsonNode & message,
2754  const SCommonRequestArguments & common_args)
2755 {
2756  x_CheckNonAnonymousClient("object deletion");
2759 
2760  if (!message.HasKey("ObjectLoc") && !message.HasKey("UserKey"))
2761  NCBI_THROW(CNetStorageServerException, eMandatoryFieldsMissed,
2762  "DELETE message must have ObjectLoc or UserKey. "
2763  "None of them was found.");
2764 
2766  NCBI_THROW(CNetStorageServerException, eInvalidMetaInfoRequest,
2767  "State changing operations are restricted in HELLO");
2768 
2769  CNSTServiceProperties service_properties;
2770 
2771  // If it was eMetadataDisabled then updates are not required
2772  bool need_meta_db_update = false;
2775  need_meta_db_update = x_DetectMetaDBNeedUpdate(message,
2776  service_properties);
2777 
2779  common_args.m_SerialNumber);
2780  CDirectNetStorageObject direct_object = x_GetObject(message);
2781  bool allow_backend_fallback = true; // default
2782  if (message.HasKey("AllowBackendFallback")) {
2783  allow_backend_fallback = message.GetBoolean("AllowBackendFallback");
2784  }
2785 
2786  int status = kSPStatusOK;
2787 
2788  if (need_meta_db_update) {
2789  x_CreateClient();
2790 
2791  // Meta information is required so delete from the DB first
2792  status = m_Server->GetDb().ExecSP_RemoveObject(
2793  direct_object.Locator().GetUniqueKey());
2794 
2795  x_CheckExpirationStatus(status);
2796  if (status == kSPObjectNotFound) {
2797  if (allow_backend_fallback == false) {
2798  // It is forbidden to consult to the backend so pretend that
2799  // the object does not exist there either
2800  reply.SetBoolean("NotFound", true);
2801 
2802  x_SendSyncMessage(reply);
2804  return;
2805  }
2806  }
2807  }
2808 
2811  try {
2812  result = direct_object.Remove();
2813  if (m_Server->IsLogTimingNSTAPI())
2814  m_Timing.Append("NetStorageAPI Remove", start);
2815  } catch (...) {
2816  if (m_Server->IsLogTimingNSTAPI())
2817  m_Timing.Append("NetStorageAPI Remove exception", start);
2818  throw;
2819  }
2820 
2822 
2823  // Explicitly tell if the object:
2824  // - was not found in the backend storage
2825  // - was found and deleted in the backend storage
2826  reply.SetBoolean("NotFound", result == eNSTRR_NotFound);
2827 
2828  x_SendSyncMessage(reply);
2830 }
2831 
2832 
2833 void
2835  const CJsonNode & message,
2836  const SCommonRequestArguments & common_args)
2837 {
2838  x_CheckNonAnonymousClient("object reloacation");
2841 
2842  // Take the arguments
2843  if (!message.HasKey("NewLocation")) {
2844  NCBI_THROW(CNetStorageServerException, eInvalidArgument,
2845  "NewLocation argument is not found");
2846  }
2847 
2849  NCBI_THROW(CNetStorageServerException, eInvalidMetaInfoRequest,
2850  "State changing operations are restricted in HELLO");
2851 
2852  CNSTServiceProperties service_properties;
2853 
2854  // If it was eMetadataDisabled then updates are not required
2855  bool need_meta_db_update = false;
2858  need_meta_db_update = x_DetectMetaDBNeedUpdate(message,
2859  service_properties);
2860 
2861 
2862  CJsonNode new_location = message.GetByKey("NewLocation");
2863  TNetStorageFlags new_location_flags = ExtractStorageFlags(new_location);
2864  SICacheSettings new_location_icache_settings =
2865  ExtractICacheSettings(new_location);
2866 
2867  x_CheckICacheSettings(new_location_icache_settings);
2868 
2870  common_args.m_SerialNumber);
2871  CDirectNetStorageObject direct_object = x_GetObject(message);
2872  string object_key =
2873  direct_object.Locator().GetUniqueKey();
2874 
2875  bool create_if_not_found = true; // default
2876  if (message.HasKey("CreateIfNotFound")) {
2877  create_if_not_found = message.GetBoolean("CreateIfNotFound");
2878  }
2879 
2880  bool need_progress_report = false; // default
2881  if (message.HasKey("NeedProgressReport")) {
2882  need_progress_report = message.GetBoolean("NeedProgressReport");
2883  }
2884 
2885  if (need_meta_db_update) {
2886  // Meta information is required so check the DB
2887  x_CreateClient();
2888 
2889  // The DoesObjectExist procedure will check the object expiration as
2890  // well.
2891  int status = m_Server->GetDb().ExecSP_DoesObjectExist(object_key);
2892  x_CheckExpirationStatus(status);
2893  if (status == kSPObjectNotFound) {
2894  if (create_if_not_found == false) {
2896  eNetStorageObjectNotFound, kObjectNotFound);
2897  }
2898  }
2899  }
2900 
2901 
2902  string new_object_loc;
2903  CRelocateCallback callback(*this, common_args, direct_object,
2904  need_progress_report);
2906  try {
2908  &callback, _1);
2909  new_object_loc = direct_object.Relocate(new_location_flags, cb);
2910  if (m_Server->IsLogTimingNSTAPI())
2911  m_Timing.Append("NetStorageAPI Relocate", start);
2912  } catch (const CNetStorageException & ex) {
2914  // Here: relocate was interrupted via a callback return value.
2915  // That means that the client socket is closed and an error is
2916  // registered for the client.
2917  // So the rest is to log a message, print stop request and exit
2918  if (m_Server->IsLogTimingNSTAPI())
2919  m_Timing.Append("NetStorageAPI Relocate interrupt", start);
2920  ERR_POST("NetStorageAPI Relocate interrupt: " << ex);
2921  if (need_meta_db_update)
2923  service_properties);
2924 
2926  return;
2927  }
2928 
2929  if (m_Server->IsLogTimingNSTAPI())
2930  m_Timing.Append("NetStorageAPI Relocate exception", start);
2931  if (need_meta_db_update)
2933  service_properties);
2934  throw;
2935  } catch (...) {
2936  if (m_Server->IsLogTimingNSTAPI())
2937  m_Timing.Append("NetStorageAPI Relocate exception", start);
2938  if (need_meta_db_update)
2940  service_properties);
2941  throw;
2942  }
2943 
2944  if (need_meta_db_update) {
2945  try {
2946  // The object expiration could have been changed while the object
2947  // was read so I need to get the expiration right here.
2948  // It is not very convenient to calculate the new expiration
2949  // time in MS SQL server so it is done in C++ via two requests
2950  // which is technically not safe in multiple access scenario...
2951  TNSTDBValue<CTime> object_expiration;
2952  TNSTDBValue<Int8> individual_object_ttl;
2954  object_expiration,
2955  individual_object_ttl);
2956 
2957  // The record is created if does not exist
2959  object_key, new_object_loc,
2960  m_DBClientID, service_properties.GetTTL(),
2961  service_properties.GetProlongOnRelocate(
2962  individual_object_ttl),
2963  object_expiration);
2964  } catch (const exception & ex) {
2965  // Append error however the overall reply must be OK
2966  ERR_POST(ex);
2967 
2968  string error_scope;
2969  Int8 error_code;
2970  unsigned int error_sub_code;
2971 
2972  if (GetReplyMessageProperties(ex, &error_scope, &error_code,
2973  &error_sub_code) == false)
2975  AppendError(reply, error_code, ex.what(), error_scope,
2976  error_sub_code, false);
2977 
2978  } catch (...) {
2979  // Append error however the overall reply must be OK
2980  string msg = "Unknown metainfo DB update error "
2981  "on object relocation";
2982  ERR_POST(msg);
2983  AppendError(reply, NCBI_ERRCODE_X_NAME(NetStorageServer_ErrorCode),
2986  }
2987  }
2988 
2990 
2991  reply.SetString("ObjectLoc", new_object_loc);
2992  x_SendSyncMessage(reply);
2993 
2994  if (m_ConnContext.NotNull()) {
2995  GetDiagContext().Extra()
2996  .Print("NewObjectLoc", new_object_loc);
2997  }
2998 
3000 }
3001 
3002 
3003 void
3005  const CJsonNode & message,
3006  const SCommonRequestArguments & common_args)
3007 {
3008  x_CheckNonAnonymousClient("object existance request");
3011 
3013  common_args.m_SerialNumber);
3014  CDirectNetStorageObject direct_object = x_GetObject(message);
3015  CNSTServiceProperties service_properties; // not used here
3016  bool need_db_access =
3018  service_properties);
3019  string locator_from_db;
3020 
3021  // Part I. MS SQL db access if needed
3022  if (need_db_access) {
3023  int status = kSPStatusOK;
3024  bool db_error = true;
3025  try {
3026  TNSTDBValue<Int8> object_size;
3027  TNSTDBValue<string> object_locator;
3028 
3030  direct_object.Locator().GetUniqueKey(),
3031  object_size, object_locator);
3032  db_error = false;
3033 
3034  // status could be:
3035  // - object expired
3036  // - object not found
3037  // - OK
3038  if (status == kSPStatusOK)
3039  if (!object_size.m_IsNull)
3040  if (!object_locator.m_IsNull)
3041  locator_from_db = object_locator.m_Value;
3042  } catch (const exception & ex) {
3043  // No exception throwing because the backend will be called anyway
3044  ERR_POST(ex);
3045  } catch (...) {
3046  // No exception throwing because the backend will be called anyway
3047  ERR_POST("Unknown exception while getting an object "
3048  "size and a locator from the DB");
3049  }
3050 
3051  if (!db_error) {
3052  // The check will throw an exception if the object is expired
3053  x_CheckExpirationStatus(status);
3054  }
3055  }
3056 
3057  // Part II. Calling the API
3058  bool exists = false;
3060 
3061  try {
3062  if (message.HasKey("ObjectLoc")) {
3063  CDirectNetStorage storage(
3064  CNcbiApplication::Instance()->GetConfig(),
3066  exists = storage.Exists(locator_from_db,
3067  message.GetString("ObjectLoc"));
3068  if (m_Server->IsLogTimingNSTAPI())
3069  m_Timing.Append("NetStorageAPI Exists", start);
3070  } else {
3071  SICacheSettings icache_settings;
3072  SUserKey user_key;
3074 
3075  x_GetStorageParams(message, &icache_settings, &user_key, &flags);
3076 
3077  CDirectNetStorageByKey storage(
3078  CNcbiApplication::Instance()->GetConfig(),
3080  user_key.m_AppDomain);
3081 
3082  exists = storage.Exists(locator_from_db,
3083  user_key.m_UniqueID, flags);
3084  if (m_Server->IsLogTimingNSTAPI())
3085  m_Timing.Append("NetStorageAPI Exists", start);
3086  }
3087  } catch (...) {
3088  if (m_Server->IsLogTimingNSTAPI())
3089  m_Timing.Append("NetStorageAPI Exists exception", start);
3090  throw;
3091  }
3092 
3093  reply.SetBoolean("Exists", exists);
3094  x_SendSyncMessage(reply);
3096 }
3097 
3098 
3099 
3100 void
3102  const CJsonNode & message,
3103  const SCommonRequestArguments & common_args)
3104 {
3105  x_CheckNonAnonymousClient("object size request");
3108 
3109  bool consult_backend_if_no_db_record = true; // default
3110 
3111  if (message.HasKey("ConsultBackendIfNoDBRecord")) {
3112  consult_backend_if_no_db_record =
3113  message.GetBoolean("ConsultBackendIfNoDBRecord");
3114  }
3115 
3116  CJsonNode reply = CreateResponseMessage(common_args.m_SerialNumber);
3117  CDirectNetStorageObject direct_object = x_GetObject(message);
3118  string object_key =
3119  direct_object.Locator().GetUniqueKey();
3120 
3121  bool object_size_is_null = false;
3122  CNSTServiceProperties service_properties; // not used here
3123  bool need_db_access =
3125  service_properties);
3126 
3127  if (need_db_access) {
3128  TNSTDBValue<Int8> db_object_size;
3129  int status = m_Server->GetDb().ExecSP_GetObjectSize(
3130  object_key, db_object_size);
3131  x_CheckExpirationStatus(status);
3132 
3133  if (status == kSPStatusOK) {
3134  if (db_object_size.m_IsNull)
3135  object_size_is_null = true;
3136  else {
3137  reply.SetInteger("Size", db_object_size.m_Value);
3138  x_SendSyncMessage(reply);
3140  return;
3141  }
3142  }
3143 
3144  // Another possible status is -1 which means the object is not found
3145  // i.e. fall through to the backend consulting
3146  }
3147 
3148 
3149  Uint8 object_size = 0;
3150  if (object_size_is_null || consult_backend_if_no_db_record) {
3152  try {
3153  object_size = direct_object.GetSize();
3154  if (m_Server->IsLogTimingNSTAPI())
3155  m_Timing.Append("NetStorageAPI GetSize", start);
3156  } catch (...) {
3157  if (m_Server->IsLogTimingNSTAPI())
3158  m_Timing.Append("NetStorageAPI GetSize exception", start);
3159  throw;
3160  }
3161  if (object_size_is_null) {
3162  // Two things to be done to finalize the execution:
3163  // - push infinity expiration time to the backend storage
3164  // - update the size in the DB
3165  // in case of errors on these operations only applog records are
3166  // required, i.e. the user will not be informed
3167  try {
3168  direct_object.SetExpiration(CTimeout(CTimeout::eInfinite));
3169  } catch (const exception & ex) {
3170  ERR_POST(ex);
3171  } catch (...) {
3172  ERR_POST("Unknown error updating the backend expiration time "
3173  "while processing the GETSIZE message");
3174  }
3175 
3176  try {
3177  TNSTDBValue<Int8> db_object_size;
3178  db_object_size.m_IsNull = false;
3179  db_object_size.m_Value = object_size;
3180 
3182  object_key, db_object_size);
3183  if (status == kSPStatusOK) {
3184  object_size = db_object_size.m_Value;
3185  }
3186  // In other cases:
3187  // -1 record not found
3188  // -4 object expired
3189  // do not update the object size
3190  } catch (const exception & ex) {
3191  ERR_POST(ex);
3192  } catch (...) {
3193  ERR_POST("Unknown error updating the object size while "
3194  "processing the GETSIZE message");
3195  }
3196  }
3197  }
3198 
3199  reply.SetInteger("Size", object_size);
3200  x_SendSyncMessage(reply);
3202 }
3203 
3204 
3205 void
3207  const CJsonNode & message,
3208  const SCommonRequestArguments & common_args)
3209 {
3210  x_CheckNonAnonymousClient("expiration time setting");
3213 
3214  if (!message.HasKey("TTL"))
3215  NCBI_THROW(CNetStorageServerException, eMandatoryFieldsMissed,
3216  "Mandatory field 'TTL' is missed");
3217 
3218  string arg_val = message.GetString("TTL");
3220 
3221  ttl.m_IsNull = NStr::EqualNocase(arg_val, "infinity");
3222 
3223  if (!ttl.m_IsNull) {
3224  try {
3225  CTimeFormat format("dTh:m:s");
3226  ttl.m_Value = CTimeSpan(arg_val, format);
3227  } catch (const exception & ex) {
3228  NCBI_THROW(CNetStorageServerException, eInvalidArgument,
3229  "TTL format is not recognized: " + string(ex.what()));
3230  } catch (...) {
3231  NCBI_THROW(CNetStorageServerException, eInvalidArgument,
3232  "TTL format is not recognized");
3233  }
3234 
3235  if (ttl.m_Value.GetSign() == eNegative || ttl.m_Value.IsEmpty())
3236  NCBI_THROW(CNetStorageServerException, eInvalidArgument,
3237  "TTL must be > 0");
3238  }
3239 
3240  if (!message.HasKey("ObjectLoc") && !message.HasKey("UserKey"))
3241  NCBI_THROW(CNetStorageServerException, eMandatoryFieldsMissed,
3242  "SETEXPTIME message must have ObjectLoc or UserKey. "
3243  "None of them was found.");
3244 
3245 
3246  // The complicated logic of what and how should be done is described in the
3247  // ticket CXX-7361 (see the attached pdf)
3248 
3250  NCBI_THROW(CNetStorageServerException, eInvalidMetaInfoRequest,
3251  "SETEXPTIME could not be used when the HELLO metadata "
3252  "option is set to Monitoring");
3253 
3254  // Detect if the MS SQL update is required
3255  bool db_update = true;
3257  db_update = false;
3258  else {
3259  CNSTServiceProperties props; // not used here
3260  db_update = x_DetectMetaDBNeedUpdate(message, props);
3261  }
3262 
3263  CJsonNode reply = CreateResponseMessage(common_args.m_SerialNumber);
3264  CDirectNetStorageObject direct_object = x_GetObject(message);
3265  // Part I. Update MS SQL if needed
3266  bool db_error = false;
3267  int status = kSPStatusOK;
3268  if (db_update) {
3269  string object_key = direct_object.Locator().GetUniqueKey();
3270  string object_loc = direct_object.Locator().GetLocator();
3271  bool create_if_not_found = true; // default
3272  if (message.HasKey("CreateIfNotFound"))
3273  create_if_not_found = message.GetBoolean("CreateIfNotFound");
3274 
3275  try {
3276  x_CreateClient();
3277 
3278  TNSTDBValue<Int8> object_size; // Not really used anymore
3279 
3280  // The SP will throw an exception if an error occured
3281  status = m_Server->GetDb().ExecSP_SetExpiration(object_key, ttl,
3282  create_if_not_found,
3283  object_loc,
3284  m_DBClientID,
3285  object_size);
3286  } catch (const exception & ex) {
3287  string error_scope;
3288  Int8 error_code;
3289  unsigned int error_sub_code;
3290 
3291  if (GetReplyMessageProperties(ex, &error_scope, &error_code,
3292  &error_sub_code) == false)
3294  AppendError(reply, error_code, ex.what(), error_scope,
3295  error_sub_code);
3296  db_error = true;
3297  } catch (...) {
3298  AppendError(reply, NCBI_ERRCODE_X_NAME(NetStorageServer_ErrorCode),
3299  "Unknown metainfo DB update error",
3302  db_error = true;
3303  }
3304 
3305  // It was decided that we DO continue in case of logical errors in
3306  // the meta info db
3307  if (db_error == false)
3308  x_CheckExpirationStatus(status);
3309  }
3310 
3311  // Part II. Call the remote object SetExpiration(...)
3312  try {
3313  CTimeout timeout;
3314  if (ttl.m_IsNull || (db_update && !db_error))
3315  timeout.Set(CTimeout::eInfinite);
3316  else
3317  timeout.Set(ttl.m_Value);
3318 
3319  direct_object.SetExpiration(timeout);
3320  } catch (const CNetStorageException & ex) {
3323  // Thanks to the CDirectNetStorageObject interface: there is no way
3324  // to test if the SetExpiration() is supported. Here it is not an
3325  // error, it is just that it makes no sense to call SetExpiration()
3326  // for the storage.
3327  if (db_error || !db_update || status == kSPObjectNotFound)
3328  AppendError(reply,
3329  NCBI_ERRCODE_X_NAME(NetStorageServer_ErrorCode),
3330  ex.what(), ex.GetType(),
3332  } else if (err == CNetStorageException::eNotExists) {
3333  // Basically it is the same condition as for NotSupported case -
3334  // see CXX-8215. It however has a distinctive nature to the
3335  // NotSupported case so a separate branch is introduced.
3336  if (db_error || !db_update || status == kSPObjectNotFound)
3337  AppendError(reply,
3338  NCBI_ERRCODE_X_NAME(NetStorageServer_ErrorCode),
3339  ex.what(), ex.GetType(),
3341  } else {
3342  // That's a real problem of setting the object expiration
3343  AppendError(reply,
3344  NCBI_ERRCODE_X_NAME(NetStorageServer_ErrorCode),
3345  ex.what(), ex.GetType(),
3347  }
3348  } catch (const exception & ex) {
3349  string error_scope;
3350  Int8 error_code;
3351  unsigned int error_sub_code;
3352 
3353  if (GetReplyMessageProperties(ex, &error_scope, &error_code,
3354  &error_sub_code) == false) {
3356  }
3357 
3358  AppendError(reply, error_code, ex.what(), error_scope,
3359  error_sub_code);
3360  } catch (...) {
3361  const string msg = "Unknown remote storage SetExpiration error";
3362  AppendError(reply, NCBI_ERRCODE_X_NAME(NetStorageServer_ErrorCode),
3365  }
3366 
3367  x_SendSyncMessage(reply);
3369 }
3370 
3371 
3372 void
3374  const CJsonNode & message,
3375  const SCommonRequestArguments & common_args)
3376 {
3377  x_CheckNonAnonymousClient("FileTrack path locking");
3380 
3381  if (!message.HasKey("ObjectLoc") && !message.HasKey("UserKey"))
3382  NCBI_THROW(CNetStorageServerException, eMandatoryFieldsMissed,
3383  "LOCKFTPATH message must have ObjectLoc or UserKey. "
3384  "None of them was found.");
3385 
3387  NCBI_THROW(CNetStorageServerException, eInvalidMetaInfoRequest,
3388  "LOCKFTPATH could not be used when the HELLO metadata "
3389  "option is set to Monitoring");
3390 
3391  CJsonNode reply = CreateResponseMessage(common_args.m_SerialNumber);
3392  CDirectNetStorageObject direct_object = x_GetObject(message);
3393  string object_key =
3394  direct_object.Locator().GetUniqueKey();
3395  CNSTServiceProperties service_properties;
3396 
3397  if (x_DetectMetaDBNeedOnGetObjectInfo(message, service_properties)) {
3398  // The only required check in the DB is if the object is expired
3399  TNSTDBValue<CTime> object_expiration;
3400  TNSTDBValue<Int8> individual_object_ttl;
3401  int status = m_Server->GetDb().ExecSP_GetObjectExpiration(object_key,
3402  object_expiration,
3403  individual_object_ttl);
3404  x_CheckExpirationStatus(status);
3405 
3406  if (status == kSPStatusOK) {
3407  // Only if the object exists and not expired its expiration time
3408  // should be updated
3409  if (!object_expiration.m_IsNull) {
3410  try {
3412  object_key,
3413  service_properties.GetTTL(),
3414  service_properties.GetProlongOnRead(
3415  individual_object_ttl),
3416  object_expiration);
3417  } catch (const std::exception & ex) {
3418  ERR_POST("Error updating object expiration on LOCKFTPATH. "
3419  "Ignore and continue. " << ex);
3420  } catch (...) {
3421  ERR_POST("Unknown error updating object "
3422  "expiration on LOCKFTPATH.");
3423  }
3424  }
3425  }
3426  }
3427 
3428 
3429  CMessageListener_Basic warnings_listener; // for collecting warnings
3430  IMessageListener::PushListener(warnings_listener);
3431 
3432  CMessageListenerResetter listener_resetter; // for reliable popping the
3433  // listener
3434 
3435 
3437  try {
3438  string lock_path = direct_object.FileTrack_Path();
3439  reply.SetString("Path", lock_path);
3440  if (m_Server->IsLogTimingNSTAPI())
3441  m_Timing.Append("NetStorageAPI FileTrack_Path", start);
3442  } catch (...) {
3443  if (m_Server->IsLogTimingNSTAPI()) {
3444  m_Timing.Append("NetStorageAPI FileTrack_Path exception", start);
3445  }
3446  throw;
3447  }
3448 
3449  // Append warnings if so
3450  size_t warn_count = warnings_listener.Count();
3451  for (size_t k = 0; k < warn_count; ++k) {
3452  const IMessage & warn = warnings_listener.GetMessage(k);
3453 
3454  // As agreed when CXX-7622 is discussed, all the collected messages are
3455  // warnings, regardless of their severity. The errors are supposed to
3456  // be reported via the C++ exceptions mechanism.
3457 
3458  AppendWarning(reply, warn.GetCode(), warn.GetText(),
3459  kScopeIMessage, warn.GetSubCode());
3460  }
3461 
3462  x_SendSyncMessage(reply);
3464 }
3465 
3466 
3469  bool need_fake_write)
3470 {
3472 
3473  if (message.HasKey("ObjectLoc")) {
3474  string object_loc = message.GetString("ObjectLoc");
3475  x_CheckObjectLoc(object_loc);
3476 
3477  try {
3478  // There could be a decryption exception so there is this try {}
3480  CDirectNetStorage storage(
3481  app->GetConfig(),
3482  m_Service,
3485 
3486  CDirectNetStorageObject object(storage.Open(object_loc));
3487 
3488  if (need_fake_write) {
3489  // This 'fake' call needs to be done to have the locator
3490  // properly formed.
3491  // See JIRA: CXX-8041
3492  object.Write("", 0);
3493  }
3494 
3495  if (m_ConnContext.NotNull()) {
3496  GetDiagContext().Extra()
3497  .Print("ObjectKey", object.Locator().GetUniqueKey());
3498 
3499  // The locator could have been changed due to the fake write
3500  // call above. If it was changed, then log it once again.
3501  string new_loc = object.Locator().GetLocator();
3502  if (new_loc != object_loc)
3503  GetDiagContext().Extra()
3504  .Print("ObjectLoc", object.Locator().GetLocator());
3505  }
3506 
3507  return object;
3508  } catch (const CRegistryException & ex) {
3511  throw;
3512  }
3513  }
3514 
3515  // Take the arguments
3516  SICacheSettings icache_settings;
3517  SUserKey user_key;
3519 
3520  x_GetStorageParams(message, &icache_settings, &user_key, &flags);
3521 
3522  try {
3523  // There could be a decryption exception so there is this try {}
3525  CDirectNetStorageByKey storage(app->GetConfig(), m_Service,
3527  user_key.m_AppDomain);
3529 
3530  CDirectNetStorageObject object(storage.Open(user_key.m_UniqueID,
3531  flags));
3532  if (need_fake_write) {
3533  // This 'fake' call needs to be done to have the locator
3534  // properly formed.
3535  // See JIRA: CXX-8041
3536  object.Write("", 0);
3537  }
3538 
3539  // Log if needed
3540  if (m_ConnContext.NotNull()) {
3541  GetDiagContext().Extra()
3542  .Print("ObjectKey", object.Locator().GetUniqueKey())
3543  .Print("ObjectLoc", object.Locator().GetLocator());
3544  }
3545 
3546  return object;
3547  } catch (const CRegistryException & ex) {
3550  throw;
3551  }
3552 }
3553 
3554 
3555 void
3556 CNetStorageHandler::x_CheckObjectLoc(const string & object_loc) const
3557 {
3558  if (object_loc.empty()) {
3559  NCBI_THROW(CNetStorageServerException, eInvalidArgument,
3560  "Object locator must not be an empty string");
3561  }
3562 }
3563 
3564 
3565 void
3567  const SICacheSettings & icache_settings)
3568 {
3569  if (!icache_settings.m_ServiceName.empty()) {
3570  // CacheName is mandatory in this case
3571  if (icache_settings.m_CacheName.empty()) {
3572  NCBI_THROW(CNetStorageServerException, eInvalidArgument,
3573  "CacheName is required if ServiceName is provided");
3574  }
3575  }
3576 }
3577 
3578 
3579 void
3581 {
3582  if (!user_key.m_UniqueID.empty()) {
3583  // AppDomain is mandatory in this case
3584  if (user_key.m_AppDomain.empty()) {
3585  NCBI_THROW(CNetStorageServerException, eInvalidArgument,
3586  "AppDomain is required if UniqueKey is provided");
3587  }
3588  }
3589 }
3590 
3591 
3592 void
3594  const CJsonNode & message,
3595  SICacheSettings * icache_settings,
3596  SUserKey * user_key,
3598 {
3599  *icache_settings = ExtractICacheSettings(message);
3600  *user_key = ExtractUserKey(message);
3601 
3602  // Check the parameters validity
3603  x_CheckICacheSettings(*icache_settings);
3604  x_CheckUserKey(*user_key);
3605 
3606  *flags = ExtractStorageFlags(message);
3607 }
3608 
3609 
3612  const SICacheSettings & icache_settings,
3614 {
3615  try {
3616  // There could be a decryption exception so there is this try {}
3618 
3620  CDirectNetStorage net_storage(app->GetConfig(), m_Service,
3623 
3624  return net_storage.Create(m_Service, flags);
3625  } catch (const CRegistryException & ex) {
3628  throw;
3629  }
3630 }
3631 
3632 
3633 EIO_Status
3635 {
3636  const char * output_buffer;
3637  size_t output_buffer_size;
3638  size_t written;
3639 
3640  do {
3641  m_UTTPWriter.GetOutputBuffer(&output_buffer, &output_buffer_size);
3642  if (output_buffer_size > 0) {
3643  // Write to the socket as a single transaction
3645  EIO_Status result =
3646  GetSocket().Write(output_buffer, output_buffer_size, &written);
3648  m_Timing.Append("Client socket write (" +
3649  NStr::NumericToString(output_buffer_size) + ")",
3650  start);
3651  if (result != eIO_Success) {
3652  // Error writing to the socket. Log what we can and close the
3653  // connection.
3654  x_OnSocketWriteError(result, written,
3655  output_buffer, output_buffer_size);
3656  return result;
3657  }
3658  }
3659  } while (m_UTTPWriter.NextOutputBuffer());
3660 
3661  return eIO_Success;
3662 }
3663 
3664 
3665 
3668 {
3669  if (!message.HasKey("Metadata"))
3670  return eMetadataNotSpecified;
3671 
3672  string value = message.GetString("Metadata");
3676 
3677  if (result == eMetadataUnknown) {
3678  vector<string> valid = g_GetSupportedMetadataOptions();
3679  string message = "Optional field 'Metadata' value is not "
3680  "recognized. Supported values are: ";
3681  for (vector<string>::const_iterator k = valid.begin();
3682  k != valid.end(); ++k) {
3683  if (k != valid.begin())
3684  message += ", ";
3685  message += *k;
3686  }
3687  NCBI_THROW(CNetStorageServerException, eInvalidArgument, message);
3688  }
3689 
3690  if (result == eMetadataRequired) {
3692  {
3693  case eMetadataOn:
3694  break; // all good
3695  case eUnknownService:
3696  NCBI_THROW(CNetStorageServerException, eInvalidArgument,
3697  "Invalid metadata option. It cannot be required "
3698  "for not configured service");
3699  case eMetadataExplicitOff:
3700  NCBI_THROW(CNetStorageServerException, eInvalidArgument,
3701  "Invalid metadata option. It cannot be required "
3702  "for a service which has metadata explicitly "
3703  "switched off");
3704  case eMetadataDefaultOff:
3705  NCBI_THROW(CNetStorageServerException, eInvalidArgument,
3706  "Invalid metadata option. It cannot be required "
3707  "for a service which has metadata "
3708  "switched off (by default)");
3709  }
3710  }
3711  return result;
3712 }
3713 
3714 
3715 void
3717  const CJsonNode & message,
3718  bool expect_object) const
3719 {
3720  if (expect_object && message.HasKey("ObjectLoc")) {
3721  // Object locator has a metadata flag and a service name
3722  string object_loc = message.GetString("ObjectLoc");
3723  x_CheckObjectLoc(object_loc);
3724 
3725  CNetStorageObjectLoc object_loc_struct(m_Server->GetCompoundIDPool(),
3726  object_loc);
3727 
3728  bool no_metadata = object_loc_struct.IsMetaDataDisabled();
3729 
3730  if (no_metadata)
3731  NCBI_THROW(CNetStorageServerException, eInvalidArgument,
3732  "DB access requested for an object which was created "
3733  "with no metadata flag");
3734 
3735  string service = object_loc_struct.GetServiceName();
3736  if (service.empty())
3737  service = m_Service;
3738 
3739  switch (m_Server->InMetadataServices(service))
3740  {
3741  case eMetadataOn:
3742  break; // all good
3743  case eUnknownService:
3744  NCBI_THROW(CNetStorageServerException, eInvalidArgument,
3745  "Effective object service (" + service +
3746  ") is not configured. Metainfo DB access declined.");
3747  case eMetadataExplicitOff:
3748  NCBI_THROW(CNetStorageServerException, eInvalidArgument,
3749  "Effective object service (" + service +
3750  ") has metadata explicitly switched off. "
3751  "Metainfo DB access declined.");
3752  case eMetadataDefaultOff:
3753  NCBI_THROW(CNetStorageServerException, eInvalidArgument,
3754  "Effective object service (" + service +
3755  ") has metadata switched off (by default). "
3756  "Metainfo DB access declined.");
3757  }
3758 
3759  return;
3760  }
3761 
3762  if (expect_object) {
3763  // This is user key identification
3765  if (flags & fNST_NoMetaData) {
3766  NCBI_THROW(CNetStorageServerException, eInvalidArgument,
3767  "Storage flags forbid access to the metainfo DB. "
3768  "Metainfo DB access declined.");
3769  }
3770  }
3771 
3772  // There is no knowledge of the service and metadata request from the
3773  // object identifier, so the HELLO service is used
3775  {
3776  case eMetadataOn:
3777  break; // all good
3778  case eUnknownService:
3779  NCBI_THROW(CNetStorageServerException, eInvalidArgument,
3780  "Service provided in HELLO (" + m_Service +
3781  ") is not configured. Metainfo DB access declined.");
3782  case eMetadataExplicitOff:
3783  NCBI_THROW(CNetStorageServerException, eInvalidArgument,
3784  "Service provided in HELLO (" + m_Service +
3785  ") has metadata explicitly switched off. "
3786  "Metainfo DB access declined.");
3787  case eMetadataDefaultOff:
3788  NCBI_THROW(CNetStorageServerException, eInvalidArgument,
3789  "Service provided in HELLO (" + m_Service +
3790  ") has metadata switched off (by default). "
3791  "Metainfo DB access declined.");
3792  }
3793 }
3794 
3795 
3796 // Detects if the meta information DB should be updated
3797 bool
3799  const CJsonNode & message,
3800  CNSTServiceProperties & props) const
3801 {
3803  return false;
3804 
3805  if (message.HasKey("ObjectLoc")) {
3806  // Object locator has a metadata flag and a service name
3807  string object_loc = message.GetString("ObjectLoc");
3808  x_CheckObjectLoc(object_loc);
3809 
3810  CNetStorageObjectLoc object_loc_struct(m_Server->GetCompoundIDPool(),
3811  object_loc);
3812 
3813  bool no_metadata = object_loc_struct.IsMetaDataDisabled();
3814 
3815  if (no_metadata)
3816  return false;
3817 
3818  string service = object_loc_struct.GetServiceName();
3819  if (service.empty())
3820  service = m_Service;
3821 
3822  bool service_configured = m_Server->GetServiceProperties(service,
3823  props);
3825  return service_configured;
3826 
3827  // This is the eMetadataRequired option: the check below is needed
3828  // because the list of services could be reconfigured on the fly
3829  if (!service_configured)
3830  NCBI_THROW(CNetStorageServerException, eInvalidArgument,
3831  "Effective object service (" + service +
3832  ") is not in the list of "
3833  "configured services. Metainfo DB access declined.");
3834  return true;
3835  }
3836 
3837  // This is user key identification
3839  if (flags & fNST_NoMetaData)
3840  return false;
3841 
3842  // There is no knowledge of the service and metadata request from the
3843  // object identifier
3844  bool service_configured = m_Server->GetServiceProperties(m_Service,
3845  props);
3847  // The service list could be reconfigured on the fly
3848  if (!service_configured)
3849  NCBI_THROW(CNetStorageServerException, eInvalidArgument,
3850  "Service provided in HELLO (" + m_Service +
3851  ") is not in the list of "
3852  "configured services. Metainfo DB access declined.");
3853  }
3854  return service_configured;
3855 }
3856 
3857 
3858 bool
3860 {
3861  if ((flags & fNST_NoMetaData) != 0)
3862  return false;
3864  return false;
3865 
3866  bool service_configured = m_Server->GetServiceTTL(m_Service,
3867  m_CreateTTL);
3869  // The services could be reconfigured on the fly so the presence of the
3870  // service in the list of configured must be done here again
3871  if (!service_configured)
3872  NCBI_THROW(CNetStorageServerException, eInvalidArgument,
3873  "Service provided in HELLO (" + m_Service +
3874  ") is not in the list of "
3875  "configured services. Metainfo DB access declined.");
3876  }
3877  return service_configured;
3878 }
3879 
3880 
3881 // Returns true if the metainfo DB should be accessed
3882 bool
3884  const CJsonNode & message,
3885  CNSTServiceProperties & props) const
3886 {
3888  return false;
3889 
3890  if (message.HasKey("ObjectLoc")) {
3891  // Object locator has a metadata flag and a service name
3892  string object_loc = message.GetString("ObjectLoc");
3893  x_CheckObjectLoc(object_loc);
3894 
3895  CNetStorageObjectLoc object_loc_struct(m_Server->GetCompoundIDPool(),
3896  object_loc);
3897 
3898  bool no_metadata = object_loc_struct.IsMetaDataDisabled();
3899 
3900  if (no_metadata)
3901  return false;
3902 
3903  string service = object_loc_struct.GetServiceName();
3904  if (service.empty())
3905  service = m_Service;
3906 
3907  bool service_configured = m_Server->GetServiceProperties(service,
3908  props);
3909  return service_configured;
3910  }
3911 
3912  // This is user key identification
3914  if (flags & fNST_NoMetaData)
3915  return false;
3916 
3917  // There is no knowledge of the service and metadata request from the
3918  // object identifier
3919  bool service_configured = m_Server->GetServiceProperties(m_Service,
3920  props);
3921  return service_configured;
3922 }
3923 
3924 
3925 // Sets the m_DBClientID from in-memory cache or via referring to the DB
3926 void
3928 {
3930 }
3931 
3932 
3933 // Retrieves the client DB ID from the in-memory registry.
3934 // If the value is not there, then retrieves it (probably via creation) from
3935 // the DB
3936 Int8
3938 {
3939  Int8 client_id = m_Server->GetClientRegistry().
3940  GetDBClientID(client);
3941  if (client_id != k_UndefinedClientID)
3942  return client_id; // It is cached and is at hand
3943 
3944  // Need to refer to the DB:
3945  // - create it or
3946  // - retrieve it
3947  m_Server->GetDb().ExecSP_CreateClient(client, client_id);
3948  if (client_id != k_UndefinedClientID)
3950  return client_id;
3951 }
3952 
3953 
3954 void
3956 {
3957  // The user comes from the context. The empty user is allowed too.
3958  // See CXX-8023 for details
3959  CNSTUserID user;
3960  string user_name = CRequestContext_PassThrough().Get("my_ncbi_id");
3961  if (!user_name.empty()) {
3962  user.SetNamespace("my_ncbi_id");
3963  user.SetName(NStr::ToLower(user_name));
3964  user.Validate();
3965  }
3966 
3967  m_DBUserID = x_GetUserID(user);
3968 }
3969 
3970 
3971 
3972 Int8
3974 {
3975  Int8 user_id = m_Server->GetUserCache().GetDBUserID(user);
3976  if (user_id != k_UndefinedUserID)
3977  return user_id; // It is cached and is at hand
3978 
3979  // Need to refer to the DB:
3980  // - create it or
3981  // - retrieve it
3982  m_Server->GetDb().ExecSP_CreateUser(user, user_id);
3983  if (user_id != k_UndefinedUserID)
3984  m_Server->GetUserCache().SetDBUserID(user, user_id);
3985  return user_id;
3986 }
3987 
3988 
3989 void
3991  CDirectNetStorageObject & object,
3992  CJsonNode & reply,
3993  const string & user_message
3994  )
3995 {
3996  // Sends the infinite expiration to the backend storage.
3997  // The errors are treated in a special way:
3998  // - the overall reply status is not changed
3999  // - an error is attached to the errors container
4000 
4001  try {
4002  object.SetExpiration(CTimeout(CTimeout::eInfinite));
4003  } catch (const exception & ex) {
4004  // Thanks to the design of CDirectNetStorageObject: there is no way to
4005  // check in fron if the operation is supported by the underlied
4006  // storage. The only way to understand that is to try, catch exception
4007  // and check an error code.
4008  const CNetStorageException * to_test_setexp_support =
4009  dynamic_cast<const CNetStorageException *>(&ex);
4010  if (to_test_setexp_support != 0)
4011  if (to_test_setexp_support->GetErrCode() ==
4013  // This is not an error. SetExpiration() is not supported.
4014  return;
4015 
4016  // Here: this is an error. Log it and append an error to the reply
4017  // message.
4018  ERR_POST(ex);
4019 
4020  string error_scope;
4021  Int8 error_code;
4022  unsigned int error_sub_code;
4023 
4024  if (GetReplyMessageProperties(ex, &error_scope, &error_code,
4025  &error_sub_code) == false)
4027 
4028  // false -> do not change response to ERROR
4029  AppendError(reply, error_code, ex.what(), error_scope,
4030  error_sub_code, false);
4031  } catch (...) {
4032  // Append error however the overall reply must be OK
4033  string msg = "Unknown error updating the backend expiration "
4034  " time while processing the " + user_message + " message";
4035  ERR_POST(msg);
4036 
4037  // false -> do not change response to ERROR
4038  AppendError(reply,
4039  NCBI_ERRCODE_X_NAME(NetStorageServer_ErrorCode),
4042  }
4043 }
4044 
4045 
4047 {
4048  if (status == kSPObjectNotFound)
4049  NCBI_THROW(CNetStorageServerException, eNetStorageObjectNotFound,
4050  kObjectNotFound);
4051 }
4052 
4053 
4055 {
4056  if (status == kSPObjectExpired)
4057  NCBI_THROW(CNetStorageServerException, eNetStorageObjectExpired,
4058  kObjectExpired);
4059 }
4060 
4061 
4063 {
4064  if (m_Client.empty()) {
4065  NCBI_THROW(CNetStorageServerException, eHelloRequired,
4066  "Anonymous client cannot perform " + op);
4067  }
4068 }
4069 
Temporary object for holding extra message arguments.
Definition: ncbidiag.hpp:1828
CDirectNetStorageObject Open(const string &unique_key, TNetStorageFlags flags=0)
Definition: netstorage.cpp:364
bool Exists(const string &db_loc, const string &key, TNetStorageFlags flags)
Definition: netstorage.cpp:372
ENetStorageRemoveResult Remove()
Definition: netstorage.cpp:69
const CNetStorageObjectLoc & Locator()
Definition: netstorage.cpp:75
string Relocate(TNetStorageFlags flags, TNetStorageProgressCb cb=TNetStorageProgressCb())
Definition: netstorage.cpp:56
pair< string, string > GetUserInfo()
Definition: netstorage.cpp:87
CDirectNetStorageObject Open(const string &object_loc)
Definition: netstorage.cpp:334
CDirectNetStorageObject Create(const string &service_name, TNetStorageFlags flags)
Definition: netstorage.cpp:327
bool Exists(const string &db_loc, const string &client_loc)
Definition: netstorage.cpp:340
Iterator for JSON arrays and objects.
JSON node abstraction.
Int8 AsInteger() const
Provided that this is a numeric node (that is, either an integer or a floating point node),...
bool IsNull() const
Return true for a null node. Return false otherwise.
static CJsonNode NewArrayNode()
Create a new JSON array node.
void SetDouble(const string &key, double value)
Set a JSON object element to the specified floating point value.
bool HasKey(const string &key) const
Check if an object node has an element accessible by the specified key.
SJsonIteratorImpl * Iterate(EIterationMode mode=eNatural) const
For a container node (that is, either an array or an object), begin iteration over its elements.
void SetString(const string &key, const string &value)
Set a JSON object element to the specified string value.
Int8 GetInteger(const string &key) const
For a JSON object node, return the integer referred to by the specified key.
void AppendString(const string &value)
For an array node, add a string node at the end of the array.
const string AsString() const
Provided that this is a string node, return the string value of this node.
string GetString(const string &key) const
For a JSON object node, return the string referred to by the specified key.
void SetBoolean(const string &key, bool value)
Set a JSON object element to the specified boolean value.
ENodeType GetNodeType() const
Return a ENodeType constant identifying the node type.
void SetInteger(const string &key, Int8 value)
Set a JSON object element to the specified integer value.
void SetByKey(const string &key, CJsonNode::TInstance value)
For a JSON object node, insert a new element or update an existing element.
bool GetBoolean(const string &key) const
For a JSON object node, return the boolean referred to by the specified key.
bool IsObject() const
Return true for a JSON object. Return false otherwise.
ENodeType
JSON node type.
static CJsonNode NewObjectNode()
Create a new JSON object node.
void Append(CJsonNode::TInstance value)
For an array node, add a new element at the end of the array.
CJsonNode GetByKey(const string &key) const
For a JSON object node, return the value associated with the specified key.
Exception class for use by CJsonNode.
const CJsonNode GetMessage() const
bool ReadMessage(CUTTPReader &reader)
bool WriteMessage(const CJsonNode &root_node)
void GetOutputBuffer(const char **output_buffer, size_t *output_buffer_size)
Default implementation of IMessageListener: collects all messages posted.
@ fReloadIfChanged
Reload if time or size has changed.
Definition: metareg.hpp:53
void AddBytesRead(const string &client, size_t count)
void AddObjectsWritten(const string &client, size_t count)
void AddObjectsRead(const string &client, size_t count)
void Touch(const string &client, const string &applications, const string &ticket, const string &service, const string &protocol_version, EMetadataOption metadataOption, unsigned int peer_address)
void AddObjectsDeleted(const string &client, size_t count)
void SetDBClientID(const string &client, Int8 id)
void AddBytesWritten(const string &client, size_t count)
CJsonNode Serialize(void) const
void RegisterSocketWriteError(const string &client)
void AppendType(const string &client, unsigned int type_to_append)
void AddObjectsRelocated(const string &client, size_t count)
int ExecSP_GetAttribute(const string &object_key, const string &attr_name, bool need_update, string &value)
int ExecSP_GetObjectExpiration(const string &object_key, TNSTDBValue< CTime > &expiration, TNSTDBValue< Int8 > &individual_object_ttl)
int ExecSP_GetClientObjects(const string &client_name, TNSTDBValue< Int8 > limit, Int8 &total, vector< string > &locators)
bool IsConnected(void) const
int ExecSP_UpdateObjectOnRead(const string &object_key, const string &object_loc, Int8 size, Int8 client_id, const TNSTDBValue< CTimeSpan > &ttl, const TNSTDBValue< CTimeSpan > &prolong_on_read, const TNSTDBValue< CTime > &object_expiration, bool &size_was_null)
int ExecSP_SetExpiration(const string &object_key, const TNSTDBValue< CTimeSpan > &ttl, bool create_if_not_found, const string &object_loc, Int8 client_id, TNSTDBValue< Int8 > &object_size)
int ExecSP_GetUsers(vector< pair< string, string > > &users)
int ExecSP_UpdateUserIDForObject(const string &object_key, Int8 user_id)
int ExecSP_GetClients(vector< string > &names)
int ExecSP_UpdateObjectOnRelocate(const string &object_key, const string &object_loc, Int8 client_id, const TNSTDBValue< CTimeSpan > &ttl, const TNSTDBValue< CTimeSpan > &prolong_on_relocate, const TNSTDBValue< CTime > &object_expiration)
int ExecSP_CreateClient(const string &client, Int8 &client_id)
map< string, string > ExecSP_GetStatDBInfo(void)
int ExecSP_GetUserObjects(const string &user_name, const string &user_name_space, TNSTDBValue< Int8 > limit, Int8 &total, vector< string > &locators)
int ExecSP_UpdateObjectOnWrite(const string &object_key, const string &object_loc, Int8 size, Int8 client_id, Int8 user_id, const TNSTDBValue< CTimeSpan > &ttl, const TNSTDBValue< CTimeSpan > &prolong_on_write, const TNSTDBValue< CTime > &object_expiration, bool &size_was_null)
int ExecSP_AddAttribute(const string &object_key, const string &object_loc, const string &attr_name, const string &attr_value, Int8 client_id, bool create_if_not_found, const TNSTDBValue< CTimeSpan > &ttl)
int UpdateExpirationIfExists(const string &object_key, const TNSTDBValue< CTimeSpan > &ttl, const TNSTDBValue< CTimeSpan > &prolong_on_read, const TNSTDBValue< CTime > &object_expiration)
int ExecSP_CreateObjectWithClientID(const string &object_key, const string &object_loc, Int8 size, Int8 client_id, Int8 user_id, const TNSTDBValue< CTimeSpan > ttl, bool &size_was_null)
int ExecSP_DoesObjectExist(const string &object_key)
int ExecSP_GetObjectSize(const string &object_key, TNSTDBValue< Int8 > &object_size)
CTimeout GetExecuteSPTimeout(void)
int ExecSP_GetObjectSizeAndLocator(const string &object_key, TNSTDBValue< Int8 > &object_size, TNSTDBValue< string > &object_locator)
int ExecSP_RemoveObject(const string &object_key)
int ExecSP_GetAttributeNames(const string &object_key, vector< string > &attr_names)
int ExecSP_DelAttribute(const string &object_key, const string &attr_name)
CJsonNode SetParameters(const IRegistry &reg)
int ExecSP_UpdateObjectSizeIfNULL(const string &object_key, TNSTDBValue< Int8 > &object_size)
int ExecSP_CreateUser(const CNSTUserID &user, Int8 &user_id)
static CNSTPreciseTime Current(void)
TNSTDBValue< CTimeSpan > GetProlongOnWrite(const TNSTDBValue< Int8 > &individual_obj_ttl) const
TNSTDBValue< CTimeSpan > GetTTL(void) const
TNSTDBValue< CTimeSpan > GetProlongOnRead(const TNSTDBValue< Int8 > &individual_obj_ttl) const
TNSTDBValue< CTimeSpan > GetProlongOnRelocate(const TNSTDBValue< Int8 > &individual_obj_ttl) const
void Clear(void)
Definition: nst_timing.cpp:76
string Serialize(CDiagContext_Extra extra)
Definition: nst_timing.cpp:49
void Append(const string &what, const CNSTPreciseTime &how_long)
Definition: nst_timing.cpp:42
bool Empty(void) const
Definition: nst_timing.cpp:64
Int8 GetDBUserID(const CNSTUserID &user) const
Definition: nst_users.cpp:64
void SetDBUserID(const CNSTUserID &user, Int8 id)
Definition: nst_users.cpp:74
void SetNamespace(const string &name_space_)
Definition: nst_users.hpp:69
void SetName(const string &name_)
Definition: nst_users.hpp:71
void Validate(void)
Definition: nst_users.cpp:45
static CNcbiApplication * Instance(void)
Singleton method.
Definition: ncbiapp.cpp:264
static void Reload(void)
Re-read key file locations and domain paths, reload encryption keys.
CNcbiOstrstreamToString class helps convert CNcbiOstrstream to a string Sample usage:
Definition: ncbistre.hpp:802
CNcbiRegistry –.
Definition: ncbireg.hpp:913
Exception class for use by CNetStorage, CNetStorageByKey, and CNetStorageObject.
Definition: netstorage.hpp:67
EIO_Status x_SendSyncMessage(const CJsonNode &message, ESocketTimeoutTreat timeout_treat=eTimeoutIsError)
string x_GetConnRef(void)
virtual void OnRead(void)
The client has just sent data.
void x_SetObjectInfoReply(CJsonNode &reply, const string &name, const TNSTDBValue< CTime > &value)
void x_ProcessHello(const CJsonNode &message, const SCommonRequestArguments &common_args)
void x_CheckExistanceStatus(int status)
void x_SendAsyncMessage(const CJsonNode &message)
virtual void OnOpen(void)
Runs in response to an external event [asynchronous].
void x_CheckNonAnonymousClient(const string &op) const
void x_ProcessConfiguration(const CJsonNode &message, const SCommonRequestArguments &common_args)
void x_ProcessSetExpTime(const CJsonNode &message, const SCommonRequestArguments &common_args)
bool x_DetectMetaDBNeedOnGetObjectInfo(const CJsonNode &message, CNSTServiceProperties &props) const
void x_PrintMessageRequestStart(const CJsonNode &message)
unsigned int x_GetPeerAddress(void)
void x_ProcessWrite(const CJsonNode &message, const SCommonRequestArguments &common_args)
void x_ProcessSetAttr(const CJsonNode &message, const SCommonRequestArguments &common_args)
void x_CheckUserKey(const SUserKey &user_key)
TNSTDBValue< CTimeSpan > m_CreateTTL
virtual EIO_Event GetEventsToPollFor(const CTime **alarm_time) const
Following three methods are guaranteed to be called NOT at the same time as On*, so if you implement ...
CDirectNetStorageObject x_CreateObjectStream(const SICacheSettings &icache_settings, TNetStorageFlags flags)
void x_ProcessGetSize(const CJsonNode &message, const SCommonRequestArguments &common_args)
EIO_Status x_SendOutputBuffer(ESocketTimeoutTreat timeout_treat)
void x_ProcessAckAlert(const CJsonNode &message, const SCommonRequestArguments &common_args)
void(CNetStorageHandler::* FProcessor)(const CJsonNode &, const SCommonRequestArguments &)
CRef< CRequestContext > m_ConnContext
void x_ProcessRead(const CJsonNode &message, const SCommonRequestArguments &common_args)
void x_CreateConnContext(void)
void x_ProcessGetClientObjects(const CJsonNode &message, const SCommonRequestArguments &comm_args)
void x_ProcessGetObjectInfo(const CJsonNode &message, const SCommonRequestArguments &common_args)
virtual void OnWrite(void)
The client is ready to receive data.
void x_ProcessShutdown(const CJsonNode &message, const SCommonRequestArguments &common_args)
CUTTPReader m_UTTPReader
void x_CreateUser(void)
void x_ProcessReconfigure(const CJsonNode &message, const SCommonRequestArguments &common_args)
CNetStorageHandler(CNetStorageServer *server)
void x_ProcessGetClientsInfo(const CJsonNode &message, const SCommonRequestArguments &common_args)
void x_SetConnRequestStatus(unsigned int status)
void x_SetQuickAcknowledge(void)
void x_CreateClient(void)
CNSTServiceProperties m_WriteServiceProps
void x_PrintMessageRequestStop(void)
void x_FillObjectInfo(CJsonNode &reply, const string &val)
void x_ProcessGetUsersInfo(const CJsonNode &message, const SCommonRequestArguments &common_args)
char m_WriteBuffer[kWriteBufferSize]
virtual void OnOverflow(EOverflowReason reason)
Runs when there are insufficient resources to queue a connection, prior to closing it.
void x_ProcessGetMetadataInfo(const CJsonNode &message, const SCommonRequestArguments &common_args)
virtual void OnTimeout(void)
Runs when a client has been idle for too long, prior to closing the connection [synchronous].
void x_ProcessDelAttr(const CJsonNode &message, const SCommonRequestArguments &common_args)
void x_OnSocketWriteError(EIO_Status status, size_t bytes_written, const char *output_buffer, size_t output_buffer_size)
CUTTPWriter m_UTTPWriter
void x_ProcessGetAttrList(const CJsonNode &message, const SCommonRequestArguments &common_args)
CFastMutex m_OutputQueueMutex
void x_CheckExpirationStatus(int status)
EMetadataOption x_ConvertMetadataArgument(const CJsonNode &message) const
CDirectNetStorageObject m_ObjectBeingWritten
void x_ProcessRelocate(const CJsonNode &message, const SCommonRequestArguments &common_args)
virtual void OnClose(IServer_ConnectionHandler::EClosePeer peer)
The connection has closed (with information on type of closing)
CNetStorageServer * m_Server
void x_ProcessBye(const CJsonNode &message, const SCommonRequestArguments &common_args)
void x_ProcessGetAttr(const CJsonNode &message, const SCommonRequestArguments &common_args)
EIO_Status x_SendOverUTTP()
CRef< CRequestContext > m_CmdContext
CDirectNetStorageObject x_GetObject(const CJsonNode &message, bool need_fake_write=false)
bool x_DetectMetaDBNeedUpdate(const CJsonNode &message, CNSTServiceProperties &props) const
void x_ProcessInfo(const CJsonNode &message, const SCommonRequestArguments &common_args)
bool m_WriteCreateNeedMetaDBUpdate
CJsonOverUTTPWriter m_JSONWriter
Int8 x_GetUserID(const CNSTUserID &user)
void x_ProcessLockFTPath(const CJsonNode &message, const SCommonRequestArguments &common_args)
void x_CheckICacheSettings(const SICacheSettings &icache_settings)
void x_OptionalExpirationUpdate(CDirectNetStorageObject &object, CJsonNode &reply, const string &user_message)
static SProcessorMap sm_Processors[]
bool x_DetectMetaDBNeedOnCreate(TNetStorageFlags flags)
EMetadataOption m_MetadataOption
void x_ProcessGetUserObjects(const CJsonNode &message, const SCommonRequestArguments &comm_args)
char m_ReadBuffer[kReadBufferSize]
Int8 x_GetClientID(const string &client)
void x_GetStorageParams(const CJsonNode &message, SICacheSettings *icache_settings, SUserKey *user_key, TNetStorageFlags *flags)
void x_SendWriteConfirmation()
vector< CJsonNode > m_OutputQueue
void x_ProlongObjectOnFailure(EOp operation, const string &object_key, const CNSTServiceProperties &service_props)
void x_ProcessCreate(const CJsonNode &message, const SCommonRequestArguments &common_args)
void x_ProcessDelete(const CJsonNode &message, const SCommonRequestArguments &common_args)
FProcessor x_FindProcessor(const SCommonRequestArguments &common_args)
void x_CheckObjectLoc(const string &object_loc) const
CJsonOverUTTPReader m_JSONReader
void x_OnData(const void *data, size_t data_size)
void x_ValidateWriteMetaDBAccess(const CJsonNode &message, bool expect_object=true) const
void x_OnMessage(const CJsonNode &message)
void x_ProcessHealth(const CJsonNode &message, const SCommonRequestArguments &common_args)
void x_ProcessExists(const CJsonNode &message, const SCommonRequestArguments &common_args)
void x_SetCmdRequestStatus(unsigned int status)
string GetLocator() const
bool IsMetaDataDisabled() const
string GetServiceName() const
string GetUniqueKey() const
unsigned int ErrCodeToHTTPStatusCode(void) const
CJsonNode SetParameters(const SNetStorageServerParameters &new_params, bool reconfigure)
Definition: nst_server.cpp:80
CJsonNode GetBackendConfDiff(const CJsonNode &conf) const
Definition: nst_server.cpp:285
void SetRAMConfigFileChecksum(const string &checksum)
Definition: nst_server.hpp:97
CNSTDatabase & GetDb(void)
Definition: nst_server.cpp:401
bool AnybodyCanReconfigure(void) const
Definition: nst_server.hpp:105
void ResetDecryptCacheIfNeed(void)
Definition: nst_server.cpp:237
enum EAlertAckResult AcknowledgeAlert(const string &id, const string &user)
Definition: nst_server.cpp:374
string GetSessionID(void) const
Definition: nst_server.hpp:83
unsigned int GetNetworkTimeout(void) const
Definition: nst_server.hpp:75
void RegisterNetStorageAPIDecryptError(const string &message)
Definition: nst_server.cpp:251
void SetAnybodyCanReconfigure(bool val)
Definition: nst_server.hpp:103
CJsonNode SerializeAlerts(void) const
Definition: nst_server.cpp:395
void ReportNetStorageAPIDecryptSuccess(void)
Definition: nst_server.cpp:259
void RegisterAlert(EAlertType alert_type, const string &messge)
Definition: nst_server.cpp:388
CNSTClientRegistry & GetClientRegistry(void)
Definition: nst_server.hpp:99
bool IsAdminClientName(const string &name) const
Definition: nst_server.cpp:354
CJsonNode GetBackendConfiguration(void) const
Definition: nst_server.hpp:107
virtual bool ShutdownRequested(void)
Runs synchronously between iterations.
Definition: nst_server.cpp:211
const CNSTPreciseTime & GetStartTime(void) const
Definition: nst_server.hpp:81
void SetBackendConfiguration(const CJsonNode &conf)
Definition: nst_server.hpp:109
EServiceMetadataPresence InMetadataServices(const string &service) const
Definition: nst_server.cpp:412
bool GetServiceProperties(const string &service, CNSTServiceProperties &service_props) const
Definition: nst_server.cpp:448
bool GetServiceTTL(const string &service, TNSTDBValue< CTimeSpan > &ttl) const
Definition: nst_server.cpp:418
string GetCommandLine(void) const
Definition: nst_server.hpp:87
CJsonNode ReadMetadataConfiguration(const IRegistry &reg)
Definition: nst_server.cpp:457
CCompoundIDPool GetCompoundIDPool(void) const
Definition: nst_server.hpp:89
void SetDiskConfigFileChecksum(const string &checksum)
Definition: nst_server.hpp:95
bool IsLogTimingClientSocket() const
Definition: nst_server.hpp:72
const bool & IsLog() const
Definition: nst_server.hpp:68
bool IsLogTimingNSTAPI() const
Definition: nst_server.hpp:70
CJsonNode SerializeMetadataInfo(void) const
Definition: nst_server.cpp:464
CNSTUserCache & GetUserCache(void)
Definition: nst_server.hpp:101
void SetShutdownFlag(int signum=0)
Definition: nst_server.cpp:217
unsigned int GetHostNetAddr() const
Definition: nst_server.hpp:79
CRegistryException –.
Definition: ncbireg.hpp:1005
const SCommonRequestArguments & m_CommonArgs
CNetStorageHandler & m_Handler
CRelocateCallback(CNetStorageHandler &handler, const SCommonRequestArguments &common_args, CDirectNetStorageObject &object, bool need_progress_report)
void Callback(CJsonNode info)
CDirectNetStorageObject & m_Object
Request context properties passed between tasks.
CSocket::
CTempString implements a light-weight string on top of a storage buffer whose lifetime management is ...
Definition: tempstr.hpp:65
CTimeFormat –.
Definition: ncbitime.hpp:131
CTimeSpan.
Definition: ncbitime.hpp:1313
CTime –.
Definition: ncbitime.hpp:296
CTimeout – Timeout interval.
Definition: ncbitime.hpp:1693
EStreamParsingEvent GetNextEvent()
Parse the input buffer until a parsing event occurs.
Definition: uttp.cpp:44
char GetControlSymbol() const
Return the control symbol that has been just read.
Definition: uttp.hpp:249
EStreamParsingEvent
Enumeration of the input stream parsing events.
Definition: uttp.hpp:98
@ eChunk
Notify that the last part of the chunk has been read.
Definition: uttp.hpp:107
@ eEndOfBuffer
Notify that the end of the input buffer has been reached.
Definition: uttp.hpp:120
@ eChunkPart
Notify that a part of a chunk has been read and can be fetched by a call to the GetChunkPart() method...
Definition: uttp.hpp:101
@ eControlSymbol
Notify that a control symbol has been read.
Definition: uttp.hpp:112
const char * GetChunkPart() const
Return a pointer to the buffer that contains a part of the chunk currently being read.
Definition: uttp.hpp:259
void SetNewBuffer(const char *buffer, size_t buffer_size)
Start processing of the next chunk of data.
Definition: uttp.hpp:242
size_t GetChunkPartSize() const
Return the size of the buffer returned by the GetChunkPart() method.
Definition: uttp.hpp:264
bool SendControlSymbol(char symbol)
Send a control symbol over the output buffer.
Definition: uttp.cpp:180
void GetOutputBuffer(const char **output_buffer, size_t *output_buffer_size)
Return data to be sent over the output stream and extend internal pointers to the next buffer.
Definition: uttp.hpp:430
bool NextOutputBuffer()
Proceed to the next output buffer.
Definition: uttp.cpp:291
bool SendChunk(const char *chunk, size_t chunk_length, bool to_be_continued)
Send a chunk of data to the output buffer.
Definition: uttp.cpp:192
void Reset(char *buffer, size_t buffer_size)
Initialize or reinitialize this object.
Definition: uttp.hpp:425
IMessage::
const_iterator begin() const
Definition: map.hpp:151
const_iterator end() const
Definition: map.hpp:152
void(*)(CSeq_entry_Handle seh, IWorkbench *wb, const CSerialObject &obj) handler
static uch flags
static const struct name_t names[]
#define true
Definition: bool.h:35
#define false
Definition: bool.h:36
char data[12]
Definition: iconv.c:80
bool ReloadConfig(CMetaRegistry::TFlags flags=CMetaRegistry::fReloadIfChanged, IRegistry::TFlags reg_flags=IRegistry::fWithNcbirc)
Reload the configuration file.
const CNcbiRegistry & GetConfig(void) const
Get the application's cached configuration parameters (read-only).
const string & GetConfigPath(void) const
Get the full path to the configuration file (if any) we ended up using.
@ eNegative
Value is negative.
Definition: ncbimisc.hpp:121
string
Definition: cgiapp.hpp:687
#define NULL
Definition: ncbistd.hpp:225
void PrintRequestStop(void)
Print request stop message (for request-driven applications)
Definition: ncbidiag.cpp:2778
CDiagContext_Extra & Print(const string &name, const string &value)
The method does not print the argument, but adds it to the string.
Definition: ncbidiag.cpp:2622
void SetBytesWr(Int8 bytes)
int GetRequestStatus(void) const
Request exit status.
string GetStringUID(TUID uid=0) const
Return string representation of UID.
Definition: ncbidiag.cpp:1691
CDiagContext & GetDiagContext(void)
Get diag context instance.
Definition: logging.cpp:818
static void SetRequestContext(CRequestContext *ctx)
Shortcut to CDiagContextThreadData::GetThreadData().SetRequestContext()
Definition: ncbidiag.cpp:1907
void PrintRequestStart(const string &message)
Print request start message (for request-driven applications)
Definition: ncbidiag.cpp:2762
void SetRequestID(TCount rid)
Set request ID.
CDiagContext_Extra Extra(void) const
Create a temporary CDiagContext_Extra object.
Definition: ncbidiag.hpp:2095
void SetClientIP(const string &client)
const string & Get(CTempString name) const
Get current property value or empty string if it's not set;.
#define NCBI_ERRCODE_X_NAME(name)
Returns value of error code by its name defined by NCBI_DEFINE_ERRCODE_X.
Definition: ncbidiag.hpp:369
TCount GetRequestID(void) const
Get request ID (or zero if not set).
static TPID GetPID(void)
Get cached PID (read real PID if not cached yet).
Definition: ncbidiag.cpp:1526
void SetRequestStatus(int status)
void SetHitID(const string &hit)
Set explicit hit id. The id is reset on request end.
void Flush(void)
Print the message and reset object.
Definition: ncbidiag.cpp:2332
void SetBytesRd(Int8 bytes)
#define ERR_POST(message)
Error posting with file, line number information but without error codes.
Definition: ncbidiag.hpp:186
virtual const char * GetType(void) const
Get class name as a string.
Definition: ncbiexpt.cpp:268
TErrCode GetErrCode(void) const
Get error code.
Definition: ncbiexpt.cpp:453
#define NCBI_THROW(exception_class, err_code, message)
Generic macro to throw an exception, given the exception class, error code and message string.
Definition: ncbiexpt.hpp:704
void Warning(CExceptionArgs_Base &args)
Definition: ncbiexpt.hpp:1191
int TErrCode
Definition: ncbiexpt.hpp:889
virtual const char * what(void) const noexcept
Standard report (includes full backlog).
Definition: ncbiexpt.cpp:342
virtual int GetSubCode(void) const =0
Get error subcode. Zero = not set.
virtual size_t Count(void) const
Get total number of collected messages.
virtual string GetText(void) const =0
Get text message.
virtual const IMessage & GetMessage(size_t index) const
Get a previously collected message.
virtual int GetCode(void) const =0
Get error code. Zero = not set.
static size_t PushListener(IMessageListener &listener, EListenFlag flag=eListen_Unhandled)
Push a new listener to the stack in the current thread.
static void PopListener(size_t depth=0)
Remove listener(s) from the current thread's stack.
bool Eof(void)
Check if the last Read() has hit EOF.
Definition: netstorage.cpp:260
string GetLoc(void) const
Return object locator.
Definition: netstorage.cpp:224
unsigned TNetStorageFlags
Bitwise OR of ENetStorageFlags.
Definition: netstorage.hpp:147
void Write(const void *buffer, size_t buf_size)
Write data to the object (starting at the current position)
Definition: netstorage.cpp:266
size_t Read(void *buffer, size_t buf_size)
Read no more than 'buf_size' bytes of the object contents (starting at the current position)
Definition: netstorage.cpp:229
void SetExpiration(const CTimeout &ttl)
Updates expiration on the object.
Definition: netstorage.cpp:316
void Close(void)
Finalize and close the current object stream.
Definition: netstorage.cpp:321
Uint8 GetSize(void)
Return size of the object.
Definition: netstorage.cpp:290
CNetStorageObjectInfo GetInfo(void)
Return detailed information about the object.
Definition: netstorage.cpp:311
CJsonNode ToJSON()
Pack the whole structure in a single JSON object.
function< void(CJsonNode)> TNetStorageProgressCb
Progress callback.
Definition: netstorage.hpp:348
ENetStorageRemoveResult
Result returned by Remove() methods.
Definition: netstorage.hpp:356
@ fNST_NoMetaData
Do not use NetStorage relational database to track ownership & changes.
Definition: netstorage.hpp:140
@ eNotSupported
Feature is not supported.
Definition: netstorage.hpp:77
@ eNotExists
Illegal op applied to non-existent object.
Definition: netstorage.hpp:71
@ eInterrupted
Operation has been interrupted.
Definition: netstorage.hpp:78
@ eNSTRR_NotFound
Removing failed due to object not found.
Definition: netstorage.hpp:357
bool NotNull(void) const THROWS_NONE
Check if pointer is not null – same effect as NotEmpty().
Definition: ncbiobj.hpp:744
void Reset(void)
Reset reference object.
Definition: ncbiobj.hpp:773
bool IsNull(void) const THROWS_NONE
Check if pointer is null – same effect as Empty().
Definition: ncbiobj.hpp:735
int64_t Int8
8-byte (64-bit) signed integer
Definition: ncbitype.h:104
uint64_t Uint8
8-byte (64-bit) unsigned integer
Definition: ncbitype.h:105
bool Write(CNcbiOstream &os, TFlags flags=0) const
Write the registry content to output stream.
Definition: ncbireg.cpp:196
@ eDecryptionFailed
Value looked encrypted, but decryption failed.
Definition: ncbireg.hpp:1013
EIO_Status Shutdown(EIO_Event how)
Shutdown socket I/O in the specified direction.
static unsigned int GetLoopbackAddress(void)
Loopback address gets returned in network byte order.
virtual EIO_Status GetOSHandle(void *handle_buf, size_t handle_size, EOwnership ownership=eNoOwnership) const
Access to the system-specific socket handle.
EIO_Status SetTimeout(EIO_Event event, const STimeout *timeout)
Set timeout for I/O in the specified direction.
void DisableOSSendDelay(bool on_off=true)
EIO_Status GetStatus(EIO_Event direction) const
Return status of *last* I/O operation without making any actual I/O.
TNCBI_BigCount GetCount(EIO_Event direction) const
void GetPeerAddress(unsigned int *host, unsigned short *port, ENH_ByteOrder byte_order) const
Get peer address.
EIO_Status Write(const void *buf, size_t size, size_t *n_written=0, EIO_WriteMethod how=eIO_WritePersist)
Write to socket.
EIO_Status Read(void *buf, size_t size, size_t *n_read=0, EIO_ReadMethod how=eIO_ReadPlain)
Read from socket.
@ eSAF_IP
only numeric IP if INET socket, empty otherwise
Definition: ncbi_socket.h:1392
@ eNH_NetworkByteOrder
Definition: ncbi_socket.h:194
IO_PREFIX::ifstream CNcbiIfstream
Portable alias for ifstream.
Definition: ncbistre.hpp:439
static string PrintableString(const CTempString str, TPrintableMode mode=fNewLine_Quote|fNonAscii_Passthru)
Get a printable version of the specified string.
Definition: ncbistr.cpp:3953
static bool EqualNocase(const CTempString s1, SIZE_TYPE pos, SIZE_TYPE n, const char *s2)
Case-insensitive equality of a substring with another string.
Definition: ncbistr.hpp:5353
TErrCode GetErrCode(void) const
Get error code.
Definition: ncbistr.hpp:4455
static enable_if< is_arithmetic< TNumeric >::value||is_convertible< TNumeric, Int8 >::value, string >::type NumericToString(TNumeric value, TNumToStringFlags flags=0, int base=10)
Convert numeric value to string.
Definition: ncbistr.hpp:673
static string TruncateSpaces(const string &str, ETrunc where=eTrunc_Both)
Truncate spaces in a string.
Definition: ncbistr.cpp:3186
static string & ToLower(string &str)
Convert string to lower case – string& version.
Definition: ncbistr.cpp:405
EClosePeer
Type of connection closing.
Definition: server.hpp:268
void WakeUpPollCycle(void)
Force poll cycle to make another iteration.
Definition: server.cpp:837
EOverflowReason
Error codes for OnOverflow method in IServer_ConnectionHandler.
Definition: server.hpp:210
void CloseConnection(CSocket *sock)
Close connection.
Definition: server.cpp:643
CSocket & GetSocket(void)
Get underlying socket.
Definition: server.hpp:294
@ eClientClose
Connection closed by other peer.
Definition: server.hpp:270
@ eOurClose
Connection closed by ourselves.
Definition: server.hpp:269
@ eOR_ConnectionPoolFull
Definition: server.hpp:212
@ eOR_UnpollableSocket
Definition: server.hpp:214
@ eOR_RequestQueueFull
Definition: server.hpp:213
bool IsEmpty(void) const
Return TRUE is an object keep zero time span.
Definition: ncbitime.hpp:2579
double GetAsDouble(void) const
Get as number of seconds (fractional value).
Definition: ncbitime.cpp:3512
ESign GetSign(void) const
Get sign of time span.
Definition: ncbitime.hpp:2529
CTime CurrentTime(CTime::ETimeZone tz=CTime::eLocal, CTime::ETimeZonePrecision tzp=CTime::eTZPrecisionDefault)
Definition: ncbitime.hpp:2184
string AsSmartString(ESmartStringPrecision precision, ERound rounding, ESmartStringZeroMode zero_mode=eSSZ_SkipZero) const
Transform time span to "smart" string.
Definition: ncbitime.hpp:2688
void Set(EType type)
Set special value.
Definition: ncbitime.cpp:3577
@ eInfinite
Infinite timeout.
Definition: ncbitime.hpp:1699
EIO_Status
I/O status.
Definition: ncbi_core.h:132
const char * IO_StatusStr(EIO_Status status)
Get the text form of an enum status value.
Definition: ncbi_core.c:56
EIO_Event
I/O event (or direction).
Definition: ncbi_core.h:118
uint64_t TNCBI_BigCount
Big unsigned integer for file size and position.
Definition: ncbi_types.h:164
@ eIO_Timeout
timeout expired before any I/O succeeded
Definition: ncbi_core.h:134
@ eIO_Interrupt
signal arrival prevented any I/O to succeed
Definition: ncbi_core.h:136
@ eIO_NotSupported
operation is not supported or is not available
Definition: ncbi_core.h:138
@ eIO_Success
everything is fine, no error occurred
Definition: ncbi_core.h:133
@ eIO_Write
write
Definition: ncbi_core.h:121
@ eIO_ReadWrite
eIO_Read | eIO_Write (also, eCONN_OnFlush)
Definition: ncbi_core.h:122
@ eIO_Open
also serves as no-event indicator in SOCK_Poll
Definition: ncbi_core.h:119
@ eIO_Read
read
Definition: ncbi_core.h:120
operation
Bit operations.
Definition: bmconst.h:191
exit(2)
static MDB_envinfo info
Definition: mdb_load.c:37
mdb_mode_t mode
Definition: lmdb++.h:38
const struct ncbi::grid::netcache::search::fields::KEY key
const GenericPointer< typename T::ValueType > T2 value
Definition: pointer.h:1227
IMessage/IMessageListener interfaces and basic implementations.
@ eVoid
To create a void (uninitialized) instance of a component.
static Format format
Definition: njn_ioutil.cpp:53
EAlertAckResult
Definition: ns_alert.hpp:63
@ eAcknowledged
Definition: ns_alert.hpp:66
@ eAlreadyAcknowledged
Definition: ns_alert.hpp:65
@ eConfigOutOfSync
Definition: ns_alert.hpp:53