summaryrefslogblamecommitdiff
path: root/src/common/socket.hpp
blob: 00f2df0a577f85d6c619c031cd60dec6ffa69539 (plain) (tree)
1
2
3
4

                  
 
                      

















































                                                                                 


                     

                  
                                                                      
                   
                   
 

                                                                              
 








                                                                   
 
                                   
 













                                                                      
 
                                            
                                     

                                                           
                           
 

                                                      

                                               
                       

                  















                                                                           
                      
 



                                                                        
 

                                        
                                                  
                     
 
                    
#ifndef SOCKET_HPP
#define SOCKET_HPP

# include "sanity.hpp"

# include <stdio.h>

# include <sys/types.h>
# include <sys/socket.h>
# include <netinet/in.h>

# include <time.h>

/// Check how much can be read
# define RFIFOREST(fd) (session[fd]->rdata_size-session[fd]->rdata_pos)
/// Read from the queue
# define RFIFOP(fd,pos) (session[fd]->rdata+session[fd]->rdata_pos+(pos))
# define RFIFOB(fd,pos) (*(uint8_t*)(RFIFOP(fd, pos)))
# define RFIFOW(fd,pos) (*(uint16_t*)(RFIFOP(fd, pos)))
# define RFIFOL(fd,pos) (*(uint32_t*)(RFIFOP(fd, pos)))
/// Done reading
void RFIFOSKIP (int fd, size_t len);
/// Internal - clean up by discarding handled bytes
// Atm this is also called in char/char.c, but that is unnecessary
# define RFIFOFLUSH(fd) (memmove(session[fd]->rdata,RFIFOP(fd,0),RFIFOREST(fd)),\
session[fd]->rdata_size=RFIFOREST(fd),\
session[fd]->rdata_pos=0)

/// Used internally - how much room there is to read more data
# define RFIFOSPACE(fd) (session[fd]->max_rdata-session[fd]->rdata_size)

/// Read from an arbitrary buffer
# define RBUFP(p,pos) (((uint8_t*)(p))+(pos))
# define RBUFB(p,pos) (*(uint8_t*)RBUFP((p),(pos)))
# define RBUFW(p,pos) (*(uint16_t*)RBUFP((p),(pos)))
# define RBUFL(p,pos) (*(uint32_t*)RBUFP((p),(pos)))



/// Unused - check how much data can be written
# define WFIFOSPACE(fd) (session[fd]->max_wdata-session[fd]->wdata_size)
/// Write to the queue
# define WFIFOP(fd,pos) (session[fd]->wdata+session[fd]->wdata_size+(pos))
# define WFIFOB(fd,pos) (*(uint8_t*)(WFIFOP(fd,pos)))
# define WFIFOW(fd,pos) (*(uint16_t*)(WFIFOP(fd,pos)))
# define WFIFOL(fd,pos) (*(uint32_t*)(WFIFOP(fd,pos)))
/// Finish writing
void WFIFOSET (int fd, size_t len);

/// Write to an arbitrary buffer
#define WBUFP(p,pos) (((uint8_t*)(p))+(pos))
#define WBUFB(p,pos) (*(uint8_t*)WBUFP((p),(pos)))
#define WBUFW(p,pos) (*(uint16_t*)WBUFP((p),(pos)))
#define WBUFL(p,pos) (*(uint32_t*)WBUFP((p),(pos)))

// Struct declaration

struct socket_data
{
    /// Checks whether a newly-connected socket actually does anything
    time_t created;
    bool connected;

    /// Flag needed since structure must be freed in a server-dependent manner
    bool eof;

    /// Since this is a single-threaded application, it can't block
    /// These are the read/write queues
    uint8_t *rdata, *wdata;
    size_t max_rdata, max_wdata;
    /// How much is actually in the queue
    size_t rdata_size, wdata_size;
    /// How much has already been read from the queue
    /// Note that there is no need for a wdata_pos
    size_t rdata_pos;

    struct sockaddr_in client_addr;

    /// Send or recieve
    /// Only called when select() indicates the socket is ready
    /// If, after that, nothing is read, it sets eof
    // These could probably be hard-coded with a little work
    void (*func_recv) (int);
    void (*func_send) (int);
    /// This is the important one
    /// Set to different functions depending on whether the connection
    /// is a player or a server/ladmin
    /// Can be set explicitly or via set_defaultparse
    void (*func_parse) (int);
    /// Server-specific data type
    void *session_data;
};

// save file descriptors for important stuff
# define SOFT_LIMIT (FD_SETSIZE - 50)

// socket timeout to establish a full connection in seconds
# define CONNECT_TIMEOUT 15

/// Everyone who has connected
// note: call delete_session(i) to null out an element
extern struct socket_data *session[FD_SETSIZE];

/// Maximum used FD, +1
extern int fd_max;

/// open a socket, bind, and listen. Return an fd, or -1 if socket() fails,
/// but exit if bind() or listen() fails
int  make_listen_port (uint16_t port);
/// Connect to an address, return a connected socket or -1
// FIXME - this is IPv4 only!
int  make_connection (uint32_t ip, uint16_t port);
/// free() the structure and close() the fd
void delete_session (int);
/// Make a the internal queues bigger
void realloc_fifo (int fd, size_t rfifo_size, size_t wfifo_size);
/// Update all sockets that can be read/written from the queues
void do_sendrecv (uint32_t next);
/// Call the parser function for every socket that has read data
void do_parsepacket (void);

/// An init function
void do_socket (void);

/// Change the default parser for newly connected clients
// typically called once per server, but individual clients may identify
// themselves as servers
void set_defaultparse (void (*defaultparse) (int));

/// Wrappers to track number of free FDs
void fclose_ (FILE * fp);
FILE *fopen_ (const char *path, const char *mode);
bool free_fds (void);

#endif // SOCKET_HPP