procedure TServerSocket.Listen;

in lib/delphi/src/Thrift.Socket.pas [1294:1494]


procedure TServerSocket.Listen;

  function CreateSocketPair(var Reader, Writer: Winapi.Winsock2.TSocket): Integer;
  label
    Error;
  type
    TSAUnion = record
    case Integer of
      0: (inaddr: TSockAddrIn);
      1: (addr: TSockAddr);
    end;
  var
    a: TSAUnion;
    listener: Winapi.Winsock2.TSocket;
    e: Integer;
    addrlen: Integer;
    flags: DWORD;
    reuse: Integer;
  begin
    addrlen := SizeOf(a.inaddr);
    flags := 0;
    reuse := 1;

    listener := Winapi.Winsock2.socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
    if listener = INVALID_SOCKET then
      Exit(SOCKET_ERROR);

    FillChar(a, SizeOf(a), 0);
    a.inaddr.sin_family := AF_INET;
    a.inaddr.sin_addr.s_addr := htonl(INADDR_LOOPBACK);
    a.inaddr.sin_port := 0;
    Reader := INVALID_SOCKET;
    Writer := INVALID_SOCKET;

    
    
    
    setsockopt(listener, SOL_SOCKET, Integer(SO_EXCLUSIVEADDRUSE), @reuse, SizeOf(reuse));
    if bind(listener, a.addr, SizeOf(a.inaddr)) = SOCKET_ERROR then
      goto Error;

    if getsockname(listener, a.addr, addrlen) = SOCKET_ERROR then
      goto Error;

    if Winapi.Winsock2.listen(listener, 1) = SOCKET_ERROR then
      goto Error;

    Reader := WSASocket(AF_INET, SOCK_STREAM, 0, nil, 0, flags);
    if Reader = INVALID_SOCKET then
      goto Error;

    if connect(Reader, a.addr, SizeOf(a.inaddr)) = SOCKET_ERROR then
      goto Error;

    Writer := Winapi.Winsock2.accept(listener, nil, nil);
    if Writer = INVALID_SOCKET then
      goto Error;

    closesocket(listener);
    Exit(0);

  Error:
    e := WSAGetLastError;
    closesocket(listener);
    closesocket(Reader);
    closesocket(Writer);
    WSASetLastError(e);
    Result := SOCKET_ERROR;
  end;

var
  TempIntReader,
  TempIntWriter: Winapi.Winsock2.TSocket;
  One: Cardinal;
  ErrnoCopy: Integer;
  Ling: TLinger;
  Retries: Integer;
  AddrInfo: IGetAddrInfoWrapper;
  SA: TSockAddrStorage;
  Len: Integer;
