ethsock.cxx
上传用户:hzhsqp
上传日期:2007-01-06
资源大小:1600k
文件大小:44k
源码类别:

IP电话/视频会议

开发平台:

Visual C++

  1. /*
  2.  * ethsock.cxx
  3.  *
  4.  * Direct Ethernet socket implementation.
  5.  *
  6.  * Portable Windows Library
  7.  *
  8.  * Copyright (c) 1993-1998 Equivalence Pty. Ltd.
  9.  *
  10.  * The contents of this file are subject to the Mozilla Public License
  11.  * Version 1.0 (the "License"); you may not use this file except in
  12.  * compliance with the License. You may obtain a copy of the License at
  13.  * http://www.mozilla.org/MPL/
  14.  *
  15.  * Software distributed under the License is distributed on an "AS IS"
  16.  * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
  17.  * the License for the specific language governing rights and limitations
  18.  * under the License.
  19.  *
  20.  * The Original Code is Portable Windows Library.
  21.  *
  22.  * The Initial Developer of the Original Code is Equivalence Pty. Ltd.
  23.  *
  24.  * Portions are Copyright (C) 1993 Free Software Foundation, Inc.
  25.  * All Rights Reserved.
  26.  *
  27.  * Contributor(s): ______________________________________.
  28.  *
  29.  * $Log: ethsock.cxx,v $
  30.  * Revision 1.21  2000/03/06 03:59:22  robertj
  31.  * Fixed warning about handle types, thanks Steve Bennett
  32.  *
  33.  * Revision 1.20  1999/10/29 03:34:19  robertj
  34.  * Fixed possible crash accessing IP addresses from SNMP tables.
  35.  *
  36.  * Revision 1.19  1999/10/14 01:34:55  robertj
  37.  * Fixed backward compatibility problem with old SNMP header file.
  38.  *
  39.  * Revision 1.18  1999/09/10 04:35:42  robertj
  40.  * Added Windows version of PIPSocket::GetInterfaceTable() function.
  41.  *
  42.  * Revision 1.17  1999/04/18 12:58:39  robertj
  43.  * MSVC 5 backward compatibility
  44.  *
  45.  * Revision 1.16  1999/02/16 08:08:06  robertj
  46.  * MSVC 6.0 compatibility changes.
  47.  *
  48.  * Revision 1.15  1998/11/30 04:48:38  robertj
  49.  * New directory structure
  50.  *
  51.  * Revision 1.14  1998/11/22 11:30:10  robertj
  52.  * Check route table function to get a list
  53.  *
  54.  * Revision 1.13  1998/11/20 03:17:43  robertj
  55.  * Split rad and write buffers to separate pools.
  56.  *
  57.  * Revision 1.12  1998/11/19 05:18:48  robertj
  58.  * Added route table manipulation functions to PIPSocket class.
  59.  *
  60.  * Revision 1.11  1998/11/14 06:31:41  robertj
  61.  * Changed semantics of os_sendto to return TRUE if ANY bytes are sent.
  62.  * Added support for MSDUN1.3 DHCP registry entries.
  63.  *
  64.  * Revision 1.10  1998/10/23 04:09:08  robertj
  65.  * Fixes for NT support.
  66.  * Allowed both old and new driver by compilation option.
  67.  *
  68.  * Revision 1.9  1998/10/15 05:41:48  robertj
  69.  * New memory leak check code.
  70.  *
  71.  * Revision 1.8  1998/10/12 09:34:42  robertj
  72.  * New method for getting IP addresses of interfaces.
  73.  *
  74.  * Revision 1.7  1998/10/06 10:24:41  robertj
  75.  * Fixed hang when using reset command, removed the command!
  76.  *
  77.  * Revision 1.6  1998/09/24 03:30:45  robertj
  78.  * Added open software license.
  79.  *
  80.  * Revision 1.5  1998/09/15 08:25:36  robertj
  81.  * Fixed a number of warnings at maximum optimisation.
  82.  *
  83.  * Revision 1.4  1998/09/08 15:14:36  robertj
  84.  * Fixed packet type based filtering in Read() function.
  85.  *
  86.  * Revision 1.3  1998/08/25 11:03:15  robertj
  87.  * Fixed proble with NT get of OID.
  88.  * Fixed bug with not setting channel name when interface opened.
  89.  *
  90.  * Revision 1.2  1998/08/21 05:27:13  robertj
  91.  * Fine tuning of interface.
  92.  *
  93.  * Revision 1.1  1998/08/20 06:04:52  robertj
  94.  * Initial revision
  95.  *
  96.  */
  97. #include <ptlib.h>
  98. #include <ptlib/sockets.h>
  99. #include <snmp.h>
  100. ///////////////////////////////////////////////////////////////////////////////
  101. // Stuff from snmp.h
  102. #ifndef RFC1157VarBindList
  103. typedef RFC1157VarBind SnmpVarBind;
  104. typedef RFC1157VarBindList SnmpVarBindList;
  105. typedef LONG AsnInteger32;
  106. #define SNMP_PDU_GET ASN_RFC1157_GETREQUEST
  107. #define SNMP_PDU_GETNEXT ASN_RFC1157_GETNEXTREQUEST
  108. #define ASN_IPADDRESS    ASN_RFC1155_IPADDRESS // Prevents GetInterfaceTable failure
  109. #pragma message("Later version of snmp.h required!")
  110. #endif
  111. ///////////////////////////////////////////////////////////////////////////////
  112. // Stuff from ndis.h
  113. #define OID_802_3_PERMANENT_ADDRESS         0x01010101
  114. #define OID_802_3_CURRENT_ADDRESS           0x01010102
  115. #define OID_GEN_DRIVER_VERSION              0x00010110
  116. #define OID_GEN_CURRENT_PACKET_FILTER       0x0001010E
  117. #define OID_GEN_MEDIA_SUPPORTED             0x00010103
  118. #define NDIS_PACKET_TYPE_DIRECTED           0x0001
  119. #define NDIS_PACKET_TYPE_MULTICAST          0x0002
  120. #define NDIS_PACKET_TYPE_ALL_MULTICAST      0x0004
  121. #define NDIS_PACKET_TYPE_BROADCAST          0x0008
  122. #define NDIS_PACKET_TYPE_PROMISCUOUS        0x0020
  123. typedef enum _NDIS_MEDIUM {
  124.     NdisMedium802_3,
  125.     NdisMedium802_5,
  126.     NdisMediumFddi,
  127.     NdisMediumWan,
  128.     NdisMediumLocalTalk,
  129.     NdisMediumDix,              // defined for convenience, not a real medium
  130.     NdisMediumArcnetRaw,
  131.     NdisMediumArcnet878_2
  132. } NDIS_MEDIUM, *PNDIS_MEDIUM;                    
  133. ///////////////////////////////////////////////////////////////////////////////
  134. #define USE_VPACKET
  135. #include <ptlib/epacket.h>
  136. #ifdef USE_VPACKET
  137. #define PACKET_SERVICE_NAME "Packet"
  138. #define PACKET_VXD_NAME     "VPacket"
  139. #else
  140. #define PACKET_SERVICE_NAME "EPacket"
  141. #define PACKET_VXD_NAME     "EPacket"
  142. #define GetQueryOidCommand(oid) IOCTL_EPACKET_QUERY_OID
  143. #endif
  144. #define SERVICES_REGISTRY_KEY "HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\"
  145. ///////////////////////////////////////////////////////////////////////////////
  146. class PWin32AsnAny : public AsnAny
  147. {
  148.   public:
  149.     PWin32AsnAny();
  150.     PWin32AsnAny(const AsnAny & any)  { memcpy(this, &any, sizeof(*this)); }
  151.     ~PWin32AsnAny();
  152.     BOOL GetInteger(AsnInteger & i);
  153.     BOOL GetIpAddress(PIPSocket::Address & addr);
  154. };
  155. ///////////////////////////////////////////////////////////////////////////////
  156. class PWin32AsnOid : public AsnObjectIdentifier
  157. {
  158.   public:
  159.     PWin32AsnOid();
  160.     PWin32AsnOid(const char * str);
  161.     PWin32AsnOid(const AsnObjectIdentifier & oid);
  162.     PWin32AsnOid(const PWin32AsnOid & oid)              { SnmpUtilOidCpy(this, (AsnObjectIdentifier *)&oid); }
  163.     void Free()                                         { SnmpUtilOidFree(this); }
  164.     PWin32AsnOid & operator=(const AsnObjectIdentifier&);
  165.     PWin32AsnOid & operator=(const PWin32AsnOid & oid)  { SnmpUtilOidCpy(this, (AsnObjectIdentifier *)&oid); return *this; }
  166.     PWin32AsnOid & operator+=(const PWin32AsnOid & oid) { SnmpUtilOidAppend(this, (AsnObjectIdentifier *)&oid); return *this; }
  167.     UINT & operator[](int idx)                          { return ids[idx]; }
  168.     UINT   operator[](int idx) const                    { return ids[idx]; }
  169.     bool operator==(const PWin32AsnOid & oid)           { return SnmpUtilOidCmp(this, (AsnObjectIdentifier *)&oid) == 0; }
  170.     bool operator!=(const PWin32AsnOid & oid)           { return SnmpUtilOidCmp(this, (AsnObjectIdentifier *)&oid) != 0; }
  171.     bool operator< (const PWin32AsnOid & oid)           { return SnmpUtilOidCmp(this, (AsnObjectIdentifier *)&oid) <  0; }
  172.     bool operator<=(const PWin32AsnOid & oid)           { return SnmpUtilOidCmp(this, (AsnObjectIdentifier *)&oid) <= 0; }
  173.     bool operator> (const PWin32AsnOid & oid)           { return SnmpUtilOidCmp(this, (AsnObjectIdentifier *)&oid) >  0; }
  174.     bool operator>=(const PWin32AsnOid & oid)           { return SnmpUtilOidCmp(this, (AsnObjectIdentifier *)&oid) >= 0; }
  175.     bool operator*=(const PWin32AsnOid & oid)           { return SnmpUtilOidNCmp(this, (AsnObjectIdentifier *)&oid, idLength) == 0; }
  176. };
  177. /////////////////////////////////////////////////////////////////////////////
  178. class PWin32SnmpLibrary : public PDynaLink
  179. {
  180.   PCLASSINFO(PWin32SnmpLibrary, PDynaLink)
  181.   public:
  182.     PWin32SnmpLibrary();
  183.     BOOL GetOid(AsnObjectIdentifier & oid, AsnInteger & value);
  184.     BOOL GetOid(AsnObjectIdentifier & oid, PIPSocket::Address & ip_address);
  185.     BOOL GetOid(AsnObjectIdentifier & oid, void * value, UINT valSize, UINT * len = NULL);
  186.     BOOL GetOid(AsnObjectIdentifier & oid, AsnAny & value);
  187.     BOOL GetNextOid(AsnObjectIdentifier & oid, AsnAny & value);
  188.     PString GetInterfaceName(int ifNum);
  189.     PString GetInterfaceName(PIPSocket::Address ipAddr);
  190.   private:
  191.     BOOL (WINAPI *Init)(DWORD,HANDLE*,AsnObjectIdentifier*);
  192.     BOOL (WINAPI *Query)(BYTE,SnmpVarBindList*,AsnInteger32*,AsnInteger32*);
  193.     HANDLE hEvent;
  194.     AsnObjectIdentifier baseOid;
  195. };
  196. ///////////////////////////////////////////////////////////////////////////////
  197. class PWin32OidBuffer
  198. {
  199.   public:
  200.     PWin32OidBuffer(UINT oid, UINT len, const BYTE * data = NULL);
  201.     ~PWin32OidBuffer() { delete buffer; }
  202.     operator void *()         { return buffer; }
  203.     operator DWORD ()         { return size; }
  204.     DWORD operator [](int i)  { return buffer[i]; }
  205.     void Move(BYTE * data, DWORD received);
  206.   private:
  207.     DWORD * buffer;
  208.     UINT size;
  209. };
  210. ///////////////////////////////////////////////////////////////////////////////
  211. class PWin32PacketDriver
  212. {
  213.   public:
  214.     static PWin32PacketDriver * Create();
  215.     virtual ~PWin32PacketDriver();
  216.     BOOL IsOpen() const;
  217.     void Close();
  218.     DWORD GetLastError() const;
  219.     virtual BOOL EnumInterfaces(PINDEX idx, PString & name) = 0;
  220.     virtual BOOL BindInterface(const PString & interfaceName) = 0;
  221.     virtual BOOL EnumIpAddress(PINDEX idx, PIPSocket::Address & addr, PIPSocket::Address & net_mask) = 0;
  222.     virtual BOOL BeginRead(void * buf, DWORD size, DWORD & received, PWin32Overlapped & overlap) = 0;
  223.     virtual BOOL BeginWrite(const void * buf, DWORD len, PWin32Overlapped & overlap) = 0;
  224.     BOOL CompleteIO(DWORD & received, PWin32Overlapped & overlap);
  225.     BOOL IoControl(UINT func,
  226.                    const void * input, DWORD inSize,
  227.                    void * output, DWORD outSize,
  228.                    DWORD & received);
  229.     BOOL QueryOid(UINT oid, DWORD & data);
  230.     BOOL QueryOid(UINT oid, UINT len, BYTE * data);
  231.     BOOL SetOid(UINT oid, DWORD data);
  232.     BOOL SetOid(UINT oid, UINT len, const BYTE * data);
  233. #ifdef USE_VPACKET
  234.     virtual UINT GetQueryOidCommand(DWORD oid) const = 0;
  235. #endif
  236.   protected:
  237.     PWin32PacketDriver();
  238.     DWORD dwError;
  239.     HANDLE hDriver;
  240. };
  241. ///////////////////////////////////////////////////////////////////////////////
  242. class PWin32PacketVxD : public PWin32PacketDriver
  243. {
  244.   public:
  245.     virtual BOOL EnumInterfaces(PINDEX idx, PString & name);
  246.     virtual BOOL BindInterface(const PString & interfaceName);
  247.     virtual BOOL EnumIpAddress(PINDEX idx, PIPSocket::Address & addr, PIPSocket::Address & net_mask);
  248.     virtual BOOL BeginRead(void * buf, DWORD size, DWORD & received, PWin32Overlapped & overlap);
  249.     virtual BOOL BeginWrite(const void * buf, DWORD len, PWin32Overlapped & overlap);
  250. #ifdef USE_VPACKET
  251.     virtual UINT GetQueryOidCommand(DWORD oid) const
  252.       { return oid >= OID_802_3_PERMANENT_ADDRESS ? IOCTL_EPACKET_QUERY_OID : IOCTL_EPACKET_STATISTICS; }
  253. #endif
  254.   protected:
  255.     PStringList transportBinding;
  256. };
  257. ///////////////////////////////////////////////////////////////////////////////
  258. class PWin32PacketSYS : public PWin32PacketDriver
  259. {
  260.   public:
  261.     PWin32PacketSYS();
  262.     virtual BOOL EnumInterfaces(PINDEX idx, PString & name);
  263.     virtual BOOL BindInterface(const PString & interfaceName);
  264.     virtual BOOL EnumIpAddress(PINDEX idx, PIPSocket::Address & addr, PIPSocket::Address & net_mask);
  265.     virtual BOOL BeginRead(void * buf, DWORD size, DWORD & received, PWin32Overlapped & overlap);
  266.     virtual BOOL BeginWrite(const void * buf, DWORD len, PWin32Overlapped & overlap);
  267. #ifdef USE_VPACKET
  268.     virtual UINT GetQueryOidCommand(DWORD) const
  269.       { return IOCTL_EPACKET_QUERY_OID; }
  270. #endif
  271.   protected:
  272.     PString registryKey;
  273. };
  274. /////////////////////////////////////////////////////////////////////////////
  275. class PWin32PacketBuffer : public PBYTEArray
  276. {
  277.   PCLASSINFO(PWin32PacketBuffer, PBYTEArray)
  278.   public:
  279.     enum Statuses {
  280.       Uninitialised,
  281.       Progressing,
  282.       Completed
  283.     };
  284.     PWin32PacketBuffer(PINDEX sz);
  285.     PINDEX GetData(void * buf, PINDEX size);
  286.     PINDEX PutData(const void * buf, PINDEX length);
  287.     HANDLE GetEvent() const { return overlap.hEvent; }
  288.     BOOL ReadAsync(PWin32PacketDriver & pkt);
  289.     BOOL ReadComplete(PWin32PacketDriver & pkt);
  290.     BOOL WriteAsync(PWin32PacketDriver & pkt);
  291.     BOOL WriteComplete(PWin32PacketDriver & pkt);
  292.     BOOL InProgress() const { return status == Progressing; }
  293.     BOOL IsCompleted() const { return status == Completed; }
  294.     BOOL IsType(WORD type) const;
  295.   protected:
  296.     Statuses         status;
  297.     PWin32Overlapped overlap;
  298.     DWORD            count;
  299. };
  300. #define new PNEW
  301. /////////////////////////////////////////////////////////////////////////////
  302. PWin32AsnAny::PWin32AsnAny()
  303. {
  304.   asnType = ASN_INTEGER;
  305.   asnValue.number = 0;
  306. }
  307. PWin32AsnAny::~PWin32AsnAny()
  308. {
  309.   switch (asnType) {
  310.     case ASN_OCTETSTRING :
  311.       SnmpUtilMemFree(asnValue.string.stream);
  312.       break;
  313. #ifdef ASN_BITS
  314.     case ASN_BITS :
  315.       SnmpUtilMemFree(asnValue.bits.stream);
  316.       break;
  317. #endif
  318.     case ASN_OBJECTIDENTIFIER :
  319.       SnmpUtilMemFree(asnValue.object.ids);
  320.       break;
  321.     case ASN_SEQUENCE :
  322.       SnmpUtilMemFree(asnValue.sequence.stream);
  323.       break;
  324.     case ASN_IPADDRESS :
  325.       SnmpUtilMemFree(asnValue.address.stream);
  326.       break;
  327. #ifdef ASN_OPAQUE
  328.     case ASN_OPAQUE :
  329.       SnmpUtilMemFree(asnValue.arbitrary.stream);
  330.       break;
  331. #endif
  332.   }
  333. }
  334. BOOL PWin32AsnAny::GetInteger(AsnInteger & i)
  335. {
  336.   if (asnType != ASN_INTEGER)
  337.     return FALSE;
  338.   i = asnValue.number;
  339.   return TRUE;
  340. }
  341. BOOL PWin32AsnAny::GetIpAddress(PIPSocket::Address & addr)
  342. {
  343.   if (asnType != ASN_IPADDRESS ||
  344.       asnValue.address.stream == NULL ||
  345.       asnValue.address.length < sizeof(addr))
  346.     return FALSE;
  347.   memcpy(&addr, asnValue.address.stream, sizeof(addr));
  348.   return TRUE;
  349. }
  350. ///////////////////////////////////////////////////////////////////////////////
  351. PWin32AsnOid::PWin32AsnOid()
  352. {
  353.   ids = NULL;
  354.   idLength = 0;
  355. }
  356. PWin32AsnOid::PWin32AsnOid(const AsnObjectIdentifier & oid)
  357. {
  358.   ids = oid.ids;
  359.   idLength = oid.idLength;
  360. }
  361. PWin32AsnOid::PWin32AsnOid(const char * str)
  362. {
  363.   idLength = 0;
  364.   ids = NULL;
  365.   AsnObjectIdentifier oid;
  366.   oid.idLength = 0;
  367.   const char * dot = strchr(str, '.');
  368.   while (dot != NULL) {
  369.     oid.idLength++;
  370.     dot = strchr(dot+1, '.');
  371.   }
  372.   if (oid.idLength > 0) {
  373.     oid.ids = new UINT[++oid.idLength];
  374.     char * next = (char *)str;
  375.     for (UINT i = 0; i < oid.idLength; i++) {
  376.       oid.ids[i] = strtoul(next, &next, 10);
  377.       if (*next != '.')
  378.         break;
  379.       next++;
  380.     }
  381.     if (*next == '')
  382.       SnmpUtilOidCpy(this, &oid);
  383.     delete [] oid.ids;
  384.   }
  385. }
  386. PWin32AsnOid & PWin32AsnOid::operator=(const AsnObjectIdentifier & oid)
  387. {
  388.   ids = oid.ids;
  389.   idLength = oid.idLength;
  390.   return *this;
  391. }
  392. ///////////////////////////////////////////////////////////////////////////////
  393. PWin32SnmpLibrary::PWin32SnmpLibrary()
  394.   : PDynaLink("inetmib1.dll")
  395. {
  396.   if (!GetFunction("SnmpExtensionInit", (Function &)Init) ||
  397.       !GetFunction("SnmpExtensionQuery", (Function &)Query) ||
  398.       !Init(0, &hEvent, &baseOid))
  399.     Close();
  400. }
  401. BOOL PWin32SnmpLibrary::GetOid(AsnObjectIdentifier & oid, AsnInteger & value)
  402. {
  403.   if (!IsLoaded())
  404.     return FALSE;
  405.   PWin32AsnAny any;
  406.   if (!GetOid(oid, any))
  407.     return FALSE;
  408.   return any.GetInteger(value);
  409. }
  410. BOOL PWin32SnmpLibrary::GetOid(AsnObjectIdentifier & oid, PIPSocket::Address & value)
  411. {
  412.   if (!IsLoaded())
  413.     return FALSE;
  414.   PWin32AsnAny any;
  415.   if (!GetOid(oid, any))
  416.     return FALSE;
  417.   return any.GetIpAddress(value);
  418. }
  419. BOOL PWin32SnmpLibrary::GetOid(AsnObjectIdentifier & oid, void * value, UINT valSize, UINT * len)
  420. {
  421.   if (!IsLoaded())
  422.     return FALSE;
  423.   PWin32AsnAny any;
  424.   if (!GetOid(oid, any))
  425.     return FALSE;
  426.   if (any.asnType != ASN_OCTETSTRING)
  427.     return FALSE;
  428.   if (len != NULL)
  429.     *len = any.asnValue.string.length;
  430.   if (any.asnValue.string.length > valSize)
  431.     return FALSE;
  432.   memcpy(value, any.asnValue.string.stream, any.asnValue.string.length);
  433.   if (valSize > any.asnValue.string.length)
  434.     ((char *)value)[any.asnValue.string.length] = '';
  435.   return TRUE;
  436. }
  437. BOOL PWin32SnmpLibrary::GetOid(AsnObjectIdentifier & oid, AsnAny & value)
  438. {
  439.   if (!IsLoaded())
  440.     return FALSE;
  441.   RFC1157VarBind var;
  442.   var.name = oid;
  443.   var.value = value;
  444.   RFC1157VarBindList vars;
  445.   vars.len = 1;
  446.   vars.list = &var;
  447.   AsnInteger status, error;
  448.   if (!Query(SNMP_PDU_GET, &vars, &status, &error))
  449.     return FALSE;
  450.   if (status != SNMP_ERRORSTATUS_NOERROR)
  451.     return FALSE;
  452.   value = var.value;
  453.   oid = var.name;
  454.   return TRUE;
  455. }
  456. BOOL PWin32SnmpLibrary::GetNextOid(AsnObjectIdentifier & oid, AsnAny & value)
  457. {
  458.   if (!IsLoaded())
  459.     return FALSE;
  460.   SnmpVarBind var;
  461.   var.name = oid;
  462.   var.value = value;
  463.   SnmpVarBindList vars;
  464.   vars.len = 1;
  465.   vars.list = &var;
  466.   AsnInteger status, error;
  467.   if (!Query(SNMP_PDU_GETNEXT, &vars, &status, &error))
  468.     return FALSE;
  469.   if (status != SNMP_ERRORSTATUS_NOERROR)
  470.     return FALSE;
  471.   value = var.value;
  472.   oid = var.name;
  473.   return TRUE;
  474. }
  475. PString PWin32SnmpLibrary::GetInterfaceName(int ifNum)
  476. {
  477.   PIPSocket::Address gwAddr = 0;
  478.   PWin32AsnOid baseOid = "1.3.6.1.2.1.4.20.1";
  479.   PWin32AsnOid oid = baseOid;
  480.   PWin32AsnAny value;
  481.   while (GetNextOid(oid, value)) {
  482.     if (!(baseOid *= oid))
  483.       break;
  484.     if (value.asnType != ASN_IPADDRESS)
  485.       break;
  486.     oid[9] = 2;
  487.     AsnInteger ifIndex = -1;
  488.     if (!GetOid(oid, ifIndex) || ifIndex < 0)
  489.       break;
  490.     if (ifIndex == ifNum) {
  491.       value.GetIpAddress(gwAddr);
  492.       break;
  493.     }
  494.     oid[9] = 1;
  495.   }
  496.   if (gwAddr == 0)
  497.     return PString();
  498.   return GetInterfaceName(gwAddr);
  499. }
  500. PString PWin32SnmpLibrary::GetInterfaceName(PIPSocket::Address ipAddr)
  501. {
  502.   PString gatewayInterface, anInterface;
  503.   PWin32PacketDriver * tempDriver = PWin32PacketDriver::Create();
  504.   PINDEX ifIdx = 0;
  505.   while (gatewayInterface.IsEmpty() && tempDriver->EnumInterfaces(ifIdx++, anInterface)) {
  506.     if (tempDriver->BindInterface(anInterface)) {
  507.       PIPSocket::Address ifAddr, ifMask;
  508.       PINDEX ipIdx = 0;
  509.       if (tempDriver->EnumIpAddress(ipIdx++, ifAddr, ifMask) && ifAddr == ipAddr) {
  510.         gatewayInterface = anInterface;
  511.         break;
  512.       }
  513.     }
  514.   }
  515.   delete tempDriver;
  516.   return gatewayInterface;
  517. }
  518. ///////////////////////////////////////////////////////////////////////////////
  519. PWin32OidBuffer::PWin32OidBuffer(UINT oid, UINT len, const BYTE * data)
  520. {
  521.   size = sizeof(DWORD)*2 + len;
  522.   buffer = new DWORD[(size+sizeof(DWORD)-1)/sizeof(DWORD)];
  523.   buffer[0] = oid;
  524.   buffer[1] = len;
  525.   if (data != NULL)
  526.     memcpy(&buffer[2], data, len);
  527. }
  528. void PWin32OidBuffer::Move(BYTE * data, DWORD received)
  529. {
  530.   memcpy(data, &buffer[2], received-sizeof(DWORD)*2);
  531. }
  532. ///////////////////////////////////////////////////////////////////////////////
  533. PWin32PacketDriver * PWin32PacketDriver::Create()
  534. {
  535.   OSVERSIONINFO info;
  536.   info.dwOSVersionInfoSize = sizeof(info);
  537.   GetVersionEx(&info);
  538.   if (info.dwPlatformId == VER_PLATFORM_WIN32_NT)
  539.     return new PWin32PacketSYS;
  540.   else
  541.     return new PWin32PacketVxD;
  542. }
  543. PWin32PacketDriver::PWin32PacketDriver()
  544. {
  545.   hDriver = INVALID_HANDLE_VALUE;
  546.   dwError = ERROR_OPEN_FAILED;
  547. }
  548. PWin32PacketDriver::~PWin32PacketDriver()
  549. {
  550.   Close();
  551. }
  552. void PWin32PacketDriver::Close()
  553. {
  554.   if (hDriver != INVALID_HANDLE_VALUE) {
  555.     CloseHandle(hDriver);
  556.     hDriver = INVALID_HANDLE_VALUE;
  557.   }
  558. }
  559. BOOL PWin32PacketDriver::IsOpen() const
  560. {
  561.   return hDriver != INVALID_HANDLE_VALUE;
  562. }
  563. DWORD PWin32PacketDriver::GetLastError() const
  564. {
  565.   return dwError;
  566. }
  567. BOOL PWin32PacketDriver::IoControl(UINT func,
  568.                               const void * input, DWORD inSize,
  569.                               void * output, DWORD outSize, DWORD & received)
  570. {
  571.   PWin32Overlapped overlap;
  572.   if (DeviceIoControl(hDriver, func,
  573.                       (LPVOID)input, inSize, output, outSize,
  574.                       &received, &overlap)) {
  575.     dwError = ERROR_SUCCESS;
  576.     return TRUE;
  577.   }
  578.   dwError = ::GetLastError();
  579.   if (dwError != ERROR_IO_PENDING)
  580.     return FALSE;
  581.   return CompleteIO(received, overlap);
  582. }
  583. BOOL PWin32PacketDriver::CompleteIO(DWORD & received, PWin32Overlapped & overlap)
  584. {
  585.   received = 0;
  586.   if (GetOverlappedResult(hDriver, &overlap, &received, TRUE)) {
  587.     dwError = ERROR_SUCCESS;
  588.     return TRUE;
  589.   }
  590.   dwError = ::GetLastError();
  591.   return FALSE;
  592. }
  593. BOOL PWin32PacketDriver::QueryOid(UINT oid, UINT len, BYTE * data)
  594. {
  595.   PWin32OidBuffer buf(oid, len);
  596.   DWORD rxsize = 0;
  597.   if (!IoControl(GetQueryOidCommand(oid), buf, buf, buf, buf, rxsize))
  598.     return FALSE;
  599.   if (rxsize == 0)
  600.     return FALSE;
  601.   buf.Move(data, rxsize);
  602.   return TRUE;
  603. }
  604. BOOL PWin32PacketDriver::QueryOid(UINT oid, DWORD & data)
  605. {
  606.   DWORD oidData[3];
  607.   oidData[0] = oid;
  608.   oidData[1] = sizeof(data);
  609.   oidData[2] = 0x12345678;
  610.   DWORD rxsize = 0;
  611.   if (!IoControl(GetQueryOidCommand(oid),
  612.                  oidData, sizeof(oidData),
  613.                  oidData, sizeof(oidData),
  614.                  rxsize))
  615.     return FALSE;
  616.   if (rxsize == 0)
  617.     return FALSE;
  618.   data = oidData[2];
  619.   return TRUE;
  620. }
  621. BOOL PWin32PacketDriver::SetOid(UINT oid, UINT len, const BYTE * data)
  622. {
  623.   DWORD rxsize = 0;
  624.   PWin32OidBuffer buf(oid, len, data);
  625.   return IoControl(IOCTL_EPACKET_SET_OID, buf, buf, buf, buf, rxsize);
  626. }
  627. BOOL PWin32PacketDriver::SetOid(UINT oid, DWORD data)
  628. {
  629.   DWORD oidData[3];
  630.   oidData[0] = oid;
  631.   oidData[1] = sizeof(data);
  632.   oidData[2] = data;
  633.   DWORD rxsize;
  634.   return IoControl(IOCTL_EPACKET_SET_OID,
  635.                    oidData, sizeof(oidData), oidData, sizeof(oidData), rxsize);
  636. }
  637. ///////////////////////////////////////////////////////////////////////////////
  638. BOOL PWin32PacketVxD::EnumInterfaces(PINDEX idx, PString & name)
  639. {
  640.   static const PString RegBase = SERVICES_REGISTRY_KEY "Class\Net";
  641.   PString keyName;
  642.   RegistryKey registry(RegBase, RegistryKey::ReadOnly);
  643.   if (!registry.EnumKey(idx, keyName))
  644.     return FALSE;
  645.   PString description;
  646.   RegistryKey subkey(RegBase + "\" + keyName, RegistryKey::ReadOnly);
  647.   if (subkey.QueryValue("DriverDesc", description))
  648.     name = keyName + ": " + description;
  649.   else
  650.     name = keyName;
  651.   return TRUE;
  652. }
  653. static PString SearchRegistryKeys(const PString & key,
  654.                                   const PString & variable,
  655.                                   const PString & value)
  656. {
  657.   RegistryKey registry(key, RegistryKey::ReadOnly);
  658.   PString str;
  659.   if (registry.QueryValue(variable, str) && (str *= value))
  660.     return key;
  661.   for (PINDEX idx = 0; registry.EnumKey(idx, str); idx++) {
  662.     PString result = SearchRegistryKeys(key + str + '\', variable, value);
  663.     if (!result)
  664.       return result;
  665.   }
  666.   return PString();
  667. }
  668. BOOL PWin32PacketVxD::BindInterface(const PString & interfaceName)
  669. {
  670.   BYTE buf[20];
  671.   DWORD rxsize;
  672.   if (hDriver == INVALID_HANDLE_VALUE) {
  673.     hDriver = CreateFile("\\.\" PACKET_VXD_NAME ".VXD",
  674.                          GENERIC_READ | GENERIC_WRITE,
  675.                          0,
  676.                          NULL,
  677.                          OPEN_EXISTING,
  678.                          FILE_ATTRIBUTE_NORMAL |
  679.                              FILE_FLAG_OVERLAPPED |
  680.                              FILE_FLAG_DELETE_ON_CLOSE,
  681.                          NULL);
  682.     if (hDriver == INVALID_HANDLE_VALUE) {
  683.       dwError = ::GetLastError();
  684.       return FALSE;
  685.     }
  686. #ifndef USE_VPACKET
  687.     rxsize = 0;
  688.     if (!IoControl(IOCTL_EPACKET_VERSION, NULL, 0, buf, sizeof(buf), rxsize)) {
  689.       dwError = ::GetLastError();
  690.       return FALSE;
  691.     }
  692.     if (rxsize != 2 || buf[0] < 1 || buf[1] < 1) {  // Require driver version 1.1
  693.       Close();
  694.       dwError = ERROR_BAD_DRIVER;
  695.       return FALSE;
  696.     }
  697. #endif
  698.   }
  699.   PString devName;
  700.   PINDEX colon = interfaceName.Find(':');
  701.   if (colon != P_MAX_INDEX)
  702.     devName = interfaceName.Left(colon);
  703.   else
  704.     devName = interfaceName;
  705.   
  706.   rxsize = 0;
  707.   if (!IoControl(IOCTL_EPACKET_BIND,
  708.                  (const char *)devName, devName.GetLength()+1,
  709.                  buf, sizeof(buf), rxsize) || rxsize == 0) {
  710.     dwError = ::GetLastError();
  711.     if (dwError == 0)
  712.       dwError = ERROR_BAD_DRIVER;
  713.     return FALSE;
  714.   }
  715.   // Get a random OID to verify that the driver did actually open
  716.   if (!QueryOid(OID_GEN_DRIVER_VERSION, 2, buf))
  717.     return FALSE;
  718.   dwError = ERROR_SUCCESS;    // Successful, even if may not be bound.
  719.   PString devKey = SearchRegistryKeys("HKEY_LOCAL_MACHINE\Enum\", "Driver", "Net\" + devName);
  720.   if (devKey.IsEmpty())
  721.     return TRUE;
  722.   RegistryKey bindRegistry(devKey + "Bindings", RegistryKey::ReadOnly);
  723.   PString binding;
  724.   PINDEX idx = 0;
  725.   while (bindRegistry.EnumValue(idx++, binding)) {
  726.     if (binding.Left(6) *= "MSTCP\") {
  727.       RegistryKey mstcpRegistry("HKEY_LOCAL_MACHINE\Enum\Network\" + binding, RegistryKey::ReadOnly);
  728.       PString str;
  729.       if (mstcpRegistry.QueryValue("Driver", str))
  730.         transportBinding.AppendString(SERVICES_REGISTRY_KEY "Class\" + str);
  731.     }
  732.   }
  733.   return TRUE;
  734. }
  735. BOOL PWin32PacketVxD::EnumIpAddress(PINDEX idx,
  736.                                     PIPSocket::Address & addr,
  737.                                     PIPSocket::Address & net_mask)
  738. {
  739.   if (idx >= transportBinding.GetSize())
  740.     return FALSE;
  741.   RegistryKey transportRegistry(transportBinding[idx], RegistryKey::ReadOnly);
  742.   PString str;
  743.   if (transportRegistry.QueryValue("IPAddress", str))
  744.     addr = str;
  745.   else
  746.     addr = 0;
  747.   if (addr != 0) {
  748.     if (transportRegistry.QueryValue("IPMask", str))
  749.       net_mask = str;
  750.     else {
  751.       if (IN_CLASSA(addr))
  752.         net_mask = "255.0.0.0";
  753.       else if (IN_CLASSB(addr))
  754.         net_mask = "255.255.0.0";
  755.       else if (IN_CLASSC(addr))
  756.         net_mask = "255.255.255.0";
  757.       else
  758.         net_mask = 0;
  759.     }
  760.     return TRUE;
  761.   }
  762.   PEthSocket::Address macAddress;
  763.   if (!QueryOid(OID_802_3_CURRENT_ADDRESS, sizeof(macAddress), macAddress.b))
  764.     return FALSE;
  765.   PINDEX dhcpCount;
  766.   for (dhcpCount = 0; dhcpCount < 8; dhcpCount++) {
  767.     RegistryKey dhcpRegistry(psprintf(SERVICES_REGISTRY_KEY "VxD\DHCP\DhcpInfo%02u", dhcpCount),
  768.                              RegistryKey::ReadOnly);
  769.     if (dhcpRegistry.QueryValue("DhcpInfo", str)) {
  770.       struct DhcpInfo {
  771.         DWORD index;
  772.         PIPSocket::Address ipAddress;
  773.         PIPSocket::Address mask;
  774.         PIPSocket::Address server;
  775.         PIPSocket::Address anotherAddress;
  776.         DWORD unknown1;
  777.         DWORD unknown2;
  778.         DWORD unknown3;
  779.         DWORD unknown4;
  780.         DWORD unknown5;
  781.         DWORD unknown6;
  782.         BYTE  unknown7;
  783.         PEthSocket::Address macAddress;
  784.       } * dhcpInfo = (DhcpInfo *)(const char *)str;
  785.       if (dhcpInfo->macAddress == macAddress) {
  786.         addr = dhcpInfo->ipAddress;
  787.         net_mask = dhcpInfo->mask;
  788.         return TRUE;
  789.       }
  790.     }
  791.     else if (dhcpRegistry.QueryValue("HardwareAddress", str) &&
  792.              str.GetSize() >= sizeof(PEthSocket::Address)) {
  793.       PEthSocket::Address hardwareAddress;
  794.       memcpy(&hardwareAddress, (const char *)str, sizeof(hardwareAddress));
  795.       if (hardwareAddress == macAddress) {
  796.         if (dhcpRegistry.QueryValue("DhcpIPAddress", str) &&
  797.             str.GetSize() >= sizeof(addr)) {
  798.           memcpy(&addr, (const char *)str, sizeof(addr));
  799.           if (dhcpRegistry.QueryValue("DhcpSubnetMask", str) &&
  800.               str.GetSize() >= sizeof(net_mask)) {
  801.             memcpy(&net_mask, (const char *)str, sizeof(net_mask));
  802.             return TRUE;
  803.           }
  804.         }
  805.       }
  806.     }
  807.   }
  808.   return FALSE;
  809. }
  810. BOOL PWin32PacketVxD::BeginRead(void * buf, DWORD size, DWORD & received, PWin32Overlapped & overlap)
  811. {
  812.   received = 0;
  813.   if (DeviceIoControl(hDriver, IOCTL_EPACKET_READ,
  814.                       buf, size, buf, size, &received, &overlap)) {
  815.     dwError = ERROR_SUCCESS;
  816.     return TRUE;
  817.   }
  818.   dwError = ::GetLastError();
  819.   return dwError == ERROR_IO_PENDING;
  820. }
  821. BOOL PWin32PacketVxD::BeginWrite(const void * buf, DWORD len, PWin32Overlapped & overlap)
  822. {
  823.   DWORD rxsize = 0;
  824.   BYTE dummy[2];
  825.   if (DeviceIoControl(hDriver, IOCTL_EPACKET_WRITE,
  826.                       (void *)buf, len, dummy, sizeof(dummy), &rxsize, &overlap)) {
  827.     dwError = ERROR_SUCCESS;
  828.     return TRUE;
  829.   }
  830.   dwError = ::GetLastError();
  831.   return dwError == ERROR_IO_PENDING;
  832. }
  833. ///////////////////////////////////////////////////////////////////////////////
  834. PWin32PacketSYS::PWin32PacketSYS()
  835. {
  836.   // Start the packet driver service
  837.   SC_HANDLE hManager = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
  838.   if (hManager != NULL) {
  839.     SC_HANDLE hService = OpenService(hManager, PACKET_SERVICE_NAME, SERVICE_START);
  840.     if (hService != NULL) {
  841.       StartService(hService, 0, NULL);
  842.       dwError = ::GetLastError();
  843.       CloseServiceHandle(hService);
  844.     }
  845.     CloseServiceHandle(hManager);
  846.   }
  847. }
  848. static BOOL RegistryQueryMultiSz(RegistryKey & registry,
  849.                                  const PString & variable,
  850.                                  PINDEX idx,
  851.                                  PString & value)
  852. {
  853.   PString allValues;
  854.   if (!registry.QueryValue(variable, allValues))
  855.     return FALSE;
  856.   const char * ptr = allValues;
  857.   while (*ptr != '' && idx-- > 0)
  858.     ptr += strlen(ptr)+1;
  859.   if (*ptr == '')
  860.     return FALSE;
  861.   value = ptr;
  862.   return TRUE;
  863. }
  864. static const char PacketDeviceStr[] = "\Device\" PACKET_SERVICE_NAME "_";
  865. BOOL PWin32PacketSYS::EnumInterfaces(PINDEX idx, PString & name)
  866. {
  867.   RegistryKey registry(SERVICES_REGISTRY_KEY PACKET_SERVICE_NAME "\Linkage",
  868.                        RegistryKey::ReadOnly);
  869.   if (!RegistryQueryMultiSz(registry, "Export", idx, name)) {
  870.     dwError = ERROR_NO_MORE_ITEMS;
  871.     return FALSE;
  872.   }
  873.   if (strnicmp(name, PacketDeviceStr, sizeof(PacketDeviceStr)-1) == 0)
  874.     name.Delete(0, sizeof(PacketDeviceStr)-1);
  875.   return TRUE;
  876. }
  877. BOOL PWin32PacketSYS::BindInterface(const PString & interfaceName)
  878. {
  879.   Close();
  880.   if (!DefineDosDevice(DDD_RAW_TARGET_PATH,
  881.                        PACKET_SERVICE_NAME "_" + interfaceName,
  882.                        PacketDeviceStr + interfaceName)) {
  883.     dwError = ::GetLastError();
  884.     return FALSE;
  885.   }
  886.   ::SetLastError(0);
  887.   hDriver = CreateFile("\\.\" PACKET_SERVICE_NAME "_" + interfaceName,
  888.                        GENERIC_READ | GENERIC_WRITE,
  889.                        0,
  890.                        NULL,
  891.                        CREATE_ALWAYS,
  892.                        FILE_FLAG_OVERLAPPED,
  893.                        NULL);
  894.   if (hDriver == INVALID_HANDLE_VALUE) {
  895.     dwError = ::GetLastError();
  896.     return FALSE;
  897.   }
  898.   registryKey = SERVICES_REGISTRY_KEY + interfaceName + "\Parameters\Tcpip";
  899.   dwError = ERROR_SUCCESS;
  900.   return TRUE;
  901. }
  902. BOOL PWin32PacketSYS::EnumIpAddress(PINDEX idx,
  903.                                     PIPSocket::Address & addr,
  904.                                     PIPSocket::Address & net_mask)
  905. {
  906.   PString str;
  907.   RegistryKey registry(registryKey, RegistryKey::ReadOnly);
  908.   if (!RegistryQueryMultiSz(registry, "IPAddress", idx, str)) {
  909.     dwError = ERROR_NO_MORE_ITEMS;
  910.     return FALSE;
  911.   }
  912.   addr = str;
  913.   if (!RegistryQueryMultiSz(registry, "SubnetMask", idx, str)) {
  914.     dwError = ERROR_NO_MORE_ITEMS;
  915.     return FALSE;
  916.   }
  917.   net_mask = str;
  918.   return TRUE;
  919. }
  920. BOOL PWin32PacketSYS::BeginRead(void * buf, DWORD size, DWORD & received, PWin32Overlapped & overlap)
  921. {
  922.   overlap.Reset();
  923.   received = 0;
  924.   if (ReadFile(hDriver, buf, size, &received, &overlap)) {
  925.     dwError = ERROR_SUCCESS;
  926.     return TRUE;
  927.   }
  928.   return (dwError = ::GetLastError()) == ERROR_IO_PENDING;
  929. }
  930. BOOL PWin32PacketSYS::BeginWrite(const void * buf, DWORD len, PWin32Overlapped & overlap)
  931. {
  932.   overlap.Reset();
  933.   DWORD sent = 0;
  934.   if (WriteFile(hDriver, buf, len, &sent, &overlap)) {
  935.     dwError = ERROR_SUCCESS;
  936.     return TRUE;
  937.   }
  938.   dwError = ::GetLastError();
  939.   return dwError == ERROR_IO_PENDING;
  940. }
  941. ///////////////////////////////////////////////////////////////////////////////
  942. PEthSocket::PEthSocket(PINDEX nReadBuffers, PINDEX nWriteBuffers, PINDEX size)
  943.   : readBuffers(min(nReadBuffers, MAXIMUM_WAIT_OBJECTS)),
  944.     writeBuffers(min(nWriteBuffers, MAXIMUM_WAIT_OBJECTS))
  945. {
  946.   driver = PWin32PacketDriver::Create();
  947.   snmp = new PWin32SnmpLibrary;
  948.   PINDEX i;
  949.   for (i = 0; i < nReadBuffers; i++)
  950.     readBuffers.SetAt(i, new PWin32PacketBuffer(size));
  951.   for (i = 0; i < nWriteBuffers; i++)
  952.     writeBuffers.SetAt(i, new PWin32PacketBuffer(size));
  953.   filterType = TypeAll;
  954. }
  955. PEthSocket::~PEthSocket()
  956. {
  957.   Close();
  958.   delete driver;
  959.   delete snmp;
  960. }
  961. BOOL PEthSocket::OpenSocket()
  962. {
  963.   PAssertAlways(PUnimplementedFunction);
  964.   return FALSE;
  965. }
  966. BOOL PEthSocket::Close()
  967. {
  968.   driver->Close();
  969.   os_handle = -1;
  970.   return TRUE;
  971. }
  972. PString PEthSocket::GetName() const
  973. {
  974.   return interfaceName;
  975. }
  976. BOOL PEthSocket::Connect(const PString & newName)
  977. {
  978.   Close();
  979.   if (!driver->BindInterface(newName)) {
  980.     osError = driver->GetLastError()|0x40000000;
  981.     return FALSE;
  982.   }
  983.   interfaceName = newName;
  984.   os_handle = 1;
  985.   return TRUE;
  986. }
  987. BOOL PEthSocket::EnumInterfaces(PINDEX idx, PString & name)
  988. {
  989.   return driver->EnumInterfaces(idx, name);
  990. }
  991. BOOL PEthSocket::GetAddress(Address & addr)
  992. {
  993.   if (driver->QueryOid(OID_802_3_CURRENT_ADDRESS, sizeof(addr), addr.b))
  994.     return TRUE;
  995.   osError = driver->GetLastError()|0x40000000;
  996.   return FALSE;
  997. }
  998. BOOL PEthSocket::EnumIpAddress(PINDEX idx,
  999.                                PIPSocket::Address & addr,
  1000.                                PIPSocket::Address & net_mask)
  1001. {
  1002.   if (IsOpen()) {
  1003.     if (driver->EnumIpAddress(idx, addr, net_mask))
  1004.       return TRUE;
  1005.     osError = ENOENT;
  1006.     lastError = NotFound;
  1007.   }
  1008.   else {
  1009.     osError = EBADF;
  1010.     lastError = NotOpen;
  1011.   }
  1012.   return FALSE;
  1013. }
  1014. static const struct {
  1015.   unsigned pwlib;
  1016.   DWORD    ndis;
  1017. } FilterMasks[] = {
  1018.   { PEthSocket::FilterDirected,     NDIS_PACKET_TYPE_DIRECTED },
  1019.   { PEthSocket::FilterMulticast,    NDIS_PACKET_TYPE_MULTICAST },
  1020.   { PEthSocket::FilterAllMulticast, NDIS_PACKET_TYPE_ALL_MULTICAST },
  1021.   { PEthSocket::FilterBroadcast,    NDIS_PACKET_TYPE_BROADCAST },
  1022.   { PEthSocket::FilterPromiscuous,  NDIS_PACKET_TYPE_PROMISCUOUS }
  1023. };
  1024. BOOL PEthSocket::GetFilter(unsigned & mask, WORD & type)
  1025. {
  1026.   if (!IsOpen()) {
  1027.     osError = EBADF;
  1028.     lastError = NotOpen;
  1029.     return FALSE;
  1030.   }
  1031.   DWORD filter = 0;
  1032.   if (!driver->QueryOid(OID_GEN_CURRENT_PACKET_FILTER, filter)) {
  1033.     osError = driver->GetLastError()|0x40000000;
  1034.     return FALSE;
  1035.   }
  1036.   if (filter == 0)
  1037.     return PEthSocket::FilterDirected;
  1038.   mask = 0;
  1039.   for (PINDEX i = 0; i < PARRAYSIZE(FilterMasks); i++) {
  1040.     if ((filter&FilterMasks[i].ndis) != 0)
  1041.       mask |= FilterMasks[i].pwlib;
  1042.   }
  1043.   type = (WORD)filterType;
  1044.   return TRUE;
  1045. }
  1046. BOOL PEthSocket::SetFilter(unsigned filter, WORD type)
  1047. {
  1048.   if (!IsOpen()) {
  1049.     osError = EBADF;
  1050.     lastError = NotOpen;
  1051.     return FALSE;
  1052.   }
  1053.   DWORD bits = 0;
  1054.   for (PINDEX i = 0; i < PARRAYSIZE(FilterMasks); i++) {
  1055.     if ((filter&FilterMasks[i].pwlib) != 0)
  1056.       bits |= FilterMasks[i].ndis;
  1057.   }
  1058.   if (!driver->SetOid(OID_GEN_CURRENT_PACKET_FILTER, bits)) {
  1059.     osError = driver->GetLastError()|0x40000000;
  1060.     return FALSE;
  1061.   }
  1062.   filterType = type;
  1063.   return TRUE;
  1064. }
  1065. PEthSocket::MediumTypes PEthSocket::GetMedium()
  1066. {
  1067.   if (!IsOpen()) {
  1068.     osError = EBADF;
  1069.     lastError = NotOpen;
  1070.     return NumMediumTypes;
  1071.   }
  1072.   DWORD medium = 0xffffffff;
  1073.   if (!driver->QueryOid(OID_GEN_MEDIA_SUPPORTED, medium) || medium == 0xffffffff) {
  1074.     osError = driver->GetLastError()|0x40000000;
  1075.     return NumMediumTypes;
  1076.   }
  1077.   static const DWORD MediumValues[NumMediumTypes] = {
  1078.     0xffffffff, NdisMedium802_3, NdisMediumWan, 0xffffffff
  1079.   };
  1080.   for (int type = Medium802_3; type < NumMediumTypes; type++) {
  1081.     if (MediumValues[type] == medium)
  1082.       return (MediumTypes)type;
  1083.   }
  1084.   return MediumUnknown;
  1085. }
  1086. BOOL PEthSocket::Read(void * data, PINDEX length)
  1087. {
  1088.   if (!IsOpen()) {
  1089.     osError = EBADF;
  1090.     lastError = NotOpen;
  1091.     return FALSE;
  1092.   }
  1093.   PINDEX idx;
  1094.   PINDEX numBuffers = readBuffers.GetSize();
  1095.   do {
  1096.     HANDLE handles[MAXIMUM_WAIT_OBJECTS];
  1097.     for (idx = 0; idx < numBuffers; idx++) {
  1098.       PWin32PacketBuffer & buffer = readBuffers[idx];
  1099.       if (buffer.InProgress()) {
  1100.         if (WaitForSingleObject(buffer.GetEvent(), 0) == WAIT_OBJECT_0)
  1101.           if (!buffer.ReadComplete(*driver))
  1102.             return ConvertOSError(-1);
  1103.       }
  1104.       else {
  1105.         if (!buffer.ReadAsync(*driver))
  1106.           return ConvertOSError(-1);
  1107.       }
  1108.       if (buffer.IsCompleted() && buffer.IsType(filterType)) {
  1109.         lastReadCount = buffer.GetData(data, length);
  1110.         return TRUE;
  1111.       }
  1112.       handles[idx] = buffer.GetEvent();
  1113.     }
  1114.     DWORD result;
  1115.     PINDEX retries = 100;
  1116.     for (;;) {
  1117.       result = WaitForMultipleObjects(numBuffers, handles, FALSE, INFINITE);
  1118.       if (result >= WAIT_OBJECT_0 && result < WAIT_OBJECT_0+numBuffers)
  1119.         break;
  1120.       if (::GetLastError() != ERROR_INVALID_HANDLE || retries == 0)
  1121.         return ConvertOSError(-1);
  1122.       retries--;
  1123.     }
  1124.     idx = result - WAIT_OBJECT_0;
  1125.     if (!readBuffers[idx].ReadComplete(*driver))
  1126.       return ConvertOSError(-1);
  1127.   } while (!readBuffers[idx].IsType(filterType));
  1128.   lastReadCount = readBuffers[idx].GetData(data, length);
  1129.   return TRUE;
  1130. }
  1131. BOOL PEthSocket::Write(const void * data, PINDEX length)
  1132. {
  1133.   if (!IsOpen()) {
  1134.     osError = EBADF;
  1135.     lastError = NotOpen;
  1136.     return FALSE;
  1137.   }
  1138.   HANDLE handles[MAXIMUM_WAIT_OBJECTS];
  1139.   PINDEX numBuffers = writeBuffers.GetSize();
  1140.   PINDEX idx;
  1141.   for (idx = 0; idx < numBuffers; idx++) {
  1142.     PWin32PacketBuffer & buffer = writeBuffers[idx];
  1143.     if (buffer.InProgress()) {
  1144.       if (WaitForSingleObject(buffer.GetEvent(), 0) == WAIT_OBJECT_0)
  1145.         if (!buffer.WriteComplete(*driver))
  1146.           return ConvertOSError(-1);
  1147.     }
  1148.     if (!buffer.InProgress()) {
  1149.       lastWriteCount = buffer.PutData(data, length);
  1150.       return ConvertOSError(buffer.WriteAsync(*driver) ? 0 : -1);
  1151.     }
  1152.     handles[idx] = buffer.GetEvent();
  1153.   }
  1154.   DWORD result = WaitForMultipleObjects(numBuffers, handles, FALSE, INFINITE);
  1155.   if (result < WAIT_OBJECT_0 || result >= WAIT_OBJECT_0+numBuffers)
  1156.     return ConvertOSError(-1);
  1157.   idx = result - WAIT_OBJECT_0;
  1158.   if (!writeBuffers[idx].WriteComplete(*driver))
  1159.     return ConvertOSError(-1);
  1160.   lastWriteCount = writeBuffers[idx].PutData(data, length);
  1161.   return ConvertOSError(writeBuffers[idx].WriteAsync(*driver) ? 0 : -1);
  1162. }
  1163. ///////////////////////////////////////////////////////////////////////////////
  1164. PWin32PacketBuffer::PWin32PacketBuffer(PINDEX sz)
  1165.   : PBYTEArray(sz)
  1166. {
  1167.   status = Uninitialised;
  1168.   count = 0;
  1169. }
  1170. PINDEX PWin32PacketBuffer::GetData(void * buf, PINDEX size)
  1171. {
  1172.   if (count > (DWORD)size)
  1173.     count = size;
  1174.   memcpy(buf, theArray, count);
  1175.   return count;
  1176. }
  1177. PINDEX PWin32PacketBuffer::PutData(const void * buf, PINDEX length)
  1178. {
  1179.   count = min(GetSize(), length);
  1180.   memcpy(theArray, buf, count);
  1181.   return count;
  1182. }
  1183. BOOL PWin32PacketBuffer::ReadAsync(PWin32PacketDriver & pkt)
  1184. {
  1185.   if (status == Progressing)
  1186.     return FALSE;
  1187.   status = Uninitialised;
  1188.   if (!pkt.BeginRead(theArray, GetSize(), count, overlap))
  1189.     return FALSE;
  1190.   if (pkt.GetLastError() == ERROR_SUCCESS)
  1191.     status = Completed;
  1192.   else
  1193.     status = Progressing;
  1194.   return TRUE;
  1195. }
  1196. BOOL PWin32PacketBuffer::ReadComplete(PWin32PacketDriver & pkt)
  1197. {
  1198.   if (status != Progressing)
  1199.     return status == Completed;
  1200.   if (!pkt.CompleteIO(count, overlap)) {
  1201.     status = Uninitialised;
  1202.     return FALSE;
  1203.   }
  1204.   status = Completed;
  1205.   return TRUE;
  1206. }
  1207. BOOL PWin32PacketBuffer::WriteAsync(PWin32PacketDriver & pkt)
  1208. {
  1209.   if (status == Progressing)
  1210.     return FALSE;
  1211.   status = Uninitialised;
  1212.   if (!pkt.BeginWrite(theArray, count, overlap))
  1213.     return FALSE;
  1214.   if (pkt.GetLastError() == ERROR_SUCCESS)
  1215.     status = Completed;
  1216.   else
  1217.     status = Progressing;
  1218.   return TRUE;
  1219. }
  1220. BOOL PWin32PacketBuffer::WriteComplete(PWin32PacketDriver & pkt)
  1221. {
  1222.   if (status != Progressing)
  1223.     return status == Completed;
  1224.   DWORD dummy;
  1225.   if (pkt.CompleteIO(dummy, overlap)) {
  1226.     status = Completed;
  1227.     return TRUE;
  1228.   }
  1229.   status = Uninitialised;
  1230.   return FALSE;
  1231. }
  1232. BOOL PWin32PacketBuffer::IsType(WORD filterType) const
  1233. {
  1234.   if (filterType == PEthSocket::TypeAll)
  1235.     return TRUE;
  1236.   const PEthSocket::Frame * frame = (const PEthSocket::Frame *)theArray;
  1237.   WORD len_or_type = ntohs(frame->snap.length);
  1238.   if (len_or_type > sizeof(*frame))
  1239.     return len_or_type == filterType;
  1240.   if (frame->snap.dsap == 0xaa && frame->snap.ssap == 0xaa)
  1241.     return ntohs(frame->snap.type) == filterType;   // SNAP header
  1242.   if (frame->snap.dsap == 0xff && frame->snap.ssap == 0xff)
  1243.     return PEthSocket::TypeIPX == filterType;   // Special case for Novell netware's stuffed up 802.3
  1244.   if (frame->snap.dsap == 0xe0 && frame->snap.ssap == 0xe0)
  1245.     return PEthSocket::TypeIPX == filterType;   // Special case for Novell netware's 802.2
  1246.   return frame->snap.dsap == filterType;    // A pure 802.2 protocol id
  1247. }
  1248. ///////////////////////////////////////////////////////////////////////////////
  1249. BOOL PIPSocket::GetGatewayAddress(Address & addr)
  1250. {
  1251.   PWin32SnmpLibrary snmp;
  1252.   PWin32AsnOid gatewayOid = "1.3.6.1.2.1.4.21.1.7.0.0.0.0";
  1253.   if (!snmp.GetOid(gatewayOid, addr))
  1254.     return FALSE;
  1255.   gatewayOid.Free();
  1256.   return TRUE;
  1257. }
  1258. PString PIPSocket::GetGatewayInterface()
  1259. {
  1260.   PWin32SnmpLibrary snmp;
  1261.   AsnInteger ifNum = -1;
  1262.   PWin32AsnOid gatewayOid = "1.3.6.1.2.1.4.21.1.2.0.0.0.0";
  1263.   if (!snmp.GetOid(gatewayOid, ifNum) && ifNum >= 0)
  1264.     return PString();
  1265.   gatewayOid.Free();
  1266.   return snmp.GetInterfaceName(ifNum);
  1267. }
  1268. BOOL PIPSocket::GetRouteTable(RouteTable & table)
  1269. {
  1270.   PWin32SnmpLibrary snmp;
  1271.   table.RemoveAll();
  1272.   PWin32AsnOid baseOid = "1.3.6.1.2.1.4.21.1";
  1273.   PWin32AsnOid oid = baseOid;
  1274.   DWORD lastVariable = 1;
  1275.   PWin32AsnAny value;
  1276.   PLongArray ifNum;
  1277.   PINDEX idx = 0;
  1278.   while (snmp.GetNextOid(oid, value) && (baseOid *= oid)) {
  1279.     if (lastVariable != oid[9]) {
  1280.       lastVariable = oid[9];
  1281.       if (lastVariable == 2)
  1282.         ifNum.SetSize(table.GetSize());
  1283.       idx = 0;
  1284.     }
  1285.     switch (lastVariable) {
  1286.       case 1 : // network address
  1287.         {
  1288.           Address addr;
  1289.           if (!value.GetIpAddress(addr))
  1290.             return FALSE;  // Very confused route table
  1291.           table.Append(new RouteEntry(addr));
  1292.           break;
  1293.         }
  1294.       case 2 : // device interface
  1295.         if (!value.GetInteger(ifNum[idx]))
  1296.           return FALSE;
  1297.         break;
  1298.       case 3 : // metric
  1299.         if (!value.GetInteger(table[idx].metric))
  1300.           return FALSE;
  1301.         break;
  1302.       case 7 : // Get destination (next hop)
  1303.         if (!value.GetIpAddress(table[idx].destination))
  1304.           return FALSE;
  1305.         break;
  1306.       case 11 : // Get mask
  1307.         if (!value.GetIpAddress(table[idx].net_mask))
  1308.           return FALSE;
  1309.         break;
  1310.     }
  1311.     idx++;
  1312.   }
  1313.   oid.Free();
  1314.   for (idx = 0; idx < table.GetSize(); idx++)
  1315.     table[idx].interfaceName = snmp.GetInterfaceName(ifNum[idx]);
  1316.   return TRUE;
  1317. }
  1318. BOOL PIPSocket::GetInterfaceTable(InterfaceTable & table)
  1319. {
  1320.   PWin32SnmpLibrary snmp;
  1321.   table.RemoveAll();
  1322.   PWin32AsnOid baseOid = "1.3.6.1.2.1.4.20.1";
  1323.   PWin32AsnOid oid = baseOid;
  1324.   PWin32AsnAny value;
  1325.   while (snmp.GetNextOid(oid, value)) {
  1326.     if (!(baseOid *= oid))
  1327.       break;
  1328.     if (value.asnType != ASN_IPADDRESS)
  1329.       break;
  1330.     Address ipAddr;
  1331.     value.GetIpAddress(ipAddr);
  1332.     oid[9] = 2;
  1333.     AsnInteger ifIndex = -1;
  1334.     if (!snmp.GetOid(oid, ifIndex))
  1335.       break;
  1336.     PString macAddr;
  1337.     PEthSocket::Address ifPhysAddress("");
  1338.     PWin32AsnOid ifOid = "1.3.6.1.2.1.2.2.1.6.0";
  1339.     ifOid[10] = ifIndex;
  1340.     UINT len;
  1341.     if (snmp.GetOid(ifOid, &ifPhysAddress, sizeof(ifPhysAddress), &len) && len > 0)
  1342.       macAddr = ifPhysAddress;
  1343.   
  1344.     PString name = snmp.GetInterfaceName(ipAddr);
  1345.     if (name.IsEmpty()) {
  1346.       PWin32AsnOid nameOid = "1.3.6.1.2.1.2.2.1.2.0";
  1347.       nameOid[10] = ifIndex;
  1348.       if (!snmp.GetOid(nameOid, name.GetPointer(100), 100))
  1349.         break;
  1350.       name.MakeMinimumSize();
  1351.     }
  1352.     table.Append(new InterfaceEntry(name, ipAddr, macAddr));
  1353.     oid[9] = 1;
  1354.   }
  1355.   return TRUE;
  1356. }
  1357. ///////////////////////////////////////////////////////////////////////////////