Permalink
Browse files

Add test server handling RPC dispatch, add script to generate proto code

- The server has a basic/unfinished implementation of the bnet RPC
  protocol over the network. Still missing is sending RPC requests
  to the client
  • Loading branch information...
1 parent 259df15 commit b76d50b282172b66e95edd49f29fc4ad3dbf1aa1 @fry committed Sep 18, 2011
Showing with 264,458 additions and 0 deletions.
  1. +27 −0 generate_proto_files.py
  2. BIN server/Google.ProtocolBuffers.dll
  3. +4,536 −0 server/Google.ProtocolBuffers.xml
  4. +20 −0 server/d3server.sln
  5. +229 −0 server/d3server/Client.cs
  6. +35 −0 server/d3server/Program.cs
  7. +36 −0 server/d3server/Properties/AssemblyInfo.cs
  8. +48 −0 server/d3server/ServiceRegistry.cs
  9. +22 −0 server/d3server/Services/AuthenticationServerImpl.cs
  10. +42 −0 server/d3server/Services/ChannelImpl.cs
  11. +57 −0 server/d3server/Services/ConnectionServiceImpl.cs
  12. +30 −0 server/d3server/Services/PresenceServiceImpl.cs
  13. +44 −0 server/d3server/Util.cs
  14. +118 −0 server/d3server/d3server.csproj
  15. +1,723 −0 server/d3server/pb/D3/Account/Account.cs
  16. +678 −0 server/d3server/pb/D3/AttributeSerializer/AttributeSerializer.cs
  17. +581 −0 server/d3server/pb/D3/Client/Settings.cs
  18. +337 −0 server/d3server/pb/D3/GameBalance/GBHandle.cs
  19. +2,937 −0 server/d3server/pb/D3/GameMessage/GameMessage.cs
  20. +6,965 −0 server/d3server/pb/D3/Hero/Hero.cs
  21. +880 −0 server/d3server/pb/D3/Hireling/Hireling.cs
  22. +722 −0 server/d3server/pb/D3/ItemCrafting/ItemCrafting.cs
  23. +4,007 −0 server/d3server/pb/D3/Items/Items.cs
  24. +2,575 −0 server/d3server/pb/D3/OnlineService/OnlineService.cs
  25. +735 −0 server/d3server/pb/D3/PartyMessage/PartyMessage.cs
  26. +718 −0 server/d3server/pb/D3/Quests/Quest.cs
  27. +692 −0 server/d3server/pb/D3/Stats/Stats.cs
  28. +383 −0 server/d3server/pb/bnet/protocol/ContentHandle.cs
  29. +310 −0 server/d3server/pb/bnet/protocol/Descriptor.cs
  30. +745 −0 server/d3server/pb/bnet/protocol/Entity.cs
  31. +1,629 −0 server/d3server/pb/bnet/protocol/Resource.cs
  32. +1,417 −0 server/d3server/pb/bnet/protocol/Rpc.cs
  33. +1,247 −0 server/d3server/pb/bnet/protocol/attribute/Attribute.cs
  34. +3,654 −0 server/d3server/pb/bnet/protocol/authentication/Authentication.cs
  35. +5,789 −0 server/d3server/pb/bnet/protocol/channel/Channel.cs
  36. +5,777 −0 server/d3server/pb/bnet/protocol/channel/ChannelTypes.cs
  37. +4,030 −0 server/d3server/pb/bnet/protocol/channel_invitation/ChannelInvitation.cs
  38. +1,258 −0 server/d3server/pb/bnet/protocol/channel_invitation/ChannelInvitationTypes.cs
  39. +199 −0 server/d3server/pb/bnet/protocol/chat/Chat.cs
  40. +385 −0 server/d3server/pb/bnet/protocol/chat/ChatTypes.cs
  41. +3,883 −0 server/d3server/pb/bnet/protocol/config/ProcessConfig.cs
  42. +3,344 −0 server/d3server/pb/bnet/protocol/connection/Connection.cs
  43. +1,335 −0 server/d3server/pb/bnet/protocol/exchange/Exchange.cs
  44. +9,050 −0 server/d3server/pb/bnet/protocol/exchange/ExchangeTypes.cs
  45. +2,497 −0 server/d3server/pb/bnet/protocol/exchange_object_provider/ExchangeObjectProvider.cs
  46. +3,531 −0 server/d3server/pb/bnet/protocol/followers/Followers.cs
  47. +5,109 −0 server/d3server/pb/bnet/protocol/friends/Friends.cs
  48. +645 −0 server/d3server/pb/bnet/protocol/friends/FriendsTypes.cs
  49. +448 −0 server/d3server/pb/bnet/protocol/game_master/GameFactory.cs
  50. +8,067 −0 server/d3server/pb/bnet/protocol/game_master/GameMaster.cs
  51. +2,335 −0 server/d3server/pb/bnet/protocol/game_master/GameMasterTypes.cs
  52. +5,509 −0 server/d3server/pb/bnet/protocol/game_utilities/GameUtilities.cs
  53. +2,227 −0 server/d3server/pb/bnet/protocol/invitation/Invitation.cs
  54. +1,965 −0 server/d3server/pb/bnet/protocol/notification/Notification.cs
  55. +198 −0 server/d3server/pb/bnet/protocol/party/Party.cs
  56. +1,894 −0 server/d3server/pb/bnet/protocol/presence/Presence.cs
  57. +1,448 −0 server/d3server/pb/bnet/protocol/presence/PresenceTypes.cs
  58. +611 −0 server/d3server/pb/bnet/protocol/profanity/Profanity.cs
  59. +1,676 −0 server/d3server/pb/bnet/protocol/search/Search.cs
  60. +1,095 −0 server/d3server/pb/bnet/protocol/search/SearchTypes.cs
  61. +1,645 −0 server/d3server/pb/bnet/protocol/server_pool/ServerPool.cs
  62. +6,446 −0 server/d3server/pb/bnet/protocol/storage/Storage.cs
  63. +940 −0 server/d3server/pb/bnet/protocol/toon/Toon.cs
  64. +2,239 −0 server/d3server/pb/bnet/protocol/toon/external/ToonExternal.cs
  65. +5,361 −0 server/d3server/pb/bnet/protocol/user_manager/UserManager.cs
  66. +1,723 −0 server/pb/D3/Account/Account.cs
  67. +678 −0 server/pb/D3/AttributeSerializer/AttributeSerializer.cs
  68. +581 −0 server/pb/D3/Client/Settings.cs
  69. +337 −0 server/pb/D3/GameBalance/GBHandle.cs
  70. +2,937 −0 server/pb/D3/GameMessage/GameMessage.cs
  71. +6,965 −0 server/pb/D3/Hero/Hero.cs
  72. +880 −0 server/pb/D3/Hireling/Hireling.cs
  73. +722 −0 server/pb/D3/ItemCrafting/ItemCrafting.cs
  74. +4,007 −0 server/pb/D3/Items/Items.cs
  75. +2,575 −0 server/pb/D3/OnlineService/OnlineService.cs
  76. +735 −0 server/pb/D3/PartyMessage/PartyMessage.cs
  77. +718 −0 server/pb/D3/Quests/Quest.cs
  78. +692 −0 server/pb/D3/Stats/Stats.cs
  79. +383 −0 server/pb/bnet/protocol/ContentHandle.cs
  80. +310 −0 server/pb/bnet/protocol/Descriptor.cs
  81. +745 −0 server/pb/bnet/protocol/Entity.cs
  82. +1,629 −0 server/pb/bnet/protocol/Resource.cs
  83. +1,417 −0 server/pb/bnet/protocol/Rpc.cs
  84. +1,247 −0 server/pb/bnet/protocol/attribute/Attribute.cs
  85. +3,654 −0 server/pb/bnet/protocol/authentication/Authentication.cs
  86. +5,789 −0 server/pb/bnet/protocol/channel/Channel.cs
  87. +5,777 −0 server/pb/bnet/protocol/channel/ChannelTypes.cs
  88. +4,030 −0 server/pb/bnet/protocol/channel_invitation/ChannelInvitation.cs
  89. +1,258 −0 server/pb/bnet/protocol/channel_invitation/ChannelInvitationTypes.cs
  90. +199 −0 server/pb/bnet/protocol/chat/Chat.cs
  91. +385 −0 server/pb/bnet/protocol/chat/ChatTypes.cs
  92. +3,883 −0 server/pb/bnet/protocol/config/ProcessConfig.cs
  93. +3,344 −0 server/pb/bnet/protocol/connection/Connection.cs
  94. +12,807 −0 server/pb/bnet/protocol/exchange/Exchange.cs
  95. +9,050 −0 server/pb/bnet/protocol/exchange/ExchangeTypes.cs
  96. +2,497 −0 server/pb/bnet/protocol/exchange_object_provider/ExchangeObjectProvider.cs
  97. +3,531 −0 server/pb/bnet/protocol/followers/Followers.cs
  98. +5,109 −0 server/pb/bnet/protocol/friends/Friends.cs
  99. +645 −0 server/pb/bnet/protocol/friends/FriendsTypes.cs
  100. +448 −0 server/pb/bnet/protocol/game_master/GameFactory.cs
  101. +8,067 −0 server/pb/bnet/protocol/game_master/GameMaster.cs
  102. +2,335 −0 server/pb/bnet/protocol/game_master/GameMasterTypes.cs
  103. +5,509 −0 server/pb/bnet/protocol/game_utilities/GameUtilities.cs
  104. +2,227 −0 server/pb/bnet/protocol/invitation/Invitation.cs
  105. +1,965 −0 server/pb/bnet/protocol/notification/Notification.cs
  106. +198 −0 server/pb/bnet/protocol/party/Party.cs
  107. +1,894 −0 server/pb/bnet/protocol/presence/Presence.cs
  108. +1,448 −0 server/pb/bnet/protocol/presence/PresenceTypes.cs
  109. +611 −0 server/pb/bnet/protocol/profanity/Profanity.cs
  110. +1,676 −0 server/pb/bnet/protocol/search/Search.cs
  111. +1,095 −0 server/pb/bnet/protocol/search/SearchTypes.cs
  112. +1,645 −0 server/pb/bnet/protocol/server_pool/ServerPool.cs
  113. +6,446 −0 server/pb/bnet/protocol/storage/Storage.cs
  114. +940 −0 server/pb/bnet/protocol/toon/Toon.cs
  115. +2,239 −0 server/pb/bnet/protocol/toon/external/ToonExternal.cs
  116. +5,361 −0 server/pb/bnet/protocol/user_manager/UserManager.cs