begin
  
  if CreateSocketPair(TempIntReader, TempIntWriter) = SOCKET_ERROR then begin
    LogDelegate(Format('TServerSocket.Listen() CreateSocketPair() Interrupt %s', [SysErrorMessage(WSAGetLastError)]));
    FInterruptSockReader := INVALID_SOCKET;
    FInterruptSockWriter := INVALID_SOCKET;
  end
  else begin
    FInterruptSockReader := TempIntReader;
    FInterruptSockWriter := TempIntWriter;
  end;

  
  if CreateSocketPair(TempIntReader, TempIntWriter) = SOCKET_ERROR then begin
    LogDelegate(Format('TServerSocket.Listen() CreateSocketPair() ChildInterrupt %s', [SysErrorMessage(WSAGetLastError)]));
    FChildInterruptSockReader := TSmartPointer<Winapi.Winsock2.TSocket>.Create(INVALID_SOCKET, nil);
    FChildInterruptSockWriter := INVALID_SOCKET;
  end
  else begin
    FChildInterruptSockReader := TSmartPointer<Winapi.Winsock2.TSocket>.Create(TempIntReader, DestroyerOfFineSockets);
    FChildInterruptSockWriter := TempIntWriter;
  end;

  if (Port < 0) or (Port > $FFFF) then
    raise TTransportExceptionBadArgs.Create('Specified port is invalid');

  AddrInfo := CreateSocket(FAddress, Port);

  
  One := 1;
  setsockopt(Socket, SOL_SOCKET, Integer(SO_EXCLUSIVEADDRUSE), @one, SizeOf(One));
  
  
  

  
  if FTcpSendBuffer > 0 then begin
    if setsockopt(Socket, SOL_SOCKET, SO_SNDBUF, @FTcpSendBuffer, SizeOf(FTcpSendBuffer)) = SOCKET_ERROR then begin
      ErrnoCopy := WSAGetLastError;
      LogDelegate(Format('TServerSocket.Listen() setsockopt() SO_SNDBUF %s', [SysErrorMessage(ErrnoCopy)]));
      raise TTransportExceptionNotOpen.Create(Format('Could not set SO_SNDBUF: %s', [SysErrorMessage(ErrnoCopy)]));
    end;
  end;

  if FTcpRecvBuffer > 0 then begin
    if setsockopt(Socket, SOL_SOCKET, SO_RCVBUF, @FTcpRecvBuffer, SizeOf(FTcpRecvBuffer)) = SOCKET_ERROR then begin
      ErrnoCopy := WSAGetLastError;
      LogDelegate(Format('TServerSocket.Listen() setsockopt() SO_RCVBUF %s', [SysErrorMessage(ErrnoCopy)]));
      raise TTransportExceptionNotOpen.Create(Format('Could not set SO_RCVBUF: %s', [SysErrorMessage(ErrnoCopy)]));
    end;
  end;

  
  Ling.l_onoff := 0;
  Ling.l_linger := 0;
  if setsockopt(Socket, SOL_SOCKET, SO_LINGER, @Ling, SizeOf(Ling)) = SOCKET_ERROR then begin
    ErrnoCopy := WSAGetLastError;
    LogDelegate(Format('TServerSocket.Listen() setsockopt() SO_LINGER %s', [SysErrorMessage(ErrnoCopy)]));
    raise TTransportExceptionNotOpen.Create(Format('Could not set SO_LINGER: %s', [SysErrorMessage(ErrnoCopy)]));
  end;

  
  if setsockopt(Socket, IPPROTO_TCP, TCP_NODELAY, @One, SizeOf(One)) = SOCKET_ERROR then begin
    ErrnoCopy := WSAGetLastError;
    LogDelegate(Format('TServerSocket.Listen() setsockopt() TCP_NODELAY %s', [SysErrorMessage(ErrnoCopy)]));
    raise TTransportExceptionNotOpen.Create(Format('Could not set TCP_NODELAY: %s', [SysErrorMessage(ErrnoCopy)]));
  end;

  
  if ioctlsocket(Socket, Integer(FIONBIO), One) = SOCKET_ERROR then begin
    ErrnoCopy := WSAGetLastError;
    LogDelegate(Format('TServerSocket.Listen() ioctlsocket() FIONBIO %s', [SysErrorMessage(ErrnoCopy)]));
    raise TTransportExceptionNotOpen.Create(Format('ioctlsocket() FIONBIO: %s', [SysErrorMessage(ErrnoCopy)]));
  end;

  
  
  
  Retries := 0;
  while True do begin
    if bind(Socket, AddrInfo.Res^.ai_addr^, AddrInfo.Res^.ai_addrlen) = 0 then
      Break;
    Inc(Retries);
    if Retries > FRetryLimit then
      Break;
    Sleep(FRetryDelay * 1000);
  end;

  
  if (Port = 0) and (Retries < FRetryLimit) then begin
    Len := SizeOf(SA);
    FillChar(SA, Len, 0);
    if getsockname(Socket, PSockAddr(@SA)^, Len) = SOCKET_ERROR then
      LogDelegate(Format('TServerSocket.Listen() getsockname() %s', [SysErrorMessage(WSAGetLastError)]))
    else begin
      if SA.ss_family = AF_INET6 then
        Port := ntohs(PSockAddrIn6(@SA)^.sin6_port)
      else
        Port := ntohs(PSockAddrIn(@SA)^.sin_port);
    end;
  end;

  
  if (Retries > FRetryLimit) then begin
    LogDelegate(Format('TServerSocket.Listen() BIND %d', [Port]));
    Close;
    raise TTransportExceptionNotOpen.Create(Format('Could not bind: %s', [SysErrorMessage(WSAGetLastError)]));
  end;

  if Assigned(FListenCallback) then
    FListenCallback(Socket);

  
  if Winapi.Winsock2.listen(Socket, FAcceptBacklog) = SOCKET_ERROR then begin
    ErrnoCopy := WSAGetLastError;
    LogDelegate(Format('TServerSocket.Listen() listen() %s', [SysErrorMessage(ErrnoCopy)]));
    raise TTransportExceptionNotOpen.Create(Format('Could not listen: %s', [SysErrorMessage(ErrnoCopy)]));
  end;

  
end;