Files @ f02df2b37b49
Branch filter:

Location: DistRen/src/client/libdistren_request.c

binki
Prevent libdistren from thinking it received the same packet multiple times.
/*
 * Copyright 2010 Nathan Phillip Brink
 *
 * This file is a part of DistRen.
 *
 * DistRen is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * DistRen is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with DistRen.  If not, see <http://www.gnu.org/licenses/>.
 */

#include "common/config.h"

#include "libdistren.h"

#include "common/protocol.h"
#include "common/remoteio.h"
#include "common/request.h"

#include <string.h>

static void handle_ping(struct remoteio *rem, struct distren_request *req, void *req_data);
static void handle_pong(distren_t distren, struct remoteio *rem, struct distren_request *req, void *req_data);
static void handle_version(distren_t distren, struct distren_request *req, void *req_data);
static void handle_disconnect(distren_t distren, struct remoteio *rem, struct distren_request *req, void *req_data);

size_t libdistren_remoteio_read_handle(struct remoteio *rem, void *garbage, void *buf, size_t len, distren_t distren)
{
  size_t to_return;
  size_t last_len;
  short err;

  struct distren_request *req;
  void *req_data;

  to_return = 0;
  while(!distren->done_ad)
    {
      if(!len)
	return to_return;

      putchar(*(char *)buf);
      if(*(char *)buf == '\n')
	distren->done_ad = 1;

      len --;
      to_return ++;
      buf ++;
    }

  /* hack to get into the loop at all ;-) */
  last_len = 1; 
  while(last_len)
    {
      last_len = distren_request_handle(NULL, buf, len, &req, &req_data, &err);
      if(err)
	{
	  remoteio_close(rem);
	  return to_return;
	}
      if(!last_len)
	return to_return;

      switch((enum distren_request_type)req->type)
	{
	case DISTREN_REQUEST_PING:
	  handle_ping(rem, req, req_data);
	  break;

	case DISTREN_REQUEST_PONG:
	  handle_pong(distren, rem, req, req_data);
	  break;

	case DISTREN_REQUEST_VERSION:
	  handle_version(distren, req, req_data);
	  break;

	case DISTREN_REQUEST_DISCONNECT:
	  handle_disconnect(distren, rem, req, req_data);
	  break;

	default:
	  /*
	   * we don't implement everything because we don't need to do
	   * so. But, we should complain when we get something we
	   * don't recognize because... server protocols change
	   * ;-). Oh, and when I'm first writing this, this
	   * block will be hit a lot ;-).
	   */
	  fprintf(stderr, "Unrecognized request type: %lu\n", (unsigned long)req->type);
	  break;
	}

      distren_request_free(req);
      buf += last_len;
      to_return += last_len;
      len -= last_len;
    }

  return to_return;
}

void libdistren_remoteio_close_handle(void *garbage, distren_t distren)
{
  distren->rem = NULL;
}


/* handlers */

static void handle_ping(struct remoteio *rem, struct distren_request *req, void *req_data)
{
  struct distren_request *pong_req;
  void *pong_req_data;

  distren_request_poing(&pong_req, &pong_req_data, 0, req_data, req->len);
  distren_request_send(rem, pong_req, pong_req_data);
  distren_request_free_with_data(pong_req, pong_req_data);
}

static void handle_pong(distren_t distren, struct remoteio *rem, struct distren_request *req, void *req_data)
{
  const char *auth_test_str = "auth test";

  if(req->len == strlen(auth_test_str)
     && !strncmp(req_data, auth_test_str, req->len))
    distren->state = DISTREN_STATE_NORMAL;
}

static void handle_version(distren_t distren, struct distren_request *req, void *req_data)
{
  struct distren_request_version version;
  int tmp;

  tmp = distren_request_parse_version(req, req_data, &version);
  if(tmp)
    {
      fprintf(stderr, "error: Invalid DISTREN_REQUEST_VERSION, disconnecting from server\n");
      /*
       * our remoteio_close handler sets distren->rem to NULL, thus we
       * don't need to return an error code.
       */
      remoteio_close(distren->rem);
      return;
    }
  distren->servertype = version.servertype;
  distren->state = DISTREN_STATE_AUTH;

  fprintf(stderr, "info: connected to a server running %s\n", version.package_string);
  if(version.servertype & DISTREN_SERVERTYPE_CLIENT)
    fprintf(stderr, "\tis a client\n");
  if(version.servertype & DISTREN_SERVERTYPE_SUBMIT)
    fprintf(stderr, "\taccepts frame submissions\n");
  if(version.servertype & DISTREN_SERVERTYPE_RENDER)
    fprintf(stderr, "\trenders frames\n");
  if(version.servertype & DISTREN_SERVERTYPE_DISTRIBUTE)
    fprintf(stderr, "\thandles file distribution\n");
}

static void handle_disconnect(distren_t distren, struct remoteio *rem, struct distren_request *req, void *req_data)
{
  size_t tmp;

  fputs("warning: The server has disconnected us because ``", stderr);
  tmp = fwrite(req_data, 1, req->len, stderr);
  fputs("''\n", stderr);

  remoteio_close(distren->rem);
}