blob: 3217547cc472197fd8973c59bd4d74f1deef88e0 [file] [log] [blame]
Jan Tattermuscha7fff862015-02-13 11:08:08 -08001#region Copyright notice and license
2
Jan Tattermuschaf77b3d2015-02-13 11:22:21 -08003// Copyright 2015, Google Inc.
Jan Tattermuscha7fff862015-02-13 11:08:08 -08004// All rights reserved.
Craig Tiller190d3602015-02-18 09:23:38 -08005//
Jan Tattermuscha7fff862015-02-13 11:08:08 -08006// Redistribution and use in source and binary forms, with or without
7// modification, are permitted provided that the following conditions are
8// met:
Craig Tiller190d3602015-02-18 09:23:38 -08009//
Jan Tattermuscha7fff862015-02-13 11:08:08 -080010// * Redistributions of source code must retain the above copyright
11// notice, this list of conditions and the following disclaimer.
12// * Redistributions in binary form must reproduce the above
13// copyright notice, this list of conditions and the following disclaimer
14// in the documentation and/or other materials provided with the
15// distribution.
16// * Neither the name of Google Inc. nor the names of its
17// contributors may be used to endorse or promote products derived from
18// this software without specific prior written permission.
Craig Tiller190d3602015-02-18 09:23:38 -080019//
Jan Tattermuscha7fff862015-02-13 11:08:08 -080020// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
23// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
24// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31
32#endregion
33
Jan Tattermuscha7608b02015-02-03 17:54:38 -080034using System;
Jan Tattermuscha7608b02015-02-03 17:54:38 -080035using System.Collections.Concurrent;
Jan Tattermusch8ce5e8b2015-02-05 10:56:49 -080036using System.Collections.Generic;
Jan Tattermusch30868622015-02-19 09:22:33 -080037using System.Diagnostics;
38using System.Runtime.InteropServices;
39using System.Threading.Tasks;
40using Grpc.Core.Internal;
Jan Tattermusch05261612015-07-24 00:28:16 -070041using Grpc.Core.Logging;
Jan Tattermusch97e294a2015-04-23 14:30:59 -070042using Grpc.Core.Utils;
Jan Tattermuscha7608b02015-02-03 17:54:38 -080043
Jan Tattermusch30868622015-02-19 09:22:33 -080044namespace Grpc.Core
Jan Tattermuscha7608b02015-02-03 17:54:38 -080045{
46 /// <summary>
Jan Tattermusch97e294a2015-04-23 14:30:59 -070047 /// A gRPC server.
Jan Tattermuscha7608b02015-02-03 17:54:38 -080048 /// </summary>
49 public class Server
50 {
Jan Tattermusch03e82e22015-05-06 16:37:12 -070051 /// <summary>
52 /// Pass this value as port to have the server choose an unused listening port for you.
53 /// </summary>
54 public const int PickUnusedPort = 0;
55
Jan Tattermusch05261612015-07-24 00:28:16 -070056 static readonly ILogger Logger = GrpcEnvironment.Logger.ForType<Server>();
57
Jan Tattermusch04eb89c2015-06-12 13:03:05 -070058 readonly GrpcEnvironment environment;
Jan Tattermusch766d72b2015-07-21 20:09:25 -070059 readonly List<ChannelOption> options;
Jan Tattermuscha7608b02015-02-03 17:54:38 -080060 readonly ServerSafeHandle handle;
Jan Tattermusch97e294a2015-04-23 14:30:59 -070061 readonly object myLock = new object();
Jan Tattermuscha7608b02015-02-03 17:54:38 -080062
Jan Tattermusch8ce5e8b2015-02-05 10:56:49 -080063 readonly Dictionary<string, IServerCallHandler> callHandlers = new Dictionary<string, IServerCallHandler>();
Jan Tattermusch8ce5e8b2015-02-05 10:56:49 -080064 readonly TaskCompletionSource<object> shutdownTcs = new TaskCompletionSource<object>();
65
Jan Tattermusch97e294a2015-04-23 14:30:59 -070066 bool startRequested;
67 bool shutdownRequested;
68
Jan Tattermusch6d53a5c2015-06-08 18:03:05 -070069 /// <summary>
70 /// Create a new server.
71 /// </summary>
72 /// <param name="options">Channel options.</param>
73 public Server(IEnumerable<ChannelOption> options = null)
Jan Tattermuscha7608b02015-02-03 17:54:38 -080074 {
Jan Tattermusch04eb89c2015-06-12 13:03:05 -070075 this.environment = GrpcEnvironment.GetInstance();
Jan Tattermusch766d72b2015-07-21 20:09:25 -070076 this.options = options != null ? new List<ChannelOption>(options) : new List<ChannelOption>();
77 using (var channelArgs = ChannelOptions.CreateChannelArgs(this.options))
Jan Tattermusch6d53a5c2015-06-08 18:03:05 -070078 {
Jan Tattermusch04eb89c2015-06-12 13:03:05 -070079 this.handle = ServerSafeHandle.NewServer(environment.CompletionQueue, channelArgs);
Jan Tattermusch6d53a5c2015-06-08 18:03:05 -070080 }
Jan Tattermuscha7608b02015-02-03 17:54:38 -080081 }
82
Jan Tattermusch97e294a2015-04-23 14:30:59 -070083 /// <summary>
84 /// Adds a service definition to the server. This is how you register
85 /// handlers for a service with the server.
86 /// Only call this before Start().
87 /// </summary>
Jan Tattermusch075dde42015-03-11 18:21:00 -070088 public void AddServiceDefinition(ServerServiceDefinition serviceDefinition)
89 {
Jan Tattermusch97e294a2015-04-23 14:30:59 -070090 lock (myLock)
Jan Tattermusch15111f52015-02-05 18:15:14 -080091 {
Jan Tattermusch97e294a2015-04-23 14:30:59 -070092 Preconditions.CheckState(!startRequested);
93 foreach (var entry in serviceDefinition.CallHandlers)
94 {
95 callHandlers.Add(entry.Key, entry.Value);
96 }
Jan Tattermusch15111f52015-02-05 18:15:14 -080097 }
Jan Tattermusch8ce5e8b2015-02-05 10:56:49 -080098 }
Jan Tattermusch15111f52015-02-05 18:15:14 -080099
Jan Tattermusch8ce5e8b2015-02-05 10:56:49 -0800100 /// <summary>
Jan Tattermuscha96ac052015-07-24 14:49:30 -0700101 /// Add a port on which server should listen.
Jan Tattermusch97e294a2015-04-23 14:30:59 -0700102 /// Only call this before Start().
Jan Tattermusch8ce5e8b2015-02-05 10:56:49 -0800103 /// </summary>
Jan Tattermusch03e82e22015-05-06 16:37:12 -0700104 /// <returns>The port on which server will be listening.</returns>
105 /// <param name="host">the host</param>
106 /// <param name="port">the port. If zero, an unused port is chosen automatically.</param>
Jan Tattermuscha96ac052015-07-24 14:49:30 -0700107 public int AddPort(string host, int port, ServerCredentials credentials)
Jan Tattermuscha7608b02015-02-03 17:54:38 -0800108 {
Jan Tattermuscha96ac052015-07-24 14:49:30 -0700109 lock (myLock)
110 {
111 Preconditions.CheckNotNull(credentials);
112 Preconditions.CheckState(!startRequested);
113 var address = string.Format("{0}:{1}", host, port);
114 using (var nativeCredentials = credentials.ToNativeCredentials())
115 {
116 if (nativeCredentials != null)
117 {
118 return handle.AddSecurePort(address, nativeCredentials);
119 }
120 else
121 {
122 return handle.AddInsecurePort(address);
123 }
124 }
125 }
Jan Tattermusch97e294a2015-04-23 14:30:59 -0700126 }
127
128 /// <summary>
129 /// Starts the server.
130 /// </summary>
131 public void Start()
132 {
133 lock (myLock)
134 {
135 Preconditions.CheckState(!startRequested);
136 startRequested = true;
137
138 handle.Start();
139 AllowOneRpc();
Jan Tattermuscha7608b02015-02-03 17:54:38 -0800140 }
141 }
142
Jan Tattermusch8ce5e8b2015-02-05 10:56:49 -0800143 /// <summary>
144 /// Requests server shutdown and when there are no more calls being serviced,
Jan Tattermusch97e294a2015-04-23 14:30:59 -0700145 /// cleans up used resources. The returned task finishes when shutdown procedure
146 /// is complete.
Jan Tattermusch8ce5e8b2015-02-05 10:56:49 -0800147 /// </summary>
Jan Tattermusch075dde42015-03-11 18:21:00 -0700148 public async Task ShutdownAsync()
149 {
Jan Tattermusch97e294a2015-04-23 14:30:59 -0700150 lock (myLock)
151 {
152 Preconditions.CheckState(startRequested);
153 Preconditions.CheckState(!shutdownRequested);
154 shutdownRequested = true;
155 }
156
Jan Tattermusch04eb89c2015-06-12 13:03:05 -0700157 handle.ShutdownAndNotify(HandleServerShutdown, environment);
Jan Tattermusch8ce5e8b2015-02-05 10:56:49 -0800158 await shutdownTcs.Task;
159 handle.Dispose();
160 }
Jan Tattermuscha7608b02015-02-03 17:54:38 -0800161
Jan Tattermusch503bbac2015-02-26 18:19:47 -0800162 /// <summary>
163 /// To allow awaiting termination of the server.
164 /// </summary>
165 public Task ShutdownTask
166 {
167 get
168 {
169 return shutdownTcs.Task;
170 }
171 }
172
Jan Tattermuschc4e81ad2015-05-29 17:39:07 -0700173 /// <summary>
174 /// Requests server shutdown while cancelling all the in-progress calls.
175 /// The returned task finishes when shutdown procedure is complete.
176 /// </summary>
177 public async Task KillAsync()
Jan Tattermusch075dde42015-03-11 18:21:00 -0700178 {
Jan Tattermuschc4e81ad2015-05-29 17:39:07 -0700179 lock (myLock)
180 {
181 Preconditions.CheckState(startRequested);
182 Preconditions.CheckState(!shutdownRequested);
183 shutdownRequested = true;
184 }
185
Jan Tattermusch04eb89c2015-06-12 13:03:05 -0700186 handle.ShutdownAndNotify(HandleServerShutdown, environment);
Jan Tattermuschc4e81ad2015-05-29 17:39:07 -0700187 handle.CancelAllCalls();
188 await shutdownTcs.Task;
Jan Tattermusch8ce5e8b2015-02-05 10:56:49 -0800189 handle.Dispose();
190 }
Jan Tattermuscha7608b02015-02-03 17:54:38 -0800191
Jan Tattermusch97e294a2015-04-23 14:30:59 -0700192 /// <summary>
193 /// Allows one new RPC call to be received by server.
194 /// </summary>
195 private void AllowOneRpc()
Jan Tattermusch075dde42015-03-11 18:21:00 -0700196 {
Jan Tattermusch97e294a2015-04-23 14:30:59 -0700197 lock (myLock)
Jan Tattermusch8ce5e8b2015-02-05 10:56:49 -0800198 {
Jan Tattermusch97e294a2015-04-23 14:30:59 -0700199 if (!shutdownRequested)
200 {
Jan Tattermusch04eb89c2015-06-12 13:03:05 -0700201 handle.RequestCall(HandleNewServerRpc, environment);
Jan Tattermusch97e294a2015-04-23 14:30:59 -0700202 }
Jan Tattermusch8ce5e8b2015-02-05 10:56:49 -0800203 }
Jan Tattermuscha7608b02015-02-03 17:54:38 -0800204 }
205
Jan Tattermusch97e294a2015-04-23 14:30:59 -0700206 /// <summary>
207 /// Selects corresponding handler for given call and handles the call.
208 /// </summary>
Jan Tattermusch5bbd8182015-07-20 20:48:40 -0700209 private async Task HandleCallAsync(ServerRpcNew newRpc)
Jan Tattermuscha7608b02015-02-03 17:54:38 -0800210 {
Jan Tattermusch97e294a2015-04-23 14:30:59 -0700211 try
212 {
213 IServerCallHandler callHandler;
Jan Tattermusch5bbd8182015-07-20 20:48:40 -0700214 if (!callHandlers.TryGetValue(newRpc.Method, out callHandler))
Jan Tattermusch97e294a2015-04-23 14:30:59 -0700215 {
Jan Tattermusch5bbd8182015-07-20 20:48:40 -0700216 callHandler = NoSuchMethodCallHandler.Instance;
Jan Tattermusch97e294a2015-04-23 14:30:59 -0700217 }
Jan Tattermusch5bbd8182015-07-20 20:48:40 -0700218 await callHandler.HandleCall(newRpc, environment);
Jan Tattermusch97e294a2015-04-23 14:30:59 -0700219 }
220 catch (Exception e)
221 {
Jan Tattermusch05261612015-07-24 00:28:16 -0700222 Logger.Warning(e, "Exception while handling RPC.");
Jan Tattermusch97e294a2015-04-23 14:30:59 -0700223 }
Jan Tattermuscha7608b02015-02-03 17:54:38 -0800224 }
225
Jan Tattermusch97e294a2015-04-23 14:30:59 -0700226 /// <summary>
227 /// Handles the native callback.
228 /// </summary>
Jan Tattermuschd3677482015-06-01 19:27:40 -0700229 private void HandleNewServerRpc(bool success, BatchContextSafeHandle ctx)
Jan Tattermusch075dde42015-03-11 18:21:00 -0700230 {
Jan Tattermusch5bbd8182015-07-20 20:48:40 -0700231 if (success)
Jan Tattermusch075dde42015-03-11 18:21:00 -0700232 {
Jan Tattermusch5bbd8182015-07-20 20:48:40 -0700233 ServerRpcNew newRpc = ctx.GetServerRpcNew();
234
235 // after server shutdown, the callback returns with null call
236 if (!newRpc.Call.IsInvalid)
237 {
238 Task.Run(async () => await HandleCallAsync(newRpc));
239 }
Jan Tattermusch075dde42015-03-11 18:21:00 -0700240 }
Jan Tattermuschd3677482015-06-01 19:27:40 -0700241
242 AllowOneRpc();
Jan Tattermuscha7608b02015-02-03 17:54:38 -0800243 }
244
Jan Tattermusch97e294a2015-04-23 14:30:59 -0700245 /// <summary>
246 /// Handles native callback.
247 /// </summary>
Jan Tattermuschd3677482015-06-01 19:27:40 -0700248 private void HandleServerShutdown(bool success, BatchContextSafeHandle ctx)
Jan Tattermusch8ce5e8b2015-02-05 10:56:49 -0800249 {
Jan Tattermuschd3677482015-06-01 19:27:40 -0700250 shutdownTcs.SetResult(null);
Jan Tattermusch8ce5e8b2015-02-05 10:56:49 -0800251 }
Jan Tattermuscha7608b02015-02-03 17:54:38 -0800252 }
Craig Tiller190d3602015-02-18 09:23:38 -0800253}