Wednesday, 3 June 2020

Voice Call Bot : Bashing NHS England's appointment booking system

What do you do when you have to call a number for availing a service, but the number being called is so contended that your call never goes through?


The COVID19 crisis has exposed the limitations of several such systems. Case in point, England's NHS (National Health Service). To get a doctor's appointment you have to call them. There is no provision for getting the appointment online. So, if you have to get an appointment for, say getting blood sugar level tested, you will be required to call them, but since the health services are already overwhelmed by COVID19 crisis, and there are thousands of people trying to call them, you, simply won't be able to make the call. Either the network would be busy, or there would be other such problem.

Similar was (and probably still is) the situation in USA. COVID19 has caused unprecedented level of unemployment, leading to a surge in calls to unemployment offices for people wanting to avail unemployment benefits. There have been reports of people calling them hundreds, and thousands of time without success.

The Bot

While people get frustrated, computers are good at doing these mundane, and repetitive tasks.
Our aim is to make a bot which calls NHS on our behalf, and when it is successful, somehow connects us to it.

Here is a state diagram explaining the process.


The bot will keep on trying to call NHS till someone answers. It will then call the user on the given number, and will connect the two calls. The user will be able to talk on the call to NHS as on a normal call.

Prerequisites 

  1. Twilio subscription [Link]
    Twilio has a rich set of telephony API. The downside is that to be able to make calls to real numbers, you will have to convert your account into a normal account if it is a trial account right now. For this you will have to load at least 20 USD in your account. This money will be utilized for making calls.
  2. A server to run the bot. The server has to have a public IP. I purchased a VPS from Digital Ocean for 5 USD a month. You can find cheaper VPS on lowendbox.com. Alternatively you can also use your local machine, however you may have to configure NAT forwarding if you want to make it accessible from public. See configuring VPS section below for more options.

Configuring Twilio 

When you load at least 20 USD in your Twilio account, your account will non longer be in trial, and you will be able to make calls to real numbers. In trial mode, you are only allowed to call Twilio provided numbers. It is a good idea to use these numbers to test your code before investing money.

You also need a number which will be used for caller identification (Caller ID) when making calls from Twilio.
You can either register the number you already have, or buy a new one from Twilio. The former will not cost you anything extra.
For registering an existing number, go to https://www.twilio.com/console/phone-numbers/verified.
For buying a new number you can go to https://www.twilio.com/console/phone-numbers/search.
I used my existing number for the purpose.

Configuring VPS

You will need VPS for 2 reasons.
1. Run script which will invoke Twilio API to make the call.
2. Host an XML file which will tell Twilio what to do once someone answers the call. This will be in TwiML, Twilio Markup language. 
3. Get status feedbacks. As your call progresses through various stages, Twilio will notify you by sending this information to a configured URL. In Twilio's terminology, this is called StatusCallbackEvent.




