/*
* 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 .
*/
#include "common/config.h"
#include "libdistren.h"
#include "common/protocol.h"
#include "common/remoteio.h"
#include "common/request.h"
#include
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;
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);
}