public unsafe PosixResult TryReceive(ArraySegment <byte> buffer) { ValidateSegment(buffer); fixed(byte *buf = buffer.Array) { IOVector ioVector = new IOVector() { Base = buf + buffer.Offset, Count = (void *)buffer.Count }; return(SocketInterop.Receive(this, &ioVector, 1)); } }
private static unsafe Exception Receive(int fd, int availableBytes, ref WritableBuffer wb) { int ioVectorLength = availableBytes <= wb.Buffer.Length ? 1 : Math.Min(1 + (availableBytes - wb.Buffer.Length + MaxPooledBlockLength - 1) / MaxPooledBlockLength, MaxIOVectorReceiveLength); var ioVectors = stackalloc IOVector[ioVectorLength]; var allocated = 0; var advanced = 0; int ioVectorsUsed = 0; for (; ioVectorsUsed < ioVectorLength; ioVectorsUsed++) { wb.Ensure(1); var memory = wb.Buffer; var length = memory.Length; void *pointer; wb.Buffer.TryGetPointer(out pointer); ioVectors[ioVectorsUsed].Base = pointer; ioVectors[ioVectorsUsed].Count = (void *)length; allocated += length; if (allocated >= availableBytes) { // Every Memory (except the last one) must be filled completely. ioVectorsUsed++; break; } wb.Advance(length); advanced += length; } var expectedMin = Math.Min(availableBytes, allocated); // Ideally we get availableBytes in a single receive // but we are happy if we get at least a part of it // and we are willing to take {MaxEAgainCount} EAGAINs. // Less data could be returned due to these reasons: // * TCP URG // * packet was not placed in receive queue (race with FIONREAD) // * ? const int MaxEAgainCount = 10; var eAgainCount = 0; var received = 0; do { var result = SocketInterop.Receive(fd, ioVectors, ioVectorsUsed); if (result.IsSuccess) { received += result.Value; if (received >= expectedMin) { // We made it! wb.Advance(received - advanced); return(null); } eAgainCount = 0; // Update ioVectors to match bytes read var skip = result.Value; for (int i = 0; (i < ioVectorsUsed) && (skip > 0); i++) { var length = (int)ioVectors[i].Count; var skipped = Math.Min(skip, length); ioVectors[i].Count = (void *)(length - skipped); ioVectors[i].Base = (byte *)ioVectors[i].Base + skipped; skip -= skipped; } } else if (result == PosixResult.EAGAIN || result == PosixResult.EWOULDBLOCK) { eAgainCount++; if (eAgainCount == MaxEAgainCount) { return(new NotSupportedException("Too many EAGAIN, unable to receive available bytes.")); } } else if (result == PosixResult.ECONNRESET) { return(new ConnectionResetException(result.ErrorDescription(), result.AsException())); } else { return(result.AsException()); } } while (true); }
public unsafe PosixResult TryReceive(IOVector *ioVectors, int ioVectorLen) { return(SocketInterop.Receive(this, ioVectors, ioVectorLen)); }