Logo Search packages:      
Sourcecode: papaya version File versions  Download package

HTTPSocket.cpp

#ifdef WIN32
#  include <winsock.h>
#  include <io.h>
#else

#  include <sys/types.h>
#  include <sys/ioctl.h>
#  include <sys/select.h>
#  include <unistd.h> // close(), fcntl()
#  include <sys/socket.h>
#  include <netinet/in.h>
#  include <arpa/inet.h>
#  include <netdb.h> // gethostbyname()
#  include <sys/time.h>
#  include <fcntl.h> // fcntl()

#endif

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


#include <errno.h>

#include <gtk/gtk.h>
#include "Message.h"
#include "Connection.h"
#include "HTTPSocket.h"
#include "papaya/system.h"

/**
 * Initialises an instance of the HTTPSocket.
 */

HTTPSocket::HTTPSocket(Connection * c) : Socket(c) {
  max_write = 100000;
  write_count = 0;
  write_fd = 0;
}

HTTPSocket::HTTPSocket(Connection * co, int f, int c, int d) : Socket(co, f, c, d) {
  max_write = 100000;
  write_count = 0;
  write_fd = 0;
  cookie = d;
}

/**
 * Destroys an instance of the HTTPSocket.
 */

HTTPSocket::~HTTPSocket() {
}

/**
 * Creates a connection to the Turf_httpd, via http proxy if necessary.
 */

int HTTPSocket::create(char * host, int port) {

  /* Connect to the Turf HTTPD in blocking mode to get required data. */

  struct sockaddr_in sock;

  int type;

  if (conn->queryPreferences()->getPreferenceBoolean("HTTPProxy"))
#ifndef IPV4
    type = resolveAddress(conn->queryPreferences()->getPreference("HttpProxyHost"), &sock, NULL);
#else   
    type = resolveAddress(conn->queryPreferences()->getPreference("HttpProxyHost"), &sock);
#endif
  else
#ifndef IPV4
    type = resolveAddress(host, &sock, NULL);
#else
    type = resolveAddress(host, &sock);
#endif

  if (type != 0)
    return -1;

  int www_fd = socket(AF_INET, SOCK_STREAM, 0);
  if (www_fd == -1)
    return -1;

  sock.sin_family = AF_INET;
  if (conn->queryPreferences()->getPreferenceBoolean("HTTPProxy"))
    sock.sin_port = htons(conn->queryPreferences()->getPreferenceInteger("HttpProxyPort"));
  else
    sock.sin_port = htons(port);
  
  /* Attempt the connect.  This will block. */
  int res;
  res = ::connect(www_fd, (struct sockaddr *)&sock, sizeof(sock));
  if (res == -1) {
    close(www_fd);
    return -1;
  }

  char buf[1024];
  if (conn->queryPreferences()->getPreferenceBoolean("HTTPProxy"))
    sprintf(buf, "GET http://%s:%d/client/ HTTP/1.0\n\n", host, port);
  else
    sprintf(buf, "GET /client/ HTTP/1.0\n\n");

  if (send(www_fd, buf, strlen(buf), 0) == -1) {
    close (www_fd);
    return -1;
  }

  int total_read;
  total_read = recv(www_fd, buf, 1024, 0);
  if (total_read == -1) {
    new Message("Error", _("::read in initial request failed."), true);
    close(www_fd);
    return -1;
  }

  buf[total_read] = '\0';
  close(www_fd);

  char * pc;
  char * start;
  start = strstr(buf, "\n\n");
  if (!start) {
    start = strstr(buf, "\r\n\r\n");
    if (!start) {
      start = strstr(buf, "\n\r\n\r");
      if (!start) {
      return -1;
      } else {
      start += 4;
      }
    } else {
      start += 4;
    }
  } else {
    start += 2;
  }

  pc = strchr(start, '\n');
  if (!pc) {
    return -1;
  }

  *pc = '\0';
  pc++;

  char screen_path[1024];
  if (sscanf(start, "/%[^/]/%d/", screen_path, &cookie) != 2) {
    return -1;
  }

  return restart(host, port);
}



