summaryrefslogtreecommitdiff
path: root/src/net/network.cpp
blob: 8f34787b62d44ade6523ded7220d26a8911d37a2 (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;

	char *temp = (char *)malloc(sizeof(char[20]));
	temp1 = LOWORD(address);
	temp2 = HIWORD(address);
	sprintf(temp, "%i.%i.%i.%i", LOBYTE(temp1), HIBYTE(temp1), LOBYTE(temp2), HIBYTE(temp2));
	return temp;
}

/** 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; //-kth5
    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);
						/*FILE *file = fopen("log.log","wb");

						fprintf(file, "%s", out[0]);
						fclose(file);*/
						// If not the whole data has been sent, empty the buffer from already sent bytes
            if(ret!=SOCKET_ERROR && ret>0) {
                buf = (char*)buf+ret; //-kth5
                out_size -= ret;
            }
        }
        if(ret==SOCKET_ERROR) {
            error("Socket Error");
#ifdef WIN32
            log_int("Error", "socket_error", 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_int("Error", "socket_error", WSAGetLastError());
#else 
		  log("Error", "socket_error", "Undefined socket error");
#endif
	  } else RFIFOSET(ret); // Set size of available data to read
    }
}