/* Copyright (c) 1999 by Inria Lorraine.  All Rights Reserved */

/***
   NAME
     IcmpSocket
   PURPOSE
     
   NOTES
     
   HISTORY
     chelius - Jul 25, 1999: Created.
     $Log: IcmpSocket.java,v $
     Revision 1.1  2000/04/27 13:24:12  sdalu
     ajout jdk1.1

     Revision 1.2  2000/04/03 08:05:33  chelius
     Javadoc

     Revision 1.1.1.1  2000/02/08 16:31:58  chelius
     Initial import

     Revision 1.1.1.1  2000/02/01 11:10:47  chelius
     Mise sous CVS des sources de libnet6 for jdk1.2.*

     Revision 1.1.1.1  1999/07/25 15:01:56  chelius
     First release of the ipv6 packages for java

***/
package java.net;


import java.io.FileDescriptor;
import java.io.IOException;
import java.io.InterruptedIOException;

/**
 * This class represents a socket for sending and receiving Icmp packets.
 *
 * <p>An Icmp socket is the sending or receiving point for a packet
 * delivery service. Each packet sent or received on a datagram socket
 * is individually addressed and routed. Multiple packets sent from
 * one machine to another may be routed differently, and may arrive in
 * any order.
 *
 * @author  Guillaume Chelius (IPv6 modifications)
 * @version 1.0, 02/04/2000
 * @see     java.net.RawPacket
 * @since JDK1.2
 */
public class IcmpSocket extends RawSocket {
 

    /**
     * Creates an Icmp socket.
     * @see        java.net.RawSocket
     * @since   JDK1.2
     */
    public IcmpSocket() throws SocketException {
	// create a raw socket.
	super(58, null);
    }

    /**
     * Creates an Icmp socket, bound to the specified local
     * address.  
     * @param laddr local address to bind
      * @see        java.net.RawSocket
    * @since   JDK1.2
     */
    public IcmpSocket(InetAddress laddr) throws SocketException {
	super(58, laddr);
    }

    /**
     * Sends an Icmp packet from this socket. The 
     * <code>IcmpPacket</code> includes information indicating the 
     * data to be sent, its length, the IP address of the remote host. 
     *
     * @param      p   the <code>IcmpPacket</code> to be sent.
     * @exception  IOException  if an I/O error occurs.
     * @see        java.net.IcmpPacket
     * @since      JDK1.2
     */
    public void send(IcmpPacket p) throws IOException  {
	
	// check the address is ok wiht the security manager on every send.
	SecurityManager security = System.getSecurityManager();
	RawPacket packet;
	byte[] buf, aux;

	// The reason you want to synchronize on Icmp packet
	// is because you dont want an applet to change the address 
	// while you are trying to send the packet for example 
	// after the security check but before the send.
	synchronized (p) {
	    if (security != null) {
		security.checkConnect(p.getAddress().getHostAddress(), -1);
	    }
            // call the  method to send
	    if (p == null)
		throw (new NullPointerException("Null pointer for IcmpPacket"));


	    buf = new byte[p.getLength() + 2];
	    aux = p.getData();
	    for (int i = 0; i < p.getLength(); i++)
		buf[i + 2] = aux[i];
	    buf[0] = p.getType();
	    buf[1] = p.getCode();

	    packet = new RawPacket(buf, buf.length, p.getAddress());
            impl.send(packet);

	    p.setLength(packet.getLength() - 2);
        }
    }
    
    /**
     * This method overrides the one of the <code>RawSocket</code> class. It throws an 
     * IOException to prevent people from hacking the protocol.
     * @exception  IOException  
     * @see        java.net.RawSocket
     * @since      JDK1.2
     */
    public void send(RawPacket p) throws IOException  {
	throw new IOException("can't send raw packets");
    }


    /**
     * Receives an Icmp packet from this socket. When this method 
     * returns, the <code>IcmpPacket</code>'s buffer is filled with 
     * the data received. The Icmp packet also contains the sender's 
     * IP address, and the type and code of the packet. 
     * <p>
     * This method blocks until a datagram is received. The 
     * <code>length</code> field of the datagram packet object contains 
     * the length of the received message. If the message is longer than 
     * the buffer length, the message is truncated. 
     *
     * @param      p   the <code>IcmpPacket</code> into which to place
     *                 the incoming data.
     * @exception  IOException  if an I/O error occurs.
     * @see        java.net.IcmpPacket
     * @see        java.net.RawSocket
     * @since      JDK1.2
     */
    public synchronized void receive(IcmpPacket p) throws IOException {
	// check the address is ok with the security manager before every recv.
	SecurityManager security = System.getSecurityManager();
	byte[] aux;
	int len;
	byte cvalue, tvalue;

      	synchronized (p) {
	    if (security != null) {

		while(true) {
		    // peek at the packet to see who it is from.
		    InetAddress peekAddress = new InetAddress();
		    impl.peek(peekAddress);

		    try {
			    security.checkConnect(p.getAddress().getHostAddress(), -1);
			// security check succeeded - so now break and recv the packet.
			break;
		    } catch (SecurityException se) {
			// Throw away the offending packet by consuming
			// it in a tmp buffer.
			RawPacket tmp = new RawPacket(new byte[1], 1);
			impl.receive(tmp);

		    	// silently discard the offending packet and continue:
			// unknown/malicious entities on nets should not make
			// runtime throw security exception and disrupt the applet
			// by sending random Icmp packets.
			continue;
		    } 
		} // end of while
	    }
	    // If the security check succeeds, then receive the packet
	    if (p == null)
		throw (new NullPointerException("Null pointer for IcmpPacket"));
 	    impl.receive(p);

	    aux = p.getData();
	    if ((len = p.getLength())  < 4)
		throw new SocketException("Not a valid Icmp packet");
	    tvalue  = aux[0];
	    cvalue  = aux[1];
	    p.setType(tvalue, cvalue);
	    for (int i = 0; i < len - 2;i++)
		aux[i] = aux[i+2];

	    p.setLength(len - 2);
	}	
    }

    /**
     * This method overrides the one of the <code>RawSocket</code> class. It throws an 
     * IOException to prevent people from hacking the protocol.
     * @exception  IOException  
     * @see        java.net.RawSocket
     * @since      JDK1.2
     */
    public synchronized void receive(RawPacket p) throws IOException  {
	throw new IOException("can't receive raw packets");
    }

     /**
     * This method overrides the one of the <code>RawSocket</code> class. It throws an 
     * IOException to prevent people from hacking the protocol.
     * @exception  SocketException  
     * @see        java.net.RawSocket
     * @since      JDK1.2
     */
    public void setChecksum(int offset) throws SocketException {
  	throw new SocketException("checksum already set for icmp");
    }

    /**
     * Closes this Icmp socket. 
     *
     * @since   JDK1.2
     */
    public void close() {
	impl.close();
    }
}















