⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 unasockets.pas

📁 Voice Commnucation Components for Delphi
💻 PAS
📖 第 1 页 / 共 5 页
字号:
    end;
    //
  end;
end;

// --  --
function getWSAObject(): unaWSA;
begin
  result := g_unaWSA;
end;

// --  --
function lookupHost(const host: string): int;
var
  ip: string;
begin
  result := lookupHost(host, ip);
end;

// --  --
function lookupHost(const host: string; defValue: unsigned): unsigned;
var
  ip: string;
begin
  if (0 = lookupHost(host, ip)) then
    result := str2ipH(ip)
  else
    result := defValue;
end;

// --  --
function lookupHost(const host: string; out ip: string; list: unaStringList): int;
var
  addr: unsigned;
  phost: pHostEnt;
  ok: bool;
  ar: pInt32;
begin
  ip := '';
  //
  if (length(trim(host)) >= 0) then begin
    //
    result := 0;
    //
    if (nil <> g_unaWSA) then
      ok := g_unaWSA.f_gate.enter(5000{$IFDEF DEBUG}, g_unaWSA._classID{$ENDIF})
    else
      ok := true;
    //
    if (ok) then begin
      try
	//
	addr := unsigned(inet_addr(pChar(host)));
	//
	if ((addr = unsigned(INADDR_NONE)) or (addr = unsigned(INADDR_ANY))) then begin
	  //
	  // try to resolve the name
	  phost := gethostbyname(pChar(host));
	  //
	  if (phost = nil) then
	    result := WSAGetLastError()
	  else begin
	    //
	    move(phost.h_addr^[0], addr, 4);
	    //
	    if (nil <> list) then begin
	      //
	      ar := pointer(phost.h_addr_list);
	      while (0 <> ar^) do begin
		//
		list.add(inet_ntoa(in_addr(pInt32(ar^)^)));
		//
		inc(ar);
	      end;
	    end;
	  end;
	end;
	//
	if (0 = result) then
	  // return IP address
	  ip := inet_ntoa(in_addr(addr));
	//
      finally
	//
	if (nil <> g_unaWSA) then
	  g_unaWSA.f_gate.Leave();
      end;
      //
    end;
  end
  else
    result := -1;
end;

// -- --
function getHostInfo(ip: uint): string;
var
  he: pHOSTENT;
begin
  ip := uint(htonl(int(ip)));
  he := gethostbyaddr(@ip, sizeOf(ip), AF_INET);
  //
  if (nil = he) then
    result := ipN2str(ip)
  else begin
    //
    result := he.h_name;
  end;
end;


// -- --
function listAddresses(const host: string; list: unaStringList): int; overload;
var
  ip: string;
begin
  list.clear();
  //
  result := lookupHost(host, ip, list);
end;

// -- --
function lookupPort(const port: string): int;
var
  port_info: protoent;
begin
  result := lookupPort(port, port_info);
end;

// -- --
function lookupPort(const port: string; out port_info: protoent): int;
var
  iport: int;
  pport: pProtoEnt;
begin
  if (0 < length(port)) then begin
    //
    result := 0;
    iport  := str2IntInt(port, -1);
    //
    if ((iport < 0) or (iport > $ffff)) then
      // try to resolve as name
      pport := getprotobyname(pChar(port))
    else
      // try to convert an int
      pport := getprotobynumber(iport);
    //
    if (pport = nil) then begin
      //
      result := WSAGetLastError();
      if (result = WSANO_DATA) and (iport >= 0) and (iport <= $ffff) then begin
        //
	port_info.p_name  := nil;
	port_info.p_aliases := nil;
	port_info.p_proto := smallint(iport);
	result := 0;
      end;
    end
    else
      port_info := pport^;
    //
  end
  else
    result := -1;
end;

// --  --
function ipH2str(ip: unsigned): string;
var
  inAddr: WinSock.in_addr;
begin
  inAddr.s_addr := htonl(int(ip));
  result := inet_ntoa(inAddr);
end;

// --  --
function ipN2str(ip: unsigned): string;
var
  inAddr: WinSock.in_addr;
begin
  inAddr.s_addr := int(ip);
  result := inet_ntoa(inAddr);
end;

// --  --
function str2ipH(const ip: string): unsigned;
begin
  result := unsigned(ntohl(inet_addr(pChar(ip))));
end;

// --  --
function str2ipN(const ip: string): unsigned;
begin
  result := unsigned(inet_addr(pChar(ip)));
end;


{ unaWSA }

// --  --
constructor unaWSA.create(active: bool; version: unsigned);
begin
  inherited create();
  //
  f_status := WSASYSNOTREADY;
  //
  f_gate := unaInProcessGate.create({$IFDEF DEBUG}_classID + '(f_gate)'{$ENDIF});
  //
  if (active) then
    startup(version);
end;

// --  --
destructor unaWSA.destroy();
begin
  if (isActive()) then
    shutdown();
  //
  freeAndNil(f_gate);
  //
  inherited;
end;

// --  --
function unaWSA.getStatus(): int;
begin
  result := f_status;
end;

// --  --
function unaWSA.isActive(): bool;
begin
  result := (f_status = 0);
end;

// --  --
function unaWSA.shutdown(): int;
begin
  result := WSACleanup();
end;

// --  --
function unaWSA.startup(version: unsigned): int;
begin
  f_status := WSAStartup(version, f_data);
  //
  result := f_status;
end;



{ unaSocket }

