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

connection.c

#include <sys/socket.h>
#include <netinet/in.h>
#include <errno.h>
#include <malloc.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <sys/time.h>
#include <netdb.h>

#include "zchat.h"

int memmove_debug = 0;

struct connection * first_connection = NULL;

void display_inbuf(struct connection * c) {

  int i;

  printf("Inbuf currently %d long with data:\n", c->inbuf_pos);

  for (i = 0; i < c->inbuf_pos; i++)
    printf("%d ", c->inbuf[i]);

  printf("\n");


}

void read_mudmaster_command(struct connection * c) {
}

void parse_zchat_command(struct connection * c, struct zmudheader * zhead, char * data) {

  switch (zhead->id) {

  case NameChange:
    zchat_name_change(c, zhead, data);
    break;

  case RequestConnections:
    zchat_request_connections(c, zhead, data);
    break;

  case ConnectionList:
    zchat_connection_list(c, zhead, data);
    break;

  case TextEverybody:
    zchat_text_everybody(c, zhead, data);
    break;
    
  case TextPersonal:
    zchat_text_personal(c, zhead, data);
    break;

  case TextGroup:
    zchat_text_group(c, zhead, data);
    break;
    
  case Message:
    zchat_message(c, zhead, data);
    break;

  case Version:
    zchat_version(c, zhead, data);
    break;

  case FileStart:
  case FileDeny:
  case FileBlockRequest:
  case FileBlock:
  case FileEnd:
  case FileCancel:
    break;

  case PingRequest:
    zchat_ping_request(c, zhead, data);
    break;

  case PingResponse:
    zchat_ping_response(c, zhead, data);
    break;

  case PeekConnections:
  case PeekList:
  case Snoop:
  case SnoopData:
    break;

  case Icon:
    zchat_icon(c, zhead, data);
    break;
    
  case Status:
    zchat_status(c, zhead, data);
    break;

  case EmailAddress:
    zchat_email_address(c, zhead, data);
    break;

  case RequestPGPKey:
    zchat_request_pgp_key(c, zhead, data);
    break;

  case PGPKey:
    zchat_pgpkey(c, zhead, data);
    break;

  case SendCommand:
    zchat_send_command(c, zhead, data);
    break;

  case Stamp:
    zchat_stamp(c, zhead, data);
    break;
    
  default:

    printf("Unsupported command %d.\n", zhead->id);
    break;

  }

}

int read_zchat_command(struct connection * c) {

  struct zmudheader zhead;
  char data[16384];
  int i = 0;

  if (c->inbuf_pos == 0)
    return 0;

  memcpy(&zhead, c->inbuf, 4);
  // @@ Protocol uses intel byte order (ugh!)
  // @@ Find a way to convert from intel byte order to host byte order
  zhead.id = zchat_to_host(zhead.id);
  zhead.len = zchat_to_host(zhead.len);

  memcpy(data, c->inbuf + 4, zhead.len);

  if (memmove_debug)
    display_inbuf(c);

  memmove(c->inbuf, c->inbuf + 4 + zhead.len, c->inbuf_pos - (4 + zhead.len));
  c->inbuf_pos -= 4 + zhead.len;

  printf("Received command (%d) of length %d.\n", zhead.id, zhead.len);
  
  if (memmove_debug) {
    display_inbuf(c);
    
    printf("Command data:\n  ");
    for (i = 0; i < zhead.len; i++)
      printf("%d ", data[i]);
    
    printf("\nEnd of command data.\n");
  }

  // Parse this command.
  parse_zchat_command(c, &zhead, data);
  return 1;
}

struct connection * new_connection(int fd) {
  struct connection * tmp = (struct connection *)malloc(sizeof(struct connection));
  if (!tmp) {
    perror("new_connection: malloc");
    exit(1);
  }

  memset(tmp, 0, sizeof(struct connection));
  memset(&tmp->clientinfo, 0, sizeof(struct client_info));

