summaryrefslogtreecommitdiff
path: root/src/net/network.cpp
blob: 993abbc72b9f589c5225bebd1563625e3b417937 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
/*
 *  The Mana World
 *  Copyright 2004 The Mana World Development Team
 *
 *  This file is part of The Mana World.
 *
 *  The Mana World 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
 *  any later version.
 *
 *  The Mana World 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 The Mana World; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */

#include "network.h"
#ifndef WIN32
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#endif

/** Warning: buffers and other variables are shared,
    so there can be only one connection active at a time */

int buffer_size = 65536;
char *in, *out;
int in_size, out_size;

SOCKET sock;
SOCKADDR_IN addr;
// File descriptors attached to socket
fd_set read_socket;
fd_set write_socket;

/** Increase size of written data */
void WFIFOSET(int len) {
    if(out_size+len>=buffer_size)
        warning("Output buffer full");
    else out_size+=len;
}

/** Convert an address from int format to string */
char *iptostring(int address) {
    short temp1, temp2;
    static char asciiIP[16];

    temp1 = LOWORD(address);
    temp2 = HIWORD(address);
    sprintf(asciiIP, "%i.%i.%i.%i", LOBYTE(temp1), HIBYTE(temp1), LOBYTE(temp2), HIBYTE(temp2));
    return asciiIP;
}

/** Open a session with a server */
SOCKET open_session(const char* address, short port) {
    #ifdef WIN32
    WSADATA wsda;
    #endif
    struct hostent *server;
    int ret;

    // Init WinSock and connect the socket
    #ifdef WIN32
    WSAStartup(MAKEWORD(2,0), &wsda);
    #endif

    sock = socket(PF_INET, SOCK_STREAM, 0); // Create socket for current session
    if(sock==SOCKET_ERROR)return SOCKET_ERROR;

    addr.sin_family = AF_INET;
    addr.sin_port = htons(port);
    addr.sin_addr.s_addr = inet_addr(address);
    if(addr.sin_addr.s_addr == INADDR_NONE){
        server = NULL;
        server = gethostbyname(address);
        if(server == NULL)return SOCKET_ERROR;
            memcpy(&addr.sin_addr, server->h_addr_list[0], server->h_length);
    }

    ret = connect(sock, (struct sockaddr *) &addr, sizeof(addr));
    if(ret == SOCKET_ERROR)return SOCKET_ERROR;

    // Init buffers
    in = (char *)malloc(buffer_size);
    out = (char *)malloc(buffer_size);
    memset(in, '\0', buffer_size);
    memset(out, '\0', buffer_size);
    in_size = 0;
    out_size = 0;
    FD_CLR(sock, &read_socket);
    FD_CLR(sock, &write_socket);

    return sock;
}

/** Close a session */
void close_session() {
    FD_CLR(sock,&read_socket);
    FD_CLR(sock,&write_socket);
    closesocket(sock);
    if(in!=NULL) {
        free(in);
    }
    if(out!=NULL) {
        free(out);
    }
    in = NULL;
    out = NULL;
    in_size = 0;
    out_size = 0;
    WSACleanup();
}

/** Send and receive data waiting in the buffers */
void flush() {
    int ret = 0;
    void *buf = out;
    timeval time_out;

    // Init the time_out struct to 0s so it won't block
    time_out.tv_sec=0;
    time_out.tv_usec=0;

    // Clear file descriptors and set them to socket
    FD_ZERO(&read_socket);
    FD_ZERO(&write_socket);
    FD_SET(sock, &read_socket);
    FD_SET(sock, &write_socket);

    // Check if socket has available data by evaluating attached file descriptors
    select(FD_SETSIZE, &read_socket, &write_socket, NULL, &time_out);

    // Send data if available
    if(FD_ISSET(sock, &write_socket)) {
        // While there wasn't a error or sent the whole data: handles partial packet send
        while((ret!=SOCKET_ERROR)&&(out_size>0)) {
            ret = send(sock, (char *)buf, out_size, 0);

            if(ret!=SOCKET_ERROR && ret>0) {
                buf = (char*)buf+ret;
                out_size -= ret;
            }
        }
        if(ret==SOCKET_ERROR) {
            error("Socket Error");
#ifdef WIN32
            log("Error", "Socket error: %i ", WSAGetLastError());
#else
            log("Error", "socket_error", "Undefined socket error");
#endif
        }
    }

    // Read data, if available
    if(FD_ISSET(sock, &read_socket)) {
        /* There's no check for partial received packets because at this level
           the app doesn't know packet length, but it will done when parsing received data */
        ret = recv(sock, in+in_size, RFIFOSPACE, 0);
        if(ret==SOCKET_ERROR) {
#ifdef WIN32
            log("Error", "Socket error: %i ", WSAGetLastError());
#else
            log("Error", "socket_error", "Undefined socket error");
#endif
        } else RFIFOSET(ret); // Set size of available data to read
    }
}