glob2-devel
[Top][All Lists]
Advanced

[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;
        }
}



reply via email to

[Prev in Thread] Current Thread [Next in Thread]