[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: [glob2-devel] Introduction
From: |
simon schuler |
Subject: |
Re: [glob2-devel] Introduction |
Date: |
Fri, 31 Dec 2004 17:02:31 +0000 |
User-agent: |
Mozilla/5.0 (X11; U; Linux i686; de-AT; rv:1.6) Gecko/20040115 |
Stephane Magnenat schrieb:
Hello,
I'm a performance oriented c and c++ coder and I'd like to contribute to
the project.
Cool, you are very welcome :-)
I had a look at the junior-jobs, but I don't know what
exactly is the task for the TCP Stream Backend. Should there just be a
NetStreamBackend for network use? What is supposed to be at the other
side of the connection?
You are right, this is the NetStreamBackend. I just named it TCP to make clear
that it is not intended to be based on UDP, as UDP is not stream but packet
oriented.
But let me introduce a bit the network architecture of glob2:
- Game setup, meta server, in game orders and chat uses UDP through SDL_net
- IRC uses TCP through SDL_net
What would be very usefull, and what I had in mind while writing this Junior
Job proposal was an HTTP backend. It is also in the roadmap
(http://www.ysagoon.com/twiki/bin/view/Glob2/RoadMap)
With it, it is possible to open stream directy from a web site, so we can make
more community based interactions such as direct upload/download of maps.
Upload could be handled using HTTP POST.
Wether or not HTTPStreamBackend inherits from a TCPStreamBackend which
implements calls to SDL_net is up to the implementer.
I know that on the JJ I have written to use directly TCP functions such as
recv or send but using SDL_Net is ok.
Is there already anyone coding on this?
I was planning to work on the HTTPStreamBackend soon but actually I'm working
with GL graphic backend so it is perfect if you want to do it.
Welcome to glob2 community and have fun,
Steph
I have made a TCPStreamBackend. I have only implemented the constructor
and destructor, and the functions write, read, putc, getc and
isEndOfStream. i don't think the seek and getposition functions make any
sense on TCP-sockets. These should be implemented protocol-specific (for
HTTP, FTP...). By the way I wonder, why in the class StreamBackend
declaration nearly all the functions return void. Wouldn't it be better
to have a return value like in the FILE* functions? Like this you could
check, if the write or read succeeded. Especially for TCP-sockets this
is not allways the case. I think of something like this:
class StreamBackend
{
public:
virtual ~StreamBackend() { }
virtual ssize_t write(const void *data, const size_t size) = 0;
//returns the number of written Bytes, -1 if error
virtual bool flush(void) = 0;
virtual ssize_t read(void *data, size_t size) = 0; //returns the
number of read Bytes, -1 if error
virtual ssize_t putc(int c) = 0;
virtual bool getc(void) = 0;
virtual bool seekFromStart(int displacement) = 0;
virtual bool seekFromEnd(int displacement) = 0;
virtual bool seekRelative(int displacement) = 0;
virtual size_t getPosition(void) = 0;
virtual bool isEndOfStream(void) = 0;
};
where all the bool return values return true if the function succeeds.
I'm not sure if the Backend works on ms windows. I don't know much about
winsock... The Class TCPStreamBackend will only work if winsock is
already initialised.
/*
Copyright (C) 2001-2004 Stephane Magnenat & Luc-Olivier de Charrière
for any question or comment contact us at address@hidden or address@hidden
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef __STREAMBACKEND_H
#define __STREAMBACKEND_H
#include <Types.h>
#include <string>
#include <stdio.h>
#ifdef putc
#undef putc
#endif
#ifdef WIN32
#include <winsock.h>
#else
#include <netdb.h>
#endif
namespace GAGCore
{
//! A stream backend is a low-level serialization structure, that can
be a file, a memory area, a network socket, ...
class StreamBackend
{
public:
virtual ~StreamBackend() { }
virtual void write(const void *data, const size_t size) = 0;
virtual void flush(void) = 0;
virtual void read(void *data, size_t size) = 0;
virtual void putc(int c) = 0;
virtual int getc(void) = 0;
virtual void seekFromStart(int displacement) = 0;
virtual void seekFromEnd(int displacement) = 0;
virtual void seekRelative(int displacement) = 0;
virtual size_t getPosition(void) = 0;
virtual bool isEndOfStream(void) = 0;
};
//! The FILE* implementation of stream backend
class FileStreamBackend : public StreamBackend
{
private:
FILE *fp;
public:
//! Constructor. If fp is NULL, isEndOfStream returns true and
all other functions excepted destructor are invalid.
FileStreamBackend(FILE *fp) { this->fp = fp; }
virtual ~FileStreamBackend() { if (fp) fclose(fp); }
virtual void write(const void *data, const size_t size) {
fwrite(data, size, 1 ,fp); }
virtual void flush(void) { fflush(fp); }
virtual void read(void *data, size_t size) { fread(data, size,
1, fp); }
virtual void putc(int c) { fputc(c, fp); }
virtual int getc(void) { return fgetc(fp); }
virtual void seekFromStart(int displacement) { fseek(fp,
displacement, SEEK_SET); }
virtual void seekFromEnd(int displacement) { fseek(fp,
displacement, SEEK_END); }
virtual void seekRelative(int displacement) { fseek(fp,
displacement, SEEK_CUR); }
virtual size_t getPosition(void) { return ftell(fp); }
virtual bool isEndOfStream(void) { return (fp == NULL) ||
(feof(fp) != 0); }
};
//! A stream backend that lies in memory
class MemoryStreamBackend : public StreamBackend
{
private:
std::string datas;
size_t index;
public:
//! Constructor. If NULL is passed to data, internal buffer is
empty, otherwise size bytes are copied from data.
MemoryStreamBackend(const void *data = NULL, const size_t size
= 0);
virtual ~MemoryStreamBackend() { }
virtual void write(const void *data, const size_t size);
virtual void flush(void) { }
virtual void read(void *data, size_t size);
virtual void putc(int c);
virtual int getc(void);
virtual void seekFromStart(int displacement);
virtual void seekFromEnd(int displacement);
virtual void seekRelative(int displacement);
virtual size_t getPosition(void);
virtual bool isEndOfStream(void);
};
//! The Tcp implementation of stream backend, eerything is read/wrote
directly, without any buffer
class TCPStreamBackend : public StreamBackend
{
private:
int sock;
bool connected;
public:
//! Constructor. If it cannot connect to the server ,
isEndOfStream returns true and all other functions except destructor are
invalid.
TCPStreamBackend(char *IP, unsigned short port);
TCPStreamBackend(int socket); //Constructor with already
connected socket
virtual ~TCPStreamBackend();
virtual void write(const void *data, const size_t size);
virtual void flush(void) { }
virtual void read(void *data, size_t size);
virtual void putc(int c);
virtual int getc(void);
virtual void seekFromStart(int displacement) { }
virtual void seekFromEnd(int displacement) { }
virtual void seekRelative(int displacement) { }
virtual size_t getPosition(void) { }
virtual bool isEndOfStream(void);
};
}
#endif
/*
Copyright (C) 2001-2004 Stephane Magnenat & Luc-Olivier de Charrière
for any question or comment contact us at address@hidden or address@hidden
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <StreamBackend.h>
namespace GAGCore
{
MemoryStreamBackend::MemoryStreamBackend(const void *data, const size_t
size)
{
index = 0;
write(data, size);
}
void MemoryStreamBackend::write(const void *data, const size_t size)
{
const char *_data = static_cast<const char *>(data);
datas.replace(index, size, _data);
index += size;
}
void MemoryStreamBackend::read(void *data, size_t size)
{
char *_data = static_cast<char *>(data);
if (index+size > datas.size())
{
// overread, read 0
std::fill(_data, _data+size, 0);
}
else
{
std::copy(datas.data() + index, datas.data() + index +
size, _data);
index += size;
}
}
void MemoryStreamBackend::putc(int c)
{
Uint8 ch = c;
write(&ch, 1);
}
int MemoryStreamBackend::getc(void)
{
Uint8 ch;
read(&ch, 1);
return ch;
}
void MemoryStreamBackend::seekFromStart(int displacement)
{
index = std::min(static_cast<size_t>(displacement),
datas.size());
}
void MemoryStreamBackend::seekFromEnd(int displacement)
{
index = static_cast<size_t>(std::max(0,
static_cast<int>(datas.size()) - displacement));
}
void MemoryStreamBackend::seekRelative(int displacement)
{
int newIndex = static_cast<int>(index) + displacement;
newIndex = std::max(newIndex, 0);
newIndex = std::min(newIndex, static_cast<int>(datas.size()));
index = static_cast<size_t>(newIndex);
}
size_t MemoryStreamBackend::getPosition(void)
{
return index;
}
bool MemoryStreamBackend::isEndOfStream(void)
{
return index >= datas.size();
}
TCPStreamBackend::TCPStreamBackend(char *address, unsigned short port)
{
connected=false;
sock = socket(AF_INET, SOCK_STREAM, 0);//standard TCP-socket
if(sock==-1)
return; //error
hostent* hp;
hp = gethostbyname(address); //resolve hostname
if ( (!hp) || (hp->h_addrtype!=AF_INET) || (hp->h_length <4) )
return;//something not good(resolve error)
sockaddr_in saddr;
saddr.sin_family = AF_INET;
saddr.sin_port= htons(port);
memcpy( &saddr.sin_addr.s_addr, hp->h_addr, 4);
if(connect(sock, (sockaddr *) &saddr, sizeof(saddr)) != -1)
connected=true; //connection success
}
TCPStreamBackend::TCPStreamBackend(int socket)
{
sock=socket;
connected=true;
}
TCPStreamBackend::~TCPStreamBackend()
{
if(sock==-1)
return;
#ifdef WIN32
closesocket(sock);
#else
close(sock);
#endif
}
void TCPStreamBackend::write(const void *data, const size_t size)
{
if (!connected)
return;
size_t sizeleft=size;
Uint8 *datap=(Uint8 *) data; //Pointer to 1-Byte values, for
pointer-arithmetic
while(sizeleft>0)
{
int sent = send(sock, datap, sizeleft, 0);
if ( sent == -1)
{
connected=false;
return;
}
sizeleft -= sent;
datap += sent;
}
return;
}
void TCPStreamBackend::read(void *data, size_t size)
{
if (!connected)
return;
size_t sizeleft=size;
Uint8 *datap=(Uint8 *) data;
while(sizeleft>0)
{
int received = recv(sock, datap, sizeleft, 0);
if ( received == -1)
{
connected=false;
return;
}
sizeleft -= received;
datap += received;
}
}
void TCPStreamBackend::putc(int c)
{
Uint8 ch = c;
write(&ch, 1);
}
int TCPStreamBackend::getc(void)
{
Uint8 ch;
read(&ch, 1);
return ch;
}
bool TCPStreamBackend::isEndOfStream(void)
{
return !connected;
}
}