-1

I'm trying to write a simple client in C that will interface with the Google Search API and return search results. I am able to send a search request and get a response back with a 200 OK code and some header text, but there are no search results. Am I doing something wrong?

Here is my code:

#include sys/socket.h
#include sys/types.h
#include netinet/in.h
#include netdb.h
#include stdio.h
#include string.h
#include stdlib.h
#include unistd.h
#include errno.h
#include openssl/rand.h
#include openssl/ssl.h
#include openssl/err.h

// Simple structure to keep track of the handle, and
// of what needs to be freed later.
typedef struct {
    int socket;
    SSL *sslHandle;
    SSL_CTX *sslContext;
} connection;

// For this example, we'll be testing on openssl.org
#define KEY     "/customsearch/v1?key=AIzaSyAOdB5MgAEmvzglw05rR1OPYEYgFuZrT9o&cx=003397780648636422832:u25rx3s92ro&q="
#define SERVER  "www.googleapis.com"
#define PORT 443

// Establish a regular tcp connection
int tcpConnect ()
{
  int error, handle;
  struct hostent *host;
  struct sockaddr_in server;

  host = gethostbyname (SERVER);
  handle = socket (AF_INET, SOCK_STREAM, 0);
  if (handle == -1)
    {
      perror ("Socket");
      handle = 0;
    }
  else
    {
      server.sin_family = AF_INET;
      server.sin_port = htons (PORT);
      server.sin_addr = *((struct in_addr *) host->h_addr);
      bzero (&(server.sin_zero), 8);

      error = connect (handle, (struct sockaddr *) &server,
                       sizeof (struct sockaddr));
      if (error == -1)
        {
          perror ("Connect");
          handle = 0;
        }
    }

  return handle;
}

// Establish a connection using an SSL layer
connection *sslConnect (void)
{
  connection *c;

  c = malloc (sizeof (connection));
  c->sslHandle = NULL;
  c->sslContext = NULL;

  c->socket = tcpConnect ();
  if (c->socket)
    {
      // Register the error strings for libcrypto & libssl
      SSL_load_error_strings ();
      // Register the available ciphers and digests
      SSL_library_init ();

      // New context saying we are a client, and using SSL 2 or 3
      c->sslContext = SSL_CTX_new (SSLv23_client_method ());
      if (c->sslContext == NULL)
        ERR_print_errors_fp (stderr);

      // Create an SSL struct for the connection
      c->sslHandle = SSL_new (c->sslContext);
      if (c->sslHandle == NULL)
        ERR_print_errors_fp (stderr);

      // Connect the SSL struct to our connection
      if (!SSL_set_fd (c->sslHandle, c->socket))
        ERR_print_errors_fp (stderr);

      // Initiate SSL handshake
      if (SSL_connect (c->sslHandle) != 1)
        ERR_print_errors_fp (stderr);
    }
  else
    {
      perror ("Connect failed");
    }

  return c;
}

// Disconnect & free connection struct
void sslDisconnect (connection *c)
{
  if (c->socket)
    close (c->socket);
  if (c->sslHandle)
    {
      SSL_shutdown (c->sslHandle);
      SSL_free (c->sslHandle);
    }
  if (c->sslContext)
    SSL_CTX_free (c->sslContext);

  free (c);
}

// Read all available text from the connection
char *sslRead (connection *c)
{
  const int readSize = 2048;
  char *rc = NULL;
  int received, count = 0;
  char buffer[2048];

  if (c)
    {
      while (1)
        {
          if (!rc)
            rc = malloc (readSize * sizeof (char) + 1);
          else
            rc = realloc (rc, (count + 1) *
                          readSize * sizeof (char) + 1);

          received = SSL_read (c->sslHandle, buffer, readSize);
          buffer[received] = '\0';

          if (received > 0)
            strcat (rc, buffer);

          if (received < readSize)
            break;
          count++;
        }
    }

  return rc;
}

// Write text to the connection
void sslWrite (connection *c, char *text)
{
  if (c)
    SSL_write (c->sslHandle, text, strlen (text)
}

// Very basic main: we send GET / and print the response.
int main (int argc, char **argv)
{
  connection *c;
  char *response;
  char request[512]="";

  c = sslConnect ();

  sprintf(request, "GET https://%s%s%s\r\n\r\n", SERVER, KEY, argv[1]);
  printf("%s", request);

  sslWrite (c, request);

  response = sslRead (c);

  printf ("%s\n", response);

  sslDisconnect (c);
  free (response);

  return 0;
}

Here are my results (running "app_name stove"):

¸h ÆÁ*HTTP/1.0 200 OK

Expires: Wed, 23 May 2012 05:49:58 GMT

Date: Wed, 23 May 2012 05:49:58 GMT

Cache-Control: private, max-age=0, must-revalidate, no-transform

ETag: "ewDGMApuuzSJ2mUepyXm8PLTiIU/uPd2cbC0DjaL0y0Y6HiAvzSqSts"

Content-Type: application/json; charset=UTF-8

X-Content-Type-Options: nosniff

X-Frame-Options: SAMEORIGIN

X-XSS-Protection: 1; mode=block

Server: GSE


There must certainly more information than nothing out there about stoves, right?

Pavan Manjunath
  • 27,404
  • 12
  • 99
  • 125
Vistian
  • 29
  • 3
  • Why write your own HTTP interface, instead of using something like [cURL](http://curl.haxx.se/libcurl/)? – Some programmer dude May 23 '12 at 05:59
  • 1
    Looks like you've got some garbage ahead of that buffer. Without seeing your code, no-one here can even guess at what your problem is. – Mat May 23 '12 at 06:01
  • @JoachimPileborg - I plan on using libcurl after I get this prototype working. I am learning interfacing with web clients and wanted to start off as low level as possible. – Vistian May 23 '12 at 06:19
  • @Mat - I noticed that, but it most certainly didn't seem to interfere with the header data that I'm getting. I added my code. Thanks. – Vistian May 23 '12 at 06:20

1 Answers1

0

The two problems in the above code are #1) the start of rc is not initialized to zero after the malloc and before using strcat -- which results in the garbage characters, and #2) the line if (received < readSize) should be if (received == 0), since servers can potentially send the header and content as separate chunks.

Mike Godin
  • 3,727
  • 3
  • 27
  • 29