Advanced Services - SMS Connectivity

CPP on Windows (BSD) Sample application using HTTP to send a UCS2 or Unicode message

HSL Mobile Messaging

The following sample application written in CPP on Windows (BSD) sends a UCS2 or Unicode message to a single mobile telephone. The application uses HTTP to communicate with HSL's systems. To send to more than one mobile telephone at a time, separate each mobile number in the destaddr field by a comma (e.g. "447968000111,447720000111,3378100100").

#include <cstring>
#include <cstdio>

#include <windows.h>
#include <wincrypt.h>
#include <winsock2.h>

char* compute_md5_hash(const char* input);
void init_winsock(void);

int main(int argc, char* argv[]) {
    const char* host = "194.247.82.149";
    const int port = 80;
    const char* action = "senducs";
    const char* client_id = "<your client_id>";
    const char* destaddr = "<some fully-qualified MSISDN>";
    const char* ucs2 = "06450631062d0628064b06270020063906270644064500200021";
    const char* secret = "<your secret>";

    // Compute the hash
    int length = strlen(secret) + strlen(ucs2) + strlen(destaddr) + 1;
    char* accumulator = new char[length];
    sprintf(accumulator, "%s%s%s", secret, ucs2, destaddr);
    char* hash = compute_md5_hash( accumulator );

    // Create the URL
    int buffer_size = strlen(action) + strlen(client_id) + strlen(destaddr)
                      + strlen(ucs2) + strlen(hash) + 64;
    char* buffer = new char[buffer_size];
    sprintf(buffer,
            "GET /%s/?client_id=%s&destaddr=%s&message=%s&key=%s HTTP/1.0\r\n\r\n",
            action,
            client_id,
            destaddr,
            ucs2,
            hash);

    // Clean up
    delete[] hash;

    // Initialise winsock
    init_winsock();

    // Create the socket
    int the_socket = socket(AF_INET, SOCK_STREAM, 0);

    // Set up the address
    struct sockaddr_in address;
    address.sin_family = AF_INET;
    address.sin_port = htons(port);
    unsigned long inet_address = inet_addr(host);
    memcpy( &(address.sin_addr), &inet_address, 4 );
    memset( &(address.sin_zero), '\0', 8 ); // zero the rest of the struct

    // Connect
    connect(the_socket, (struct sockaddr *)&address, sizeof(address));

    // Variables used for IO
    int bytes_to_io = strlen(buffer);
    int total_bytes_iod = 0;
    int bytes_iod = 0;

    // Send the request
    while(total_bytes_iod < bytes_to_io
          && (bytes_iod = send(the_socket,
                               buffer + total_bytes_iod,
                               bytes_to_io - total_bytes_iod,
                               0)) != SOCKET_ERROR)
    {
        total_bytes_iod += bytes_iod;
    }

    // Read the response
    buffer_size = 4096;
    buffer = new char[buffer_size];
    bytes_to_io = buffer_size;
    total_bytes_iod = 0;
    while(total_bytes_iod < buffer_size
          && (bytes_iod = recv(the_socket,
                               buffer + total_bytes_iod,
                               buffer_size - total_bytes_iod,
                               0)) > 0)
    {
        total_bytes_iod += bytes_iod;
    }

    buffer[total_bytes_iod] = '\0';

    // Inform the user of the outcome
    fprintf(stdout, "HTTP response:\n%s\n", buffer);

    delete[] buffer;

    closesocket(the_socket);

    // Clean up winsock
    WSACleanup();

    return EXIT_SUCCESS;
}

/*
 * This method computes the MD5 hash of the secret, text and destination
 * address. It should be clear how this can be extended to other hash
 * algorithms and arbitrary data.
 */
char* compute_md5_hash(const char* input)
{
    // Variables used during the hashing process
    HCRYPTPROV cryptoProvider;
    HCRYPTHASH rawHash;

    // Get the cryptographic provider for MD5 hashing
    // NOTE: This call could (potentially) fail and this should be checked for
    CryptAcquireContext(&cryptoProvider,
                        NULL,
                        NULL,
                        PROV_RSA_FULL,
                        CRYPT_VERIFYCONTEXT);

    // Create an object that will perform the hash
    // NOTE: This call could (potentially) fail and this should be checked for
    CryptCreateHash(cryptoProvider,
                    CALG_MD5,
                    0,
                    0,
                    &rawHash);

    // Feed data into the hash
    // NOTE: This call could (potentially) fail and this should be checked for
    CryptHashData(rawHash, (unsigned char*)input, strlen(input), 0);

    // Extract the hash data
    // NOTE: This call could (potentially) fail and this should be checked for
    DWORD hashLength = 16; //(MD5 length)
    unsigned char* hashData = new unsigned char[hashLength];
    CryptGetHashParam(rawHash, HP_HASHVAL, hashData, &hashLength, 0);

    // Create a hex-encoded string of the hash bytes
    char lut[] = { '0', '1', '2', '3', '4', '5', '6', '7',
                   '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
    char* hash = new char[33];
    for(int i = 0; i < 16; i++) {
        hash[2 * i] = lut[(hashData[i] & 0xF0) >> 4];
        hash[2 * i + 1] = lut[hashData[i] & 0x0F];
    }
    hash[32] = '\0';

    // After processing, cryptoProvider and hasher must be released.
    if(rawHash) {
        CryptDestroyHash(rawHash);
    }
    if(cryptoProvider) {
        CryptReleaseContext(cryptoProvider, 0);
    }

    delete[] hashData;

    return hash;
}

void init_winsock(void)
{
    WORD wVersionRequested;
    WSADATA wsaData;
    int err;

    wVersionRequested = MAKEWORD(2, 2);

    err = WSAStartup( wVersionRequested, &wsaData );
    if(err != 0) {
        fprintf(stderr, "no winsock was found\n");
        exit(EXIT_FAILURE);
    }

    /* Check that the Winsock version installed is of a high-enough version. */
    if(LOBYTE(wsaData.wVersion) != 2 || HIBYTE(wsaData.wVersion) != 2)
    {
        WSACleanup();

        fprintf(stderr, "no suitable winsock was available\n");
        exit(EXIT_FAILURE);
    }
}

ucs2_http.cpp


Copyright © Hay Systems Ltd 2004

Owner: support@haysystems.com 20 September 2004

Sample code link | Developers section link