This is the timeline of a typical Twilio call (image taken from https://www.twilio.com). For each of these stages, when it is reached, the given URL will received information. This is how your code will come to know the status of your call. The call state which is of most interest to us is answered. This is the point which indicates that NHS has picked up our call, and Twilio should call the user on the given mobile number, and then connect the 2 calls.

To save money, you can run the script on your local machine, and get call status feedback on a php script hosted on a website for free. I gave https://infinityfree.net a shot for free hosting, but it didn't work out for me, as the site sets some cookies automatically, and the twilio API wasn't able to handle them, maybe there is a way, but I didn't explore further.

The VPS I purchased had Ubuntu 18.04, with apache2, lib-apache2-mod-php, python, python-pip packages installed. I also had to install Twilio python package from pip.


pip install twilio

Writing scripts

I wrote 2 scripts. One in python, the other in PHP. While the Python script calls Twilio API, the PHP script provides an endpoint where Twilio can send call status events.

The python script

 
from twilio.rest import Client
import os.path
import time
import pdb

# Your Account Sid and Auth Token from twilio.com/console
# DANGER! This is insecure. See http://twil.io/secure
account_sid = 'ACXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX'
auth_token = 'YYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYY'
client = Client(account_sid, auth_token)

filePath='/var/www/html/callid.txt'

while True:
    call = client.calls.create(method='GET',  status_callback='http://xxxx.com/yyy.php', status_callback_event=['initiated', 'answered', 'completed'], status_callback_method='POST', url='http://xxxx.com/response.xml', to='+44xxxxxxxxxx', from_='+91xxxxxxxxxx')
    print(call.sid)
    while True:
        if os.path.isfile(filePath):
            print("file exists")
        else:
            print("file does not exist. sleep 5s ...")
            time.sleep(5)
            continue
        try:
            print("sleep 5s ...")
            time.sleep(5)
            with open(filePath) as f:
                fline = f.readline()
                print(fline)
                if(len(fline) == 0):
                    continue
                ftokens=fline.split(' ')
                fcid    =   ftokens[0]
                fstatus =   ftokens[1]
                if str(call.sid).upper() == fcid.upper():
                    print("cid match")
                    if(fstatus.lower() in ["busy", "canceled", "completed", "failed", "no-answer"]):
                        print("call ended. dialing again in 60s ...")
                        time.sleep(60)
                        break
        except IOError:
            print("file open error")

You can get account_sid, and auth_token from twilio console (https://www.twilio.com/console).
Additionally, you will have to configure following parts in the script.
  1. url='http://xxxx.com/response.xml'
    This this the XML file which has Directions written in TwiML.
    Once a call is answered Twilio reads this file to decide the
    actions which have to be taken. For example you can instruct
    Twilio to say something, play an audio file, etc. In our XML file we instruct Twilio to call the user.
    <Response>
            <Say voice="alice">Hello</Say>
            <Dial>+91xxxxxxxxxx</Dial>
    </Response>
    
    The XML file tells twilio to say hello once call is picked up,
    and then dial the given number. The given number will be
    automatically joined to the current call.
      
    

  2. status_callback='http://xxxx.com/yyy.php'
    This is the URL on which Twilio sends call status data as call progresses. Once this URL receives information that a call has ended, our python script tries again.
  3. to='+44xxxxxxxxxx', from_='+91xxxxxxxxxx'
    These are the to, and from numbers. In my case to was NHS's number, and from was my number which I had registered with Twilio for caller ID.

The PHP script

The PHP script is meant to receive call status information from Twilio. The PHP, and Python scripts work together to decide when a call failed, so that we can try calling again.

<?php
$req_dump = print_r($_REQUEST, TRUE);
$fp = fopen('request.log', 'a');
fwrite($fp, $req_dump);
fwrite($fp, "#\n");
fclose($fp);

$fp2 = fopen('callid.txt', 'w');
fwrite($fp2, $_REQUEST['CallSid']);
fwrite($fp2, ' ');
fwrite($fp2, $_REQUEST['CallStatus']);
//fwrite($fp2, '\n');
fclose($fp2);

?>
<!DOCTYPE html>
<html>
</html>

This PHP script writes to a file named callid.txt which is monitored by the Python script.
When Python script makes a call it gets an ID identifying the call (call.sid). When it sees that the
status of the call it just placed is one of "busy", "canceled", "completed", "failed", "no-answer", it realises that call has ended, and it is time to try again.

One thing to note here is that the python script will keep calling even when call is disconnected after being answered. Since the user will get a call as soon as call is answered, the user can then manually kill the script, so I didn't feel like investing time on this.

Running the bot

Put the PHP script in apache's directory, and create two files, callid.txt, and request.log in it, with read/write permissions given so that both PHP, and Python scripts are able to access them.

Configure the python script as explained above, and then just run it.
Make sure to kill it once you get a call on your phone.

Parting thoughts

As of now it has been 6 hours since I started the script. Probably the NHS number I have is unattended.
The script does work, as before running it on NHS number I tested it with several US, UK, and Indian numbers.

My initial Idea was to script it using Tasker on Android, but Android sufferes from a major drawback. There is no public API which would tell us if the call has been answered. The dialer on Android starts the call timer only when the call gets answered, this means the OS is aware, but has not exposed any API for it. See the comment on PreciseCallState hidden Android API on the following stack overflow page - https://stackoverflow.com/questions/9684866/how-to-detect-when-phone-is-answered-or-rejected

References

  1. Samples and tutorials on making call using Twilio API - https://www.twilio.com/docs/voice/make-calls?code-sample=code-make-a-call-and-monitor-progress-events&code-language=PHP&code-sdk-version=6.x#specify-a-recordingstatuscallback
  2. Call recording API - https://www.twilio.com/docs/voice/api/call-resource#fetch-a-call-resource 
  3. Twilio conference calls (Note that we didn't use this API in our bot) - https://www.twilio.com/docs/voice/tutorials/how-to-create-conference-calls-python
     

Saturday, 14 July 2018

Getting descriptors from a USB device (Windows) - PART 2 (Getting the device descriptor)

As explained in Part 1, the Device descriptor is the most fundamental descriptor a USB device has.

Getting USB Descriptor : Basics

Getting any descriptor from a USB device is a two step process. We first prepare an input buffer in which we put information about the descriptor we need to get, for ex. in the buffer we will tell the type of descriptor we want to get. We then pass the buffer to an IOCTL call, which fills the required output in an output buffer. The ioctl to be used for getting descriptors will be IOCTL_USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION.

IOCTL call
For the sake of simplicity, we will use the same buffer for input and output. This is how Microsoft's USBView program fetches descriptors. It is open sourced by Microsoft, and during my initial days of learning I found the source code to be immensely helpful, specially the enum.c file in the source, which fetches all the descriptors. Github Link.

The buffer consists of two parts - a part in which we specify the descriptor we want to get from the USB device, and a part in which the IOCTL call fills the required information. This information can be for eg. a Device descriptor if we are requesting it.
The first part is typically the same (not always), and consists of a structure called USB_DESCRIPTOR_REQUEST. The second part varies according to the descriptor we are requesting.
Out common buffer would look something like the following.

IOCTL Buffer
Conceptually, the location of a USB device is given by handle of the parent hub, and the port number of the hub to which the USB device is attached. Thus you will see that whenever an IOCTL call is made to get descriptor from a USB device we will always be using these two things for identifying the device.
Let's have a look at some of the important members of USB_DESCRIPTOR_REQUEST.

The USB_DESCRIPTOR_REQUEST Structure

This structure as discussed is used to tell the IOCTL call what information we require, and from which device. The following definition of the structure is copied from usbioctl.h file (located at c:\Program Files (x86)\Windows Kits\10\Include\10.0.17134.0\shared\usbioctl.h on my computer).

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
typedef struct _USB_DESCRIPTOR_REQUEST {
    ULONG ConnectionIndex;
    struct {
        UCHAR bmRequest;
        UCHAR bRequest;
        USHORT wValue;
        USHORT wIndex;
        USHORT wLength;
    } SetupPacket;
    UCHAR Data[0];
} USB_DESCRIPTOR_REQUEST, *PUSB_DESCRIPTOR_REQUEST;

  1. Connection Index : Port number of the USB hub to which a device is connected.
  2. bmRequest : It is a bit-field which specifies direction of request, type of request, and recipient. For getting USB descriptors this will always be 0x80.
  3. bRequest: The request being made. Since we are trying to get descriptors, this will be set to USB_REQUEST_GET_DESCRIPTOR. This is a macro which evaluates to 0x06.
  4. wValue : Request dependent parameter. For getting descriptors, this will specify the descriptor we want. Its format would be something like this.

    wValue = (DescryptorType << 8)  | descriptorIndex

    Descriptor index is used when we have several descriptors of the same kind. For ex. it will be used for getting string descriptors, interface descriptors, etc. Since there can be only one device descriptor in a device, the descriptor index will be zero. For getting Device Descriptor, the wValue field will be:

    wValue = (USB_DEVICE_DESCRIPTOR_TYPE << 8 | 0)
  5. wIndex : This is again a request dependent parameter. This will not be used when getting Device descriptors, but for ex. if we want to get string descriptors this field will specify the language ID.
  6. wLength : This in technical terms specifies the number of bytes to be transferred in the data phase of a control request. Do not get overwhelmed by it. In simpler terms this corresponds to the data we are expecting to get from the device. For ex. if we are trying to get Device descriptor, this field will be set to sizeof(USB_DEVICE_DESCRIPTOR). The term data phase relates to the mechanism of data transfer on the USB bus - how a transfer is divided into stages, phases, frames, etc. This is beyond the scope of this post. Refer USB Complete book by Jan Axelson.
  7. Data: Bytes following this member correspond to the output that the ioctl gives.

The SetupDi_ , and CM_ API in Windows

SetupDi_ API in windows is a set of API which can be used to interact with devices present on a system. For ex. If you want to get names of all the monitors connected to a system, use this; if you want to get information about all the USB devices present in the system, use this. Similarly the CM_ API can be used to get information about devices. 
Di, and CM specify the prefixes that the functions in the API sets have, ex. SetupDiGetClassDevs(), CM_Get_Parent(), etc.
To enumerate all the USB devices in the system, we will have to use the following code.


 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
    /*A set containing info about all USB devices present on the system*/
    HDEVINFO usbDeviceInfoSet = SetupDiGetClassDevs(&GUID_CLASS_USB_DEVICE, NULL, NULL, (DIGCF_PRESENT | DIGCF_DEVICEINTERFACE));

    /*Iterate over the set to obtain info about each device in it*/
    SP_DEVINFO_DATA deviceData;
    deviceData.cbSize = sizeof(SP_DEVIFO_DATA);

    for(int i = 0; SetupDiEnumDeviceInfo(usbDeviceInfoSet, i, &deviceData); i++)
    {
        /*The tuple <usbDeviceInfoSet, deviceData> uniquely identifies a USB device in the system*/
    }

We will not be looking more into these API. The above code will be enough for further exploration. We will encounter more functions from these API sets as we progress.

Getting the Device Descriptor

Now that we have understood the basics, let us move to actually getting the device descriptor of a USB device. Steps 1 to 3 are for getting information from SetupDi_* API, and if already familiar with the API, you can directly jump to step 4.

Step 1: Get <usbDeviceInfoSet, deviceData> tuple

As we learned previously the tuple will uniquely identify a USB device. Use the code given above to enumerate through all devices, and get the tuples for them. To simplify things we will simply be getting device descriptors of all USB devices in the system.

Step 2: Get parent hub handle

We will use the deviceData member from the tuple to get DEVINST structure of the parent device. The parent device of a USB device will always be a HUB.
1
2
DEVINST parentDevInst=0;
 CM_Get_Parent(&parentDevInst, deviceInfoData.DevInst, 0);

Note that we used deviceInfoData.DevInst in the above code. Using parentDevInst we must get device path of the parent device. For this we must iterate through all the hubs on the system using the SetupDi_ APIs we used for USB devices, but this time using GUID_CLASS_USBHUB, instead of GUID_CLASS_USB_DEVICE. Once we have the <usbDeviceInfoSet, deviceData> tuple for the USB hubs, We will compare the DEVINST  with parentDevInst obtained above. For the hub which matches, we can use SetupDiGetDeviceInterfaceDetail() function to get SP_DEVICE_INTERFACE_DETAIL_DATA structure, which contains the device path.

Instead of going the longer way, I have used a shortcut (described here - stackoverflow.com) to get parent device path directly from parentDevInst. The complete code for getting parent hub handle for a USB device is the following.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
    /*A set containing info about all USB devices present on the system*/
    HDEVINFO usbDeviceInfoSet = SetupDiGetClassDevs(&GUID_CLASS_USB_DEVICE, NULL, NULL, (DIGCF_PRESENT | DIGCF_DEVICEINTERFACE));

    /*Iterate over the set to obtain info about each device in it*/
    SP_DEVINFO_DATA deviceData;
    deviceData.cbSize = sizeof(SP_DEVINFO_DATA);

    for(int i = 0; SetupDiEnumDeviceInfo(usbDeviceInfoSet, i, &deviceData); i++)
    {
        /*The tuple <usbDeviceInfoSet, deviceData> uniquely identifies a USB device in the system*/

        /*Get parent hub handle*/
        DEVINST parentDevInst = 0;
        CM_Get_Parent(&parentDevInst, deviceData.DevInst, 0);
        wchar_t deviceId[MAX_PATH];
        CM_Get_Device_ID(parentDevInst, deviceId, MAX_PATH, 0);
        std::wstring devIdWStr(deviceId);

        //convert device id string to device path - https://stackoverflow.com/a/32641140/981766
        devIdWStr = std::regex_replace(devIdWStr, std::wregex(LR"(\\)"), L"#"); // '\' is special for regex
        devIdWStr = std::regex_replace(devIdWStr, std::wregex(L"^"), LR"(\\?\)", std::regex_constants::format_first_only);
        devIdWStr = std::regex_replace(devIdWStr, std::wregex(L"$"), L"#", std::regex_constants::format_first_only);

        constexpr int sz64 = 64;
        wchar_t guidString[sz64];//guid is 32 chars+4 hyphens+2 paranthesis+null => 64 should be more than enough
        StringFromGUID2(GUID_CLASS_USBHUB, guidString, sz64);
        devIdWStr.append(guidString);

        std::wstring& usbHubPath = devIdWStr; //devIdWStr now contains USB hub path
        HANDLE hUsbHub = CreateFile(usbHubPath.c_str(), GENERIC_WRITE, FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL);

        /*hUsbHub now contains the handle to the parent hub of a device*/

    }

Note that this is a modified version of code presented earlier to enumerate USB devices in the system. Also, note that this is a shortcut, a hack, and therefore is not guaranteed to work always. A better (albeit with poorer performance) is the one discussed at the beginning of this step.


Step 3: Get USB port number 

Getting the port number to which a USB device is connected on a hub (the handle to which we obtained in the previous step) is fairly easy. We just have to use SetupDiGetDeviceRegistryProperty() function. Add the following code to the code shown in previous step. To make it easier to understand where this code has to be pasted, the comment "/*hUsbHub now contains the handle to the parent hub of a device*/" is pasted as is from previous code


1
2
3
4
5
6
7
        /*hUsbHub now contains the handle to the parent hub of a device*/

        /*Get port number to which the usb device is attached on the hub*/
        DWORD usbPortNumber = 0, requiredSize = 0;
        SetupDiGetDeviceRegistryProperty(usbDeviceInfoSet, &deviceData, SPDRP_ADDRESS, nullptr, (PBYTE)&usbPortNumber, sizeof(usbPortNumber), &requiredSize);

        /*We now have the port number*/


Step 4: Prepare USB request packet (USB_DESCRIPTOR_REQUEST)

Prepare USB_DESCRIPTOR_REQUEST structure by filling in required information. We have already discussed fields of the structure and the buffer used to send data to and get data from IOCTL, hence we can directly move to code. Again the comment " /*We now have the port number*/" from previous code is kept to give a context of where the following piece of code lies.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
        /*We now have the port number*/

        /*Prepare USB request packet (USB_DESCRIPTOR_REQUEST)*/
        USB_DESCRIPTOR_REQUEST* requestPacket = nullptr;
        USB_DEVICE_DESCRIPTOR* deviceDescriptor = nullptr;
        int bufferSize = sizeof(USB_DESCRIPTOR_REQUEST) + sizeof(USB_DEVICE_DESCRIPTOR);
        BYTE *buffer = new BYTE[bufferSize];

        /*We know from out previous discussion that the first part of the buffer contains the request packet, and latter part contains the data to be filled by the IOCTL - in our case the device descriptor*/
        requestPacket = (USB_DESCRIPTOR_REQUEST*)buffer;
        deviceDescriptor = (USB_DEVICE_DESCRIPTOR*)((BYTE*)buffer + sizeof(USB_DESCRIPTOR_REQUEST));

        //fill information in packet
        requestPacket->SetupPacket.bmRequest = 0x80;
        requestPacket->SetupPacket.bRequest = USB_REQUEST_GET_DESCRIPTOR;
        requestPacket->ConnectionIndex = usbPortNumber;
        requestPacket->SetupPacket.wValue = (USB_DEVICE_DESCRIPTOR_TYPE << 8 | 0 /*Since only 1 device descriptor => index : 0*/);
        requestPacket->SetupPacket.wLength = sizeof(USB_DEVICE_DESCRIPTOR);

Step 5 : Issue IOCTL, and print some data 

Now we simply have to issue the ioctl, passing the prepared request packet, and data buffer.


1
2
3
4
5
6
7
        /*Issue ioctl*/
        DWORD bytesReturned = 0;
        BOOL err = DeviceIoControl(hUsbHub, IOCTL_USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION, buffer, bufferSize, buffer, bufferSize, &bytesReturned, nullptr);

        /*print some data*/
        std::cout << "0x" << std::hex << (int)deviceDescriptor->bDescriptorType << std::endl;  //should be 0x01 for device descriptor
        std::cout << "0x" << std::hex << (int)deviceDescriptor->bDeviceClass << std::endl;

Complete code

The complete code, consisting of all the individual code fragments we have developed so far is the following. Note that before running this code you must add Setupapi.lib in Linker's Additional dependencies. The application I built, and for which the code is given is a Native console application written in C++.

My system configuration :
                   Visual Studio 2017 Professional
                   Windows 10 14393 build



 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
// USBGetDeviceDescriptor.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"
#include <iostream>
#include <Windows.h>
#include <SetupAPI.h>
#include <cfgmgr32.h >
#include <initguid.h>
#include <usbiodef.h>
#include <usbioctl.h>
#include <regex>

void USBGetDeviceDescriptor()
{
    /*A set containing info about all USB devices present on the system*/
    HDEVINFO usbDeviceInfoSet = SetupDiGetClassDevs(&GUID_CLASS_USB_DEVICE, NULL, NULL, (DIGCF_PRESENT | DIGCF_DEVICEINTERFACE));

    /*Iterate over the set to obtain info about each device in it*/
    SP_DEVINFO_DATA deviceData;
    deviceData.cbSize = sizeof(SP_DEVINFO_DATA);

    for(int i = 0; SetupDiEnumDeviceInfo(usbDeviceInfoSet, i, &deviceData); i++)
    {
        /*The tuple <usbDeviceInfoSet, deviceData> uniquely identifies a USB device in the system*/

        /*Get parent hub handle*/
        DEVINST parentDevInst = 0;
        CM_Get_Parent(&parentDevInst, deviceData.DevInst, 0);
        wchar_t deviceId[MAX_PATH];
        CM_Get_Device_ID(parentDevInst, deviceId, MAX_PATH, 0);
        std::wstring devIdWStr(deviceId);

        //convert device id string to device path - https://stackoverflow.com/a/32641140/981766
        devIdWStr = std::regex_replace(devIdWStr, std::wregex(LR"(\\)"), L"#"); // '\' is special for regex
        devIdWStr = std::regex_replace(devIdWStr, std::wregex(L"^"), LR"(\\?\)", std::regex_constants::format_first_only);
        devIdWStr = std::regex_replace(devIdWStr, std::wregex(L"$"), L"#", std::regex_constants::format_first_only);

        constexpr int sz64 = 64;
        wchar_t guidString[sz64];//guid is 32 chars+4 hyphens+2 paranthesis+null => 64 should be more than enough
        StringFromGUID2(GUID_CLASS_USBHUB, guidString, sz64);
        devIdWStr.append(guidString);

        std::wstring& usbHubPath = devIdWStr; //devIdWStr now contains USB hub path
        HANDLE hUsbHub = CreateFile(usbHubPath.c_str(), GENERIC_WRITE, FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL);

        /*hUsbHub now contains the handle to the parent hub of a device*/

        /*Get port number to which the usb device is attached on the hub*/
        DWORD usbPortNumber = 0, requiredSize = 0;
        SetupDiGetDeviceRegistryProperty(usbDeviceInfoSet, &deviceData, SPDRP_ADDRESS, nullptr, (PBYTE)&usbPortNumber, sizeof(usbPortNumber), &requiredSize);

        /*We now have the port number*/

        /*Prepare USB request packet (USB_DESCRIPTOR_REQUEST)*/
        USB_DESCRIPTOR_REQUEST* requestPacket = nullptr;
        USB_DEVICE_DESCRIPTOR* deviceDescriptor = nullptr;
        int bufferSize = sizeof(USB_DESCRIPTOR_REQUEST) + sizeof(USB_DEVICE_DESCRIPTOR);
        BYTE *buffer = new BYTE[bufferSize];

        /*We know from out previous discussion that the first part of the buffer contains the request packet, and latter part contains the data to be filled by the IOCTL - in our case the device descriptor*/
        requestPacket = (USB_DESCRIPTOR_REQUEST*)buffer;
        deviceDescriptor = (USB_DEVICE_DESCRIPTOR*)((BYTE*)buffer + sizeof(USB_DESCRIPTOR_REQUEST));

        //fill information in packet
        requestPacket->SetupPacket.bmRequest = 0x80;
        requestPacket->SetupPacket.bRequest = USB_REQUEST_GET_DESCRIPTOR;
        requestPacket->ConnectionIndex = usbPortNumber;
        requestPacket->SetupPacket.wValue = (USB_DEVICE_DESCRIPTOR_TYPE << 8 | 0 /*Since only 1 device descriptor => index : 0*/);
        requestPacket->SetupPacket.wLength = sizeof(USB_DEVICE_DESCRIPTOR);

        /*Issue ioctl*/
        DWORD bytesReturned = 0;
        BOOL err = DeviceIoControl(hUsbHub, IOCTL_USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION, buffer, bufferSize, buffer, bufferSize, &bytesReturned, nullptr);

        /*print some data*/
        std::cout << "0x" << std::hex << (int)deviceDescriptor->bDescriptorType << std::endl;  //should be 0x01 for device descriptor
        std::cout << "0x" << std::hex << (int)deviceDescriptor->bDeviceClass << std::endl;


    }
    
}

int main()
{
    USBGetDeviceDescriptor();
    return 0;
}

Output

Here is the annotated output from one run of the application on my system.
Sample run

References

  1. USB request data structure explained on USB in a nutshell - https://www.beyondlogic.org/usbnutshell/usb6.shtml
  2.  Information on data stage, and related stuff in chapter 5 of USB COMPLETE book (5th edition) by Jan Axelson. Must read this book if you are developing any non trivial USB application.
  3. Getting handle to parent hub directly from <usbDeviceInfoSet, deviceData> tuple of a device - https://stackoverflow.com/q/28007468/981766
  4. SPDRP_ADDRESS property gives the port number in case of USB devices is mentioned here - https://web.archive.org/web/20100109085245/http://msdn.microsoft.com/en-us/library/dd852021.aspx
  5. A list of USB class codes (till USB 1.0) - http://www.usb.org/developers/defined_class

Tuesday, 12 June 2018

Getting descriptors from a USB device (Windows) - PART 1 (Introduction)

This is the first post of my 3 part series on USB. This introduces some basic concepts, which we will use in PART 2, where we will be fetching the Device descriptor from a USB device, and also in PART 3 where we will try to understand what a billboard device is, how is it related to USB-C alternate mode, and how to get the billboard capability descriptor. If some terms don't make sense to you, don't worry. They will be explained as we progress. You can also directly jump to Part 2, and Part 3 if you already know the basics.

USB Introduction

The 3 letter acronym USB stands for Universal Serial Bus. Why Universal, you say? This is because USB in its most basic form can be seen as a conduit to allow host and devices to copy to-and-fro buffers. The capacity to transfer bytes from host to device and back is all USB tries to offer. The way a device, and its host interprets those bytes gives rise to the myriad of USB devices we see all around us. Therefore, USB is not tied to a single device, or functionality, it can be used to implement any feature which can be expressed in terms of flow of data (bytes) between two participating nodes.

USB as a conduit
USB as a conduit

Any USB device has two mechanisms in place for proper connection and for exchange of data.
Once mechanism is by which a host learns about a USB device. Another mechanism is by which the actual transfer of data takes place. The former is implemented via descriptors, which we will study in next section. The latter is implemented by the concept on end points.

An end point is nothing but a part on device which has buffers which can be sent to a host, or empty buffers which can receive data from host. A USB device implementing a camera would place the pixel data on an end point, which will then be read by the host.

Lets consider a USB device having multiple functionalities on it. Let's say it has a camera, a mic, and a data storage area (like a pen drive). Although we have a single device, but we have multiple "interfaces". An interface is logical grouping of end points. An interface for camera will have end points which are only involved in sending, and receiving camera related data to, and from the host.
Our device in discussion can be said to have 3 interfaces.

All interfaces, and end points are numbered. Numbering of interfaces start at 1, and continues till 255. Numbering of end points start from 0, and end at 255. Every interface must implement end point 0. End point 0 is a special end point which is only responsible for transmission of control information. For transfer of data (eg. pixel data from our USB camera) end point 1 onward can be used.

More complex USB devices can even combine several interfaces, something called Interface association (described by IAD - Interface Association Descriptors), which will not explore any further.

USB Hierarchy

The USB specification allows for a tree/star like hierarchy for all devices involved. At the root of a tree would be USB controller. It can be though of as a chip, or an IC which manages everything on USB bus. Much like the brain in our nervous system. Different devices can connect to a host via a set of intervening hubs. Hub is exactly the hub you see lying all around you. A USB controller has connected to it a special kind of hub, called the root hub. There can only be a single root hub between a USB controller, and a USB device. To the root hub a device can be connected either directly or via a series of hubs. A host can have multiple USB controllers.


USB Descriptors

A USB device has various data structures, called descriptors which store in them the properties of the USB device, like USB class, USB protocol supported (1.1, 2.0, 3.0, etc.). A descriptor can either describe some general properties of the entire device, or it may describe only a specific functionality of the device. When you connect a USB device to a computer, it is through these descriptors that the OS learns that the device is a mouse, or a keyboard, and so on.

Following are some of the type of USB descriptors you may find on a device. This list is not exhaustive.

  1. Device descriptor
    This is the very first descriptor a host reads from device. All USB devices (except the most simple ones perhaps, like USB-C analog audio accessory mode - the USB-C to eaphone jack converters you see) must have this descriptor. This can specify the USB class in bDevice class field. If this field is 0x00 then the USB class is specified for each interface separately and is given by the corresponding interface descriptor. What this means that the device has interfaces belonging to different classes (as our multi functional USB device discussed earlier).

  2. Configuration descriptor
    This describes the various configurations which a device can support. A device can operate only in one configuration at a time. Most devices are simple and support only a single configuration. Things such as how the device is powered (if self/bus - powered - only USB1.1, newer devices report power the device needs from the bus in bMaxPower field in units of 2 milli ampere), max power consumption, if the device supports remote wake up, and number of interfaces. When a configuration descriptor is read, it returns its entire sub hierarchy comprising of all related interface, and endpoint descriptors.

  3. Interface descriptor
    Interface refers to a feature or a function a USB device specifies. A feature may use more than 1 interface required (in which case an Interface Association descriptor - IAD must also be used). For eg. a camera on the USB device may use one interface for video, and another for audio. This can also specify class type for an interfaces, if different interfaces on the device belong to different USB classes.

  4. Endpoint descriptor
    An Endpoint in USB refers to source or sink of data. You can visualize it as a buffer of bytes kept on a device. bNumEndPoints field of the interface descriptor specifies the number of end points in the interface except end point zero (control end point). All interfaces must have end point zero, and if there are no end points for the interface other than end point zero this field is 0. Each end point except the 0 end point must have a descriptor. End point zero doesn't have a descriptor.
    The descriptor specifies direction of data transfer (host-to-device/device-to-host), type of transfer (control/isochronous/bulk/interrupt), and address of the end point.

    The following image shows the hierarchical relation between Device, Configuration, Interface, and Endpoint descriptors.

    USB descriptors
    USB descriptors

  5. Binary Object Store (BOS) descriptor and device capability descriptor
    These two descriptor types were introduced in USB 3.0, and USB 2.0 Low Power Mode specification. Their aim is to provide an extensible framework to give information specific to a technology or a device. Capability descriptors give information about certain USB capabilities. For eg. if the device supports Wireless USB, there will be a Wireless USB capability descriptor in the device. An application wanting to know more about the wireless USB capability of the device can read the descriptor. The format of each capability descriptor can be different (except for the standard fields like bLength, bDescriptortype, etc. which all USB descriptors should have), this gives the aforementioned extensibility. Right now we have the following capability types (the values in Hex next to them can be ignored for now).         
               1. Wireless USB (0x01)
               2. USB 2.0 extension (0x02)
               3. Superspeed USB (0x03)
               4. Container ID (0x04)
               5. Platform (0x05)
               6. Power delivery (0x06)
               7. Battery info (0x07)
               8. Power delivery consumer port (0x08)
               9. Power delivery provider port (0x09)
               10. Superspeed plus (0x0A)
               11. Precision time measurement (0x0B)
               12. Wireless USB extension (0x0C)
               13. Billboard (0x0D)
               14. 0x00, 0x0E - 0x0F are reserved
    The BOS descriptor functions as a base descriptor for one or more device capability descriptors. Thus if the USB device supports (say) Wireless USB, Superspeed USB, and Superspeed Plus capabilities, then we will have 3 capability descriptors following a BOS descriptor.
    BOS descriptor, and Capability descriptors
    BOS descriptor, and Capability descriptors
    Individual capability descriptors cannot be fetched, always the BOS + all capability descriptors are fetched as s single unit. The BOS descriptor can be fetched individually.

  6. String descriptor
    In all other descriptors, whenever there is a need for providing a string (device name, url for further information, etc.), an index into string descriptor is given. For eg. iManufacturer field of device descriptor refers to manufacturer string. This field is not a string, instead this string gives an integer which refers to string descriptor where the string is stored. For example to get manufacturer name, we will have to fetch DeviceDescriptor->iManufacturerth string descriptor. The string descriptor 0 occupies a special positing among all the string descriptors. It stores a list of all language IDs. For eg. if you would like to know if a USB device has strings for English (US) language, the language ID for which is 0x0409, you will have to fetch string descriptor 0, and check if 0x0409 is their in the list of IDs.
Common USB descriptor

This is not a descriptor present in a USB device per say, but is the data structure which represents the common fields that all USB descriptors may have. In windows this structure is called USB_COMMON_DESCRIPTOR (usbspec.h), but using a structure provided by OS API is not necessary, as the definition is given by USB spec, hence you can define the structure on your own.
Common USB descriptor
Common USB descriptor
This can be used to iterate over descriptors without going into details of each descriptor. For eg. if we are only interested in knowing about device descriptor in a list of USB descriptors provided to us, we can iterate through all descriptors using this common data structure, and check bDescriptorType for each. Device descriptor will have the field bDescriptorType set to 0x01.

IOCTLs - Input/Output control

Like system calls IOCTLs are also a way to request an operation from OS kernel. However while system calls are implemented by an OS, IOCTLs are specific to devices, and handled by the corresponding device drivers. Thus while system calls remain static for a system, IOCTL for a device can change with a newer driver, and will be different for different devices. In Linux a device driver exposes a file in /dev file system. An applications opens a handle to this device, and requests ioctl using ioctl() system call. In Windows an application first finds the device path (don't confuse it with device instance path shown in device manager). It then obtains a handle using CreateFile(), and requests ioctl using DeviceIoControl() function. Let's say tomorrow a new USB device comes which has a driver only provided by the vendor. How does an application in the user space now communicate with the device? As you might have guessed, the vendor must provide a set of IOCTLs which the application can use.

References

  1. A more comprehensive list of language ID can be found in the following document - Link.
  2. USB in a nutshell has a ton of information written in a very accessible manner (in terms of difficulty to read). The following page on the site talks about USB descriptors - Link.

Thursday, 23 February 2017

Vector graphics in MFC/Visual C++

Although MFC, and Visual C++ are old technologies, yet they have supported vector graphics for long. Do not be too excited though, you won't be able to load up your SVG file in an MFC application just yet, and for that you will still require a non Microsoft library. But as the topic suggests, we will be able to load vector graphics.

In Windows vector graphics is natively supported by meta files (or enhanced meta files - EMF). These files can store both a raster image, and a vector image. Like any other vector image file format, an EMF file stores image in the form of commands which are to be issued to a graphics device. Thus, the file is capable of storing vector graphics. More about these files can be found at blogs.msdn.microsoft.com.

With the advent of high resolution displays, and DPI scaling, it becomes even more significant than before that we use vector graphics in our applications. In this post we will go through the process of creating a vector image in Inkcape, and then displaying it in an MFC application (same process can be used for any other win32 app created in Visual C++ without MFC).

Creating EMF Vector graphics in Inkscape


Let's create some clouds in Inkscape, we will call it clouds.svg. Note that it is important to save the image first in SVG so that later on we are able to make modifications to it. EMF file may also permit modifications, but I think SVG would be better supported by Inkscape.

Clouds.svg
Now from Inkscape, save the image as an EMF file (say clouds.emf).

Save as EMF

Displaying vector EMF file in an MFC application


Create a simple MFC dialog based application.








In Dialog's OK button's click handler, write the following code.




void CmetaFileDlg::OnBnClickedOk()
{
    // TODO: Add your control notification handler code here
    CClientDC client(this);

    HENHMETAFILE hEmf = GetEnhMetaFile(L"clouds.emf");
    
    if(hEmf==NULL)
    {
        TRACE("Error getting enhanced meta file\n");
    }
    else
    {
    TRACE("Success - enhanced metafile");
    CRect rc;
    GetClientRect(rc);
    PlayEnhMetaFile(client,hEmf,&rc);
    }

    //CDialogEx::OnOK(); //preventing Dialog from closing
}

Now compile and run the application. On pressing "OK" button, the application will show our vector image.

MFC application rendering a vector image

Since our image is a vector image, we can vary the third parameter passed to PlayEnhMetaFile() to change the size of displayed image, and we will see no pixellation/blurring. I even modified the code slightly to make the clouds appear on my 4K monitor (yes I have one!). Here is how it looked.

Vector image on 4K display

I was hoping that the background of the clouds would be transparent, as it was when we drew earlier, but it was black. SetBkMode(TRANSPARENT) also didn't help.

Here is the modified code.


void CmetaFileDlg::OnBnClickedOk()
{
    // TODO: Add your control notification handler code here
    CClientDC client(NULL);//draw on desktop

    HENHMETAFILE hEmf = GetEnhMetaFile(L"clouds.emf");
    
    if(hEmf==NULL)
    {
        TRACE("Error getting enhanced meta file\n");
    }
    else
    {
    TRACE("Success - enhanced metafile");
    CRect rc;
    
    rc.top=rc.left=0;
    rc.right=3840; rc.bottom=2160; //4K monitor

    PlayEnhMetaFile(client,hEmf,&rc);
    }

    //CDialogEx::OnOK(); //preventing Dialog from closing
}

References -

  • Creating meta files programmatically - http://www.functionx.com/visualc/gdi/cmetafile.htm
  • EMF File Overview - https://blogs.msdn.microsoft.com/openspecification/2011/06/28/emf-file-overview/
  • Opening an Enhanced Metafile and Displaying Its Contents - https://msdn.microsoft.com/en-us/library/windows/desktop/dd162750(v=vs.85).aspx

Friday, 16 December 2016

Libclang python : hello world!

Many a time we are faced with the challenge of trying to understand large code repositories for various reasons. There is a plethora of tools out there, but sometimes you just get stuck with a problem for which there simply isn't any tool. One such problem hit me today, I wanted to find the call graph of a function, say A, and check where a function, say B lies in it, and what's the call path if I want to go from function A to B.

This is where code analysis libraries enter. They allow us to parse source code in a programmatic way, thus for my case - no more manually exploring the call path.
One such library is libclang (from the awesome CLANG/LLVM project). libclang is for c, but it has python bindings as well, which we are going to explore.

Credits - The following awesome blog helped me in getting started with libclang, and some code, and examples may be from it.

http://eli.thegreenplace.net/2011/07/03/parsing-c-in-python-with-clang

Before you proceed, make sure of the following.

  • LLVM(Clang) is installed, and is present in computer's path
  • minGW is installed, and is present in computer's path
  • You are using 32bit (x86) windows OS (I was unable to use it on x64 windows, I kept getting access violation errors, which is perhaps due to a known bug). I have not tested this on Linux, but it should work on x32 Linux equally well.
  • Install python clang module from "https://github.com/llvm-mirror/clang/tree/master/bindings/python"
    Here are the steps -
       a. Download clang folder from the link
       b. Put it in python's lib folder. On my windows 7 x86, I had to paste it in "C:\Python27\Lib".
           
    If you are not sure where the lib folder is on your system, open a python console, import a module for which you are sure that it exists in your system, say ctypes, and print the value of ctypes.__file__. This will give you an idea about the location of the folder. See the following screenshot.
Finding python lib folder
Finding python lib folder


Let's suppose we have the following C++ code that we want to parse.


//demo_code.cpp
class Person {
};


class Room {
public:
    void add_person(Person person)
    {
        // do stuff
    }

private:
    Person* people_in_room;
};


template <class T, int N>
class Bag<T, N> {
};


int main()
{
    Person* p = new Person();
    Bag<Person, 42> bagofpersons;

    return 0;
}

Let's start writing the python script which will parse this code.

Step 1 Import clang


import clang.cindex

Step 2 Load the C++ source code


index = clang.cindex.Index.create()
translation_unit = index.parse("demo_code.cpp")

Step 3 Get an iterator over the syntax tree of the source code, and print some tokens


print 'Translation unit:', translation_unit.spelling
for child in translation_unit.cursor.get_children():
   print child.spelling

for node in translation_unit.cursor.walk_preorder():
   print "pre-order-traversal",node.spelling,node.get_usr()

See the following screenshot.


python libclang parsing over our source code demo_code.cpp
Few things to note

  1. spelling member in python code tells the name of the token we are referring to.
  2. get_usr() gives us something called as Unified Symbol Resolution, this is like a global name for the token we are referring to. This helps is identifying a token uniquely when we have multiple source files.
Here is the complete python code.


import sys
import clang.cindex

index = clang.cindex.Index.create()
translation_unit = index.parse("demo_code.cpp")
print 'Translation unit:', translation_unit.spelling
for child in translation_unit.cursor.get_children():
    print child.spelling
for node in translation_unit.cursor.walk_preorder():
    print "preorder",node.spelling,node.get_usr()

This is my first attempt at parsing source code via a python script, and I believe it will help me greatly  in debugging and understanding source codes, as I learn more. Hope it helps you as well.

References-
  • Installing clang on windows - http://blog.johannesmp.com/2015/09/01/installing-clang-on-windows-pt2
  • Parsing C++ in Python with Clang - http://eli.thegreenplace.net/2011/07/03/parsing-c-in-python-with-clang
  • libclang slides - http://llvm.org/devmtg/2010-11/Gregor-libclang.pdf