1 module hunt.io.channel.iocp.AbstractStream; 2 3 // dfmt off 4 version (HAVE_IOCP) : 5 // dfmt on 6 7 import hunt.collection.ByteBuffer; 8 import hunt.collection.BufferUtils; 9 import hunt.event.selector.Selector; 10 import hunt.io.channel.AbstractSocketChannel; 11 import hunt.io.channel.Common; 12 import hunt.io.channel.iocp.Common; 13 import hunt.logging.ConsoleLogger; 14 import hunt.Functions; 15 import hunt.concurrency.thread.Helper; 16 17 import core.atomic; 18 import core.sys.windows.windows; 19 import core.sys.windows.winsock2; 20 import core.sys.windows.mswsock; 21 22 import std.format; 23 import std.socket; 24 import core.sync.mutex; 25 import core.stdc.string; 26 27 /** 28 TCP Peer 29 */ 30 abstract class AbstractStream : AbstractSocketChannel { 31 32 // data event handlers 33 34 /** 35 * Warning: The received data is stored a inner buffer. For a data safe, 36 * you would make a copy of it. 37 */ 38 protected DataReceivedHandler dataReceivedHandler; 39 protected SimpleActionHandler dataWriteDoneHandler; 40 41 protected AddressFamily _family; 42 protected ByteBuffer _bufferForRead; 43 44 private Mutex _mutex; 45 private bool _Closed = false; 46 47 this(Selector loop, AddressFamily family = AddressFamily.INET, size_t bufferSize = 4096 * 2) { 48 super(loop, ChannelType.TCP); 49 // setFlag(ChannelFlag.Read, true); 50 // setFlag(ChannelFlag.Write, true); 51 52 version (HUNT_IO_DEBUG) 53 trace("Buffer size for read: ", bufferSize); 54 // _readBuffer = new ubyte[bufferSize]; 55 _family = family; 56 _bufferForRead = BufferUtils.allocate(bufferSize); 57 _bufferForRead.clear(); 58 _readBuffer = cast(ubyte[])_bufferForRead.array(); 59 _writeQueue = new WritingBufferQueue(); 60 this.socket = new TcpSocket(family); 61 62 loadWinsockExtension(this.handle); 63 _mutex = new Mutex; 64 } 65 66 mixin CheckIocpError; 67 68 override void onRead() { 69 version (HUNT_IO_DEBUG) 70 trace("ready to read"); 71 super.onRead(); 72 } 73 74 /** 75 * Should be thread-safe. 76 */ 77 override void onWrite() { 78 version (HUNT_IO_DEBUG) 79 tracef("checking write status, isWritting: %s, writeBuffer: %s", _isWritting, writeBuffer is null); 80 81 //if(!_isWritting){ 82 // version (HUNT_IO_DEBUG) infof("No data to write out. fd=%d", this.handle); 83 // return; 84 //} 85 86 if(isClosing() && isWriteCancelling) { 87 version (HUNT_IO_DEBUG) infof("Write cancelled, fd=%d", this.handle); 88 resetWriteStatus(); 89 return; 90 } 91 tryNextBufferWrite(); 92 } 93 94 protected override void onClose() { 95 infof("onClose cancelled"); 96 _isWritting = false; 97 _Closed = true; 98 resetWriteStatus(); 99 if(this._socket is null) { 100 import core.sys.windows.winsock2; 101 .closesocket(this.handle); 102 } else { 103 // FIXME: Needing refactor or cleanup -@Administrator at 2019/8/9 1:20:27 pm 104 // 105 infof("socket closed: fd=%d ", this.handle); 106 while(!_isSingleWriteBusy) 107 { 108 this._socket.shutdown(SocketShutdown.BOTH); 109 this._socket.close(); 110 } 111 } 112 super.onClose(); 113 } 114 115 public void stopAction() 116 { 117 _isSingleWriteBusy = true; 118 _Closed = true; 119 _endFristRead = false; 120 } 121 122 public void beginRead() { 123 //synchronized (_mutex){ 124 125 // https://docs.microsoft.com/en-us/windows/desktop/api/winsock2/nf-winsock2-wsarecv 126 //if (this._socket !is null) 127 //{ 128 try 129 { 130 // synchronized (_mutex) 131 // { 132 if (!_Closed ) 133 { 134 _isSingleWriteBusy = true; 135 136 WSABUF _dataReadBuffer; 137 _dataReadBuffer.len = cast(uint) _readBuffer.length; 138 _dataReadBuffer.buf = cast(char*) _readBuffer.ptr; 139 _iocpread.channel = this; 140 _iocpread.operation = IocpOperation.read; 141 DWORD dwReceived = 0; 142 DWORD dwFlags = 0; 143 memset(&_iocpread.overlapped , 0 ,_iocpread.overlapped.sizeof ); 144 version (HUNT_IO_DEBUG) 145 tracef("start receiving [fd=%d] ", this.socket.handle); 146 // _isSingleWriteBusy = true; 147 int nRet = WSARecv(cast(SOCKET) this.socket.handle, &_dataReadBuffer, 1u, &dwReceived, &dwFlags, 148 &_iocpread.overlapped, cast(LPWSAOVERLAPPED_COMPLETION_ROUTINE) null); 149 if (nRet == SOCKET_ERROR) 150 { 151 _isSingleWriteBusy = false; 152 tracef("WSARecv close"); 153 close(); 154 } 155 //checkErro(nRet, SOCKET_ERROR); 156 } 157 // } 158 } catch (Exception e) 159 { 160 161 } 162 // } 163 164 165 //} 166 } 167 168 protected bool doConnect(Address addr) { 169 try { 170 Address binded = createAddress(this.socket.addressFamily); 171 this.socket.bind(binded); 172 _iocpread.channel = this; 173 _iocpread.operation = IocpOperation.connect; 174 int nRet = ConnectEx(cast(SOCKET) this.socket.handle(), 175 cast(SOCKADDR*) addr.name(), addr.nameLen(), null, 0, null, 176 &_iocpread.overlapped); 177 checkErro(nRet, SOCKET_ERROR); 178 179 } catch (SocketOSException e) 180 { 181 return false; 182 } 183 return true; 184 } 185 186 private uint doWrite(const(ubyte)[] data) { 187 // synchronized (_mutex){ 188 DWORD dwSent = 0;//cast(DWORD)data.length; 189 DWORD dwFlags = 0; 190 191 tracef("is busy ------- ---------------------------------------- %d",_isSingleWriteBusy); 192 193 //scope(exit) { 194 // _isSingleWriteBusy = false; 195 //} 196 try { 197 // synchronized (_mutex){ 198 199 200 //if (this.socket.handle() == INVALID_SOCKET) 201 //{ 202 // tracef("nonononono"); 203 //} 204 if ( !_Closed) 205 { 206 _iocpread.channel = this; 207 _iocpread.operation = IocpOperation.write; 208 memset(&_iocpread.overlapped , 0 ,_iocpread.overlapped.sizeof ); 209 // tracef("To write %d bytes, fd=%d", data.length, this.socket.handle()); 210 version (HUNT_IO_DEBUG) { 211 size_t bufferLength = data.length; 212 tracef("To write %d bytes", bufferLength); 213 if (bufferLength > 32) 214 tracef("%(%02X %) ...", data[0 .. 32]); 215 else 216 tracef("%s", data); 217 } 218 // size_t bufferLength = data.length; 219 // tracef("To write %d bytes", bufferLength); 220 // tracef("%s", data); 221 WSABUF _dataWriteBuffer; 222 223 //char[] bf = new char[data.length]; 224 //memcpy(bf.ptr,data.ptr,data.length); 225 //_dataWriteBuffer.buf = bf.ptr; 226 _dataWriteBuffer.buf = cast(char*) data.ptr; 227 _dataWriteBuffer.len = cast(uint) data.length; 228 tracef("To write %s bytes %d", _dataWriteBuffer.buf , _dataWriteBuffer.len); 229 _isSingleWriteBusy = true; 230 int nRet = WSASend( cast(SOCKET) this.socket.handle(), &_dataWriteBuffer, 1, &dwSent, 231 dwFlags, &_iocpread.overlapped, cast(LPWSAOVERLAPPED_COMPLETION_ROUTINE) null); 232 if (nRet != NO_ERROR) 233 { 234 _isSingleWriteBusy = false; 235 tracef("WSASend close"); 236 close(); 237 } 238 239 checkErro( nRet, SOCKET_ERROR); 240 } 241 //} 242 } catch(Exception e) 243 { 244 _isSingleWriteBusy = false; 245 return 0; 246 } 247 248 249 // FIXME: Needing refactor or cleanup -@Administrator at 2019/8/9 12:18:20 pm 250 // Keep this to prevent the buffer corrupted. Why? 251 version (HUNT_IO_DEBUG) { 252 tracef("sent: %d / %d bytes, fd=%d", dwSent, bufferLength, this.handle); 253 } 254 255 256 257 if (this.isError) { 258 errorf("Socket error on write: fd=%d, message=%s", this.handle, this.errorMessage); 259 this.close(); 260 } 261 262 return dwSent; 263 // } 264 265 } 266 267 protected void doRead() { 268 //_isSingleWriteBusy = false; 269 this.clearError(); 270 version (HUNT_IO_DEBUG) 271 tracef("start reading: %d nbytes", this.readLen); 272 273 if (readLen > 0) { 274 // import std.stdio; 275 // writefln("length=%d, data: %(%02X %)", readLen, _readBuffer[0 .. readLen]); 276 version (HUNT_IO_DEBUG) 277 tracef("reading done: %d nbytes", readLen); 278 279 auto ss = this.socket; 280 if (dataReceivedHandler !is null){ 281 //if (dataReceivedHandler !is null && !_Closed && this.socket.handle() != INVALID_SOCKET && this.socket.handle() != -1 && this.socket.handle() != 0) { 282 _bufferForRead.limit(cast(int)readLen); 283 _bufferForRead.position(0); 284 dataReceivedHandler(_bufferForRead); 285 } 286 287 this.beginRead(); 288 //if (_endFristRead) 289 //{ 290 // 291 //} 292 // continue reading 293 294 } else if (readLen == 0) { 295 version (HUNT_IO_DEBUG) { 296 if (_remoteAddress !is null) 297 warningf("connection broken: %s", _remoteAddress.toString()); 298 } 299 onDisconnected(); 300 // if (_isClosed) 301 // this.close(); 302 } else { 303 version (HUNT_IO_DEBUG) { 304 warningf("undefined behavior on thread %d", getTid()); 305 } else { 306 this._error = true; 307 this._errorMessage = "undefined behavior on thread"; 308 } 309 } 310 } 311 312 // try to write a block of data directly 313 protected size_t tryWrite(const ubyte[] data) { 314 version (HUNT_IO_DEBUG) 315 tracef("start to write, total=%d bytes, fd=%d", data.length, this.handle); 316 clearError(); 317 size_t nBytes; 318 //scope(exit) { 319 // _isSingleWriteBusy = false; 320 //} 321 if (!_isSingleWriteBusy) 322 { 323 nBytes = doWrite(data); 324 } 325 326 return nBytes; 327 } 328 329 // try to write a block of data from the write queue 330 private void tryNextBufferWrite() { 331 if(checkAllWriteDone()){ 332 _isSingleWriteBusy = false; 333 return; 334 } 335 336 // keep thread-safe here 337 //if(!cas(&_isSingleWriteBusy, false, true)) { 338 // version (HUNT_IO_DEBUG) warningf("busy writing. fd=%d", this.handle); 339 // return; 340 //} 341 342 //scope(exit) { 343 // _isSingleWriteBusy = false; 344 //} 345 346 clearError(); 347 348 bool haveBuffer = _writeQueue.tryDequeue(writeBuffer); 349 if(haveBuffer) { 350 writeBufferRemaining(); 351 } else { 352 version (HUNT_IO_DEBUG) 353 warning("No buffer in queue"); 354 } 355 } 356 357 private void writeBufferRemaining() { 358 if (writeBuffer is null ||_isSingleWriteBusy) 359 { 360 return; 361 } 362 const(ubyte)[] data = cast(const(ubyte)[])writeBuffer.getRemaining(); 363 364 size_t nBytes = doWrite(data); 365 366 version (HUNT_IO_DEBUG) 367 tracef("written data: %d bytes, fd=%d", nBytes, this.handle); 368 if(nBytes == data.length) { 369 writeBuffer = null; 370 } else if (nBytes > 0) { 371 writeBuffer.nextGetIndex(cast(int)nBytes); 372 version (HUNT_IO_DEBUG) 373 warningf("remaining data: %d / %d, fd=%d", data.length - nBytes, data.length, this.handle); 374 } else { 375 version (HUNT_IO_DEBUG) 376 warningf("I/O busy: writing. fd=%d", this.handle); 377 } 378 } 379 380 protected bool checkAllWriteDone() { 381 if(_writeQueue.isEmpty() && writeBuffer is null) { 382 resetWriteStatus(); 383 version (HUNT_IO_DEBUG) 384 tracef("All data are written out. fd=%d", this.handle); 385 if(dataWriteDoneHandler !is null) 386 dataWriteDoneHandler(this); 387 return true; 388 } 389 390 return false; 391 } 392 393 void resetWriteStatus() { 394 _writeQueue.clear(); 395 _isWritting = false; 396 isWriteCancelling = false; 397 sendDataBuffer = null; 398 sendDataBackupBuffer = null; 399 writeBuffer = null; 400 _isSingleWriteBusy = true; 401 _endFristRead = false; 402 } 403 404 /** 405 * Called by selector after data sent 406 * Note: It's only for IOCP selector: 407 */ 408 void onWriteDone(size_t nBytes) { 409 version (HUNT_IO_DEBUG) { 410 tracef("write done once: %d bytes, isWritting: %s, writeBuffer: %s, fd=%d", 411 nBytes, _isWritting, writeBuffer is null, this.handle); 412 } 413 //if (isWriteCancelling) { 414 // version (HUNT_IO_DEBUG) tracef("write cancelled."); 415 // resetWriteStatus(); 416 // return; 417 //} 418 419 420 //while(_isSingleWriteBusy) { 421 // version(HUNT_IO_DEBUG) 422 // info("waiting for last writting get finished..."); 423 //} 424 425 version (HUNT_IO_DEBUG) { 426 tracef("write done once: %d bytes, isWritting: %s, writeBuffer: %s, fd=%d", 427 nBytes, _isWritting, writeBuffer is null, this.handle); 428 } 429 430 if (writeBuffer !is null && writeBuffer.hasRemaining()) { 431 version (HUNT_IO_DEBUG) tracef("try to write the remaining in buffer."); 432 writeBufferRemaining(); 433 } else { 434 version (HUNT_IO_DEBUG) tracef("try to write next buffer."); 435 tryNextBufferWrite(); 436 } 437 } 438 439 private void notifyDataWrittenDone() { 440 if(dataWriteDoneHandler !is null && _writeQueue.isEmpty()) { 441 dataWriteDoneHandler(this); 442 } 443 } 444 445 void cancelWrite() { 446 isWriteCancelling = true; 447 } 448 449 void setFristRead(bool read) 450 { 451 _endFristRead = read; 452 } 453 454 bool getFristRead() 455 { 456 return _endFristRead; 457 } 458 459 void setBusyWrite( bool write) 460 { 461 _isSingleWriteBusy = write; 462 } 463 464 abstract bool isConnected() nothrow; 465 abstract protected void onDisconnected(); 466 467 // protected void initializeWriteQueue() { 468 // if (_writeQueue is null) { 469 // _writeQueue = new WritingBufferQueue(); 470 // } 471 // } 472 473 SimpleEventHandler disconnectionHandler; 474 475 protected WritingBufferQueue _writeQueue; 476 protected bool isWriteCancelling = false; 477 private bool _isSingleWriteBusy = false; // keep a single I/O write operation atomic 478 private bool _endFristRead = false; 479 private const(ubyte)[] _readBuffer; 480 private const(ubyte)[] sendDataBuffer; 481 private const(ubyte)[] sendDataBackupBuffer; 482 private ByteBuffer writeBuffer; 483 484 private IocpContext _iocpread; 485 //private IocpContext _iocpwrite; 486 }