Fimbulwinter Project  Pre-Alpha
An Ragnarok Online Emulator
Common/tcp_connection.hpp
00001 /*==================================================================*
00002 *     ___ _           _           _          _       _                          *
00003 *    / __(_)_ __ ___ | |__  _   _| |_      _(_)_ __ | |_ ___ _ __       *
00004 *   / _\ | | '_ ` _ \| '_ \| | | | \ \ /\ / / | '_ \| __/ _ \ '__|      *
00005 *  / /   | | | | | | | |_) | |_| | |\ V  V /| | | | | ||  __/ |         *
00006 *  \/    |_|_| |_| |_|_.__/ \__,_|_| \_/\_/ |_|_| |_|\__\___|_|         *
00007 *                                                                                                                                       *
00008 * ------------------------------------------------------------------*
00009 *                                                        Emulator                                       *
00010 * ------------------------------------------------------------------*
00011 *                     Licenced under GNU GPL v3                     *
00012 * ----------------------------------------------------------------- *
00013 *                          Socket Macros                                *
00014 * ==================================================================*/
00015 
00016 #pragma once
00017 
00018 #include <boost/bind.hpp>
00019 #include <boost/shared_ptr.hpp>
00020 #include <boost/enable_shared_from_this.hpp>
00021 #include <boost/asio.hpp>
00022 #include <boost/asio/ip/tcp.hpp>
00023 #include <malloc.h>
00024 #include <stdint.h>
00025 #include <map>
00026 
00027 using namespace boost::asio::ip;
00028 
00029 #define FIFOSIZE_SERVERLINK (256 * 1024)
00030 
00031 /*==============================================================*
00032 * Function:     Socket Manipulation Macros                                                      *
00033 * Author: GreenBox                                              *
00034 * Date: 08/12/11                                                                                                *
00035 * Description: Read "packet_guide.txt" in documentation         *
00036 * for more information.                                                                     *
00037 **==============================================================*/
00038 
00039 #define RFIFOHEAD(cl)
00040 #define WFIFOHEAD(cl, size) if(cl->wdata_size + (size) > cl->max_wdata) cl->realloc_writefifo(size);
00041 #define RFIFOP(cl,pos) (cl->rdata + cl->rdata_pos + (pos))
00042 #define WFIFOP(cl,pos) (cl->wdata + cl->wdata_size + (pos))
00043 
00044 #define RFIFOB(cl,pos) (*(unsigned char*)RFIFOP(cl,pos))
00045 #define WFIFOB(cl,pos) (*(unsigned char*)WFIFOP(cl,pos))
00046 #define RFIFOW(cl,pos) (*(unsigned short*)RFIFOP(cl,pos))
00047 #define WFIFOW(cl,pos) (*(unsigned short*)WFIFOP(cl,pos))
00048 #define RFIFOL(cl,pos) (*(unsigned int*)RFIFOP(cl,pos))
00049 #define WFIFOL(cl,pos) (*(unsigned int*)WFIFOP(cl,pos))
00050 #define RFIFOQ(cl,pos) (*(unsigned long long*)RFIFOP(cl,pos))
00051 #define WFIFOQ(cl,pos) (*(unsigned long long*)WFIFOP(cl,pos))
00052 #define RFIFOSPACE(cl) (cl->max_rdata - cl->rdata_size)
00053 #define WFIFOSPACE(cl) (cl->max_wdata - cl->wdata_size)
00054 
00055 #define RFIFOREST(cl)  (cl->flags.eof ? 0 : cl->rdata_size - cl->rdata_pos)
00056 #define RFIFOFLUSH(cl) \
00057         if(cl->rdata_size == cl->rdata_pos) { \
00058                 cl->rdata_size = cl->rdata_pos = 0; \
00059         } else { \
00060                 cl->rdata_size -= cl->rdata_pos; \
00061                 memmove(cl->rdata, cl->rdata + cl->rdata_pos, cl->rdata_size); \
00062                 cl->rdata_pos = 0; \
00063         }
00064 
00065 #define RBUFP(p,pos) (((unsigned char*)(p)) + (pos))
00066 #define RBUFB(p,pos) (*(unsigned char*)RBUFP((p),(pos)))
00067 #define RBUFW(p,pos) (*(unsigned short*)RBUFP((p),(pos)))
00068 #define RBUFL(p,pos) (*(unsigned int*)RBUFP((p),(pos)))
00069 #define RBUFQ(p,pos) (*(unsigned long long*)RBUFP((p),(pos)))
00070 
00071 #define WBUFP(p,pos) (((unsigned char*)(p)) + (pos))
00072 #define WBUFB(p,pos) (*(unsigned char*)WBUFP((p),(pos)))
00073 #define WBUFW(p,pos) (*(unsigned short*)WBUFP((p),(pos)))
00074 #define WBUFL(p,pos) (*(unsigned int*)WBUFP((p),(pos)))
00075 #define WBUFQ(p,pos) (*(unsigned long long*)WBUFP((p),(pos)))
00076 
00077 #define TOB(n) ((unsigned char)((n)&UCHAR_MAX))
00078 #define TOW(n) ((unsigned short)((n)&USHORT_MAX))
00079 #define TOL(n) ((unsigned int)((n)&UINT_MAX))
00080 #define TOQ(n) ((unsigned long long)((n)&ULLONG_MAX))
00081 
00082 #define RFIFO_SIZE (2 * 1024)
00083 #define WFIFO_SIZE (16 * 1024)
00084 #define WFIFO_MAX (1 * 1024 * 1024)
00085 
00086 class tcp_connection
00087         : public boost::enable_shared_from_this<tcp_connection>
00088 {
00089 public:
00090         typedef boost::shared_ptr<tcp_connection> pointer;
00091         typedef boost::function<int (pointer)> parse;
00092 
00093         static pointer create(boost::asio::io_service &io_service)
00094         {
00095                 return pointer(new tcp_connection(io_service));
00096         }
00097 
00098         tcp::socket &socket()
00099         {
00100                 return socket_;
00101         }
00102 
00103         void do_close()
00104         {
00105                 try
00106                 {
00107                         socket_.close();
00108 
00109                         sessions_.erase(tag_);
00110                 }
00111                 catch (void *)
00112                 {
00113                 }
00114         }
00115 
00116         bool is_eof() 
00117         {
00118                 return flags.eof == 1;
00119         }
00120 
00121         void set_eof()
00122         {
00123                 flags.eof = 1;
00124 
00125                 if (parse_)
00126                         parse_((pointer)this->shared_from_this());
00127         }
00128 
00129         void *get_data()
00130         {
00131                 return data_;
00132         }
00133 
00134         void set_data(char *data)
00135         {
00136                 data_ = data;
00137         }
00138 
00139         void set_parser(parse p)
00140         {
00141                 parse_ = p;
00142         }
00143 
00144         void start();
00145         void send_buffer(size_t len);
00146         int skip(size_t len);
00147 
00148         int realloc_writefifo(size_t addition);
00149         int realloc_fifo(unsigned int rfifo_size, unsigned int wfifo_size);
00150 
00151         unsigned char *rdata, *wdata;
00152         size_t max_rdata, max_wdata;
00153         size_t rdata_size, wdata_size;
00154         size_t rdata_pos;
00155 
00156         struct 
00157         {
00158                 unsigned char eof : 1;
00159                 unsigned char server : 1;
00160         } flags;
00161 
00162         ~tcp_connection()
00163         {
00164                 free(rdata);
00165                 free(wdata);
00166         }
00167 
00168         int tag()
00169         {
00170                 return tag_;
00171         }
00172 
00173         static pointer get_session_by_tag(int t)
00174         {
00175                 return sessions_[t];
00176         }
00177 
00178         static bool session_exists(int t)
00179         {
00180                 return sessions_.count(t) == 1;
00181         }
00182 
00183 private:
00184         tcp_connection(boost::asio::io_service &io_service)
00185                 : socket_(io_service)
00186         {
00187                 flags.eof = 0;
00188                 flags.server = 0;
00189 
00190                 data_ = NULL;
00191                 parse_ = NULL;
00192 
00193                 max_rdata  = RFIFO_SIZE;
00194                 max_wdata  = WFIFO_SIZE;
00195 
00196                 rdata = (unsigned char *)malloc(max_rdata);
00197                 wdata = (unsigned char *)malloc(max_wdata);
00198 
00199                 rdata_size = rdata_pos = 0;
00200                 wdata_size = 0;
00201         }
00202 
00203         void start_read();
00204         void handle_write(const boost::system::error_code& error);
00205         void handle_read(const boost::system::error_code &error, size_t bytes_transferred);
00206 
00207         tcp::socket socket_;
00208         void *data_;
00209         parse parse_;
00210         int tag_;
00211 
00212         static int tag_counter_;
00213         static std::map<int, pointer> sessions_;
00214 };
 All Classes Functions