/*
* 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
}
}