/// <summary> /// Packet Type: 1052. This packet is sent as a response to the account server's authentication reply to /// complete the authentication process. This packet contains the client's identification data and the client's /// region and patch number. The client should be authenticated by the message server and connected with the /// map server. /// </summary> /// <param name="pClient">The client requesting access to the server.</param> /// <param name="pMsg">The authentication packet requesting processing.</param> public static void HandleConnect(Client pClient, MsgConnect pMsg) { if (pClient.Identity == 0) // not authenticated { if (ServerKernel.LoginServer == null) // if login server is down, no login allowed { pClient.Disconnect(); return; } // Decrypt important client data from the Account Server: var pCipher = new PhoenixTransferCipher(ServerKernel.TransferKey, ServerKernel.TransferSalt, pClient.IpAddress); var pDecrypted = pCipher.Decrypt(new[] { pMsg.Identity, pMsg.Authentication }); // let's check if the player has really requested the login into the account server LoginRequest pRequest; if (ServerKernel.LoginQueue.TryRemove(pDecrypted[0], out pRequest)) { // user found if (!pRequest.IsValid(pDecrypted[0], pDecrypted[1], pClient.IpAddress)) { // something is not right, disconnect. pClient.Disconnect(); return; } } else { Client trash; if (!ServerKernel.CharacterCreation.TryRemove(pDecrypted[0], out trash)) { // user did not request a login token on the account server pClient.Disconnect(); return; } } // Assign authentication data to the client: pClient.AccountIdentity = pMsg.Identity = pDecrypted[0]; pClient.Language = pMsg.Language; //pClient.VipLevel = pRequest.VipLevel; //pClient.Authority = pRequest.Authority; InitializeCharacter(pClient, pMsg); } else { InitializeCharacter(pClient, pMsg); } }
private static unsafe void notificationLoop(object natTraversalSession) { NatTraversalSession session = (NatTraversalSession)natTraversalSession; Timer keepAliveTimer = null; try { IPEndPoint serviceEndPoint = null; // connect to service to open a port on the NAT devices using (Socket notificationSocket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp)) { notificationSocket.Connect(natTraversalServiceUrl, natTraversalServicePort); serviceEndPoint = (IPEndPoint)notificationSocket.RemoteEndPoint; session.LocalEndPoint = (IPEndPoint)notificationSocket.LocalEndPoint; } // create a new socket in listening mode using the port just opened using (Socket notificationSocket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp)) { notificationSocket.ReceiveTimeout = 1000; notificationSocket.Bind(session.LocalEndPoint); // send "open notification channel" message { MsgOpenNotificationChannel msg = new MsgOpenNotificationChannel(session.SessionId); byte[] datagram = new byte[sizeof(MsgOpenNotificationChannel)]; for (int i = 0; i < datagram.Length; ++i) { datagram[i] = ((byte *)&msg)[i]; } notificationSocket.SendTo(datagram, serviceEndPoint); } while (true) { // block until a message is received or 1 second has elapsed EndPoint any = new IPEndPoint(IPAddress.Any, 0); byte[] bytesReceived = new byte[1024]; int bytesReceivedLength = notificationSocket.ReceiveFrom(bytesReceived, ref any); IPEndPoint remoteEndPoint = (IPEndPoint)any; // test for stop condition: a message send from this local endpoint to itself if (remoteEndPoint.Equals(session.LocalEndPoint)) { break; } else if (remoteEndPoint.Equals(serviceEndPoint)) { // handle the message if (bytesReceivedLength >= 3 && bytesReceived[0] == 'z' && bytesReceived[1] == 't') { switch (bytesReceived[2]) { case (byte)MessageType.AckOpenNotificationChannel: if (bytesReceivedLength == sizeof(MsgAckOpenNotificationChannel)) { MsgAckOpenNotificationChannel msg = new MsgAckOpenNotificationChannel(); for (int i = 0; i < sizeof(MsgAckOpenNotificationChannel); ++i) { ((byte *)&msg)[i] = bytesReceived[i]; } // handle MsgAckOpenNotificationChannel // send "host" message, from the same port as DirectPlay (spoofed) IPEndPoint spoofedEndPoint = new IPEndPoint(session.LocalEndPoint.Address, session.PrivatePort); MsgHost msgHost = new MsgHost(session.SessionId, session.LocalEndPoint.Address, (ushort)session.PrivatePort); byte[] datagram = new byte[sizeof(MsgHost)]; for (int i = 0; i < datagram.Length; ++i) { datagram[i] = ((byte *)&msgHost)[i]; } PortSpoofing.Send(spoofedEndPoint, serviceEndPoint, datagram); } break; case (byte)MessageType.AckHost: if (bytesReceivedLength == sizeof(MsgAckHost)) { if (keepAliveTimer == null) // ignore if already handled { MsgAckHost msg = new MsgAckHost(); for (int i = 0; i < sizeof(MsgAckHost); ++i) { ((byte *)&msg)[i] = bytesReceived[i]; } // handle MsgAckHost // record public address/port session.PublicIpAddress = new IPAddress((uint)IPAddress.HostToNetworkOrder((int)msg.HostPublicIp)).ToString(); session.PublicPort = msg.HostPublicPort; // notify main thread that NAT traversal is enabled session.Enabled = true; if (session.NatTraversalEnabled != null) { session.NatTraversalEnabled.Set(); } // set reception so it can't time-out notificationSocket.ReceiveTimeout = 0; // send a keep alive message every 19 seconds KeepAliveSettings settings = new KeepAliveSettings(); settings.SpoofedLocalEndPoint = session.LocalEndPoint; settings.ServiceEndPoint = serviceEndPoint; MsgKeepAlive msgKeepAlive = new MsgKeepAlive(session.SessionId); settings.Datagram = new byte[sizeof(MsgKeepAlive)]; for (int i = 0; i < settings.Datagram.Length; ++i) { settings.Datagram[i] = ((byte *)&msgKeepAlive)[i]; } keepAliveTimer = new Timer(new TimerCallback(keepAlive), settings, 19000, 19000); } } break; case (byte)MessageType.Connect: if (bytesReceivedLength == sizeof(MsgConnect)) { MsgConnect msg = new MsgConnect(); for (int i = 0; i < sizeof(MsgConnect); ++i) { ((byte *)&msg)[i] = bytesReceived[i]; } // handle MsgConnect // punch hole targeting client's public and private addresses IPAddress publicClientAddress = new IPAddress((uint)IPAddress.HostToNetworkOrder((int)msg.ClientPublicIp)); IPAddress privateClientAddress = new IPAddress((uint)IPAddress.HostToNetworkOrder((int)msg.ClientPrivateIp)); IPEndPoint spoofedEndPoint = new IPEndPoint(session.LocalEndPoint.Address, session.PrivatePort); byte[] emptyDatagram = new byte[0]; PortSpoofing.Send(spoofedEndPoint, new IPEndPoint(publicClientAddress, msg.ClientPublicPort), emptyDatagram); PortSpoofing.Send(spoofedEndPoint, new IPEndPoint(privateClientAddress, msg.ClientPrivatePort), emptyDatagram); // send acknowledgement through notification channel MsgAckConnect msgAckConnect = new MsgAckConnect(session.SessionId, publicClientAddress, msg.ClientPublicPort); byte[] datagram = new byte[sizeof(MsgAckConnect)]; for (int i = 0; i < datagram.Length; ++i) { datagram[i] = ((byte *)&msgAckConnect)[i]; } notificationSocket.SendTo(datagram, serviceEndPoint); } break; } } } } } } catch { if (!session.Enabled && session.NatTraversalEnabled != null) { session.NatTraversalEnabled.Set(); } } finally { if (keepAliveTimer != null) { keepAliveTimer.Change(Timeout.Infinite, Timeout.Infinite); keepAliveTimer.Dispose(); } } }
public static ClientBasePacket HandlePacket(byte[] data, int offset, GameSession client) { // Calculate message size var size = (short)((data[offset + 1] << 8) + data[offset]); // Copy the packet to a new byte array // Skipping the header var packet = new byte[size]; Array.Copy(data, offset, packet, 0, size); ClientBasePacket msg; // Get the id var id = packet[2]; // Handle the packet // TODO: Can we group these into login / game / etc? switch (id) { case 0x00: msg = new ProtocolVersion(packet, client); break; case 0x01: msg = new ValidateClient(packet, client); break; case 0x03: msg = new ConnectClient(packet, client); break; case 0x04: msg = new ConnectSwitch(packet, client); break; case 0x05: msg = new SwitchServer(packet, client); break; case 0x06: msg = new ServerTime(packet, client); break; case 0x07: msg = new Message(packet, client); break; case 0x0d: msg = new Log(packet, client); break; case 0x0c: msg = new SyncMoney(packet, client); break; case 0x11: msg = new FactoryModifyUnit(packet, client); break; case 0x12: msg = new FactoryModifyEnd(packet, client); break; case 0x16: msg = new IsValidName(packet, client); break; case 0x17: msg = new FactoryChangeUnitName(packet, client); break; case 0x18: msg = new RequestInventory(packet, client); break; case 0x19: msg = new RequestSearchGame(packet, client); break; case 0x1b: msg = new CreateGame(packet, client); break; case 0x1c: msg = new EnterGame(packet, client); break; case 0x1f: msg = new ListUser(packet, client); break; case 0x20: msg = new Ready(packet, client); break; case 0x21: msg = new Exit(packet, client); break; case 0x22: msg = new StartGame(packet, client); break; case 0x2b: msg = new SelectBase(packet, client); break; case 0x2c: msg = new ReadyGame(packet, client); break; case 0x2e: msg = new RequestPalette(packet, client); break; case 0x2f: msg = new MoveUnit(packet, client); break; case 0x30: msg = new AimUnit(packet, client); break; case 0x31: msg = new StartAttack(packet, client); break; case 0x32: msg = new StopAttack(packet, client); break; case 0x35: msg = new RequestRegain(packet, client); break; case 0x38: msg = new ModeSniper(packet, client); break; case 0x3a: msg = new RequestChangeWeaponset(packet, client); break; case 0x3b: msg = new RequestQuitBattle(packet, client); break; case 0x3f: msg = new BuyList(packet, client); break; case 0x40: msg = new RequestGoodsData(packet, client); break; case 0x46: msg = new RequestAvatarInfo(packet, client); break; case 0x47: case 0x48: case 0x49: case 0x4a: case 0x4b: case 0x4c: case 0x4d: msg = new RequestStatsInfo(packet, client); break; case 0x4e: msg = new RequestBestInfo(packet, client); break; case 0x57: msg = new TutorialSelect(packet, client); break; case 0x5a: msg = new UnAimUnit(packet, client); break; case 0x63: msg = new MsgConnect(packet, client); break; case 0x64: msg = new MsgUserStateInfo(packet, client); break; case 0x66: msg = new MsgUserClanInfo(packet, client); break; case 0x67: msg = new MsgGetBuddyList(packet, client); break; case 0x69: msg = new MsgGetChannelList(packet, client); break; case 0x6a: msg = new MsgJoinChannel(packet, client); break; case 0x6b: msg = new MsgLeaveChannel(packet, client); break; case 0x6c: msg = new MsgChannelChatting(packet, client); break; case 0x71: msg = new RequestOperator(packet, client); break; case 0x72: msg = new SelectOperator(packet, client); break; default: msg = new UnknownPacket(packet, client); //Console.WriteLine("Unknown packet id [{0}] from user {1}", id, client.GetUserName()); break; } return(msg); }
public void HandleAuthenticationComplete(Client pClient, byte[] pBuffer) { MsgConnect pMsg = new MsgConnect(pBuffer); }
/// <summary> /// This function is called once the client has been authenticated. If the character for the client /// does not exist in the database, then this function will open the character creation screen; else, /// it will load character data and send the client information needed to log into the world. It will /// also connect the player to the map server. /// </summary> /// <param name="pClient">The client being processed.</param> /// <param name="pPacket">The authentication packet to be sent to the map server.</param> private static void InitializeCharacter(Client pClient, MsgConnect pPacket, bool bCreate = false) { // check if the server is full if (ServerKernel.Players.Count >= ServerKernel.MaxOnlinePlayer) { pClient.Send(ServerMessages.Login.ServerFull); pClient.Disconnect(); return; } DbAccount pAccount = new AccountRepository().SearchByIdentity(pClient.AccountIdentity); DbUser pUser = new CharacterRepository().SearchByAccount(pClient.AccountIdentity); if (pAccount != null && pUser != null) { if (pUser.Life <= 0) { pUser.Life = 1; } pClient.VipLevel = pAccount.Vip; pClient.Identity = pUser.Identity; pClient.AccountIdentity = pAccount.Identity; if (CheckGamePool(pClient, pClient.Identity) && ServerKernel.Players.TryAdd(pClient.Identity, pClient)) { // The client is ready and authorized for login. Prepare the client for the game world: load // spawn information and send it to the map server, and initialize game structures necessary // to log into the server. if (!bCreate) { pClient.Send(ServerMessages.Login.AnswerOk); } pClient.Send(new MsgUserIpInfo()); pClient.Send(new MsgServerInfo() { ClassicMode = 0, PotencyMode = 0 }); if (pUser.Lookface < 10000) { ushort body = (ushort)(pUser.Lookface % 10000); uint lookface = 0; if (body == (ushort)BodyType.THIN_MALE || body == (ushort)BodyType.HEAVY_MALE) { if ((pUser.Profession / 10) == 5) { lookface = (uint)(new Random().Next(103, 107)); } else if ((pUser.Profession / 10) == 6) { lookface = (uint)(new Random().Next(109, 113)); } else { lookface = (uint)(new Random().Next(1, 102)); } } else { if ((pUser.Profession / 10) == 5) { lookface = (uint)(new Random().Next(291, 295)); } else if ((pUser.Profession / 10) == 6) { lookface = (uint)(new Random().Next(300, 304)); } else { lookface = (uint)(new Random().Next(201, 290)); } } pUser.Lookface = lookface * 10000 + pUser.Lookface; } var pInfo = new MsgUserInfo(pUser.Name, string.Empty, pUser.Mate) { Agility = pUser.Agility, AncestorProfession = (byte)pUser.FirstProfession, Attributes = pUser.AdditionalPoints, BoundEmoney = pUser.BoundEmoney, ConquerPoints = pUser.Emoney, Enlighten = pUser.EnlightPoints, EnlightenExp = 0, Experience = pUser.Experience, Hairstyle = pUser.Hair, Health = pUser.Life, Mana = pUser.Mana, Identity = pUser.Identity, Level = pUser.Level, Mesh = pUser.Lookface, Vitality = pUser.Vitality, Spirit = pUser.Spirit, Metempsychosis = pUser.Metempsychosis, Strength = pUser.Strength, QuizPoints = pUser.StudentPoints, Silver = pUser.Money, PreviousProfession = (byte)pUser.LastProfession, Profession = (byte)pUser.Profession, PlayerTitle = pUser.SelectedTitle, PkPoints = pUser.PkPoints }; pClient.Character = new Character(pInfo, pUser, pClient); pClient.Send(pInfo); pClient.Send(new MsgData()); pClient.Screen = new Screen(pClient.Character); if (ServerKernel.Players.Count > ServerKernel.OnlineRecord) { ServerKernel.OnlineRecord = (ushort)ServerKernel.Players.Count; } ServerKernel.Log.SaveLog(string.Format("User [{0}] has logged in.", pClient.Character.Name), true, LogType.MESSAGE); ServerKernel.LoginServer.Send(new MsgLoginSvPlayerAmount((ushort)ServerKernel.Players.Count, LoginPlayerAmountRequest.REPLY_ONLINE_AMOUNT)); pUser.LastLogin = (uint)UnixTimestamp.Timestamp(); Database.Characters.SaveOrUpdate(pUser); } } else if (pAccount != null && CheckGamePool(pClient, 0) && ServerKernel.CharacterCreation.TryAdd(pClient.AccountIdentity, pClient)) { pClient.Send(ServerMessages.Login.NewRole); } else { pClient.Send(ServerMessages.Login.TransferFailed); pClient.Disconnect(); } }