int HTTPSocket::restart(char * host, int port) {
  int res;
  char buf[16384];

  if (conn->queryPreferences()->getPreferenceBoolean("HTTPProxy"))
    res = Socket::create(conn->queryPreferences()->getPreference("HttpProxyHost"), conn->queryPreferences()->getPreferenceInteger("HttpProxyPort"));
  else
    res = Socket::create(host, port);
  if (res == -1) {
    return -1;
  }

  if (conn->queryPreferences()->getPreferenceBoolean("HTTPProxy"))
    sprintf(buf, "GET http://%s:%d/screen_plain/%d HTTP/1.0\n\n", host, port, cookie);
  else
    sprintf(buf, "GET /screen_plain/%d HTTP/1.0\n\n", cookie);

  while (1) {
    res = ::send(fd, buf, strlen(buf), 0);

#ifdef WIN32
      if (res == -1 && (errno == EBADF || errno == WSAEBADF || errno == WSAEWOULDBLOCK)) {            
      Sleep(1000);
#else
    if (res == -1 && (errno == EAGAIN || errno == ENOTCONN)) {
      usleep(1000);
#endif
      continue;
    }

    if (res >= 0)
      break;

    perror("write");
    return -1;
  }

  return res;
}

int HTTPSocket::connectWrite() {

  char buf[16384];
  struct sockaddr_in sock;

  write_count = 0;

  if (write_fd)
    close(write_fd);

  int type;
  if (conn->queryPreferences()->getPreferenceBoolean("HTTPProxy"))
#ifdef IPV4
    type = resolveAddress(conn->queryPreferences()->getPreference("HttpProxyHost"), &sock);
#else
    type = resolveAddress(conn->queryPreferences()->getPreference("HttpProxyHost"), &sock, NULL);
#endif
  else
#ifdef IPV4
    type = resolveAddress(conn->getHost(), &sock);
#else
    type = resolveAddress(conn->getHost(), &sock, NULL);
#endif
  if (type != 0) {
    printf(_("Unable to resolve address to a valid IPv4 address."));
    printf(CRLF);
    return -1;
  }

  write_fd = socket(AF_INET, SOCK_STREAM, 0);
  if (write_fd == -1) {
    printf(_("Failet to create socket()."));
    printf(CRLF);
    return -1;
  }

  sock.sin_family = AF_INET;
  if (conn->queryPreferences()->getPreferenceBoolean("HTTPProxy"))
    sock.sin_port = htons(conn->queryPreferences()->getPreferenceInteger("HttpProxyPort"));
  else
    sock.sin_port = htons(conn->getPort());

  /* Attempt the connect.  This will block. */
  if (connect(write_fd, (struct sockaddr *)&sock, sizeof(sock)) == -1) {
    printf(_("Connect call failed."));
    printf(CRLF);
    close(write_fd);
    write_fd = 0;
    return -1;  
  }

  if (conn->queryPreferences()->getPreferenceBoolean("HTTPProxy"))
    sprintf(buf, "POST http://%s:%d/command_plain/%d HTTP/1.0\n"      "User-Agent: Papaya %s\n"
          "Content-Type: text/plain\n"
          "Content-Length: %d\n"
          "Content-Disposition: form-data; name=\"pics\"; filename=\"file1.txt\"\n\n"
          , conn->getHost(), conn->getPort(), cookie, VERSION, max_write);
  else
    sprintf(buf, "POST /command_plain/%d HTTP/1.0\n"
          "User-Agent: Papaya %s\n"
          "Content-Type: text/plain\n"
          "Content-Length: %d\n"
          "Content-Disposition: form-data; name=\"pics\"; filename=\"file1.txt\"\n\n"
          , cookie, VERSION, max_write);
  
  int res = ::send(write_fd, buf, strlen(buf), 0);
  write_count += res;

  if ((unsigned int)res != strlen(buf)) {
    perror("::send(connect)");
    close(write_fd);
    write_fd = 0;
    return -1;
  }

  /* Turn on non-blocking IO.  After the connect. */
#ifdef WIN32
  unsigned long enable = 1;
  ioctlsocket(write_fd, FIONBIO, &enable);
#else
  fcntl(write_fd, F_SETFL, O_NONBLOCK);
#endif

  //  addCommandResponseCallback(write_fd);
  printf(CRLF);
  return write_fd;
}

int HTTPSocket::write(char * buf, int len) {

  if (write_count + strlen(buf) > (unsigned int)max_write) {
    char * spaces = (char *)malloc(max_write - write_count + 1);
    if (!spaces)
      return -1;

    memset(spaces, ' ', max_write - write_count);
    spaces[max_write-write_count] = '\0';
    realWrite(spaces, strlen(spaces));
    free(spaces);

    if (connectWrite() == -1) {
      perror("write: connectWrite");
      return -1;
    }
  }

  return realWrite(buf, len);  

}

int HTTPSocket::sentOk() {
  char buf[1024];
  
  int res = recv(write_fd, buf, 1024, 0);

  if (res == 0)
    return 0; // Remote end cleanly closed socket.

#ifdef WIN32
  if (res == -1 && errno == WSAEWOULDBLOCK || errno == 0)
    return 1;
#else
  if (res == -1 && (errno == EAGAIN || errno == EWOULDBLOCK))
    return 1; // Read no data, but non-blocking socket.
#endif

  if (res == -1)
    return 0; // Socket was closed uncleanly.

  // Read +ve amount of data.
  return 1;
}

int HTTPSocket::realWrite(char * buf, int len) {

  int res;

  if (!sentOk() || write_fd == 0) {
    if (connectWrite() == -1) {
      perror("realWrite: connectWrite");
      return -1;
    }
  }

  res = ::send(write_fd, buf, len, 0);
  
  if (res <= 0 || !sentOk() || write_fd == 0) {

    if (connectWrite() == -1) {
      perror("realWrite: connectWrite");
      return -1;
    }

    res = ::send(write_fd, buf, len, 0);
    if (res <= 0 || !sentOk() || write_fd == 0) {
      perror("realWrite: send");
      return -1;
    }
  }

  write_count += res;
  stats_written += res;
  return 0;
}

gint httpsocket_timeout(gpointer data) {
  int fdesc = *(int *)data;
  char buf[16384];

  int res = ::recv(fdesc, buf, 16383, 0);
  if (res == -1 && errno == EAGAIN)
    return 1;

  //  close(fdesc);
  //  free(data);
  return 1;
}

void HTTPSocket::addCommandResponseCallback(int fdesc) {

  int * alloc_fd = (int *)malloc(sizeof(int));
  *alloc_fd = fdesc;

  g_timeout_add(1000, httpsocket_timeout, alloc_fd);
}

void HTTPSocket::http_sanitise(char * buffer, char * output) {
  int r_pos = 0;
  int w_pos = 0;
  
  for (; buffer[r_pos] != '\0' && w_pos < 16384 - 1; ++r_pos )
    {
      
      if ((unsigned char)buffer[r_pos] > 128)
      continue;

      // Pass Turf Protocol character untouched.
      if ((unsigned char)buffer[r_pos] == '\x1f')
      {
        output[w_pos++] = buffer[r_pos];
        continue;
      }

      if ( ( buffer[r_pos] >= 'A' && buffer[r_pos] <= 'Z' )
           || ( buffer[r_pos] >= 'a' && buffer[r_pos] <= 'z' )
           || ( buffer[r_pos] >= '0' && buffer[r_pos] <= '9' ) )
        {
        output[w_pos++] = buffer[r_pos];
        continue;
        }
      
      if ( buffer[r_pos] == ' ' )
        {
        output[w_pos++] = '+';
        continue;
        }
      
      if ( w_pos < 16384 - 3 )
        {
        output[w_pos++] = '%';
        sprintf( &output[w_pos], "%2.2x", buffer[r_pos] );
        w_pos += 2;
        }
    }
  
  output[w_pos] = '\0';
}

int HTTPSocket::getCookie() {
  return cookie;
}

Generated by  Doxygen 1.6.0   Back to index