📄 btecho.cxx
字号:
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
//
// Use of this source code is subject to the terms of the Microsoft end-user
// license agreement (EULA) under which you licensed this SOFTWARE PRODUCT.
// If you did not accept the terms of the EULA, you are not authorized to use
// this source code. For a copy of the EULA, please see the LICENSE.RTF on your
// install media.
//
/**
THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND,
EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE.
Abstract:
Windows CE Bluetooth application sample
**/
#define _STRSAFE_H_INCLUDED_ 1
#include <windows.h>
#include <stdio.h>
#if ! defined (UNDER_CE)
#include <stddef.h>
#endif
#include <bt_api.h>
#include "../l2capapi/l2capapi.hxx"
#include <svsutil.hxx>
#define MAX_THREADS 100
#define MAX_RUNS 100000
#define MAX_REQS 1000000
#define RANDOM(x) (((x * 214013 + 2531011) >> 16 ) & 0x7fff)
#define BIG_RANDOM(x) (x | (RANDOM(x) << 15))
class Packet {
public:
int iRequest;
int iRandom;
unsigned int cPos;
unsigned int cSize;
unsigned char uc[1];
};
class ThreadData {
public:
unsigned short cid;
unsigned short outMTU;
};
class Paragraph {
public:
unsigned int cText;
unsigned char *pText;
};
SVSExpArray<class Paragraph> *g_pFile;
unsigned int g_cParagraphs = 0;
unsigned short g_usMaxPacket = 0;
int g_iRequests = 0;
unsigned short g_usPSM = 0;
BT_ADDR g_ba;
#if defined (USE_RPC)
extern "C" handle_t bluetooth_IfHandle;
extern "C" void __RPC_FAR * __RPC_API midl_user_allocate (size_t len) {
return malloc(len);
}
extern "C" void __RPC_API midl_user_free (void * __RPC_FAR ptr) {
free (ptr);
}
#endif
#if ! defined (UNDER_CE)
BOOL WINAPI cmd_InterruptHandler (DWORD dwCtrl) {
if (dwCtrl == CTRL_C_EVENT) {
L2CAPClosePSM (g_usPSM);
return TRUE;
}
return FALSE;
}
#endif
int GetBA (WCHAR **pp, BT_ADDR *pba) {
while (**pp == ' ')
++*pp;
for (int i = 0 ; i < 4 ; ++i, ++*pp) {
if (! iswxdigit (**pp))
return FALSE;
int c = **pp;
if (c >= 'a')
c = c - 'a' + 0xa;
else if (c >= 'A')
c = c - 'A' + 0xa;
else c = c - '0';
if ((c < 0) || (c > 16))
return FALSE;
*pba = *pba * 16 + c;
}
for (i = 0 ; i < 8 ; ++i, ++*pp) {
if (! iswxdigit (**pp))
return FALSE;
int c = **pp;
if (c >= 'a')
c = c - 'a' + 0xa;
else if (c >= 'A')
c = c - 'A' + 0xa;
else c = c - '0';
if ((c < 0) || (c > 16))
return FALSE;
*pba = *pba * 16 + c;
}
if ((**pp != ' ') && (**pp != '\0'))
return FALSE;
return TRUE;
}
int GetUS (WCHAR **pp, unsigned short *pus) {
while (**pp == ' ')
++*pp;
if (**pp != '0')
return FALSE;
++*pp;
if (**pp != 'x')
return FALSE;
++*pp;
int iDig = 0;
*pus = 0;
while (iswxdigit (**pp)) {
int c = **pp;
if (c >= 'a')
c = c - 'a' + 0xa;
else if (c >= 'A')
c = c - 'A' + 0xa;
else c = c - '0';
if ((c < 0) || (c > 16))
return FALSE;
*pus = *pus * 16 + c;
++*pp;
++iDig;
}
if (iDig > 4)
return FALSE;
return TRUE;
}
int SendPacket (int iRequest, int iRandom, int cid, unsigned char *ub, unsigned int cb) {
Packet *pr = (Packet *)ub;
pr->iRequest = iRequest;
pr->iRandom = iRandom;
pr->cPos = BIG_RANDOM(iRandom) % g_cParagraphs;
pr->cSize = (*g_pFile)[pr->cPos].cText;
if (pr->cSize + offsetof(Packet, uc) > cb)
pr->cSize = cb - offsetof(Packet, uc);
memcpy (pr->uc, (*g_pFile)[pr->cPos].pText, pr->cSize);
int iErr = L2CAPWrite (cid, pr->cSize + offsetof(Packet, uc), ub);
if (iErr != ERROR_SUCCESS) {
wprintf (L"0x%04x Error 0x%08x (%d)\n", cid, iErr);
return FALSE;
}
return TRUE;
}
int ProcessRequest (int iRequest, int iRandom, int cid, unsigned char *ub, unsigned int cb) {
if (cb < sizeof(Packet)) {
wprintf (L"0x%04x Bad request %d: too small\n", cid, iRequest);
return FALSE;
}
Packet *pr = (Packet *)ub;
if (pr->iRequest != iRequest) {
wprintf (L"0x%04x Bad request %d: ordinals do not match (got %d)\n", cid, iRequest, pr->iRequest);
return FALSE;
}
if (pr->iRandom != iRandom) {
wprintf (L"0x%04x Bad request %d: random numbers do not match (got %d, expected %d)\n",
cid, iRequest, pr->iRandom, iRandom);
return FALSE;
}
if (offsetof (Packet, uc) + pr->cSize != cb) {
wprintf (L"0x%04x Bad request %d: inconsistent packet size (got %d, expected %d + %d)\n",
cid, iRequest, cb, offsetof (Packet, uc), pr->cSize);
return FALSE;
}
if (pr->cPos >= g_cParagraphs) {
wprintf (L"0x%04x Bad request %d: position too big (pos %d, file size is %d)\n",
cid, iRequest, pr->cPos, g_cParagraphs);
return FALSE;
}
if ((pr->cSize > (*g_pFile)[pr->cPos].cText) ||
(memcmp (pr->uc, (*g_pFile)[pr->cPos].pText, pr->cSize) != 0)) {
wprintf (L"0x%04x Bad request %d: mismatched text\n");
return FALSE;
}
if (iRequest % 10)
wprintf (L"0x%04x Successfully received %d th packet\n", cid, iRequest);
return TRUE;
}
DWORD WINAPI ClientReadThread (LPVOID lpVoid) {
unsigned short cid;
unsigned short usMTU;
BT_ADDR ba;
ba = g_ba;
int iErr = L2CAPConnect (&ba, g_usPSM, g_usMaxPacket, &cid, &usMTU);
if (iErr != ERROR_SUCCESS) {
wprintf (L"Connect to %04x%08x has failed\n", GET_NAP(ba), GET_SAP(ba));
return 0;
}
wprintf (L"Client thread 0x%08x created for connection 0x%04x\n", GetCurrentThreadId(), cid);
int iRandom = 0;
unsigned char *ub = (unsigned char *)malloc (0xffff);
for (int i = 0 ; i < g_iRequests ; ) {
unsigned int cSize = 0;
iRandom = ((iRandom * 214013 + 2531011) >> 16 ) & 0x7fff;
if (! SendPacket (++i, iRandom, cid, ub, usMTU)) {
wprintf (L"0x%04x Connection ended in error\n", cid);
L2CAPCloseCID (cid);
break;
}
int iErr = L2CAPRead (cid, 0xffff, &cSize, ub);
if (iErr != ERROR_SUCCESS) {
wprintf (L"0x%04x Error 0x%08x (%d)\n", cid, iErr, iErr);
L2CAPCloseCID (cid);
break;
}
if (cSize == 0) {
wprintf (L"0x%04x Connection ended in error <closed>!\n", cid);
L2CAPCloseCID (cid);
break;
}
iRandom = ((iRandom * 214013 + 2531011) >> 16 ) & 0x7fff;
if (! ProcessRequest (++i, iRandom, cid, ub, cSize)) {
wprintf (L"0x%04x Connection ended in error\n");
L2CAPCloseCID (cid);
break;
}
}
free (ub);
if (i == g_iRequests)
L2CAPCloseCID (cid);
wprintf (L"0x%04x Client thread finished\n", cid);
return 0;
}
DWORD WINAPI ServerReadThread (LPVOID lpVoid) {
ThreadData *ptd = (ThreadData *)lpVoid;
unsigned short cid = ptd->cid;
unsigned short usMTU = ptd->outMTU;
free (ptd);
wprintf (L"Server thread 0x%08x created for connection 0x%04x\n", GetCurrentThreadId(), cid);
int i = 0;
int iRandom = 0;
unsigned char *ub = (unsigned char *)malloc (0xffff);
for ( ; ; ) {
unsigned int cSize = 0;
int iErr = L2CAPRead (cid, 0xffff, &cSize, ub);
if (iErr != ERROR_SUCCESS) {
wprintf (L"0x%04x Error 0x%08x (%d)\n", cid, iErr, iErr);
L2CAPCloseCID (cid);
break;
}
if (cSize == 0) {
wprintf (L"0x%04x Connection ended\n", cid);
L2CAPCloseCID (cid);
break;
}
iRandom = ((iRandom * 214013 + 2531011) >> 16 ) & 0x7fff;
if (! (ProcessRequest (++i, iRandom, cid, ub, cSize) &&
SendPacket (++i,
iRandom = ((iRandom * 214013 + 2531011) >> 16 ) & 0x7fff,
cid, ub, usMTU))) {
wprintf (L"0x%04x Connection ended in error\n");
L2CAPCloseCID (cid);
break;
}
}
free (ub);
wprintf (L"0x%04x Server thread finished\n", cid);
return 0;
}
int wmain (int argc, WCHAR **argv) {
#if defined (USE_RPC)
WCHAR *pszUuid = NULL;
WCHAR *pszProtocolSequence = L"ncalrpc";
WCHAR *pszNetworkAddress = NULL;
WCHAR *pszEndpoint = L"bt_server";
WCHAR *pszOptions = NULL;
WCHAR *pszStringBinding = NULL;
RpcStringBindingCompose (pszUuid, pszProtocolSequence, pszNetworkAddress,
pszEndpoint, pszOptions, &pszStringBinding);
wprintf (L"String binding : %s\n", pszStringBinding);
RpcBindingFromStringBinding (pszStringBinding, &bluetooth_IfHandle);
#endif
svsutil_Initialize ();
int fArgError = TRUE;
int fServer = FALSE;
int iRuns = 0;
int iThreads = 0;
WCHAR szTargetName[_MAX_PATH];
// -server name psm <max packet>
// -client name psm <max packet> <bt_addr/name/*> <runs> <iterations per run> <threads active>
while (argc > 4) {
if (wcsicmp (argv[1], L"-server") == 0)
fServer = TRUE;
else if (wcsicmp (argv[1], L"-client") != 0) {
wprintf (L"Neither server nor client...\n");
break;
}
WCHAR *p = argv[3];
if (! GetUS (&p, &g_usPSM)) {
wprintf (L"Bad PSM format\n");
break;
}
p = argv[4];
if ((! GetUS (&p, &g_usMaxPacket)) || (g_usMaxPacket < sizeof(Packet))) {
wprintf (L"Bad max packet format or too small (min %d)\n", sizeof (Packet));
break;
}
g_pFile = new SVSExpArray<Paragraph>;
FILE *fp = _wfopen (argv[2], L"r");
if (! fp) {
wprintf (L"Cannot open %s for read\n", argv[2]);
break;
}
char *szCurrentText = NULL;
int cCurrentText = 1;
int fArgError2 = FALSE;
while (! feof (fp)) {
char szString[512];
if (! fgets (szString, sizeof(szString), fp))
break;
int c = strlen (szString);
if ((szString[0] != '\0') && (szString[0] != '\n')) {
szCurrentText = (char *)realloc (szCurrentText, c + cCurrentText);
if (! szCurrentText) {
wprintf (L"No memory for the string!\n");
fArgError2 = TRUE;
break;
}
memcpy (szCurrentText + cCurrentText - 1, szString, c + 1);
cCurrentText += c;
} else if (szCurrentText) {
if (! (*g_pFile).SRealloc (g_cParagraphs + 1)) {
wprintf (L"No memory for the string!\n");
fArgError2 = TRUE;
break;
}
(*g_pFile)[g_cParagraphs].cText = cCurrentText;
(*g_pFile)[g_cParagraphs].pText = (unsigned char *)szCurrentText;
++g_cParagraphs;
cCurrentText = 1;
szCurrentText = NULL;
}
}
fclose (fp);
if (fArgError2)
break;
wprintf (L"Read file %s successfully\n", argv[2]);
if (! fServer) {
if (argc != 9) {
wprintf (L"Not enough or too many args for client\n");
break;
}
p = argv[5];
if (! GetBA (&p, &g_ba)) {
wcsncpy (szTargetName, argv[5], _MAX_PATH-2);
szTargetName[_MAX_PATH-1] = '\0';
}
iRuns = _wtoi (argv[6]);
g_iRequests = _wtoi (argv[7]);
iThreads = _wtoi (argv[8]);
if ((iRuns <= 0) || (iRuns > MAX_RUNS)) {
wprintf (L"runs number out of bounds\n");
break;
}
if ((iThreads <= 0) || (iThreads > MAX_THREADS)) {
wprintf (L"threads number out of bounds\n");
break;
}
if ((g_iRequests <= 0) || (g_iRequests > MAX_REQS)) {
wprintf (L"number of requests out of bounds\n");
break;
}
}
fArgError = FALSE;
break;
}
if (fArgError) {
wprintf (L"Usage:\n\t%s -server name psm <max packet>\nor\n\t%s -client name psm <max packet> <machine name or *> <runs> <iterations per run> <threads active>\n", argv[0], argv[0]);
exit (1);
}
if (fServer) {
#if ! defined (UNDER_CE)
HANDLE hConsoleOutput = GetStdHandle (STD_OUTPUT_HANDLE);
SetConsoleCtrlHandler (cmd_InterruptHandler, TRUE);
#endif
int iErr = BthWriteScanEnableMask (3);
wprintf (L"Enabled inquiry and connect scan. Return code %d\n", iErr);
wprintf (L"Entering server.\n");
iErr = L2CAPListen (g_usPSM, g_usMaxPacket);
wprintf (L"L2CAPListen returns 0x%08x (%d)\n", iErr, iErr);
while (iErr == ERROR_SUCCESS) {
unsigned short cid, outmtu;
BT_ADDR ba;
int iErr = L2CAPAccept (g_usPSM, &ba, &cid, &outmtu);
if (iErr != ERROR_SUCCESS) {
wprintf (L"Accept exited with code 0x%08x (%d)\n", iErr, iErr);
L2CAPClosePSM (g_usPSM);
break;
}
if (outmtu < sizeof(Packet)) {
wprintf (L"0x%04x New connection rejected: too small an MTU (%d)\n", cid, outmtu);
L2CAPCloseCID (cid);
continue;
}
wprintf (L"0x%04x New connection successful - spinning read thread\n", cid);
ThreadData *ptd = (ThreadData *)malloc(sizeof(ThreadData));
ptd->cid = cid;
ptd->outMTU = outmtu;
CloseHandle (CreateThread (NULL, 0, ServerReadThread, (void *)ptd, 0, NULL));
}
wprintf (L"Exiting server\n");
return 0;
}
if (szTargetName[0]) {
wprintf (L"Performing inquiry\n");
BthInquiryResult ir[256];
unsigned int cGot = 0;
int iError = BthPerformInquiry (0x9e8b33, 0x10, szTargetName[0] == '*' ? 1 : 0, 256, &cGot, ir);
if ((iError != ERROR_SUCCESS) || (! cGot)) {
wprintf (L"Inquiry returned error code %d, %d entries\n", iError, cGot);
return 0;
}
if (szTargetName[0] == '*')
g_ba = ir[0].ba;
else {
for (int i = 0 ; i < (int)cGot ; ++i) {
WCHAR sz[_MAX_PATH];
unsigned int cLen;
iError = BthRemoteNameQuery (&ir[i].ba, _MAX_PATH, &cLen, sz);
if ((iError == ERROR_SUCCESS) && (wcsicmp (sz, szTargetName) == 0))
break;
}
if (i != (int)cGot) {
g_ba = ir[i].ba;
} else {
wprintf (L"Name %s not found!\n", szTargetName);
return 0;
}
}
}
// client
HANDLE hThreads[MAX_THREADS];
DWORD dwTicks[MAX_THREADS];
for (int i = 0 ; i < iThreads ; ++i) {
dwTicks[i] = GetTickCount ();
if (hThreads[i] = CreateThread (NULL, 0, ClientReadThread, NULL, 0, NULL))
--iRuns;
else
break;
}
for ( ; i < iThreads ; ++i)
hThreads[i] = NULL;
for ( ; ; ) {
int iActive = 0;
for (i = 0 ; i < iThreads ; ++i, ++iActive) {
if (! hThreads[i])
break;
}
if (iActive == 0)
break;
DWORD dwRes = WaitForMultipleObjects (iActive, hThreads, FALSE, 10000);
if (dwRes == WAIT_TIMEOUT) {
DWORD dwNow = GetTickCount ();
for (i = 0 ; i < iActive ; ++i) {
if (dwNow - dwTicks[i] > 3600000) {
wprintf (L"Thread 0x%08x is running for over an hour\n", hThreads[i]);
dwTicks[i] += 300000; // check in 5 minutes
}
}
continue;
}
if ((dwRes >= WAIT_OBJECT_0) && (dwRes < WAIT_OBJECT_0 + (DWORD)iActive)) {
i = dwRes - WAIT_OBJECT_0;
CloseHandle (hThreads[i]);
if (i < iActive - 1) {
hThreads[i] = hThreads[iActive - 1];
dwTicks[i] = dwTicks[iActive - 1];
}
hThreads[iActive-1] = NULL;
dwTicks[iActive-1] = 0;
iActive--;
if (iRuns > 0) {
dwTicks[iActive] = GetTickCount ();
hThreads[iActive] = CreateThread (NULL, 0, ClientReadThread, NULL, 0, NULL);
if (hThreads[iActive]) {
wprintf (L"New thread created (0x%08x)\n", hThreads[iActive]);
--iRuns;
} else
wprintf (L"Failed to create new thread, error 0x%08x %d\n", GetLastError (), GetLastError ());
}
} else {
wprintf (L"Error in main thread (0x%08x %d)\n", dwRes, dwRes);
break;
}
}
wprintf (L"All done!\n");
return 0;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -