blob: 0bbb021c73fb928ba7d28d9e1518a487b1aa7464 [file] [log] [blame]
// $Id$
//
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
//
using System;
using System.IO;
using System.Net;
using System.Net.Sockets;
using System.Runtime.CompilerServices;
namespace Org.Apache.Etch.Bindings.Csharp.Util
{
/// <summary>
/// Implementation of a connection which handles a socket listener.
/// </summary>
public class TcpListener : Connection<SessionListener<Socket>>
{
/// <summary>
/// Constructs the TcpListener.
/// </summary>
/// <param name="backlog">max number of pending connection requests.</param>
/// <param name="host">address to listen to. Null means any local address.</param>
/// <param name="port">port to listen on. Port must be >= 0. Port of 0
/// means allocate an available port.</param>
/// <param name="delay">how long in milliseconds to wait before retrying a
/// failure. Delay must be >= 0. Delay of 0 means do not retry.</param>
private TcpListener( int backlog, String host, int port, int delay )
{
if ( backlog < 0 )
throw new ArgumentException( "backlog < 0" );
if ( port < 0 || port > 65535 )
throw new ArgumentException( "port < 0 || port > 65535" );
if ( delay < 0 )
throw new ArgumentException( "delay < 0" );
this.backlog = backlog;
this.host = host;
this.port = port;
this.delay = delay;
}
/// <summary>
/// Query term from URI to specify backlog value to ServerSocket. The
/// value is "TcpListener.backlog".
/// </summary>
public const String BACKLOG = "TcpListener.backlog";
public TcpListener(URL uri, Resources resources)
: this((int)uri.GetIntegerTerm(BACKLOG, 0), TranslateHost(uri.Host), uri.Port != null ? uri.Port.Value : 0, 0)
{
// nothing else.
}
/// <summary>
/// Constructs a TcpListener, initialized from the URI. Listens on the host
/// and port specified in the URI. To listen on all interfaces, specify
/// host as ALL_INTFS ("0.0.0.0"). If port is specified or defaulted to 0,
/// an unused port will be selected.
/// </summary>
/// <param name="uri"></param>
public TcpListener(string uri, Resources resources)
: this(new URL(uri), resources)
{
// nothing else.
}
private int backlog;
private String host;
private int port;
private int delay;
/// <summary>
///
/// </summary>
/// Exception:
/// throws Exception
protected override void Stop0()
{
Close( true );
base.Stop0();
}
/// <summary>
///
/// </summary>
/// Exception:
/// throws Exception
/// <returns></returns>
private Socket CheckSocket()
{
Socket ss = serverSocket;
if ( ss == null )
{
//Console.WriteLine( "----socket was null----" );
throw new IOException("server socket is closed");
}
return ss;
}
private Socket serverSocket;
public override string ToString()
{
Socket ss = serverSocket;
if ( ss == null )
return String.Format("TcpListener (down, {0}:{1})", host, port);
return String.Format("TcpListener (up, {0})", ss.LocalEndPoint);
}
[MethodImpl (MethodImplOptions.Synchronized)]
protected override bool OpenSocket( bool reconnect )
{
bool first = true;
while ( IsStarted() )
{
if ( reconnect || !first )
{
if ( delay == 0 )
return false;
System.Threading.Monitor.Wait(this, delay);
if ( !IsStarted() )
break;
}
try
{
//IPHostEntry ipEntry = Dns.GetHostEntry( host );
IPAddress addr;
if ( host != null )
{
IPAddress[] addrs = Dns.GetHostAddresses( host );
if ( addrs == null || addrs.Length == 0 )
throw new ArgumentException( "host is invalid" );
addr = addrs[ 0 ];
}
else
{
addr = IPAddress.Any;
}
//IPAddress[] addr = ipEntry.AddressList;
//string sIPAddress = addr[ 0 ].ToString();
IPEndPoint ipe = new IPEndPoint( addr, port );
serverSocket = new Socket( ipe.AddressFamily, SocketType.Stream, ProtocolType.Tcp );
try
{
serverSocket.Bind(ipe);
}
catch (SocketException e)
{
throw new IOException("Could not bind address "+host+":"+port, e);
}
serverSocket.Listen( backlog );
return true;
}
catch (Exception e)
{
if ( first )
{
first = false;
FireException( "open", e );
}
}
}
return false;
}
/// <summary>
///
/// </summary>
/// Exception:
/// throws Exception
protected override void SetUpSocket()
{
// nothing to do.
}
/// <summary>
///
/// </summary>
/// Exception:
/// throws Exception
protected override void ReadSocket()
{
try
{
Socket ss = CheckSocket();
while (IsStarted())
{
Socket s = ss.Accept();
try
{
session.SessionAccepted(s);
}
catch (Exception e)
{
s.Close();
FireException("accepted", e);
}
}
}
catch (SocketException e)
{
if (e.Message != null && e.Message.Contains("interrupted"))
return;
throw;
}
}
/// <summary>
///
/// </summary>
/// <param name="reset"></param>
/// Exception:
/// throws Exception
public override void Close( bool reset )
{
Socket ss = serverSocket;
if ( ss != null )
{
serverSocket = null;
ss.Close();
}
}
public override EndPoint LocalAddress()
{
return CheckSocket().LocalEndPoint;
}
public override EndPoint RemoteAddress()
{
// ignore
return null;
}
}
}