Advanced Services - SMS Connectivity

CPP on Windows (BSD) Sample application using HTTP to send an EMS message

HSL Mobile Messaging

The following sample application written in CPP on Windows (BSD) sends an EMS 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 = "submitsm";
    const char* client_id = "<your client_id>";
    const char* destaddr = "<some fully-qualified MSISDN>";
    const char* shortmessage = "7C0C7A00424547494E3A494D454C4F44590D0A5645525" \
        "3494F4E3A312E320D0A464F524D41543A434C415353312E300D0A4D454C4F44593A6" \
        "43323633364332363336433723264332363336433653323663365332366336733613" \
        "3236733613323673361337232613323673361330D0A454E443A494D454C4F44590D0A";
    const char* secret = "<your secret>";

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

    // Create the URL
    const char* pattern = "GET /%s/?client_id=%s&destaddr=%s&esm=64" \
        "&shortmessage=%s&key=%s HTTP/1.0\r\n\r\n";
    int buffer_size = strlen(action) + strlen(client_id) + strlen(destaddr)
        + strlen(shortmessage) + strlen(hash) + 64;
    char* buffer = new char[buffer_size];
    sprintf(buffer,
            pattern,
            action,
            client_id,
            destaddr,
            shortmessage,
            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);
    }
}

ems_http.cpp


Copyright © Hay Systems Ltd 2009

Owner: support@haysystems.com 20 September 2004

Sample code link | Developers section link