Example #1
0
File: Ping.cs Project: vargaz/mono
		private PingReply SendPrivileged (IPAddress address, int timeout, byte [] buffer, PingOptions options)
		{
			IPEndPoint target = new IPEndPoint (address, 0);
			IPEndPoint client = new IPEndPoint (GetNonLoopbackIP (), 0);

			// FIXME: support IPv6
			using (Socket s = new Socket (AddressFamily.InterNetwork, SocketType.Raw, ProtocolType.Icmp)) {
				if (options != null) {
					s.DontFragment = options.DontFragment;
					s.Ttl = (short) options.Ttl;
				}
				s.SendTimeout = timeout;
				s.ReceiveTimeout = timeout;
				// not sure why Identifier = 0 is unacceptable ...
				IcmpMessage send = new IcmpMessage (8, 0, identifier, 0, buffer);
				byte [] bytes = send.GetBytes ();
				s.SendBufferSize = bytes.Length;
				s.SendTo (bytes, bytes.Length, SocketFlags.None, target);

				DateTime sentTime = DateTime.Now;

				// receive
				bytes = new byte [100];
				do {
					EndPoint endpoint = client;
					int error = 0;
					int rc = s.ReceiveFrom_nochecks_exc (bytes, 0, 100, SocketFlags.None,
							ref endpoint, false, out error);

					if (error != 0) {
						if (error == (int) SocketError.TimedOut) {
							return new PingReply (null, new byte [0], options, 0, IPStatus.TimedOut);
						}
						throw new NotSupportedException (String.Format ("Unexpected socket error during ping request: {0}", error));
					}
					long rtt = (long) (DateTime.Now - sentTime).TotalMilliseconds;
					int headerLength = (bytes [0] & 0xF) << 2;
					int bodyLength = rc - headerLength;

					// Ping reply to different request. discard it.
					if (!((IPEndPoint) endpoint).Address.Equals (target.Address)) {
						long t = timeout - rtt;
						if (t <= 0)
							return new PingReply (null, new byte [0], options, 0, IPStatus.TimedOut);
						s.ReceiveTimeout = (int) t;
						continue;
					}

					IcmpMessage recv = new IcmpMessage (bytes, headerLength, bodyLength);

					/* discard ping reply to different request or echo requests if running on same host. */
					if (recv.Identifier != identifier || recv.Type == 8) {
						long t = timeout - rtt;
						if (t <= 0)
							return new PingReply (null, new byte [0], options, 0, IPStatus.TimedOut);
						s.ReceiveTimeout = (int) t;
						continue; 
					}

					return new PingReply (address, recv.Data, options, rtt, recv.IPStatus);
				} while (true);
			}
		}