c++httpwinsock2philips-hue

Getting no response from bridge while trying to control Philips Hue Lights


I was trying to write some C++ code to control my Philips Hue lights. After using the browser debug tool to figure out my bridge's IP and adding a user to control the lights with, I tried to replicate the messages sent by my browser in code to create my own routines.

This is the code I'm using:

#include <winsock2.h>
#include <ws2tcpip.h>
#include <stdio.h>
#include <string>

#pragma comment(lib, "Ws2_32.lib")
#define PORT "80"

int main() {
    const char* adress = "192.168.178.x";

    // Initializing Winsock
    WSADATA wsaData;

    int iResult = WSAStartup(MAKEWORD(2, 2), &wsaData); //MAKEWORD(2, 2) specifies the version
    if (iResult != 0)
    {
        printf("WSAStartup failed: %d\n", iResult);
        return 1;
    }

    // Data structure to hold info for the socket
    struct addrinfo *result = NULL,
                    *ptr = NULL,
                    hints;

    ZeroMemory(&hints, sizeof(hints));
    hints.ai_family = AF_INET; // Only using IPv4 adresses
    hints.ai_socktype = SOCK_STREAM; // TCP socket
    hints.ai_protocol = IPPROTO_TCP;

    // Converting adress to readable format and stuffing it into result.
    iResult = getaddrinfo(adress, PORT, &hints, &result);
    if (iResult != 0)
    {
        printf("getaddrinfo failed: %d\n", iResult);
        WSACleanup();
        return 1;
    }

    // Actually creating a socket
    SOCKET ConnectSocket = INVALID_SOCKET;

    ptr = result;

    // Creating socket with previously initialized data
    ConnectSocket = socket(ptr->ai_family, ptr->ai_socktype, ptr->ai_protocol);
    if (ConnectSocket == INVALID_SOCKET)
    {
        printf("Error at socket(): %ld\n", WSAGetLastError());
        freeaddrinfo(result);
        WSACleanup();
        return 1;
    }

    // Connecting to the server socket
    iResult = connect(ConnectSocket, ptr->ai_addr, (int)ptr->ai_addrlen);

    // Error checking
    if (iResult == SOCKET_ERROR)
    {
        closesocket(ConnectSocket);
        ConnectSocket = INVALID_SOCKET;
    }

    freeaddrinfo(result);

    if (ConnectSocket == INVALID_SOCKET)
    {
        printf("Unable to connect to server!\n");
        WSACleanup();
        return 1;
    }


    /////////////////////////////////////////////////////////
    // ACTUAL MESSAGE
    std::string request = "GET /api/<username>/lights/2 HTTP/1.1\r\n";
    request.append("Host: 192.168.178.x\r\n");
    request.append("\r\n");

    ////////////////////////////////////////////////////////

    printf("Request:\n%s", request.c_str());

    // Send message
    iResult = send(ConnectSocket, request.c_str(),(int) request.size(), 0);

    // Error check
    if (iResult == SOCKET_ERROR)
    {
        printf("send failed: %d\n", WSAGetLastError());
        closesocket(ConnectSocket);
        WSACleanup();
        return 1;
    }

    printf("Bytes Sent: %ld\n", iResult);

    // Shutting down socket since it won't be used anymore (can still receive data)
    iResult = shutdown(ConnectSocket, SD_SEND);
    if (iResult == SOCKET_ERROR)
    {
        printf("shutdown failed: %d\n", WSAGetLastError());
        closesocket(ConnectSocket);
        WSACleanup();
        return 1;
    }

    const int buflen = 8196;
    char recvbuf[buflen];
    ZeroMemory(recvbuf, buflen);

    // Keep socket open until connection is closed
    do
    {
        iResult = recv(ConnectSocket, recvbuf, buflen, 0);
        if (iResult > 0)
        {
            printf("Bytes received: %d\n", iResult);
            printf("\nResponse:\n%s\n", recvbuf);
        }
        else if (iResult == 0)
        {
            printf("Connection closed\n");
        }
        else
        {
            printf("recv failed: %d\n", WSAGetLastError());
        }
    } while (iResult > 0);

    closesocket(ConnectSocket);
    WSACleanup();

    return 0;
}


If you look at the edit history of this question, you will see that I previously thought that something was wrong with my HTTP messages but I found some weird behavior:

After every reboot of my system I get a proper response the first time I sent my message. But all following attempts result in an immediate closed connection.

Still no clue what's causing this, but I guess something isn't closed or terminated properly?


Solution

  • After some trial and error I found something that made it work.

    If I put this part:

    iResult = shutdown(ConnectSocket, SD_SEND);
        if (iResult == SOCKET_ERROR)
        {
            printf("shutdown failed: %d\n", WSAGetLastError());
            closesocket(ConnectSocket);
            WSACleanup();
            return 1;
        }
    

    after the part that is receiving messages it works.

    My guess is that although the documentation says that the socket can still receive messages after being shut down, it changes something that makes the server think that the connection should be closed.
    No idea whether that is correct though.

    If somebody knows the actual reason then feel free to add a comment.
    I'm just happy I don't have to deal with this anymore.