View
@@ -0,0 +1,27 @@
+import subprocess
+import sys
+import os
+
+if len(sys.argv) < 3:
+ print "Usage: %s in_dir out_dir" % sys.argv[0]
+ sys.exit()
+
+in_dir = sys.argv[1]
+out_dir = sys.argv[2]
+
+in_files = []
+for root, dirs, files in os.walk(in_dir):
+ for file in files:
+ in_files.append(os.path.join(root, file))
+
+#for file in in_files:
+# print "Building " + file
+subprocess.call([
+ "protogen",
+ "--proto_path=%s" % in_dir,
+ "--include_imports",
+ "-service_generator_type=GENERIC",
+ "-expand_namespace_directories=true",
+ "-cls_compliance=false",
+ "-ignore_google_protobuf=true",
+ "-output_directory=%s" % out_dir] + in_files)
Binary file not shown.

Large diffs are not rendered by default.

Oops, something went wrong.
View
@@ -0,0 +1,20 @@
+
+Microsoft Visual Studio Solution File, Format Version 11.00
+# Visual Studio 2010
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "d3server", "d3server\d3server.csproj", "{0F53B868-28AC-4ABA-9D7A-B49047FF8CA7}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|x86 = Debug|x86
+ Release|x86 = Release|x86
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {0F53B868-28AC-4ABA-9D7A-B49047FF8CA7}.Debug|x86.ActiveCfg = Debug|x86
+ {0F53B868-28AC-4ABA-9D7A-B49047FF8CA7}.Debug|x86.Build.0 = Debug|x86
+ {0F53B868-28AC-4ABA-9D7A-B49047FF8CA7}.Release|x86.ActiveCfg = Release|x86
+ {0F53B868-28AC-4ABA-9D7A-B49047FF8CA7}.Release|x86.Build.0 = Release|x86
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+EndGlobal
View
@@ -0,0 +1,229 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using Google.ProtocolBuffers;
+using System.Net.Sockets;
+using System.Threading;
+using Google.ProtocolBuffers.Descriptors;
+using System.Diagnostics;
+using System.IO;
+
+namespace d3server {
+ public class Client: IRpcChannel {
+ const int RESPONSE_SERVICE_ID = 0xFE;
+
+ struct ResponseData {
+ public IMessage ResponsePrototype;
+ public Action<IMessage> Callback;
+ }
+
+ class SendQueueEntry {
+ public byte ServiceId;
+ public uint MethodId;
+ public ushort RequestId;
+ public uint? ListenerId;
+ public IMessage Message;
+ }
+
+ // TODO: add a service type -> service lookup map
+ // The services the server exports to the client
+ Dictionary<uint, IService> exportedServices = new Dictionary<uint, IService>();
+ // Counter for ID to use for next exported service
+ uint exportCounter = 0;
+ // The services the client exports to the server (or the server imports from the client)
+ Dictionary<uint, IService> importedServices = new Dictionary<uint, IService>();
+ // Callback functions waiting for responses to the specified requestID
+ Dictionary<int, ResponseData> awaitingResponse = new Dictionary<int, ResponseData>();
+
+ ServiceRegistry registry;
+ TcpClient socket;
+
+ Queue<SendQueueEntry> sendQueue = new Queue<SendQueueEntry>();
+
+ public Client(ServiceRegistry registry) {
+ this.registry = registry;
+
+ // ConnectionService is expected to be exported on index 0
+ ExportService("bnet.protocol.connection.ConnectionService", 0);
+ }
+
+ public void Start(TcpClient socket) {
+ this.socket = socket;
+
+ new Thread(new ThreadStart(ReadLoop)).Start();
+ new Thread(new ThreadStart(WriteLoop)).Start();
+ }
+
+ /// <summary>
+ /// Export a service to the client based on its name
+ /// </summary>
+ /// <param name="name">the fully qualified name of the service, i.e.: "bnet.protocol.connection.ConnectionService"</param>
+ /// <param name="overwriteIndex"></param>
+ /// <returns></returns>
+ public uint ExportService(string name, uint? overwriteIndex = null) {
+ var hash = ServiceRegistry.GetServiceHash(name);
+ return ExportService(hash, overwriteIndex);
+ }
+
+ /// <summary>
+ /// Export a service to the client based on its hash
+ /// </summary>
+ /// <param name="hash"></param>
+ /// <param name="overwriteIndex"></param>
+ /// <returns></returns>
+ public uint ExportService(uint hash, uint? overwriteIndex = null) {
+ // TODO: check if the service is already bound
+
+ // Lookup the service with this hash in the registry
+ var service = registry.CreateBoundService(hash, this);
+ // Determine the index to use
+ uint index = exportCounter ++;
+ // If an overwrite index is specified (required for ConnectionService), correct counter
+ if (overwriteIndex.HasValue) {
+ index = overwriteIndex.Value;
+ exportCounter = index + 1;
+ }
+ exportedServices.Add(index, service);
+ return index;
+ }
+
+ public void ImportService(uint hash, uint index) {
+ var service = registry.CreateStub(hash, this);
+ }
+
+ public void CallMethod(MethodDescriptor method, IRpcController controller, IMessage request, IMessage responsePrototype, Action<IMessage> done) {
+ // TODO: send RPC call to client
+ throw new NotImplementedException();
+ }
+
+ public void SendResponse(ushort requestId, IMessage message) {
+ lock (sendQueue) {
+ sendQueue.Enqueue(new SendQueueEntry {
+ ServiceId = RESPONSE_SERVICE_ID,
+ ListenerId = null,
+ RequestId = requestId,
+ MethodId = 0, // TODO: Add error code here
+ Message = message
+ });
+
+ // Notify the waiting write loop
+ Monitor.Pulse(sendQueue);
+ }
+ }
+
+ public void Disconnect(string reason) {
+ Debug.WriteLine("Disconnecting client: " + reason);
+ socket.Close();
+ }
+
+ void ReadLoop() {
+ var reader = CodedInputStream.CreateInstance(socket.GetStream());
+ while (socket.Connected) {
+ try {
+ HandlePacket(reader);
+ } catch (Exception e) {
+ Disconnect(e.Message);
+ }
+ }
+ }
+
+ void WriteLoop() {
+ var writer = CodedOutputStream.CreateInstance(socket.GetStream());
+ while (socket.Connected) {
+ try {
+ SendQueueEntry send_data = null;
+ lock (sendQueue) {
+ // Wait for messages in the send queue
+ while (sendQueue.Count == 0)
+ Monitor.Wait(sendQueue);
+
+ send_data = sendQueue.Dequeue();
+ }
+
+ SendData(writer, send_data);
+ } catch (Exception e) {
+ Disconnect(e.Message);
+ }
+ }
+ }
+
+ void SendData(CodedOutputStream writer, SendQueueEntry data) {
+ // Write to a temp buffer so we can inspect what we send
+ var stream = new MemoryStream();
+ var temp_writer = CodedOutputStream.CreateInstance(stream);
+ temp_writer.WriteRawByte(data.ServiceId);
+ temp_writer.WriteUInt32NoTag(data.MethodId);
+ temp_writer.WriteFixedUInt16(data.RequestId);
+ if (data.ListenerId.HasValue)
+ temp_writer.WriteUInt32NoTag(data.ListenerId.Value);
+
+ temp_writer.WriteMessageNoTag(data.Message);
+ temp_writer.Flush();
+
+ var buffer = stream.ToArray();
+ Debug.WriteLine("Sending data: ");
+ Debug.WriteLine(buffer.ToHexString());
+
+ writer.WriteRawBytes(buffer);
+ writer.Flush();
+ }
+
+ void HandlePacket(CodedInputStream reader) {
+ var service_id = reader.ReadRawByte();
+ var method_id = reader.ReadInt32() - 1;
+ var request_id = reader.ReadFixedUInt16();
+
+ Debug.WriteLine("Received packet [service_id: 0x{0:X2}, method_id: {1}, request_id: {2}]", service_id, method_id, request_id);
+ Debug.Indent();
+ // Handle RPC responses
+ if (service_id == RESPONSE_SERVICE_ID) {
+ Debug.WriteLine("received response");
+ HandleResponse(request_id, reader);
+ } else {
+ var listener_id = reader.ReadInt64();
+ Debug.WriteLine("listener_id: {0}", listener_id);
+
+ IService service;
+ if (!exportedServices.TryGetValue(service_id, out service))
+ throw new ArgumentException("No service bound on index " + service_id);
+
+ // Load correct descriptor for the requested method
+ var method_descriptor = service.DescriptorForType.Methods[method_id];
+ // Create a prototype of the request message
+ var message_prototype = service.GetRequestPrototype(method_descriptor);
+ // And create a builder for that message
+ var builder = message_prototype.WeakCreateBuilderForType();
+ // Read the message into the correct builder
+ var message = ReadMessage(reader, builder);
+
+ Debug.WriteLine("passing RPC to {0}::{1}", method_descriptor.Service.Name, method_descriptor.Name);
+ Debug.WriteLine(message.ToString());
+
+ // Response callback sends the repsponse
+ service.CallMethod(method_descriptor, null, message, m => SendResponse(request_id, m));
+ }
+ Debug.Unindent();
+ }
+
+ void HandleResponse(int requestId, CodedInputStream reader) {
+ // Lookup the request id in the dictionary containing pending responses
+ ResponseData response_data;
+ if (!awaitingResponse.TryGetValue(requestId, out response_data))
+ throw new ArgumentException("No pending response with the id " + requestId);
+
+ // Retrieve the correct prototype and create a builder
+ var message_builder = response_data.ResponsePrototype.WeakCreateBuilderForType();
+ // Read the message into the correct builder
+ var message = ReadMessage(reader, message_builder);
+
+ // Invoke the registered callback
+ response_data.Callback(message);
+ }
+
+ IMessage ReadMessage(CodedInputStream reader, IBuilder builder) {
+ reader.ReadMessage(builder, ExtensionRegistry.Empty);
+ return builder.WeakBuild();
+ }
+ }
+}
View
@@ -0,0 +1,35 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+using Google.ProtocolBuffers;
+using System.Net.Sockets;
+using System.Net;
+using Google.ProtocolBuffers.Descriptors;
+using System.Threading;
+using d3server.Services;
+
+namespace d3server {
+
+
+ class Program {
+ static void Main(string[] args) {
+ var listener = new TcpListener(IPAddress.Any, 6666);
+
+ var registry = new ServiceRegistry();
+
+ registry.RegisterService("bnet.protocol.connection.ConnectionService", typeof(ConnectionServiceImpl));
+ registry.RegisterService("bnet.protocol.channel.Channel", typeof(ChannelImpl));
+ registry.RegisterService("bnet.protocol.presence.PresenceService", typeof(PresenceServiceImpl));
+ registry.RegisterService("bnet.protocol.authentication.AuthenticationServer", typeof(AuthenticationServerImpl));
+
+ listener.Start();
+
+ var client = new Client(registry);
+ client.Start(listener.AcceptTcpClient());
+
+ Console.ReadLine();
+ }
+ }
+}
@@ -0,0 +1,36 @@
+using System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+// General Information about an assembly is controlled through the following
+// set of attributes. Change these attribute values to modify the information
+// associated with an assembly.
+[assembly: AssemblyTitle("d3server")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("Microsoft")]
+[assembly: AssemblyProduct("d3server")]
+[assembly: AssemblyCopyright("Copyright © Microsoft 2011")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+// Setting ComVisible to false makes the types in this assembly not visible
+// to COM components. If you need to access a type in this assembly from
+// COM, set the ComVisible attribute to true on that type.
+[assembly: ComVisible(false)]
+
+// The following GUID is for the ID of the typelib if this project is exposed to COM
+[assembly: Guid("25b8f990-f2cb-4bf3-8cc5-b56e24f0d08e")]
+
+// Version information for an assembly consists of the following four values:
+//
+// Major Version
+// Minor Version
+// Build Number
+// Revision
+//
+// You can specify all the values or you can default the Build and Revision Numbers
+// by using the '*' as shown below:
+// [assembly: AssemblyVersion("1.0.*")]
+[assembly: AssemblyVersion("1.0.0.0")]
+[assembly: AssemblyFileVersion("1.0.0.0")]
Oops, something went wrong.

0 comments on commit b76d50b

Please sign in to comment.