windows-nt/Source/XPSP1/NT/net/irda/irxfer/adhoc.cpp
2020-09-26 16:20:57 +08:00

693 lines
16 KiB
C++

#include "precomp.h"
#include <malloc.h>
#include <ssdp.h>
#include <iptypes.h>
#include <iphlpapi.h>
#include <mswsock.h>
#ifdef IP_OBEX
#define Trace1 DbgPrint
GUID gWsMobilityServiceClassGuid = NLA_SERVICE_CLASS_GUID;
#define MAX_ADDRESSES (16)
typedef struct _NLA_ADDRESS_LIST {
LONG AddressCount;
sockaddr_in Address[MAX_ADDRESSES];
} NLA_ADDRESS_LIST, *PNLA_ADDRESS_LIST;
BOOL
GetIpAddressFromAdapterName(
CHAR *AdapterName,
ULONG *IpAddress
);
VOID
AddressListChangeHandler(
DWORD Error,
DWORD BytesTransfered,
LPWSAOVERLAPPED WsOverLapped,
DWORD Flags
);
DWORD
NetWorkWorker(
PVOID Context
);
typedef struct _ADDRESS_ENTRY {
in_addr IpAddress;
PVOID AddressContext;
HANDLE SsdpHandle;
BOOL InUse;
BOOL Present;
BOOL Reported;
CHAR AdapterName[MAX_ADAPTER_NAME_LENGTH + 4];
NLA_CONNECTIVITY_TYPE Type;
} ADDRESS_ENTRY, *PADDRESS_ENTRY;
typedef struct _NET_CONTROL {
LONG ReferenceCount;
BOOL Closing;
HANDLE QueryHandle;
WSAOVERLAPPED WsOverlapped;
HANDLE RegistrationContext;
NEW_ADDRESS_CALLBACK NewAddressCallback;
ADDRESS_GONE_CALLBACK AddressGoneCallback;
ADDRESS_ENTRY AddressEntry[MAX_ADDRESSES];
} NET_CONTROL, *PNET_CONTROL;
VOID
GetAddressList(
PNET_CONTROL NetControl,
HANDLE QueryHandle
);
VOID
RemoveReferenceOnNetControl(
PNET_CONTROL NetControl
)
{
LONG CurrentCount;
CurrentCount=InterlockedDecrement(&NetControl->ReferenceCount);
if (CurrentCount == 0) {
HeapFree(GetProcessHeap(),0,NetControl);
}
return;
}
VOID
UnRegisterForAdhocNetworksNotification(
HANDLE RegistrationHandle
)
{
PNET_CONTROL NetControl=(PNET_CONTROL)RegistrationHandle;
NetControl->Closing=TRUE;
WSALookupServiceEnd(NetControl->QueryHandle);
RemoveReferenceOnNetControl(NetControl);
return;
}
HANDLE
RegisterForAdhocNetworksNotification(
HANDLE RegistrationContext,
NEW_ADDRESS_CALLBACK NewAddressCallback,
ADDRESS_GONE_CALLBACK AddressGoneCallback
)
{
PNET_CONTROL NetControl=NULL;
WORD wVersionRequested;
WSADATA wsaData;
int err;
BOOL bResult;
int j;
LONG Status;
NetControl=(PNET_CONTROL)HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(*NetControl));
if (NetControl == NULL) {
goto CleanUp;
}
NetControl->NewAddressCallback=NewAddressCallback;
NetControl->AddressGoneCallback=AddressGoneCallback;
NetControl->RegistrationContext=RegistrationContext;
for (j=0; j< MAX_ADDRESSES; j++) {
NetControl->AddressEntry[j].InUse=FALSE;
}
WSAQUERYSET restrictions;
ZeroMemory(&restrictions, sizeof(restrictions));
restrictions.dwSize = sizeof(restrictions);
restrictions.lpServiceClassId = &gWsMobilityServiceClassGuid;
restrictions.dwNameSpace = NS_NLA;
Status = WSALookupServiceBegin(
&restrictions,
LUP_NOCONTAINERS | LUP_RETURN_ALL | LUP_DEEP ,
&NetControl->QueryHandle
);
if (Status != ERROR_SUCCESS) {
goto CleanUp;
}
//
// one refcount for the creation of the object
//
NetControl->ReferenceCount=1;
//
// add one refcount for the workitem
//
InterlockedIncrement(&NetControl->ReferenceCount);
bResult=QueueUserWorkItem(
NetWorkWorker,
NetControl,
WT_EXECUTEINIOTHREAD
);
if (bResult) {
return NetControl;
}
CleanUp:
if (NetControl != NULL) {
HeapFree(GetProcessHeap(),0,NetControl);
}
return NULL;
}
DWORD
NetWorkWorker(
PVOID Context
)
{
PNET_CONTROL NetControl=(PNET_CONTROL)Context;
int err;
DWORD BytesReturned;
BOOL bResult;
GetAddressList(NetControl,NetControl->QueryHandle);
ZeroMemory(&NetControl->WsOverlapped,sizeof(NetControl->WsOverlapped));
NetControl->WsOverlapped.hEvent=NetControl;
WSACOMPLETION Completion;
Completion.Type=NSP_NOTIFY_APC;
Completion.Parameters.Apc.lpOverlapped=&NetControl->WsOverlapped;
Completion.Parameters.Apc.lpfnCompletionProc=AddressListChangeHandler;
err=WSANSPIoctl(
NetControl->QueryHandle,
SIO_NSP_NOTIFY_CHANGE,
NULL,
0,
NULL,
0,
&BytesReturned,
&Completion
);
if (err == SOCKET_ERROR) {
if (WSAGetLastError() != WSA_IO_PENDING) {
//
// the call failed and return value was not pending
//
RemoveReferenceOnNetControl(NetControl);
}
}
return 0;
}
VOID
AddressListChangeHandler(
DWORD Error,
DWORD BytesTransfered,
LPWSAOVERLAPPED WsOverlapped,
DWORD Flags
)
{
PNET_CONTROL NetControl=(PNET_CONTROL)WsOverlapped->hEvent;
if (!NetControl->Closing) {
NetWorkWorker(
NetControl
);
} else {
//
// we are closing, remove all the addresses
//
ULONG i;
for (i=0; i< MAX_ADDRESSES; i++) {
//
// See if any address disappeared
//
if (NetControl->AddressEntry[i].InUse) {
//
// was in use at one time
//
if (NetControl->AddressEntry[i].Reported) {
DbgPrint("IRMON: removing address %s\n",inet_ntoa(NetControl->AddressEntry[i].IpAddress));
(NetControl->AddressGoneCallback)(
NetControl->RegistrationContext,
NetControl->AddressEntry[i].AddressContext
);
UnregisterWithSsdp(
NetControl->AddressEntry[i].SsdpHandle
);
ZeroMemory(&NetControl->AddressEntry[i],sizeof(NetControl->AddressEntry[i]));
}
}
}
RemoveReferenceOnNetControl(NetControl);
}
return;
}
VOID
AddAddressToList(
PNET_CONTROL NetControl,
CHAR *AdapterName,
in_addr IpAddress,
NLA_CONNECTIVITY_TYPE Type
)
{
ULONG j;
ULONG i;
LONG FreeSlot;
BOOL bResult;
for (j=0; j< MAX_ADDRESSES; j++) {
if (NetControl->AddressEntry[j].InUse) {
// if (NetControl->AddressEntry[j].IpAddress.S_un.S_addr == IpAddress.S_un.S_addr) {
if (0 == lstrcmpA(AdapterName,NetControl->AddressEntry[j].AdapterName)) {
//
// we have already seen this address
//
DbgPrint("net: dup local address %s\n",inet_ntoa(IpAddress));
NetControl->AddressEntry[j].Present=TRUE;
break;
}
} else {
FreeSlot=j;
}
}
if (j == MAX_ADDRESSES) {
//
// we have a new address
//
SOCKET ListenSocket;
NetControl->AddressEntry[FreeSlot].InUse=TRUE;
NetControl->AddressEntry[FreeSlot].Present=TRUE;
NetControl->AddressEntry[FreeSlot].IpAddress = IpAddress;
lstrcpyA(NetControl->AddressEntry[FreeSlot].AdapterName,AdapterName);
NetControl->AddressEntry[FreeSlot].Type=Type;
if (((IpAddress.S_un.S_addr != INADDR_NONE) && (IpAddress.S_un.S_addr != 0)) &&
((Type == NLA_NETWORK_AD_HOC)
||
(Type == NLA_NETWORK_UNMANAGED))) {
NetControl->AddressEntry[FreeSlot].Reported=TRUE;
bResult=RegisterWithSsdp(
&IpAddress,
&ListenSocket,
&NetControl->AddressEntry[FreeSlot].SsdpHandle,
650
);
if (!bResult) {
DbgPrint("IRMON: failed to register with ssdp\n");
NetControl->AddressEntry[FreeSlot].Reported=FALSE;
} else {
(NetControl->NewAddressCallback)(
NetControl->RegistrationContext,
ListenSocket,
&NetControl->AddressEntry[FreeSlot].AddressContext
);
}
}
}
return;
}
VOID
RemoveAddressFromList(
PNET_CONTROL NetControl,
CHAR *AdapterName
)
{
ULONG i;
for (i=0; i< MAX_ADDRESSES; i++) {
//
// See if any address disappeared
//
if (NetControl->AddressEntry[i].InUse) {
//
// was in use at one time
//
if (0 == lstrcmpA(AdapterName,NetControl->AddressEntry[i].AdapterName)) {
//
// This matched the device that is being removed
//
if (NetControl->AddressEntry[i].Reported) {
//
// this one was reported to the client
//
DbgPrint("IRMON: removing address %s\n",inet_ntoa(NetControl->AddressEntry[i].IpAddress));
(NetControl->AddressGoneCallback)(
NetControl->RegistrationContext,
NetControl->AddressEntry[i].AddressContext
);
UnregisterWithSsdp(
NetControl->AddressEntry[i].SsdpHandle
);
}
ZeroMemory(&NetControl->AddressEntry[i],sizeof(NetControl->AddressEntry[i]));
}
}
}
return;
}
VOID
GetAddressList(
PNET_CONTROL NetControl,
HANDLE QueryHandle
)
{
int ret = FALSE;
WSADATA wsaData;
PWSAQUERYSET result = NULL;
DWORD length;
DWORD LengthRequested;
int error;
ret = TRUE;
while (1) {
length = 0;
WSALookupServiceNext(QueryHandle, 0, &length, NULL);
if (((error = WSAGetLastError()) != WSAEFAULT) && (error != WSA_E_NO_MORE)) {
Trace1("WSALookupServiceNext1 failed %d\n", error);
ret = FALSE;
break;
}
result = (PWSAQUERYSET)HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,length);
if (result != NULL) {
LengthRequested=length;
ret = WSALookupServiceNext(QueryHandle, 0, &length, result);
if (ret == ERROR_SUCCESS) {
if (result->lpBlob != NULL) {
NLA_BLOB *blob = (NLA_BLOB *)result->lpBlob->pBlobData;
int next;
IN_ADDR IpAddress;
NLA_CONNECTIVITY_TYPE ConnectivityType=NLA_NETWORK_UNKNOWN;
CHAR AdapterName[MAX_ADAPTER_NAME_LENGTH + 4];
AdapterName[0]='\0';
IpAddress.S_un.S_addr=INADDR_NONE;
do {
// The next four lines need changing when network interface type is implemented
DbgPrint("NLA: Blob type %d\n",blob->header.type);
if (blob->header.type == NLA_CONNECTIVITY) {
DbgPrint("NLA: connectivity=%d, Internet=%d\n",blob->data.connectivity.type,blob->data.connectivity.internet);
ConnectivityType=blob->data.connectivity.type;
}
if (blob->header.type == NLA_INTERFACE) {
DbgPrint("NLA: adapter name %s, speed %d\n",blob->data.interfaceData.adapterName,blob->data.interfaceData.dwSpeed);
GetIpAddressFromAdapterName(blob->data.interfaceData.adapterName,&IpAddress.S_un.S_addr);
lstrcpynA(AdapterName,blob->data.interfaceData.adapterName,sizeof(AdapterName)-1);
}
next = blob->header.nextOffset;
blob = (NLA_BLOB *)(((char *)blob) + next);
} while(next != 0);
if (AdapterName[0] != '\0') {
//
// we got an adapter name
//
if (result->dwOutputFlags & RESULT_IS_ADDED) {
//
// new interface
//
DbgPrint("NLA: add\n");
AddAddressToList(
NetControl,
AdapterName,
IpAddress,
ConnectivityType
);
} else {
if (result->dwOutputFlags & RESULT_IS_DELETED) {
DbgPrint("NLA: delete\n");
RemoveAddressFromList(
NetControl,
AdapterName
);
} else {
if (result->dwOutputFlags & RESULT_IS_CHANGED) {
DbgPrint("NLA: change\n");
RemoveAddressFromList(
NetControl,
AdapterName
);
AddAddressToList(
NetControl,
AdapterName,
IpAddress,
ConnectivityType
);
} else {
DbgPrint("NLA: other dwOutputFlags %x\n",result->dwOutputFlags);
}
}
}
}
}
} else {
if ((error = WSAGetLastError()) != WSA_E_NO_MORE) {
Trace1("WSALookupServiceNext failed %d, needed=%d, req=%d\n", error,length, LengthRequested);
ret = FALSE;
}
break;
}
HeapFree(GetProcessHeap(),0,result);
result=NULL;
}
}
return ;
}
BOOL
GetIpAddressFromAdapterName(
CHAR *AdapterName,
ULONG *IpAddress
)
{
PIP_ADAPTER_INFO AdapterInfo;
PIP_ADAPTER_INFO CurrentAdapter;
ULONG BufferNeeded;
DWORD ReturnValue;
BOOL bReturn=FALSE;
BufferNeeded=0;
// DbgPrint("irmon: GetIpAddressFromAdapterName\n");
ReturnValue=GetAdaptersInfo(
NULL,
&BufferNeeded
);
if (ReturnValue != ERROR_BUFFER_OVERFLOW) {
//
// failed for some other reason
//
DbgPrint("irmon: GetAdaptersInfo(1) failed\n");
return FALSE;
}
AdapterInfo=(PIP_ADAPTER_INFO)HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,BufferNeeded);
if (AdapterInfo != NULL) {
ReturnValue=GetAdaptersInfo(
AdapterInfo,
&BufferNeeded
);
if (ReturnValue == ERROR_SUCCESS) {
CurrentAdapter=AdapterInfo;
while (CurrentAdapter != NULL) {
int Match;
// DbgPrint("IRMON: comp AdapterName=%s, comp=%s\n",AdapterName,CurrentAdapter->AdapterName);
Match=lstrcmpiA(AdapterName,CurrentAdapter->AdapterName);
if (Match == 0) {
DbgPrint("IRMON: match AdapterName=%s, ip=%s\n",CurrentAdapter->AdapterName,CurrentAdapter->IpAddressList.IpAddress.String);
*IpAddress=inet_addr(&CurrentAdapter->IpAddressList.IpAddress.String[0]);
if (*IpAddress != INADDR_NONE) {
bReturn=TRUE;
break;
}
} else {
// DbgPrint("IRMON: mismatch AdapterName=%s, comp=%s\n",AdapterName,CurrentAdapter->AdapterName);
}
CurrentAdapter=CurrentAdapter->Next;
}
} else {
DbgPrint("irmon: GetAdaptersInfo(2) failed\n");
}
HeapFree(GetProcessHeap(),0,AdapterInfo);
AdapterInfo=NULL;
} else {
DbgPrint("irmon: allocation failed\n");
}
return bReturn;
}
#endif //ip_obex