📄 irdasocket.cpp
字号:
//////////////////////////////////////////////////////////////////////////
//
// IrDASocket.cpp - IrDA socket support for Pocket PC
//
// Written by Daniel Strigl (daniel.strigl@web.de).
// Copyright (c) 2003. All Rights Reserved.
//
// The original code was written by Ramon de Klein (R.de.Klein@iaf.nl).
//
// The original IrDA socket support class can be found in
// the "Bubbles for Pocket PC" application from Ramon de Klein
// at http://www.codeproject.com/ce/bubbles.asp or
// http://home.ict.nl/~ramklein/Projects/Bubbles.html.
//
// Feel free to modify the source code and / or use it in your
// own programs. By the way, I would appreciate and enjoy hearing
// about them (just send an e-mail to daniel.strigl@web.de).
//
// Please report any bug, comment, suggestion, etc. to the
// following address: daniel.strigl@web.de
//
// Contact:
// --------
//
// Daniel Strigl
// daniel.strigl@web.de
// http://www.hh-system.com/danielstrigl
//
// History:
// --------
//
// 02.04.2003: The original IrDA socket support class was written
// to use in ATL/WTL applications. Modified the class
// so that it can be used in every MFC application.
//
// 03.04.2003: Added the "VerifyService" function.
//
// 16.04.2003: Added a second "VerifyService" function and modified
// the original "VerifyService" function.
//
// ORIGINAL COPYRIGHT STATEMENTS:
// ------------------------------
//
// IrDASocket.cpp - Bubbles for Pocket PC (IrDA socket support)
//
// Copyright (C) 2000 Ramon de Klein (R.de.Klein@iaf.nl)
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
//
//////////////////////////////////////////////////////////////////////////
#include "StdAfx.h"
#include "IrDASocket.h"
#include <atlconv.h> // Need for ATL conversion macros!
#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif
//////////////////////////////////////////////////////////////////////////
// CWinSock class
int CWinSock::mg_iInstance = 0;
WSADATA CWinSock::mg_wsaData = {0};
CWinSock::CWinSock()
{
// Only initialize WinSock the first time
if (++mg_iInstance == 1)
{
WSAStartup(MAKEWORD(1,1), &mg_wsaData);
}
}
CWinSock::~CWinSock()
{
// Cleanup WinSock when the last instance is gone
if (--mg_iInstance == 0)
{
WSACleanup();
}
}
//////////////////////////////////////////////////////////////////////////
// CIrDASocket class
CIrDASocket::CIrDASocket() : m_sd(INVALID_SOCKET)
{
}
CIrDASocket::~CIrDASocket()
{
// Close socket if left open
if (m_sd != INVALID_SOCKET)
closesocket(m_sd);
}
bool CIrDASocket::WaitForOperation(const bool fRead, const bool fWrite, const DWORD dwTimeout)
{
// Check if the call would block
const int iError = WSAGetLastError();
if (iError != WSAEWOULDBLOCK)
{
TRACE(_T("WaitForOperation called unexpectedly (error=%08Xh).\n"),iError);
return false;
}
// Setup the socket descriptors
fd_set fdsRead = {0};
fdsRead.fd_count = 1;
fdsRead.fd_array[0] = m_sd;
fd_set fdsWrite = {0};
fdsWrite.fd_count = 1;
fdsWrite.fd_array[0] = m_sd;
// Setup the timeout structure
struct timeval tv = {0};
if (dwTimeout != INFINITE)
{
// Convert to correct values
tv.tv_sec = dwTimeout/1000;
tv.tv_usec = dwTimeout%1000;
}
// Wait for the socket to accept
if (select(0,fRead?&fdsRead:0,fWrite?&fdsWrite:0,0,(dwTimeout!=INFINITE)?&tv:0) == 0)
{
TRACE(_T("WaitForOperation select failed (error=%08Xh).\n"),WSAGetLastError());
return false;
}
// Return successful
TRACE(_T("WaitForOperation succeeded.\n"));
return true;
}
bool CIrDASocket::EnumDevices(DEVICELIST* pDevList, int cbDevices)
{
// Check pre-conditions
ASSERT(m_sd != INVALID_SOCKET);
ASSERT(pDevList != 0);
// Obtain the available devices
pDevList->numDevice = 0;
if (getsockopt(m_sd,SOL_IRLMP,IRLMP_ENUMDEVICES,reinterpret_cast<char*>(pDevList),&cbDevices) == SOCKET_ERROR)
return false;
// Return successful
return true;
}
bool CIrDASocket::VerifyService(PIAS_QUERY pIASQuery, int iasqlen)
{
// Check pre-conditions
ASSERT(m_sd != INVALID_SOCKET);
ASSERT(pIASQuery != 0);
ASSERT(iasqlen > 0);
// Do the query
if (getsockopt(m_sd,SOL_IRLMP,IRLMP_IAS_QUERY,reinterpret_cast<char*>(pIASQuery),&iasqlen) == SOCKET_ERROR)
return false;
// Check the query result - class not found?
if (pIASQuery->irdaAttribType == IAS_ATTRIB_NO_CLASS)
return false;
// Check the query result - attribute not found?
if (pIASQuery->irdaAttribType == IAS_ATTRIB_NO_ATTRIB)
return false;
// Return successful
return true;
}
bool CIrDASocket::VerifyService(const LPBYTE pDeviceId, LPCSTR lpszClassName)
{
USES_CONVERSION; // declare locals used by the ATL macros
IAS_QUERY iasq = {0};
// Check pre-conditions
ASSERT(m_sd != INVALID_SOCKET);
ASSERT(pDeviceId != 0);
ASSERT(lpszClassName != 0);
ASSERT(strlen(lpszClassName) < sizeof(iasq.irdaClassName));
// Initialize the query structure
int iasqlen = sizeof(iasq);
memset(&iasq,0,iasqlen);
// Copy the device id, classname and attribute
memcpy(iasq.irdaDeviceID,pDeviceId,sizeof(iasq.irdaDeviceID));
strcpy(iasq.irdaClassName,lpszClassName);
// This mean that the LSAP-SEL will be returned
strcpy(iasq.irdaAttribName,T2CA(_T("IrDA:TinyTP:LsapSel")));
// Do the query
return VerifyService(&iasq, iasqlen);
}
bool CIrDASocket::Open()
{
// Check pre-conditions
ASSERT(m_sd == INVALID_SOCKET);
// Open socket
m_sd = socket(AF_IRDA,SOCK_STREAM,0);
if (m_sd == INVALID_SOCKET)
return false;
// Set socket as non-blocking socket
u_long ulArg = 1;
if (ioctlsocket(m_sd,FIONBIO,&ulArg) == SOCKET_ERROR)
return false;
// Return succcesful
return true;
}
bool CIrDASocket::Close()
{
// Only open sockets can be closed
if (m_sd == INVALID_SOCKET)
return false;
// Close socket
closesocket(m_sd);
m_sd = INVALID_SOCKET;
// Return succcesful
return true;
}
bool CIrDASocket::Bind(LPCSTR lpszServiceName)
{
SOCKADDR_IRDA sa = {0};
// Check pre-conditions
ASSERT(m_sd != INVALID_SOCKET);
ASSERT(lpszServiceName != 0);
ASSERT(strlen(lpszServiceName) < sizeof(sa.irdaServiceName));
// Set the socket address
sa.irdaAddressFamily = AF_IRDA;
strcpy(sa.irdaServiceName,lpszServiceName);
// Associate the server socket address with the server socket
if (bind(m_sd,reinterpret_cast<SOCKADDR*>(&sa),sizeof(sa)) == SOCKET_ERROR)
return false;
// Return succcesful
return true;
}
bool CIrDASocket::Listen(const int iBackLog)
{
// Check pre-conditions
ASSERT(m_sd != INVALID_SOCKET);
// Establish a socket to listen for incoming connections
if (listen(m_sd,iBackLog) == SOCKET_ERROR)
return false;
// Return succcesful
return true;
}
bool CIrDASocket::Accept(SOCKET* psd, const DWORD dwTimeout)
{
// Check pre-conditions
ASSERT(m_sd != INVALID_SOCKET);
ASSERT(psd != 0);
// Accept a connection
SOCKET sd = accept(m_sd,0,0);
if (sd == INVALID_SOCKET)
{
// Wait for operation to complete
if (!WaitForOperation(true,false,dwTimeout))
return false;
// Accept a connection
sd = accept(m_sd,0,0);
if (sd == INVALID_SOCKET)
return false;
}
// Set socket as non-blocking socket
u_long ulArg = 1;
if (ioctlsocket(sd,FIONBIO,&ulArg) == SOCKET_ERROR)
return false;
// Set socket descriptor and return
*psd = sd;
return true;
}
bool CIrDASocket::Connect(LPCSTR lpszServiceName, const LPBYTE pDeviceId, const DWORD dwTimeout)
{
SOCKADDR_IRDA sa = {0};
// Check pre-conditions
ASSERT(m_sd != INVALID_SOCKET);
ASSERT(lpszServiceName != 0);
ASSERT(strlen(lpszServiceName) < sizeof(sa.irdaServiceName));
// Setup the IrDA address
sa.irdaAddressFamily = AF_IRDA;
strcpy(sa.irdaServiceName,lpszServiceName);
memcpy(sa.irdaDeviceID,pDeviceId,sizeof(sa.irdaDeviceID));
// Try to connect
if (connect(m_sd,reinterpret_cast<SOCKADDR*>(&sa),sizeof(sa)) == SOCKET_ERROR)
{
// Wait for operation to complete
if (!WaitForOperation(false,true,dwTimeout))
return false;
}
// Return succesful
return true;
}
bool CIrDASocket::Send(LPCVOID lpData, DWORD cbBytes, const DWORD dwTimeout)
{
ASSERT(m_sd != INVALID_SOCKET);
TRACE(_T("Send(%d) operation started.\n"),cbBytes);
// Try to send the data
DWORD dwBytes = send(m_sd,reinterpret_cast<const char*>(lpData),cbBytes,0);
if (dwBytes != cbBytes)
{
TRACE(_T("Send(%d) operation cannot complete synchronous.\n"),cbBytes);
// Wait for operation to complete
if (!WaitForOperation(false,true,dwTimeout))
{
TRACE(_T("Send(%d) operation failed.\n"),cbBytes);
return false;
}
// Retry the send operation
dwBytes = send(m_sd,reinterpret_cast<const char*>(lpData),cbBytes,0);
if (dwBytes != cbBytes)
return false;
}
// Return succesful
TRACE(_T("Send(%d) operation succeeded.\n"),cbBytes);
return true;
}
bool CIrDASocket::Receive(LPVOID lpData, DWORD cbBytes, const DWORD dwTimeout)
{
ASSERT(m_sd != INVALID_SOCKET);
// Try to Receive the data
DWORD dwBytes = recv(m_sd,reinterpret_cast<char*>(lpData),cbBytes,0);
if (dwBytes != cbBytes)
{
TRACE(_T("Receive(%d) operation cannot complete synchronous.\n"),cbBytes);
// Wait for operation to complete
if (!WaitForOperation(true,false,dwTimeout))
{
TRACE(_T("Receive(%d) operation failed.\n"),cbBytes);
return false;
}
// Retry the read operation
dwBytes = recv(m_sd,reinterpret_cast<char*>(lpData),cbBytes,0);
if (dwBytes != cbBytes)
return false;
}
// Return succesful
TRACE(_T("Receive(%d) operation succeeded.\n"),cbBytes);
return true;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -