From 184aae8cb1fb072b40d63f69c569d92ad7ed2eef Mon Sep 17 00:00:00 2001 From: Eugenio Favalli Date: Fri, 28 Apr 2006 12:08:06 +0000 Subject: Merged enet_switch changes r2268:2309 into the trunk. --- ChangeLog | 24 + src/client.cpp | 1164 +++++++++++++++++++++++---------------------- src/connectionhandler.cpp | 110 ++++- src/connectionhandler.h | 3 +- src/main.cpp | 79 ++- src/messagein.cpp | 15 +- src/messageout.cpp | 20 +- src/messageout.h | 10 + src/netcomputer.cpp | 12 +- src/netcomputer.h | 11 +- src/netsession.cpp | 86 +++- src/netsession.h | 7 +- src/utils/logger.cpp | 3 - tmwserv.dev | 2 +- 14 files changed, 914 insertions(+), 632 deletions(-) diff --git a/ChangeLog b/ChangeLog index cfde9af0..bca4bb63 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,27 @@ +2006-04-11 Eugenio Favalli + + * src/client.cpp, src/connectionhandler.cpp, tmwserv.dev: Updated some + code to latest enet version, and fixed a linking issue in windows. + +2006-03-26 Eugenio Favalli + + * src/messagein.cpp, src/messageout.cpp: Got rid of SDL_net endianess + code. + * src/messagein.cpp: Fixed a mistake. + +2006-03-20 Eugenio Favalli + + * src/client.cpp, src/connectionhandler.cpp, src/connectionhandler.h, + src/main.cpp, src/messagein.cpp, src/messageout.cpp, + src/netcomputer.cpp, src/netcomputer.h, src/netsession.cpp, + src/netsession.h, src/utils/logger.cpp, tmwserv.dev: Got rid of + SDL_net, now both server and test client use enet. + +2006-03-18 Eugenio Favalli + + * src/client.cpp, src/messageout.cpp, src/messageout.h: Converted the + test client to use enet. + 2006-03-14 Eugenio Favalli * tmwserv.dev: Updated project file. diff --git a/src/client.cpp b/src/client.cpp index 87646f10..81f023c7 100644 --- a/src/client.cpp +++ b/src/client.cpp @@ -21,7 +21,7 @@ */ #include -#include +#include #include "defines.h" #include "messageout.h" @@ -33,6 +33,8 @@ #define PACKAGE_VERSION PRODUCT_VERSION #endif +void parsePacket(char *data, int recvLength); + int main(int argc, char *argv[]) { @@ -40,639 +42,665 @@ int main(int argc, char *argv[]) #include "../config.h" #endif std::cout << "The Mana World Test Client v" << PACKAGE_VERSION << std::endl; - - // Initialize SDL - if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_TIMER) == -1) { - std::cout << "SDL_Init: " << SDL_GetError() << std::endl; - exit(1); + + if (enet_initialize () != 0) + { + printf("An error occurred while initializing ENet.\n"); + return EXIT_FAILURE; } - // Set SDL to quit on exit - atexit(SDL_Quit); + atexit(enet_deinitialize); - // Initialize SDL_net - if (SDLNet_Init() == -1) { - std::cout << "SDLNet_Init: " << SDLNet_GetError() << std::endl; - exit(2); - } + ENetHost *client; - // Try to connect to server - IPaddress ip; - TCPsocket tcpsock; + client = enet_host_create(NULL /* create a client host */, + 1 /* only allow 1 outgoing connection */, + 57600 / 8 /* 56K modem with 56 Kbps downstream bandwidth */, + 14400 / 8 /* 56K modem with 14 Kbps upstream bandwidth */); - if (SDLNet_ResolveHost(&ip, "localhost", 9601) == -1) { - std::cout << "SDLNet_ResolveHost: " << SDLNet_GetError() << std::endl; - exit(1); + if (client == NULL) + { + printf("An error occurred while trying to create an ENet client host.\n"); + exit (EXIT_FAILURE); } - tcpsock = SDLNet_TCP_Open(&ip); - if (!tcpsock) { - std::cout << "SDLNet_TCP_Open: " << SDLNet_GetError() << std::endl; - exit(2); - } + ENetAddress address; + ENetPeer *peer; - std::cout << "Successfully connected!" << std::endl; + /* Connect to localhost:9601. */ + enet_address_set_host(&address, "localhost"); + address.port = 9601; - int answer = 1; - char line[256] = ""; + /* Initiate the connection, allocating one channel. */ + peer = enet_host_connect(client, &address, 1); - while (answer != 0) + if (peer == NULL) { - bool responseRequired = true; - MessageOut msg; - - std::cout << "0) Quit 9) Character selection" << std::endl; - std::cout << "1) Register 10) Delete Character" << std::endl; - std::cout << "2) Unregister 11) List Characters" << std::endl; - std::cout << "3) Login 12) Move Character" << std::endl; - std::cout << "4) Logout 13) Chat" << std::endl; - std::cout << "5) Change Password 14) Equip Item" << std::endl; - std::cout << "6) Change Email 15) Ruby Expression" << std::endl; - std::cout << "7) Get Email" << std::endl; - std::cout << "8) Create character" << std::endl; - std::cout << "Choose your option: "; - std::cin >> answer; - - switch (answer) { - case 1: - // Register - msg.writeShort(CMSG_REGISTER); - // We send the client version - msg.writeString(PACKAGE_VERSION); - std::cout << "Account name: "; - std::cin >> line; - msg.writeString(line); - std::cout <<"Password: "; - std::cin >> line; - msg.writeString(line); - std::cout << "Email address: "; - std::cin >> line; - msg.writeString(line); - break; - - case 2: - // Unregister (deleting an account) - msg.writeShort(CMSG_UNREGISTER); - std::cout << "Account name: "; - std::cin >> line; - msg.writeString(line); - std::cout << "Password: "; - std::cin >> line; - msg.writeString(line); - break; + printf("No available peers for initiating an ENet connection.\n"); + exit (EXIT_FAILURE); + } - case 3: - // Login - msg.writeShort(CMSG_LOGIN); - // We send the client version - msg.writeString(PACKAGE_VERSION); - std::cout << "Account name: "; - std::cin >> line; - msg.writeString(line); - std::cout << "Password: "; - std::cin >> line; - msg.writeString(line); - break; + ENetEvent event; + bool exit = false; + bool connected = false; + int answer = 0; + char line[256] = ""; + bool responseRequired = false; - case 4: - // Logout - msg.writeShort(CMSG_LOGOUT); - std::cout << "Logout" << std::endl; - break; + printf("Starting client...\n"); - case 5: - // Change Password - msg.writeShort(CMSG_PASSWORD_CHANGE); - std::cout << "Old Password: "; - std::cin >> line; - msg.writeString(line); - std::cout << "New Password: "; - std::cin >> line; - msg.writeString(line); - std::cout << "Retype new Password: "; - std::cin >> line; - msg.writeString(line); - break; + /* Wait up to 1000 milliseconds for an event. */ + while (!exit) { + if (connected) { + std::cout << std::endl; + std::cout << "0) Quit 9) Character selection" << std::endl; + std::cout << "1) Register 10) Delete Character" << std::endl; + std::cout << "2) Unregister 11) List Characters" << std::endl; + std::cout << "3) Login 12) Move Character" << std::endl; + std::cout << "4) Logout 13) Chat" << std::endl; + std::cout << "5) Change Password 14) Equip Item" << std::endl; + std::cout << "6) Change Email 15) Ruby Expression" << std::endl; + std::cout << "7) Get Email" << std::endl; + std::cout << "8) Create character" << std::endl; + std::cout << "Choose your option: "; + std::cin >> answer; + + MessageOut msg; + + switch (answer) { + case 0: + // Disconnection + if (connected) { + enet_peer_disconnect(&client->peers[0], 0); + } + exit = true; + break; + + case 1: + // Register + msg.writeShort(CMSG_REGISTER); + // We send the client version + msg.writeString(PACKAGE_VERSION); + std::cout << "Account name: "; + std::cin >> line; + msg.writeString(line); + std::cout <<"Password: "; + std::cin >> line; + msg.writeString(line); + std::cout << "Email address: "; + std::cin >> line; + msg.writeString(line); + break; - case 6: - // Change Email - msg.writeShort(CMSG_EMAIL_CHANGE); - std::cout << "New Email: "; - std::cin >> line; - msg.writeString(line); - break; + case 2: + // Unregister (deleting an account) + msg.writeShort(CMSG_UNREGISTER); + std::cout << "Account name: "; + std::cin >> line; + msg.writeString(line); + std::cout << "Password: "; + std::cin >> line; + msg.writeString(line); + break; - case 7: - // Get current Account's Email value - msg.writeShort(CMSG_EMAIL_GET); - break; + case 3: + // Login + msg.writeShort(CMSG_LOGIN); + // We send the client version + msg.writeString(PACKAGE_VERSION); + std::cout << "Account name: "; + std::cin >> line; + msg.writeString(line); + std::cout << "Password: "; + std::cin >> line; + msg.writeString(line); + break; - case 8: - { - // Create character - msg.writeShort(CMSG_CHAR_CREATE); - std::cout << "Name: "; - std::cin >> line; - msg.writeString(line); - - std::cout << "Hair Style ID (0 - " << MAX_HAIRSTYLE_VALUE << "): "; - std::cin >> line; - msg.writeByte(atoi(line)); - - std::cout << "Hair Color ID (0 - " << MAX_HAIRCOLOR_VALUE << "): "; - std::cin >> line; - msg.writeByte(atoi(line)); - - std::cout << "Gender ID (0 - " << MAX_GENDER_VALUE << "): "; - std::cin >> line; - msg.writeByte(atoi(line)); - - std::cout << "Strength: "; - std::cin >> line; - msg.writeShort(atoi(line)); - - std::cout << "Agility: "; - std::cin >> line; - msg.writeShort(atoi(line)); - - std::cout << "Vitality: "; - std::cin >> line; - msg.writeShort(atoi(line)); - - std::cout << "Intelligence: "; - std::cin >> line; - msg.writeShort(atoi(line)); - - std::cout << "Dexterity: "; - std::cin >> line; - msg.writeShort(atoi(line)); - - std::cout << "Luck: "; - std::cin >> line; - msg.writeShort(atoi(line)); - } break; + case 4: + // Logout + msg.writeShort(CMSG_LOGOUT); + std::cout << "Logout" << std::endl; + break; - case 9: - { - // Select character - msg.writeShort(CMSG_CHAR_SELECT); - std::cout << "Character ID: "; - std::cin >> line; - msg.writeByte(atoi(line)); - } break; + case 5: + // Change Password + msg.writeShort(CMSG_PASSWORD_CHANGE); + std::cout << "Old Password: "; + std::cin >> line; + msg.writeString(line); + std::cout << "New Password: "; + std::cin >> line; + msg.writeString(line); + std::cout << "Retype new Password: "; + std::cin >> line; + msg.writeString(line); + break; - case 10: - { - // Delete character - msg.writeShort(CMSG_CHAR_DELETE); - std::cout << "Character ID: "; - std::cin >> line; - msg.writeByte(atoi(line)); - } break; + case 6: + // Change Email + msg.writeShort(CMSG_EMAIL_CHANGE); + std::cout << "New Email: "; + std::cin >> line; + msg.writeString(line); + break; - case 11: - { - // List characters - msg.writeShort(CMSG_CHAR_LIST); - } break; + case 7: + // Get current Account's Email value + msg.writeShort(CMSG_EMAIL_GET); + break; - case 12: - { - // Move character - long x, y; - std::cout << "X: "; - std::cin >> x; - std::cout << "Y: "; - std::cin >> y; - - msg.writeShort(CMSG_WALK); - msg.writeLong(x); - msg.writeLong(y); - - responseRequired = false; - } break; + case 8: + { + // Create character + msg.writeShort(CMSG_CHAR_CREATE); + std::cout << "Name: "; + std::cin >> line; + msg.writeString(line); + + std::cout << "Hair Style ID (0 - " << MAX_HAIRSTYLE_VALUE << "): "; + std::cin >> line; + msg.writeByte(atoi(line)); + + std::cout << "Hair Color ID (0 - " << MAX_HAIRCOLOR_VALUE << "): "; + std::cin >> line; + msg.writeByte(atoi(line)); + + std::cout << "Gender ID (0 - " << MAX_GENDER_VALUE << "): "; + std::cin >> line; + msg.writeByte(atoi(line)); + + std::cout << "Strength: "; + std::cin >> line; + msg.writeShort(atoi(line)); + + std::cout << "Agility: "; + std::cin >> line; + msg.writeShort(atoi(line)); + + std::cout << "Vitality: "; + std::cin >> line; + msg.writeShort(atoi(line)); + + std::cout << "Intelligence: "; + std::cin >> line; + msg.writeShort(atoi(line)); + + std::cout << "Dexterity: "; + std::cin >> line; + msg.writeShort(atoi(line)); + + std::cout << "Luck: "; + std::cin >> line; + msg.writeShort(atoi(line)); + } break; + + case 9: + { + // Select character + msg.writeShort(CMSG_CHAR_SELECT); + std::cout << "Character ID: "; + std::cin >> line; + msg.writeByte(atoi(line)); + } break; + + case 10: + { + // Delete character + msg.writeShort(CMSG_CHAR_DELETE); + std::cout << "Character ID: "; + std::cin >> line; + msg.writeByte(atoi(line)); + } break; + + case 11: + { + // List characters + msg.writeShort(CMSG_CHAR_LIST); + } break; + + case 12: + { + // Move character + long x, y; + std::cout << "X: "; + std::cin >> x; + std::cout << "Y: "; + std::cin >> y; + + msg.writeShort(CMSG_WALK); + msg.writeLong(x); + msg.writeLong(y); + + responseRequired = false; + } break; + + case 13: + // Chat + msg.writeShort(CMSG_SAY); + std::cout << "Chat: "; + std::cin >> line; + msg.writeString(line); + msg.writeShort(0); + responseRequired = false; + break; - case 13: - // Chat - msg.writeShort(CMSG_SAY); - std::cout << "Chat: "; - std::cin >> line; - msg.writeString(line); - msg.writeShort(0); - responseRequired = false; - break; + case 14: + { + // Equip + unsigned int itemId; + unsigned int slot; + std::cout << "Item ID: "; + std::cin >> itemId; + std::cout << "Slot: "; + std::cin >> slot; + msg.writeShort(CMSG_EQUIP); + msg.writeLong(itemId); + msg.writeByte(slot); + } break; + + case 15: + { + std::cout << "Expr: "; + std::cin >> line; + msg.writeShort(0x800); + msg.writeString(line); + + responseRequired = false; + } break; - case 14: - { - // Equip - unsigned int itemId; - unsigned int slot; - std::cout << "Item ID: "; - std::cin >> itemId; - std::cout << "Slot: "; - std::cin >> slot; - msg.writeShort(CMSG_EQUIP); - msg.writeLong(itemId); - msg.writeByte(slot); - } break; + default: + continue; + break; + } // end switch + + // Send prepared message + if (!exit && connected) { + ENetPacket *packet = enet_packet_create( + msg.getData(), + msg.getDataSize() + 1, + ENET_PACKET_FLAG_RELIABLE); + // Send the packet to the peer over channel id 0. + enet_peer_send(peer, 0, packet); + } // end if + + } // end if + + while (enet_host_service(client, &event, 1000)) { + switch (event.type) { + case ENET_EVENT_TYPE_CONNECT: + printf("Connected to server\n"); + connected = true; + break; - case 15: - { - std::cout << "Expr: "; - std::cin >> line; - msg.writeShort(0x800); - msg.writeString(line); + case ENET_EVENT_TYPE_RECEIVE: + std::cout << "A packet of length " + << event.packet->dataLength + << " was received from " + << event.peer->address.host + << std::endl; + + parsePacket((char *)event.packet->data, + event.packet->dataLength); + + // Clean up the packet now that we're done using it. + enet_packet_destroy(event.packet); + break; - responseRequired = false; - } break; + case ENET_EVENT_TYPE_DISCONNECT: + printf("Disconected.\n"); + connected = false; + break; - default: - continue; - } - std::cout << "Sent: " << std::endl; + default: + //printf("Unhandled enet event.\n"); + break; + } // end switch + } // end while - // Message hex - for (unsigned int i = 0; i < msg.getPacket()->length; i++) { - std::cout << int(msg.getPacket()->data[i]) << " "; + if (!connected) { + exit = true; } - std::cout << std::endl; - - SDLNet_TCP_Send(tcpsock, msg.getPacket()->data, - msg.getPacket()->length); + } // end while - // Raw Datas - char data[1024]; - int recvLength = SDLNet_TCP_Recv(tcpsock, data, 1024); + if (connected) { + // The disconnection attempt didn't succeed yet. Force disconnection. + enet_peer_reset(&client->peers[0]); + } + + enet_host_destroy(client); - if (responseRequired) { - std::cout << "Received: "; - if (recvLength != -1) { - for (unsigned int i = 0; i < recvLength; i++) { - std::cout << int(data[i]) << " "; - } - } else { - std::cout << "ERROR!" << std::endl; - } - std::cout << std::endl; - } + return 0; +} - // Response handling - // Transforming it into a MessageIn object - if (recvLength >= 2) - { - Packet *packet = new Packet(data, recvLength); - MessageIn msg(packet); // (MessageIn frees packet) +void parsePacket(char *data, int recvLength) { + // Response handling + // Transforming it into a MessageIn object + if (recvLength >= 2) { + Packet *packet = new Packet(data, recvLength); + MessageIn msg(packet); // (MessageIn frees packet) - switch (msg.getId()) { - case SMSG_REGISTER_RESPONSE: - // Register - switch (msg.readByte()) - { - case REGISTER_OK: - std::cout << "Account registered." << std::endl; + switch (msg.getId()) { + case SMSG_REGISTER_RESPONSE: + // Register + switch (msg.readByte()) { + case REGISTER_OK: + std::cout << "Account registered." << std::endl; break; - case REGISTER_INVALID_USERNAME: - std::cout << "Account registering: Invalid username." << std::endl; + case REGISTER_INVALID_USERNAME: + std::cout << "Account registering: Invalid username." << std::endl; break; - case REGISTER_INVALID_PASSWORD: - std::cout << "Account registering: Invalid password." << std::endl; + case REGISTER_INVALID_PASSWORD: + std::cout << "Account registering: Invalid password." << std::endl; break; - case REGISTER_INVALID_EMAIL: - std::cout << "Account registering: Invalid Email." << std::endl; + case REGISTER_INVALID_EMAIL: + std::cout << "Account registering: Invalid Email." << std::endl; break; - case REGISTER_INVALID_VERSION: - std::cout << "Account registering: Invalid version." << std::endl; + case REGISTER_INVALID_VERSION: + std::cout << "Account registering: Invalid version." << std::endl; break; - case REGISTER_EXISTS_USERNAME: - std::cout << "Account registering: Username already exists." << std::endl; + case REGISTER_EXISTS_USERNAME: + std::cout << "Account registering: Username already exists." << std::endl; break; - case REGISTER_EXISTS_EMAIL: - std::cout << "Account registering: Email already exists." << std::endl; + case REGISTER_EXISTS_EMAIL: + std::cout << "Account registering: Email already exists." << std::endl; break; - default: - case REGISTER_UNKNOWN: - std::cout << "Account registering: Unknown error." << std::endl; + default: + case REGISTER_UNKNOWN: + std::cout << "Account registering: Unknown error." << std::endl; break; - } - break; + } + break; - case SMSG_UNREGISTER_RESPONSE: - // Register - switch (msg.readByte()) - { - case UNREGISTER_OK: - std::cout << "Account unregistered." << std::endl; + case SMSG_UNREGISTER_RESPONSE: + // Register + switch (msg.readByte()) { + case UNREGISTER_OK: + std::cout << "Account unregistered." << std::endl; break; - case UNREGISTER_INVALID_PASSWORD: - std::cout << "Account unregistering: Invalid password." << std::endl; + case UNREGISTER_INVALID_PASSWORD: + std::cout << "Account unregistering: Invalid password." << std::endl; break; - case UNREGISTER_INVALID_USERNAME: - std::cout << "Account unregistering: Invalid username." << std::endl; + case UNREGISTER_INVALID_USERNAME: + std::cout << "Account unregistering: Invalid username." << std::endl; break; - case UNREGISTER_INVALID_UNSUFFICIENT_RIGHTS: - std::cout << "Account unregistering: unsufficient rights." << std::endl; + case UNREGISTER_INVALID_UNSUFFICIENT_RIGHTS: + std::cout << "Account unregistering: unsufficient rights." << std::endl; break; - default: - case UNREGISTER_UNKNOWN: - std::cout << "Account unregistering: Unknown error." << std::endl; + default: + case UNREGISTER_UNKNOWN: + std::cout << "Account unregistering: Unknown error." << std::endl; break; - } - break; + } + break; - case SMSG_LOGIN_RESPONSE: - // Register - switch (msg.readByte()) - { - case LOGIN_OK: - char charNumber; - charNumber = msg.readByte(); - std::cout << "Account has " << int(charNumber) << " characters." << std::endl; - for (unsigned int i = 0; i < charNumber; i++) - { - if (i >0) std::cout << ", "; - std::cout << msg.readString(); - } - std::cout << "." << std::endl; + case SMSG_LOGIN_RESPONSE: + // Register + switch (msg.readByte()) { + case LOGIN_OK: + char charNumber; + charNumber = msg.readByte(); + std::cout << "Account has " << int(charNumber) << " characters." << std::endl; + for (unsigned int i = 0; i < charNumber; i++) { + if (i >0) std::cout << ", "; + std::cout << msg.readString(); + } + std::cout << "." << std::endl; break; - case LOGIN_INVALID_USERNAME: - std::cout << "Login: Invalid Username." << std::endl; + case LOGIN_INVALID_USERNAME: + std::cout << "Login: Invalid Username." << std::endl; break; - case LOGIN_INVALID_PASSWORD: - std::cout << "Login: Invalid Password." << std::endl; + case LOGIN_INVALID_PASSWORD: + std::cout << "Login: Invalid Password." << std::endl; break; - case LOGIN_INVALID_VERSION: - std::cout << "Login: Invalid Version." << std::endl; + case LOGIN_INVALID_VERSION: + std::cout << "Login: Invalid Version." << std::endl; break; - case LOGIN_ALREADY_LOGGED: - std::cout << "Login: Already logged with another account." << std::endl; + case LOGIN_ALREADY_LOGGED: + std::cout << "Login: Already logged with another account." << std::endl; break; - case LOGIN_SERVER_FULL: - std::cout << "Login: Server has reached maximum of clients." << std::endl; + case LOGIN_SERVER_FULL: + std::cout << "Login: Server has reached maximum of clients." << std::endl; break; - case LOGIN_ACCOUNT_BANNED: - std::cout << "Login: Your account has been banned." << std::endl; + case LOGIN_ACCOUNT_BANNED: + std::cout << "Login: Your account has been banned." << std::endl; break; - case LOGIN_ACCOUNT_REVIEW: - std::cout << "TODO:Login: Your account is being reviewed." << std::endl; + case LOGIN_ACCOUNT_REVIEW: + std::cout << "TODO:Login: Your account is being reviewed." << std::endl; break; - default: - case LOGIN_UNKNOWN: - std::cout << "Login: Unknown error." << std::endl; + default: + case LOGIN_UNKNOWN: + std::cout << "Login: Unknown error." << std::endl; break; - } - break; - - case SMSG_LOGOUT_RESPONSE: - { - switch (msg.readByte()) - { - case LOGOUT_OK: - std::cout << "Logout..." << std::endl; - break; - default: - case LOGOUT_UNSUCCESSFULL: - std::cout << "Logout: unsuccessfull." << std::endl; - break; - } - } - break; - - case SMSG_PASSWORD_CHANGE_RESPONSE: - { - switch (msg.readByte()) - { - case PASSCHG_OK: - std::cout << "Password correctly changed." << std::endl; - break; - case PASSCHG_NOLOGIN: - std::cout << "Password change: Not logged in." << std::endl; - break; - case PASSCHG_MISMATCH: - std::cout << "Password change: Passwords mismatch." << std::endl; - break; - case PASSCHG_INVALID: - std::cout << "Password change: New password is invalid." << std::endl; - break; - default: - case PASSCHG_UNKNOWN: - std::cout << "Password change: Unknown error." << std::endl; - break; - } - } - break; + } + break; - case SMSG_EMAIL_CHANGE_RESPONSE: - { - switch (msg.readByte()) - { - case EMAILCHG_OK: - std::cout << "Email correctly changed." << std::endl; - break; - case EMAILCHG_NOLOGIN: - std::cout << "Email change: Not logged in." << std::endl; - break; - case EMAILCHG_EXISTS_EMAIL: - std::cout << "Email change: Email already exists." << std::endl; - break; - case EMAILCHG_INVALID: - std::cout << "Email change: New Email is invalid." << std::endl; - break; - default: - case EMAILCHG_UNKNOWN: - std::cout << "Email change: Unknown error." << std::endl; - break; - } - } - break; + case SMSG_LOGOUT_RESPONSE: + { + switch (msg.readByte()) { + case LOGOUT_OK: + std::cout << "Logout..." << std::endl; + break; + default: + case LOGOUT_UNSUCCESSFULL: + std::cout << "Logout: unsuccessfull." << std::endl; + break; + } + } break; - case SMSG_EMAIL_GET_RESPONSE: - { - switch (msg.readByte()) - { - case EMAILGET_OK: - std::cout << "Current Email: " << msg.readString() << std::endl; - break; - case EMAILGET_NOLOGIN: - std::cout << "Get Email: Not logged in." << std::endl; - break; - default: - case EMAILGET_UNKNOWN: - std::cout << "Get Email: Unknown error." << std::endl; - break; - } - } - break; + case SMSG_PASSWORD_CHANGE_RESPONSE: + { + switch (msg.readByte()) { + case PASSCHG_OK: + std::cout << "Password correctly changed." << std::endl; + break; + case PASSCHG_NOLOGIN: + std::cout << "Password change: Not logged in." << std::endl; + break; + case PASSCHG_MISMATCH: + std::cout << "Password change: Passwords mismatch." << std::endl; + break; + case PASSCHG_INVALID: + std::cout << "Password change: New password is invalid." << std::endl; + break; + default: + case PASSCHG_UNKNOWN: + std::cout << "Password change: Unknown error." << std::endl; + break; + } + } break; - case SMSG_CHAR_CREATE_RESPONSE: - { - switch (msg.readByte()) - { - case CREATE_OK: - std::cout << "Character Created successfully." << std::endl; - break; - case CREATE_EXISTS_NAME: - std::cout << "Character Creation: Character's name already exists." - << std::endl; - break; - case CREATE_NOLOGIN: - std::cout << "Character Creation: Not logged in." << std::endl; - break; - case CREATE_TOO_MUCH_CHARACTERS: - std::cout << "Character Creation: Too much characters." << std::endl; - break; - case CREATE_INVALID_HAIRSTYLE: - std::cout << "Character Creation: Invalid Hair Style Value." << std::endl; - break; - case CREATE_INVALID_HAIRCOLOR: - std::cout << "Character Creation: Invalid Hair Color Value." << std::endl; - break; - case CREATE_INVALID_GENDER: - std::cout << "Character Creation: Invalid Gender Value." << std::endl; - break; - case CREATE_INVALID_NAME: - std::cout << "Character Creation: Invalid Name." << std::endl; - break; - case CREATE_RAW_STATS_EQUAL_TO_ZERO: - std::cout << "Character Creation: a Statistic is equal to zero." << std::endl; - break; - case CREATE_RAW_STATS_INVALID_DIFF: - std::cout << "Character Creation: Statistics disproportionned." << std::endl; - break; - case CREATE_RAW_STATS_TOO_HIGH: - std::cout << "Character Creation: Statistics too high for level 1." << std::endl; - break; - case CREATE_RAW_STATS_TOO_LOW: - std::cout << "Character Creation: Statistics too low for level 1." << std::endl; - break; - default: - case CREATE_UNKNOWN: - std::cout << "Character Creation: Unknown error." << std::endl; - break; - } - } - break; + case SMSG_EMAIL_CHANGE_RESPONSE: + { + switch (msg.readByte()) { + case EMAILCHG_OK: + std::cout << "Email correctly changed." << std::endl; + break; + case EMAILCHG_NOLOGIN: + std::cout << "Email change: Not logged in." << std::endl; + break; + case EMAILCHG_EXISTS_EMAIL: + std::cout << "Email change: Email already exists." << std::endl; + break; + case EMAILCHG_INVALID: + std::cout << "Email change: New Email is invalid." << std::endl; + break; + default: + case EMAILCHG_UNKNOWN: + std::cout << "Email change: Unknown error." << std::endl; + break; + } + } break; + + case SMSG_EMAIL_GET_RESPONSE: + { + switch (msg.readByte()) { + case EMAILGET_OK: + std::cout << "Current Email: " << msg.readString() << std::endl; + break; + case EMAILGET_NOLOGIN: + std::cout << "Get Email: Not logged in." << std::endl; + break; + default: + case EMAILGET_UNKNOWN: + std::cout << "Get Email: Unknown error." << std::endl; + break; + } + } break; - case SMSG_CHAR_DELETE_RESPONSE: - { - switch (msg.readByte()) - { - case DELETE_OK: - std::cout << "Character deleted." << std::endl; - break; - case DELETE_INVALID_ID: - std::cout << "Character Deletion: Character's ID doesn't exist." - << std::endl; - break; - case DELETE_NOLOGIN: - std::cout << "Character Deletion: Not logged in." << std::endl; - break; - case DELETE_NO_MORE_CHARACTERS: - std::cout << "Character Deletion: No more characters." << std::endl; - break; - default: - case DELETE_UNKNOWN: - std::cout << "Character Deletion: Unknown error." << std::endl; - break; - } - } - break; + case SMSG_CHAR_CREATE_RESPONSE: + { + switch (msg.readByte()) { + case CREATE_OK: + std::cout << "Character Created successfully." << std::endl; + break; + case CREATE_EXISTS_NAME: + std::cout << "Character Creation: Character's name already exists." + << std::endl; + break; + case CREATE_NOLOGIN: + std::cout << "Character Creation: Not logged in." << std::endl; + break; + case CREATE_TOO_MUCH_CHARACTERS: + std::cout << "Character Creation: Too much characters." << std::endl; + break; + case CREATE_INVALID_HAIRSTYLE: + std::cout << "Character Creation: Invalid Hair Style Value." << std::endl; + break; + case CREATE_INVALID_HAIRCOLOR: + std::cout << "Character Creation: Invalid Hair Color Value." << std::endl; + break; + case CREATE_INVALID_GENDER: + std::cout << "Character Creation: Invalid Gender Value." << std::endl; + break; + case CREATE_INVALID_NAME: + std::cout << "Character Creation: Invalid Name." << std::endl; + break; + case CREATE_RAW_STATS_EQUAL_TO_ZERO: + std::cout << "Character Creation: a Statistic is equal to zero." << std::endl; + break; + case CREATE_RAW_STATS_INVALID_DIFF: + std::cout << "Character Creation: Statistics disproportionned." << std::endl; + break; + case CREATE_RAW_STATS_TOO_HIGH: + std::cout << "Character Creation: Statistics too high for level 1." << std::endl; + break; + case CREATE_RAW_STATS_TOO_LOW: + std::cout << "Character Creation: Statistics too low for level 1." << std::endl; + break; + default: + case CREATE_UNKNOWN: + std::cout << "Character Creation: Unknown error." << std::endl; + break; + } + } break; - case SMSG_CHAR_SELECT_RESPONSE: - { - switch (msg.readByte()) - { - case SELECT_OK: - { - std::cout << "Character selected successfully."; - std::cout << std::endl; - std::cout << "Current Map: "; - std::cout << msg.readString() << " (X:"; - std::cout << (int)msg.readShort() << ", Y:"; - std::cout << (int)msg.readShort() << ")" << std::endl; - } - break; - case SELECT_INVALID: - std::cout << "Character Selection: invalid ID." - << std::endl; - break; - case SELECT_NOLOGIN: - std::cout << "Character Selection: Not logged in." << std::endl; - break; - case SELECT_NO_CHARACTERS: - std::cout << "Character Selection: No character to select." << std::endl; - break; - case SELECT_NO_MAPS: - std::cout << "Character Selection: Can't load default map for character." - << std::endl; - break; - default: - case SELECT_UNKNOWN: - std::cout << "Character Selection: Unknown error." << std::endl; - break; - } - } - break; + case SMSG_CHAR_DELETE_RESPONSE: + { + switch (msg.readByte()) { + case DELETE_OK: + std::cout << "Character deleted." << std::endl; + break; + case DELETE_INVALID_ID: + std::cout << "Character Deletion: Character's ID doesn't exist." + << std::endl; + break; + case DELETE_NOLOGIN: + std::cout << "Character Deletion: Not logged in." << std::endl; + break; + case DELETE_NO_MORE_CHARACTERS: + std::cout << "Character Deletion: No more characters." << std::endl; + break; + default: + case DELETE_UNKNOWN: + std::cout << "Character Deletion: Unknown error." << std::endl; + break; + } + } break; - case SMSG_CHAR_LIST_RESPONSE: + case SMSG_CHAR_SELECT_RESPONSE: + { + switch (msg.readByte()) { + case SELECT_OK: { - switch (msg.readByte()) - { - case CHAR_LIST_OK: - char charNumber; - charNumber = msg.readByte(); - std::cout << "Character List:" << std::endl - << "---------------" << std::endl; - std::cout << int(charNumber) << " character(s) in the account." - << std::endl; - char charID; - for (unsigned int i = 0; i < charNumber; i++) - { - charID = msg.readByte(); - std::cout << int(charID) << ". " - << msg.readString() << ":" << std::endl; - std::cout << "Gender: " << int(msg.readByte()) << ", "; - std::cout << "Hair Style: " << int(msg.readByte()) << ", "; - std::cout << "Hair Color: " << int(msg.readByte()) << ", " - << std::endl; - std::cout << "Level: " << int(msg.readByte()) << ", "; - std::cout << "Money: " << int(msg.readShort()) << ", " - << std::endl; - std::cout << "Strength: " << int(msg.readShort()) << ", "; - std::cout << "Agility: " << int(msg.readShort()) << ", "; - std::cout << "Vitality: " << int(msg.readShort()) << ", " - << std::endl; - std::cout << "Intelligence: " << int(msg.readShort()) << ", "; - std::cout << "Dexterity: " << int(msg.readShort()) << ", "; - std::cout << "Luck: " << int(msg.readShort()) << ". " - << std::endl; - std::cout << "Current Map: " << msg.readString() << " (X:"; - std::cout << int(msg.readShort()) << ", Y:" << int(msg.readShort()) << ")." - << std::endl << std::endl; - } - break; - case CHAR_LIST_NOLOGIN: - std::cout << "Character List: Not logged in." - << std::endl; - break; - default: - case CHAR_LIST_UNKNOWN: - std::cout << "Character List: Unknown error." << std::endl; - break; - } - } - break; - - - default: - continue; - } // End switch MessageId + std::cout << "Character selected successfully."; + std::cout << std::endl; + std::cout << "Current Map: "; + std::cout << msg.readString() << " (X:"; + std::cout << (int)msg.readShort() << ", Y:"; + std::cout << (int)msg.readShort() << ")" << std::endl; + } break; + case SELECT_INVALID: + std::cout << "Character Selection: invalid ID." + << std::endl; + break; + case SELECT_NOLOGIN: + std::cout << "Character Selection: Not logged in." << std::endl; + break; + case SELECT_NO_CHARACTERS: + std::cout << "Character Selection: No character to select." << std::endl; + break; + case SELECT_NO_MAPS: + std::cout << "Character Selection: Can't load default map for character." + << std::endl; + break; + default: + case SELECT_UNKNOWN: + std::cout << "Character Selection: Unknown error." << std::endl; + break; + } + } break; - } // end if recLength > 2 (MessageLength > 2) + case SMSG_CHAR_LIST_RESPONSE: + { + switch (msg.readByte()) { + case CHAR_LIST_OK: + char charNumber; + charNumber = msg.readByte(); + std::cout << "Character List:" << std::endl + << "---------------" << std::endl; + std::cout << int(charNumber) << " character(s) in the account." + << std::endl; + char charID; + for (unsigned int i = 0; i < charNumber; i++) { + charID = msg.readByte(); + std::cout << int(charID) << ". " + << msg.readString() << ":" << std::endl; + std::cout << "Gender: " << int(msg.readByte()) << ", "; + std::cout << "Hair Style: " << int(msg.readByte()) << ", "; + std::cout << "Hair Color: " << int(msg.readByte()) << ", " + << std::endl; + std::cout << "Level: " << int(msg.readByte()) << ", "; + std::cout << "Money: " << int(msg.readShort()) << ", " + << std::endl; + std::cout << "Strength: " << int(msg.readShort()) << ", "; + std::cout << "Agility: " << int(msg.readShort()) << ", "; + std::cout << "Vitality: " << int(msg.readShort()) << ", " + << std::endl; + std::cout << "Intelligence: " << int(msg.readShort()) << ", "; + std::cout << "Dexterity: " << int(msg.readShort()) << ", "; + std::cout << "Luck: " << int(msg.readShort()) << ". " + << std::endl; + std::cout << "Current Map: " << msg.readString() << " (X:"; + std::cout << int(msg.readShort()) << ", Y:" << int(msg.readShort()) << ")." + << std::endl << std::endl; + } break; + case CHAR_LIST_NOLOGIN: + std::cout << "Character List: Not logged in." + << std::endl; + break; + default: + case CHAR_LIST_UNKNOWN: + std::cout << "Character List: Unknown error." << std::endl; + break; + } + } break; - } // End running loop + default: + break; + } // end switch MessageId - SDLNet_TCP_Close(tcpsock); + } // end if recLength > 2 (MessageLength > 2) - return 0; } + diff --git a/src/connectionhandler.cpp b/src/connectionhandler.cpp index e3b30dde..c70f34e4 100644 --- a/src/connectionhandler.cpp +++ b/src/connectionhandler.cpp @@ -100,6 +100,7 @@ ConnectionHandler::ConnectionHandler() void ConnectionHandler::startListen(ListenThreadData *ltd) { + /* // Allocate a socket set SDLNet_SocketSet set = SDLNet_AllocSocketSet(MAX_CLIENTS); if (!set) { @@ -226,7 +227,114 @@ ConnectionHandler::startListen(ListenThreadData *ltd) // - Disconnect all clients (close sockets) - SDLNet_FreeSocketSet(set); + SDLNet_FreeSocketSet(set);*/ + + while (ltd->running) + { + ENetEvent event; + + // Wait up to 1000 milliseconds for an event. + while (enet_host_service(ltd->host, &event, 1000) > 0) + { + switch (event.type) + { + case ENET_EVENT_TYPE_CONNECT: + { + LOG_INFO("A new client connected from " << + ip4ToString(event.peer->address.host) << ":" << + event.peer->address.port, 0); + NetComputer *comp = new NetComputer(this, event.peer); + clients.push_back(comp); + computerConnected(comp); + /*LOG_INFO(ltd->host->peerCount << + " client(s) connected", 0);*/ + + // Store any relevant client information here. + event.peer->data = (void *)comp; + } break; + + case ENET_EVENT_TYPE_RECEIVE: + { + LOG_INFO("A packet of length " << event.packet->dataLength + << " was received from " << event.peer->address.host, + 2); + + NetComputer *comp = (NetComputer *)event.peer->data; + +#ifdef SCRIPT_SUPPORT + // This could be good if you wanted to extend the + // server protocol using a scripting language. This + // could be attained by using allowing scripts to + // "hook" certain messages. + + //script->message(buffer); +#endif + + // If the scripting subsystem didn't hook the message + // it will be handled by the default message handler. + + // Convert the client IP address to string + // representation + std::string ipaddr = ip4ToString(event.peer->address.host); + + // Make sure that the packet is big enough (> short) + if (event.packet->dataLength >= 2) + { + Packet *packet = new Packet((char *)event.packet->data, + event.packet->dataLength); + MessageIn msg(packet); // (MessageIn frees packet) + + short messageId = msg.getId(); + + if (handlers.find(messageId) != handlers.end()) + { + // send message to appropriate handler + handlers[messageId]->receiveMessage(*comp, msg); + } + else { + // bad message (no registered handler) + LOG_ERROR("Unhandled message (" << messageId + << ") received from " << ipaddr, 0); + } + } + else { + LOG_ERROR("Message too short from " << ipaddr, 0); + } + + /* Clean up the packet now that we're done using it. */ + enet_packet_destroy(event.packet); + } break; + + case ENET_EVENT_TYPE_DISCONNECT: + { + NetComputer *comp = (NetComputer *)event.peer->data; + /*LOG_INFO(event.peer->address.host + << " disconected.", 0);*/ + // Reset the peer's client information. + computerDisconnected(comp); + delete comp; + event.peer->data = NULL; + } break; + } + } + } + + // - Disconnect all clients (close sockets) + + // TODO: probably there's a better way. + ENetPeer *currentPeer; + + for (currentPeer = ltd->host->peers; + currentPeer < <d->host->peers[ltd->host->peerCount]; + ++currentPeer) + { + if (currentPeer->state == ENET_PEER_STATE_CONNECTED) + { + enet_peer_disconnect(currentPeer, 0); + enet_host_flush(ltd->host); + enet_peer_reset(currentPeer); + } + } } void ConnectionHandler::computerConnected(NetComputer *comp) diff --git a/src/connectionhandler.h b/src/connectionhandler.h index 3eb4ac2c..dd6cf207 100644 --- a/src/connectionhandler.h +++ b/src/connectionhandler.h @@ -26,7 +26,6 @@ #include #include -#include #include "being.h" @@ -48,7 +47,7 @@ class ClientData public: ClientData(); - TCPsocket sock; /**< The socket used for communication */ + //TCPsocket sock; /**< The socket used for communication */ int inp; /**< The amount of data in the in buffer */ char in[IN_BUFFER_SIZE]; /**< The in buffer for incoming messages */ diff --git a/src/main.cpp b/src/main.cpp index 833492b2..679408fb 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -26,7 +26,7 @@ #include #include #include -#include +#include #if (defined __USE_UNIX98 || defined __FreeBSD__) #include "../config.h" @@ -41,6 +41,7 @@ #include "configuration.h" #include "connectionhandler.h" #include "gamehandler.h" +#include "messageout.h" #include "netsession.h" #include "resourcemanager.h" #include "skill.h" @@ -184,7 +185,7 @@ void initialize() accountHandler = new AccountHandler(); gameHandler = new GameHandler(); connectionHandler = new ConnectionHandler(); - + // Make SDL use a dummy videodriver so that it doesn't require an X server putenv("SDL_VIDEODRIVER=dummy"); @@ -196,13 +197,16 @@ void initialize() // Reset to default segmentation fault handling for debugging purposes signal(SIGSEGV, SIG_DFL); - + // set SDL to quit on exit. atexit(SDL_Quit); - // initialize SDL_net. - if (SDLNet_Init() == -1) { - LOG_FATAL("SDLNet_Init: " << SDLNet_GetError(), 0) + // set enet to quit on exit. + atexit(enet_deinitialize); + + // initialize enet. + if (enet_initialize() != 0) { + LOG_FATAL("An error occurred while initializing ENet", 0) exit(2); } @@ -259,9 +263,12 @@ void deinitialize() // Stop world timer SDL_RemoveTimer(worldTimerID); + + // Quit SDL + SDL_Quit(); - // Quit SDL_net - SDLNet_Quit(); + // Quit ENet + enet_deinitialize(); #ifdef RUBY_SUPPORT // Finish up ruby @@ -390,8 +397,10 @@ int main(int argc, char *argv[]) connectionHandler->registerHandler(CMSG_REQ_TRADE, gameHandler); connectionHandler->registerHandler(CMSG_EQUIP, gameHandler); - session->startListen(connectionHandler, int(config.getValue("ListenOnPort", DEFAULT_SERVER_PORT))); - LOG_INFO("Listening on port " << config.getValue("ListenOnPort", DEFAULT_SERVER_PORT) << "...", 0) + session->startListen(connectionHandler, int(config.getValue("ListenOnPort", + DEFAULT_SERVER_PORT))); + LOG_INFO("Listening on port " << + config.getValue("ListenOnPort", DEFAULT_SERVER_PORT) << "...", 0) using namespace tmwserv; @@ -428,6 +437,53 @@ int main(int argc, char *argv[]) running = false; } } + + /*ENetEvent netEvent; + + while (enet_host_service(server, &netEvent, 3000) > 0) + { + switch (netEvent.type) + { + case ENET_EVENT_TYPE_CONNECT: + printf("A new client connected from %x:%u.\n", + netEvent.peer->address.host, + netEvent.peer->address.port); + + netEvent.peer->data = (void *)"Client information"; + break; + + case ENET_EVENT_TYPE_RECEIVE: + { + printf("A packet of length %u containing %s was received from %s on channel %u.\n", + netEvent.packet->dataLength, + netEvent.packet->data, + netEvent.peer->data, + netEvent.channelID); + + MessageOut msg; + msg.writeShort(SMSG_REGISTER_RESPONSE); + msg.writeByte(REGISTER_OK); + ENetPacket *packet = enet_packet_create(msg.getData(), + msg.getDataSize() + 1, + ENET_PACKET_FLAG_RELIABLE); + // Send the packet to the peer over channel id 0. + enet_peer_send(netEvent.peer, 0, packet); + // Clean up the packet now that we're done using it. + enet_packet_destroy(netEvent.packet); + } + break; + + case ENET_EVENT_TYPE_DISCONNECT: + printf("%s disconected.\n", netEvent.peer->data); + + netEvent.peer->data = NULL; + break; + + default: + printf("Unhandled enet event\n"); + break; + } + }*/ // We know only about 10 events will happen per second, // so give the CPU a break for a while. @@ -435,7 +491,8 @@ int main(int argc, char *argv[]) } LOG_INFO("Received: Quit signal, closing down...", 0) - session->stopListen(int(config.getValue("ListenOnPort", DEFAULT_SERVER_PORT))); + session->stopListen(int(config.getValue("ListenOnPort", + DEFAULT_SERVER_PORT))); deinitialize(); } diff --git a/src/messagein.cpp b/src/messagein.cpp index 88e673d7..c1736bbd 100644 --- a/src/messagein.cpp +++ b/src/messagein.cpp @@ -23,9 +23,10 @@ #include "messagein.h" -#include #include +#include + #include "packet.h" MessageIn::MessageIn(Packet *packet): @@ -60,12 +61,14 @@ char MessageIn::readByte() short MessageIn::readShort() { + short value = -1; + if (mPacket) { if ( (mPos + sizeof(short)) <= mPacket->length ) { + value = ENET_NET_TO_HOST_16(*(short *)(mPacket->data + mPos)); mPos += sizeof(short); - return (short) SDLNet_Read16(&(mPacket->data[mPos - sizeof(short)])); } else { @@ -73,17 +76,19 @@ short MessageIn::readShort() // that requires less length. } } - return -1; + return value; } long MessageIn::readLong() { + long value = -1; + if (mPacket) { if ( (mPos + sizeof(long)) <= mPacket->length ) { + value = ENET_NET_TO_HOST_32(*(long *)(mPacket->data + mPos)); mPos += sizeof(long); - return (long) SDLNet_Read32(&(mPacket->data[mPos - sizeof(long)])); } else { @@ -91,7 +96,7 @@ long MessageIn::readLong() // that requires less length. } } - return -1; + return value; } std::string MessageIn::readString(int length) diff --git a/src/messageout.cpp b/src/messageout.cpp index e5400e64..7fa6e1fd 100644 --- a/src/messageout.cpp +++ b/src/messageout.cpp @@ -23,10 +23,10 @@ #include "messageout.h" -#include -#include #include +#include + #include "packet.h" MessageOut::MessageOut(): @@ -66,7 +66,7 @@ MessageOut::writeByte(char value) void MessageOut::writeShort(short value) { expand(mPos + sizeof(short)); - SDLNet_Write16(value, &mData[mPos]); + (*(short *)&mData[mPos]) = ENET_HOST_TO_NET_16(value); mPos += sizeof(short); } @@ -74,7 +74,7 @@ void MessageOut::writeLong(long value) { expand(mPos + sizeof(long)); - SDLNet_Write32(value, &mData[mPos]); + (*(long *)&mData[mPos]) = ENET_HOST_TO_NET_32(value); mPos += sizeof(long); } @@ -119,3 +119,15 @@ MessageOut::getPacket() return mPacket; } + +char* +MessageOut::getData() +{ + return mData; +} + +unsigned int +MessageOut::getDataSize() +{ + return mDataSize; +} diff --git a/src/messageout.h b/src/messageout.h index f13695ab..245c3dca 100644 --- a/src/messageout.h +++ b/src/messageout.h @@ -60,6 +60,16 @@ class MessageOut * a call to this method. */ const Packet *getPacket(); + + /** + * Returns the content of the message. + */ + char *getData(); + + /** + * Returns the length of the data. + */ + unsigned int getDataSize(); private: /** diff --git a/src/netcomputer.cpp b/src/netcomputer.cpp index f3f1aeb7..1c736f47 100644 --- a/src/netcomputer.cpp +++ b/src/netcomputer.cpp @@ -27,9 +27,9 @@ #include "packet.h" #include "state.h" -NetComputer::NetComputer(ConnectionHandler *handler, TCPsocket sock): +NetComputer::NetComputer(ConnectionHandler *handler, ENetPeer *peer): handler(handler), - socket(sock), + peer(peer), mAccountPtr(NULL), mCharacterPtr(NULL) { @@ -48,7 +48,13 @@ void NetComputer::disconnect(const std::string &reason) void NetComputer::send(const Packet *p) { - SDLNet_TCP_Send(socket, p->data, p->length); + // Create a reliable packet. + ENetPacket *packet = enet_packet_create(p->data, + p->length + 1, + ENET_PACKET_FLAG_RELIABLE); + + // Send the packet to the peer over channel id 0. + enet_peer_send(peer, 0, packet); } void NetComputer::setAccount(tmwserv::AccountPtr acc) diff --git a/src/netcomputer.h b/src/netcomputer.h index 89ad6ba7..2e74c960 100644 --- a/src/netcomputer.h +++ b/src/netcomputer.h @@ -25,9 +25,10 @@ #define _TMWSERV_NETCOMPUTER_H_ #include -#include #include +#include + #include "account.h" #include "being.h" @@ -45,7 +46,7 @@ class NetComputer /** * Constructor. */ - NetComputer(ConnectionHandler *handler, TCPsocket sock); + NetComputer(ConnectionHandler *handler, ENetPeer *peer); /** * Destructor @@ -73,9 +74,9 @@ class NetComputer //void send(Packet *p, bool reliable = true); /** - * Return the socket + * Return the peer */ - TCPsocket getSocket() { return socket; } + ENetPeer *getPeer() { return peer; } /** * Set the account associated with the connection @@ -112,7 +113,7 @@ class NetComputer ConnectionHandler *handler; std::queue queue; /**< Message Queue (FIFO) */ - TCPsocket socket; /**< Client socket */ + ENetPeer *peer; /**< Client peer */ tmwserv::AccountPtr mAccountPtr; /**< Account associated with connection */ tmwserv::BeingPtr mCharacterPtr; /**< Selected character */ diff --git a/src/netsession.cpp b/src/netsession.cpp index 23476f6d..0a56d7c0 100644 --- a/src/netsession.cpp +++ b/src/netsession.cpp @@ -23,8 +23,12 @@ #include "netsession.h" +#include + #include "connectionhandler.h" +#include "utils/logger.h" + /** * This function is the new thread created to listen to a server socket. It * immediately passes control over to the connection handler instance that will @@ -58,28 +62,32 @@ void NetSession::startListen(ConnectionHandler *handler, Uint16 port) data->handler = handler; data->running = true; - // Fill in IPaddress for opening local server socket - if (SDLNet_ResolveHost(&data->address, NULL, port) == -1) { - printf("SDLNet_ResolveHost: %s\n", SDLNet_GetError()); - exit(6); - } + ENetHost *server; - // Attempt to open the local server socket - data->socket = SDLNet_TCP_Open(&data->address); + // Bind the server to the default localhost. + data->address.host = ENET_HOST_ANY; + data->address.port = port; - if (!data->socket) { - printf("SDLNet_TCP_Open: %s\n", SDLNet_GetError()); + server = enet_host_create(&data->address /* the address to bind the server host to */, + MAX_CLIENTS /* allow up to MAX_CLIENTS clients and/or outgoing connections */, + 0 /* assume any amount of incoming bandwidth */, + 0 /* assume any amount of outgoing bandwidth */); + if (server == NULL) + { + LOG_ERROR("Unable to create an ENet server host.", 0); exit(3); } - + + data->host = server; + // Start the listening thread data->thread = SDL_CreateThread(startListenThread, data); if (data->thread == NULL) { - printf("SDL_CreateThread: %s\n", SDL_GetError()); - exit(5); + LOG_ERROR("SDL_CreateThread: " << SDL_GetError(), 0); + exit(4); } - + listeners[port] = data; } @@ -99,13 +107,13 @@ void NetSession::stopListen(Uint16 port) // Note: Somewhere in this process the ConnectionHandler should receive // disconnect notifications about all the connected clients. SDL_WaitThread(data->thread, NULL); - SDLNet_TCP_Close(data->socket); + enet_host_destroy(data->host); delete data; listeners.erase(threadDataI); } else { - printf("NetSession::stopListen() not listening to port %d!\n", port); + LOG_WARN("NetSession::stopListen() not listening to port %d!\n", port); } } @@ -115,22 +123,48 @@ NetComputer *NetSession::connect(const std::string &host, Uint16 port) // can be used to send messages that way, or NULL when failing to connect. // // An asynchroneous wrapper could be created around this method. + + ENetHost *client; + + client = enet_host_create(NULL, 1, 0, 0); + + if (client == NULL) + { + LOG_ERROR("Unable to create an ENet client host.", 0); + exit(3); + } + + ENetAddress address; + ENetEvent event; + ENetPeer *peer; - IPaddress address; + // Connect to host:port. + enet_address_set_host(&address, host.c_str()); + address.port = port; - if (!SDLNet_ResolveHost(&address, host.c_str(), port)) + // Initiate the connection, allocating the channel 0. + peer = enet_host_connect(client, &address, 1); + + if (peer == NULL) { - TCPsocket tcpsock = SDLNet_TCP_Open(&address); - if (!tcpsock) { - printf("SDLNet_TCP_Open: %s\n", SDLNet_GetError()); - exit(3); - } + LOG_ERROR("No available peer for initiating an ENet connection.", 0); + exit(4); + } - // return computer; + // Wait up to 5 seconds for the connection attempt to succeed. + if (enet_host_service (client, &event, 5000) > 0 && + event.type == ENET_EVENT_TYPE_CONNECT) + { + LOG_INFO("Connection succeeded.", 0); } - else { - printf("SDLNet_ResolveHost: Could not resolve %s\n", host.c_str()); - exit(4); + else + { + /* Either the 5 seconds are up or a disconnect event was */ + /* received. Reset the peer in the event the 5 seconds */ + /* had run out without any significant event. */ + enet_peer_reset(peer); + LOG_ERROR("Connection failed.", 0); + exit(5); } return NULL; diff --git a/src/netsession.h b/src/netsession.h index b02b9ede..e50cc6e7 100644 --- a/src/netsession.h +++ b/src/netsession.h @@ -25,9 +25,10 @@ #define _TMWSERV_NETSESSION_H_ #include -#include #include +#include + class ConnectionHandler; class NetComputer; @@ -37,8 +38,8 @@ class NetComputer; */ struct ListenThreadData { - IPaddress address; /**< Includes the port to listen to. */ - TCPsocket socket; /**< The socket that's been opened. */ + ENetAddress address; /**< Includes the port to listen to. */ + ENetHost *host; /**< The host that listen for connections. */ SDL_Thread *thread; /**< The thread, ignored by thread itself. */ ConnectionHandler *handler; /**< Handler for events. */ bool running; /**< Wether to keep listening. */ diff --git a/src/utils/logger.cpp b/src/utils/logger.cpp index cd620f69..93dd289b 100644 --- a/src/utils/logger.cpp +++ b/src/utils/logger.cpp @@ -238,9 +238,6 @@ Logger::fatal(const std::string& msg, unsigned short atVerbosity) else { log((mLogFile.is_open() ? mLogFile : std::cerr), msg, "[FTL]"); } -#ifdef WIN32 - MessageBox(NULL, msg.c_str(), "Fatal error", MB_ICONERROR | MB_OK); -#endif } diff --git a/tmwserv.dev b/tmwserv.dev index a325e6b6..931d73cc 100644 --- a/tmwserv.dev +++ b/tmwserv.dev @@ -12,7 +12,7 @@ ResourceIncludes= MakeIncludes= Compiler=_@@_ CppCompiler=-DSQLITE_SUPPORT_@@_ -Linker=-lmingw32_@@_-lSDL_@@_-lSDL_net_@@_-lsqlite3_@@_-lxml2_@@_-lphysfs_@@_-lz_@@_-mconsole_@@_-mwindows_@@_ +Linker=-lmingw32_@@_-lSDL_@@_-lenet_@@_-lws2_32_@@_-lsqlite3_@@_-lxml2_@@_-lphysfs_@@_-lz_@@_-mconsole_@@_-mwindows_@@_-lwinmm_@@_ IsCpp=1 Icon= ExeOutput= -- cgit v1.2.3-60-g2f50