  tmp->fd = fd;
  tmp->status = ConnDisconnected;
  tmp->proto = ProtoZChat; /* Default to ZChat Protocol */
  // Insert into the linked connection list
  tmp->next = first_connection;
  tmp->inbuf_pos = 0;
  tmp->hostname = NULL;
  tmp->client = NULL;
  tmp->server_connection = 0;
  first_connection = tmp;
  return tmp;
}

void delete_connection(struct connection * c) {
  struct connection * tmp = first_connection;

  if (!c)
    return;

  if (tmp == c) {
    first_connection = NULL;
    free(c);
    return;
  }

  if (tmp->hostname)
    free(tmp->hostname);

  if (tmp->client)
    free(tmp->client);

  for (; tmp; tmp = tmp->next) {
    if (tmp->next == c) {
      tmp->next = c->next;
      free(c);
      return;
    }
  }
}

void readall(struct connection * c) {

  char buf[16384];
  int res = 0;

  res = read(c->fd, buf, 16384);
  if (res <= 0) {
    printf("Read result of %d.\n", res);
    return;
  }

  memcpy(c->inbuf+c->inbuf_pos, buf, res);
  c->inbuf_pos += res;

  c->inbuf[c->inbuf_pos] = '\0';

}

void read_connection(struct connection * c) {

  char buf[16384];
  char * pc;
  char * tab;
  struct hostent * hp;

  readall(c);

  switch (c->status) {
  case ConnDisconnected:
  case ConnConnecting:
    return;

  case ConnWaitingForConnectString:
    // Try and read a connection request.
    pc = c->inbuf;
    while (*pc != '\0') {
      pc++;
    }
    // End of request.

    // parse stuff between c->inbuf and pc.
    
    tab = strchr(c->inbuf, '\t');
    if (!tab) {
      printf("Invalid request.\n");
      // @@ Close connection
      return;
    }

    *tab = '\0';
    c->clientinfo.name = strdup(c->inbuf+6);

    // Move the inbuf along.

    if (memmove_debug)
    display_inbuf(c);

    memmove(c->inbuf, pc+1, c->inbuf_pos - (pc - c->inbuf));
    c->inbuf_pos -= (pc-c->inbuf);

    if (memmove_debug)
    display_inbuf(c);

    //  "ZCHAT:chatname\tchatid\nipaddrport\nsecinfo\0"


    /* Resolve hostname of new client. */
    hp = gethostbyaddr((char *)&c->client->sin_addr, sizeof(unsigned long), AF_INET);
    if (!hp) {
      output_append("Couldn't resolve address for client.  Closing connection.\n");
      write(c->fd, "NO", 2);
      delete_connection(c);
      return;
    }

    c->hostname = strdup(hp->h_name);

    sprintf(buf, "YES:%s\n", get_chat_name());
    write(c->fd, buf, strlen(buf));
    c->status = ConnConnected;
    break;

  case ConnWaitingForConnectResponse:
    // Start parsing c->inbuf.
    if (!strncmp(c->inbuf, "NO", 2)) {
      // Connection refused.
      delete_connection(c);
      return;
    }

    if (!strncmp(c->inbuf, "YES:", 4)) {
      // Connection accepted.
      pc = strchr(c->inbuf, '\n');
      if (!pc) {
      printf("Freaky YES connection ok string.\n");
      abort();
      }

      *pc = '\0'; // To get rid of the \n

      if (c->clientinfo.name)
      free(c->clientinfo.name);

      c->clientinfo.name = strdup(c->inbuf+4);
      c->status = ConnConnected;

      if (memmove_debug)
      display_inbuf(c);
      
      memmove(c->inbuf, pc+1, c->inbuf_pos - (pc - c->inbuf) - 1);
      c->inbuf_pos -= (pc-c->inbuf) + 1;

      if (memmove_debug)
      display_inbuf(c);

      return;
    }

    abort();

  case ConnConnected:

    switch (c->proto) {
    case ProtoZChat:
      while (read_zchat_command(c));
      break;

    case ProtoMudMaster:
      read_mudmaster_command(c);
      break;
    } // c->proto switch in case ConnConnected
    break;
  } // c->status switch

}