// --  --
function checkError(value: int; fatal: bool = true {$IFDEF DEBUG}; const caller: string = ''{$ENDIF}): int;
begin
  if (SOCKET_ERROR = value) then begin
    //
    result := WSAGetLastError();
    //
    if (fatal) then
      assert(assertLog('* socket error in ' + {$IFDEF DEBUG}caller{$ELSE}'()'{$ENDIF} + ': ' + int2Str(result)));
  end
  else
    result := value;
end;

// --  --
function unaSocket.accept(out socket: tSocket; timeout: unsigned): unaSocket;
var
  addr: sockaddr_in;
  len : unsigned;
begin
  result := nil;
  len := sizeof(addr);
  //
  if (check_read(timeout)) then begin
    //
    socket := winSock.accept(f_socket, @addr, @len);
    //
    if (socket <> INVALID_SOCKET) then begin
      //
      result := unaSocket.create();
      result.f_socket := socket;
      result.f_socketAddressFamily := addr.sin_family;
      result.f_socketProtocol := socketProtocol;
      result.f_socketType := socketType;
      //
      lookupHost(inet_ntoa(addr.sin_addr), result.f_host);
      lookupPort(int2str(ntohs(addr.sin_port)), result.f_port);
    end
    else
      socket := checkError(SOCKET_ERROR, true {$IFDEF DEBUG}, self._classID + '.accept()'{$ENDIF});
    //  
  end
  else
    socket := WSAETIMEDOUT;
end;

// --  --
function unaSocket.bind(addr: pSockAddrIn): int;
var
  laddr: sockaddr_in;
begin
  result := socket();
  //
  if (0 = result) then begin
    //
    if (addr <> nil) then
      laddr := addr^
    else begin
      //
      laddr.sin_family := AF_INET;
      if (0 = word(f_bindToPort.p_proto)) then
	laddr.sin_port := htons(getPortInt())
      else
	laddr.sin_port := htons(word(f_bindToPort.p_proto));
      //
      laddr.sin_addr.s_addr := inet_addr(pChar(f_bindToIp));
      if (int(INADDR_NONE) = int(laddr.sin_addr.s_addr)) then
	laddr.sin_addr.s_addr := INADDR_ANY;
      //
    end;
    //
    result := checkError(WinSock.bind(f_socket, laddr, sizeof(laddr)), true {$IFDEF DEBUG}, self._classID + '.bind()'{$ENDIF});
  end;
end;

// --  --
function unaSocket.bindSocketToPort(port: int): int;
var
  laddr: sockaddr_in;
begin
  laddr.sin_family := AF_INET;
  if (0 > port) then begin
    //
    if (0 = word(f_bindToPort.p_proto)) then
      laddr.sin_port := 0	// use first availabe port
    else
      laddr.sin_port := htons(word(f_bindToPort.p_proto));
  end
  else
    laddr.sin_port := htons(word(port));
  //
  laddr.sin_addr.s_addr := inet_addr(pChar(f_bindToIp));
  if (int(INADDR_NONE) = int(laddr.sin_addr.s_addr)) then
    laddr.sin_addr.s_addr := INADDR_ANY;
  //
  result := bind(@laddr);
end;

// --  --
function unaSocket.check_error(timeout: unsigned): bool;
var
  e: bool;
  r: int;
begin
  if (INVALID_SOCKET = f_socket) then begin
    //
    result := true
  end
  else begin
    //
    r := select(nil, nil, @e, timeout);
    //
    if (r = 1) then
      result := e
    else
      result := (r <> 0);
  end;
end;

// --  --
function unaSocket.check_read(timeout: unsigned): bool;
var
  r: bool;
begin
  if (1 = select(@r, nil, nil, timeout)) then
    result := r
  else
    result := false;
end;

// --  --
function unaSocket.check_write(timeout: unsigned): bool;
var
  w: bool;
begin
  if (1 = select(nil, @w, nil, timeout)) then
    result := w
  else
    result := false;
end;

// --  --
function unaSocket.close(graceful: bool): int;
begin
  if (not isListening() and graceful) then
    result := shutdown(SD_BOTH)
  else
    result := 0;
  //
  if (0 = result) then
    result := closeSocket();
end;

// --  --
function unaSocket.closeSocket(): int;
begin
  if (INVALID_SOCKET <> f_socket) then begin
    //
    result := checkError(WinSock.closeSocket(f_socket), true {$IFDEF DEBUG}, self._classID + '.closeSocket()'{$ENDIF});
    //
    if (0 = result) then
      f_socket := INVALID_SOCKET;
  end    
  else
    result := 0;
end;

// --  --
function unaSocket.connect(addr: pSockAddrIn): int;
var
  laddr: sockaddr_in;
begin
  if (isActive) then begin
    //
    result := 0;
  end
  else begin
    //
    result := socket();
    if (0 = result) then begin
      //
      if (nil = addr) then begin
	//
	result := getSockAddr(laddr)
      end
      else begin
	//
	f_port.p_proto := ntohs(addr.sin_port);
	f_host := inet_ntoa(addr.sin_addr);
	//
	laddr := addr^;
	result := 0;
      end;
      //
      if (0 = result) then begin
	//
	bindSocketToPort();	// bind the socket to first available (or specified with bindToPort) port before connecting
	//
	// even if explicit bind fail, connect will bind the socket to first availbale port number 
	result := checkError(WinSock.connect(f_socket, laddr, sizeof(laddr)), true {$IFDEF DEBUG}, self._classID + '.connect()'{$ENDIF});
      end;	
      //	
    end;
  end;
end;

// --  --
constructor unaSocket.create();
begin
  inherited ;
  //
  f_socket := INVALID_SOCKET;
  //
  f_bindToIP := '0.0.0.0';
end;

// --  --

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -