1 #ifndef NETCACHE__SRV_SOCKETS__HPP 2 #define NETCACHE__SRV_SOCKETS__HPP 3 /* $Id: srv_sockets.hpp 544804 2017-08-28 14:38:49Z gouriano $ 4 * =========================================================================== 5 * 6 * PUBLIC DOMAIN NOTICE 7 * National Center for Biotechnology Information 8 * 9 * This software/database is a "United States Government Work" under the 10 * terms of the United States Copyright Act. It was written as part of 11 * the author's official duties as a United States Government employee and 12 * thus cannot be copyrighted. This software/database is freely available 13 * to the public for use. The National Library of Medicine and the U.S. 14 * Government have not placed any restriction on its use or reproduction. 15 * 16 * Although all reasonable efforts have been taken to ensure the accuracy 17 * and reliability of the software and data, the NLM and the U.S. 18 * Government do not and cannot warrant the performance or results that 19 * may be obtained by using this software or data. The NLM and the U.S. 20 * Government disclaim all warranties, express or implied, including 21 * warranties of performance, merchantability or fitness for any particular 22 * purpose. 23 * 24 * Please cite the author in any work or product based on this material. 25 * 26 * =========================================================================== 27 * 28 * Authors: Pavel Ivanov 29 * 30 * File Description: 31 */ 32 33 34 namespace intr = boost::intrusive; 35 36 37 BEGIN_NCBI_SCOPE 38 39 40 /// For TaskServer's internal use only. 41 /// This structure is used as base for both CSrvSocketTask and internal 42 /// listening socket structure. Pointer to SSrvSocketInfo is remembered in 43 /// epoll and value of is_listening is used to distinguish between listening 44 /// socket structure and CSrvSocketTask. 45 struct SSrvSocketInfo 46 { 47 bool is_listening; 48 }; 49 50 51 /* 52 from here: 53 http://www.boost.org/doc/libs/1_56_0/doc/html/intrusive/usage.html 54 55 If there is a virtual inheritance relationship between the parent and 56 the member hook, then the distance between the parent and the hook is not 57 a compile-time fixed value so obtaining the address of the parent from 58 the member hook is not possible without reverse engineering compiler produced RTTI. 59 Apart from this, the non-standard pointer to member implementation for classes with 60 complex inheritance relationships in MSVC ABI compatible-compilers is not supported 61 by member hooks since it also depends on compiler-produced RTTI information. 62 63 This means member hooks are potentially dangerous, because we DO use virtual inheritance here. 64 With Boost 1.53 this compiles on MSVC 65 With Boost 1.56 it does not. 66 With GCC it compiles so far... but.. who knows... 67 */ 68 #define NC_SOCKLIST_USE_MEMBER_HOOK 1 69 #define NC_SOCKLIST_USE_BASE_HOOK 2 70 #define NC_SOCKLIST_USE_STD_LIST 3 71 #define NC_SOCKLIST_USE_TYPE NC_SOCKLIST_USE_BASE_HOOK 72 73 74 #if NC_SOCKLIST_USE_TYPE == NC_SOCKLIST_USE_MEMBER_HOOK 75 struct SSrvSockList_tag; 76 typedef intr::list_member_hook<intr::tag<SSrvSockList_tag> > TSrvSockListHook; 77 #elif NC_SOCKLIST_USE_TYPE == NC_SOCKLIST_USE_BASE_HOOK 78 struct SSrvSockList_tag; 79 typedef intr::list_base_hook<intr::tag<SSrvSockList_tag> > TSrvSockListHook; 80 #endif 81 82 83 84 85 /// Task controlling a socket. 86 /// This task always becomes runnable in 3 cases: 87 /// - when socket changes from non-readable to readable (some data came into 88 /// socket and can be read by user); 89 /// - when socket changes from non-writable to writable (socket has been just 90 /// opened, connection established and data can be written to the other side); 91 /// - when some error appears in socket, e.g. client disconnected. 92 /// When task became runnable and ExecuteSlice() is called it's user's code 93 /// responsibility to process event completely (not necessarily immediately 94 /// but eventually). I.e. TaskServer won't set the task runnable again if user 95 /// didn't read all the data from socket. 96 /// CSrvSocketTask cannot attach to any random socket. It should be either 97 /// returned from CSrvSocketFactory and TaskServer will attach it to just 98 /// connected socket, or CSrvSocketTask::Connect() method should be called 99 /// to create socket with other server. 100 #if NC_SOCKLIST_USE_TYPE == NC_SOCKLIST_USE_BASE_HOOK 101 class CSrvSocketTask : public virtual CSrvTask, public SSrvSocketInfo, 102 public TSrvSockListHook 103 #else 104 class CSrvSocketTask : public virtual CSrvTask, public SSrvSocketInfo 105 #endif 106 { 107 public: 108 CSrvSocketTask(void); 109 virtual ~CSrvSocketTask(void); 110 111 /// Checks if there's some data available for reading in internal buffers. 112 /// Method doesn't say anything about data available in socket but not yet 113 /// retrieved from kernel. 114 bool IsReadDataAvailable(void); 115 /// Checks if there's some data pending in write buffers and waiting to be 116 /// sent to kernel. 117 bool IsWriteDataPending(void); 118 /// Checks if socket has some error in it. 119 bool HasError(void); 120 /// Checks if socket can ever have more data to read even though it may not 121 /// have it at the moment. Socket won't have more data to read if EOF 122 /// received. 123 bool CanHaveMoreRead(void); 124 /// Checks if socket should be closed because of long inactivity or 125 /// because server is in "hard" shutdown phase. User code should always 126 /// check result of this method at some pivot points where it has the 127 /// ability to close. 128 bool NeedToClose(void); 129 /// Checks if socket should be closed because of internal reasons (long 130 /// inactivity or "hard" shutdown as in NeedToClose()) or because of 131 /// external reasons, like error or EOF in the socket. 132 bool NeedEarlyClose(void); 133 134 /// Read from socket into internal buffer. 135 /// Method tries to completely fill the buffer even if there's some data 136 /// already waiting in it. 137 bool ReadToBuf(void); 138 /// Read from socket into memory. 139 /// Method combines reading from internal buffer and directly from socket 140 /// (without changing data order) and reads as much as possible to do 141 /// without blocking. Method returns total size of read data (can be 0 if 142 /// no data immediately available). 143 size_t Read(void* buf, size_t size); 144 /// Read from socket one line which ends with '\n', '\r\n' or '\0'. 145 /// Line read should fit into internal read buffer, i.e. it shouldn't be 146 /// too long, otherwise method returns FALSE and raises error flag which 147 /// means you won't be able to anything else with socket (besides closing). 148 /// Method returns TRUE if line was successfully read and FALSE if there's 149 /// no data or no line end markers in it. When method returned TRUE 150 /// variable line will point to internal read buffer. Thus it should be 151 /// used before calling any other Read*() methods -- after that memory can 152 /// become invalid. 153 bool ReadLine(CTempString* line); 154 /// Read from socket exactly the given data size. If given size is not 155 /// immediately available (without blocking) method doesn't read anything 156 /// and returns FALSE. Otherwise data is copied to buf and TRUE is 157 /// returned. Requested size must be less than internal read buffer. 158 bool ReadData(void* buf, Uint2 size); 159 /// Read from socket a number in native machine representation. 160 /// If sizeof(NumType) bytes is not immediately available in the socket 161 /// method returns FALSE and doesn't read anything. Otherwise it copies 162 /// data into num and returns TRUE. 163 template <typename NumType> 164 bool ReadNumber(NumType* num); 165 166 /// Write text into socket. 167 /// The whole text message will be written, internal write buffer will be 168 /// expanded to accommodate the message if necessary. 169 CSrvSocketTask& WriteText(CTempString message); 170 /// Write number into socket as string, i.e. number is converted to string 171 /// using NStr::NumericToString() first and then the result is written to 172 /// socket as string. The whole number will be written, internal write 173 /// buffer will be expanded to accommodate it if necessary. 174 template <typename NumType> 175 CSrvSocketTask& WriteNumber(NumType num); 176 CSrvSocketTask& WriteBool(bool b); 177 /// Write the exact amount of data into the socket. All the data will be 178 /// written, internal write buffer will be expanded to accommodate it 179 /// if necessary. 180 void WriteData(const void* buf, size_t size); 181 /// Write into the socket as much as immediately possible (including 182 /// writing into internal write buffers and writing directly into socket) 183 /// without blocking and without expanding write buffer. Method returns 184 /// amount of data written which can be 0 if socket is not writable at the 185 /// moment. 186 size_t Write(const void* buf, size_t size); 187 /// Flush all data saved in internal write buffers to socket. 188 /// Method must be called from inside of ExecuteSlice() of this task and 189 /// no other writing methods should be called until FlushIsDone() returns 190 /// TRUE. 191 void Flush(void); 192 /// Request flushing of all data saved in internal write buffers to socket. 193 /// Method can be called from anywhere even concurrently with 194 /// ExecuteSlice() of this task. No other writing methods should be called 195 /// until FlushIsDone() returns TRUE. 196 void RequestFlush(void); 197 /// Check if data flushing requested earlier is complete. 198 bool FlushIsDone(void); 199 200 /// Start proxying of raw data from this socket to the one in dst_task. 201 /// Method must be called from inside of ExecuteSlice() of this task. And 202 /// nothing else should be done with both sockets until IsProxyInProgress() 203 /// returns FALSE. Only proxy_size bytes is transferred between sockets. 204 /// Proxying can stop earlier only if NeedEarlyClose() on either socket 205 /// returns true. In this case ProxyHadError() will return true and 206 /// nothing else could be done with sockets except closing. 207 void StartProxyTo(CSrvSocketTask* dst_task, Uint8 proxy_size); 208 /// Check whether proxying started earlier is still in progress. 209 bool IsProxyInProgress(void); 210 /// Check whether proxying started earlier finished successfully or any of 211 /// sockets had some error in it. 212 bool ProxyHadError(void); 213 214 /// Create new socket and connect it to given IP and port. 215 /// If operation is successful TRUE is returned, FALSE returned otherwise. 216 /// FALSE will be returned only in case of errors like network interface 217 /// is down or things like that. If server is inaccessible then Connect() 218 /// will return TRUE but later there will be error in the socket. 219 bool Connect(Uint4 host, Uint2 port); 220 /// Start processing of the socket and include it into TaskServer's 221 /// central epoll. Until this method is called TaskServer won't make this 222 /// task runnable and won't check if it's readable or writable -- any 223 /// Read/Write operation will be unsuccessful (processing 0 bytes). 224 bool StartProcessing(TSrvThreadNum thread_num = 0, bool boost = false); 225 /// Close the socket gracefully, i.e. if any socket's data is still in 226 /// kernel's buffers and didn't make it to wire it will be sent later. But 227 /// internal task's write buffers won't be flushed. 228 void CloseSocket(void); 229 /// Abort the socket, i.e. anything unsent in kernel buffers will be 230 /// dropped. 231 void AbortSocket(void); 232 233 /// Get peer IP and port for this socket. 234 void GetPeerAddress(string& host, Uint2& port); 235 /// Get local port this socket was created on. 236 Uint2 GetLocalPort(void); 237 238 /// Terminate the task. Method is overridden here to add some extra 239 /// processing for sockets. 240 virtual void Terminate(void); 241 242 private: 243 CSrvSocketTask(const CSrvSocketTask&); 244 CSrvSocketTask& operator= (const CSrvSocketTask&); 245 246 /// Internal function to execute time slice work. Overridden here to add 247 /// some extra socket processing before and after call to user's code in 248 /// ExecuteSlice(). 249 virtual void InternalRunSlice(TSrvThreadNum thr_num); 250 251 /// Close or abort the socket -- they have little difference, thus they 252 /// joined in one method. 253 void x_CloseSocket(bool do_abort); 254 /// Prints socket's error if there's any error pending on the socket. 255 void x_PrintError(void); 256 257 // Consider this section private as it's public for internal use only 258 // to minimize implementation-specific clutter in headers. 259 public: 260 /// Source task for proxying. 261 /// This variable is set to non-NULL value only in destination tasks for 262 /// proxying. 263 CSrvSocketTask* m_ProxySrc; 264 /// Destination task for proxying. 265 /// This variable is set to non-NULL value only in source tasks for 266 /// proxying. 267 CSrvSocketTask* m_ProxyDst; 268 /// Amount left to proxy if proxying operation is in progress. 269 /// Value is set only in source tasks for proxying. 270 Uint8 m_ProxySize; 271 #if NC_SOCKLIST_USE_TYPE == NC_SOCKLIST_USE_MEMBER_HOOK 272 /// Hook to include the task to lists of open sockets. 273 TSrvSockListHook m_SockListHook; 274 #endif 275 /// Read buffer. 276 char* m_RdBuf; 277 /// Write buffer. 278 char* m_WrBuf; 279 /// Jiffy number when Connect() method was called. Variable is used to 280 /// track connection timeouts. 281 Uint8 m_ConnStartJfy; 282 /// File descriptor for the socket. 283 int m_Fd; 284 /// Size of data available for reading in the read buffer. 285 Uint2 m_RdSize; 286 /// Position of current reading in the read buffer, i.e. all data in 287 /// [0, m_RdPos) was already read; data in [m_RdPos, m_RdSize) are queued 288 /// for reading. 289 Uint2 m_RdPos; 290 /// Size of memory allocated for write buffer. This size can grow in 291 /// methods requiring exact writing like WriteData(), WriteText() etc. 292 Uint2 m_WrMemSize; 293 /// Size of data in the write buffer waiting for writing. 294 Uint2 m_WrSize; 295 /// Position of current writing pointer in the write buffer. 296 Uint2 m_WrPos; 297 /// Flag showing if '\r' symbol was seen at the end of last line but '\n' 298 /// wasn't seen yet. 299 bool m_CRMet; 300 /// Flag showing that last proxying operation finished with error. 301 bool m_ProxyHadError; 302 /// Flag showing that socket is readable. 303 bool m_SockHasRead; 304 /// Flag showing that socket is writable. 305 bool m_SockCanWrite; 306 /// Flag showing that socket can have more reads, i.e. there was no EOF yet. 307 bool m_SockCanReadMore; 308 /// Flag showing that socket needs to be closed because of long 309 /// inactivity. 310 bool m_NeedToClose; 311 /// Flag showing that task needs to flush all write buffers. 312 bool m_NeedToFlush; 313 /// Flag showing that write buffers were flushed. 314 bool m_FlushIsDone; 315 /// Number of last read event seen by Read() when it read from socket. If 316 /// this number is equal to m_RegReadEvts then no new "readable" events 317 /// came from epoll and thus result of last read defines if there is more 318 /// data in the socket to read (if last read returned less data than 319 /// provided buffer size then there's no more data in the socket). 320 Uint1 m_SeenReadEvts; 321 /// Number of last write event seen by Write() when it wrote to socket. If 322 /// this number is equal to m_RegWriteEvts then no new "writable" events 323 /// came from epoll and thus result of last write defines if more data 324 /// can be written in the socket (if last write have written less data than 325 /// provided buffer size then nothing else can be written in the socket). 326 Uint1 m_SeenWriteEvts; 327 /// Total number of bytes read from socket. 328 Uint8 m_ReadBytes; 329 /// Total number of bytes written to socket. 330 Uint8 m_WrittenBytes; 331 /// Counter of "readable" events received from epoll. 332 Uint1 m_RegReadEvts; 333 /// Counter of "writable" events received from epoll. 334 Uint1 m_RegWriteEvts; 335 /// Flag showing if epoll returned RDHUP on this socket. 336 bool m_RegReadHup; 337 /// Flag showing if there's error pending on the socket. 338 bool m_RegError; 339 /// Flag showing if pending error in socket was printed in logs. 340 bool m_ErrorPrinted; 341 /// Remembered peer port. Value valid only for sockets created from 342 /// listening sockets. 343 Uint2 m_PeerPort; 344 /// Remembered peer IP address. Value valid only for sockets created from 345 /// listening sockets. 346 Uint4 m_PeerAddr; 347 /// 348 string m_ConnReqId; 349 }; 350 351 352 /// Factory that creates CSrvSocketTask-derived object for each connection 353 /// coming to listening port which this factory is assigned to. 354 class CSrvSocketFactory 355 { 356 public: 357 CSrvSocketFactory(void); 358 virtual ~CSrvSocketFactory(void); 359 360 virtual CSrvSocketTask* CreateSocketTask(void) = 0; 361 }; 362 363 364 END_NCBI_SCOPE 365 366 #endif /* NETCACHE__SRV_SOCKETS__HPP */ 367