void check_connection_data() {
  int max_desc = 0;
  fd_set in_set, out_set, exc_set;
  struct connection * tmp = first_connection;
  struct connection * tmp_next;
  struct timeval tv;

  tv.tv_sec = 0;
  tv.tv_usec = 0;

  if (!first_connection)
    return;

  FD_ZERO(&in_set);
  FD_ZERO(&out_set);
  FD_ZERO(&exc_set);

  for (; tmp; tmp = tmp->next) {
    FD_SET(tmp->fd, &in_set);
    FD_SET(tmp->fd, &exc_set);
    if (tmp->fd > max_desc)
      max_desc = tmp->fd;
  }

  if (!select(max_desc + 1, &in_set, &out_set, &exc_set, &tv))
    return; /* Nothing ready for reading or exceptions yet. */

  for (tmp = first_connection; tmp; tmp = tmp_next) {
    /* delete_connection is destructive */
    tmp_next = tmp->next;

    if (FD_ISSET(tmp->fd, &in_set)) {
      read_connection(tmp);
      continue;
    }

    if (FD_ISSET(tmp->fd, &exc_set)) {
      delete_connection(tmp);
      continue;
    }
  }
}

char * get_status_string(ConnStatus status) {
  switch (status) {
  case ConnDisconnected:
    return "Disconnected";
  case ConnConnecting:
    return "Connecting";
  case ConnWaitingForConnectString:
    return "Waiting for Request";
  case ConnWaitingForConnectResponse:
    return "Waiting for Response";
  case ConnConnected:
    return "Connected";
  default:
    return "Unknown State";
  }
}


void list_connections() {
  struct connection * tmp;
  int count = 0;

  char buf[16384];
  char buf2[16485];

  sprintf(buf, "Active Connections:\n");
  for (tmp = first_connection; tmp; tmp = tmp->next) {
    sprintf(buf2, "  [%.2d %.2d]%s %13s %s\n", tmp->fd, tmp->status, tmp->server_connection ? "S" : "C", tmp->clientinfo.name, tmp->hostname);
    strcat(buf, buf2);
    count++;
  }

  sprintf(buf2, "Total of %d connection%s.\n", count, count == 1 ? "" : "s");
  strcat(buf, buf2);
  output_append(buf);
}


void request_connection(struct connection * tmp) {
  // Create a ZChat connection request.
  char buf[16384];
  sprintf(buf, "ZCHAT:%s\t%s\n%s%-5u\n%s", get_chat_name(), get_chat_ID(), get_client_addr(), get_port(), "");
  printf("Writing %s\n", buf);
  write(tmp->fd, buf, strlen(buf));
  tmp->status = ConnWaitingForConnectResponse;
}

void check_newly_connected() {
  struct connection * tmp = first_connection;

  for (; tmp; tmp = tmp->next) {
    if (tmp->status == ConnConnecting) {
      request_connection(tmp);
    }
  }
}

void send_command(struct connection * conn, struct command * cmd) {
  printf("Writing %s\n", cmd->zchat);
  
  if (conn->proto == ProtoMudMaster)
    write(conn->fd, cmd->mudmaster, cmd->len + 2);
  else
    write(conn->fd, cmd->zchat, cmd->len + 4);
}

void send_command_to_all(struct command * c) {

  struct connection * tmp = first_connection;

  printf("Sending a command to everyone.\n");

  for (; tmp; tmp = tmp->next) {
    if (tmp->proto == ProtoMudMaster) {
      write(tmp->fd, c->mudmaster, c->len + 2);
      printf("Writing mudmaster command to fd %d\n", tmp->fd);
    } else {
      printf("Writing zchat command to fd %d.\n", tmp->fd);
      write(tmp->fd, c->zchat, c->len + 4);
    }
  }


}

Generated by  Doxygen 1.6.0   Back to index