package network.platform.ip; import model.interfaces.network.INetworkTraffic; import network.platform.NetworkPlatformMessage; import model.interfaces.network.INetworkSender; import util.Parameters; import java.util.Vector; import java.net.Socket; import java.io.IOException; import java.io.ObjectOutputStream; import java.io.InvalidClassException; import java.io.NotSerializableException; import java.net.UnknownHostException; import java.net.SocketException; import util.NetworkAddress; import platform.servicesregister.ServicesRegisterManager; import platform.servicesregister.ServiceClosedException; import platform.servicesregister.ServicesRegister; import network.platform.PingService; import platform.context.ContextManager; import platform.context.ContextInformation; import util.SizeCountOutputStream; import platform.plugins.installables.network.DNS.KalimuchoDNS; import java.net.InetSocketAddress; /** * Thread that sends messages for the PF on IP * * @author Dalmau */ // Classe du thread qui gere les emission reseau IP faites par la PF public class IPPlatformMessagesSender extends Thread implements INetworkSender, INetworkTraffic { // messages du superviseur private Vector<NetworkPlatformMessage> messagesDePingEnAttente, messagesEnAttente, messagesUrgentsEnAttente, messagesLentsEnAttente; private boolean enMarche, arrete, termine; private NetworkAddress monAdresse; private ContextManager gestionnaireContexte; private int sendedData; /** * Creates the thread that sends messages for the PF * @param adr address to which this thread is associated */ public IPPlatformMessagesSender(NetworkAddress adr) { monAdresse = adr; messagesEnAttente = new Vector<NetworkPlatformMessage>(); messagesUrgentsEnAttente = new Vector<NetworkPlatformMessage>(); messagesLentsEnAttente = new Vector<NetworkPlatformMessage>(); messagesDePingEnAttente = new Vector<NetworkPlatformMessage>(); enMarche = true; arrete = false; sendedData = 0; gestionnaireContexte = (ContextManager)ServicesRegisterManager.platformWaitForService(Parameters.CONTEXT_MANAGER); setPriority(Thread.NORM_PRIORITY+2); start(); } /** * Returns the local host address on the network on which this sender works * @return the local host address on the network on which this sender works */ public NetworkAddress getSenderAddress() { return monAdresse; } /** * Post a normal message to be sent * @param tr message to be sent */ public synchronized void posterMessage(NetworkPlatformMessage tr) { // Methode utilisee par la PF pour envoyer un message par IP messagesEnAttente.addElement(tr.clone()); notifyAll(); // debloquer le thread d'envoi de messages } /** * Post an urgent message to be sent * @param tr message to be sent */ public synchronized void posterMessageUrgent(NetworkPlatformMessage tr) { // Methode utilisee par la PF pour envoyer un message par IP messagesUrgentsEnAttente.addElement(tr.clone()); notifyAll(); // debloquer le thread d'envoi de messages } /** * Post a slow message to be sent * @param tr message to be sent */ public synchronized void posterMessageLent(NetworkPlatformMessage tr) { // Methode utilisee par la PF pour envoyer un message par IP messagesLentsEnAttente.addElement(tr.clone()); notifyAll(); // debloquer le thread d'envoi de messages } /** * Post a PING message to be sent * @param tr message to be sent */ public synchronized void posterMessagePING(NetworkPlatformMessage tr) { // Methode utilisee par la PF pour envoyer un message par IP messagesDePingEnAttente.addElement(tr.clone()); notifyAll(); // debloquer le thread d'envoi de messages } /** * Sends a normal incomplete message. This message is put in a queue and sent by the sender's thread. * This message is completed by the address of the sending host on this network * @param tr message to complete and to send */ public synchronized void posterMessageIncomplet(NetworkPlatformMessage tr) { NetworkPlatformMessage env = tr.clone(); env.addContent(env.getContent()+monAdresse.getNormalizedAddress()); messagesEnAttente.addElement(env); notifyAll(); // debloquer le thread d'envoi de messages } // Methode semaphore de traitement des demandes d'emission de messages par la PF private synchronized void traiterDemandes() { while ((messagesEnAttente.size() == 0) && ((messagesUrgentsEnAttente.size() == 0)) && ((messagesDePingEnAttente.size() == 0))) { try { wait(); // si pas de message se bloquer if ((messagesEnAttente.size() == 0) && (messagesUrgentsEnAttente.size() == 0) && (messagesLentsEnAttente.size() == 0) && (messagesDePingEnAttente.size() == 0) && arrete) { enMarche = false; return; } } catch (InterruptedException ie) { } } // on a un message a envoyer (deblocage du thread) NetworkPlatformMessage envoi; boolean isPing = false; if (messagesDePingEnAttente.size() >0) { isPing = true; envoi = messagesDePingEnAttente.elementAt(0); messagesDePingEnAttente.removeElementAt(0); // enlever le message } else { if (messagesUrgentsEnAttente.size() >0) { envoi = messagesUrgentsEnAttente.elementAt(0); messagesUrgentsEnAttente.removeElementAt(0); // enlever le message } else { if (messagesEnAttente.size() >0) { envoi = messagesEnAttente.elementAt(0); messagesEnAttente.removeElementAt(0); // enlever le message } else { envoi = messagesLentsEnAttente.elementAt(0); messagesLentsEnAttente.removeElementAt(0); // enlever le message } } } //System.out.println(" a envoyer pour "+tr.getOwner()+" au port : "+tr.getPortNumber()+" reonse au port :"+tr.getReplyPort()) ; if (envoi.getPortNumber() == 0) envoi.setPortNumber(Parameters.PORT_IP_COMMANDS_PF); int numPort = envoi.getPortNumber(); if (envoi.getFinalPort() == 0) envoi.setFinalPort(Parameters.PORT_IP_COMMANDS_PF); String adresseIP = envoi.getAddress(); int compteEssaiRestants = 3; Socket env = null; while (compteEssaiRestants > 0) { try { // essayer d'etablir la connexion IP env = new Socket(); env.connect(new InetSocketAddress(adresseIP, numPort), Parameters.IP_SOCKET_CONNEXION_TIME_OUT); try { env.setTcpNoDelay(true); } catch (SocketException ie) { System.err.println("Can't put socket in TCP no delay mode"); } // creation du flux d'objets pour emettre par reseau ObjectOutputStream ecrire = new ObjectOutputStream(env.getOutputStream()); if (envoi.getExpeditorAddress().equals("")) envoi.setExpeditorAddress(monAdresse.getNormalizedAddress()); if (envoi.getExpeditorPort() == 0) envoi.setExpeditorPort(Parameters.PORT_IP_COMMANDS_PF); sendedData = sendedData+getMessageSize(envoi); ecrire.writeObject(envoi); ecrire.flush(); ecrire.close(); env.close(); compteEssaiRestants = -1; } catch (SecurityException e) { compteEssaiRestants = 0; if (!arrete) { try { KalimuchoDNS dns = (KalimuchoDNS)ServicesRegisterManager.lookForService(Parameters.KALIMUCHO_DNS_MANAGER); dns.removeReference(new NetworkAddress(adresseIP)); } catch (ServiceClosedException sce) { } gestionnaireContexte.signalEvent(new ContextInformation("Error when sending PF message: security")); } } catch (SocketException e) { if (env != null) try { env.close(); } catch (IOException sce) {} if (arrete || isPing) compteEssaiRestants =0; else { compteEssaiRestants--; if (compteEssaiRestants == 0) { try { KalimuchoDNS dns = (KalimuchoDNS)ServicesRegisterManager.lookForService(Parameters.KALIMUCHO_DNS_MANAGER); dns.removeReference(new NetworkAddress(adresseIP)); } catch (ServiceClosedException sce) { } gestionnaireContexte.signalEvent(new ContextInformation("Error when sending PF message: socket")); } } } catch (NotSerializableException e) { compteEssaiRestants = 0; if (!arrete) gestionnaireContexte.signalEvent(new ContextInformation("Error when sending PF message: not serializable class")); } catch (UnknownHostException e) { if (env != null) try { env.close(); } catch (IOException sce) {} if (arrete || isPing) compteEssaiRestants =0; else { compteEssaiRestants--; if (compteEssaiRestants == 0) { try { KalimuchoDNS dns = (KalimuchoDNS)ServicesRegisterManager.lookForService(Parameters.KALIMUCHO_DNS_MANAGER); dns.removeReference(new NetworkAddress(adresseIP)); } catch (ServiceClosedException sce) { } gestionnaireContexte.signalEvent(new ContextInformation("Error when sending PF message: unknown host")); } } } catch (InvalidClassException e) { compteEssaiRestants = 0; if (!arrete) gestionnaireContexte.signalEvent(new ContextInformation("Error when sending PF message: invalid class")); } catch (IOException e) { if (env != null) try { env.close(); } catch (IOException sce) {} if (arrete || isPing) compteEssaiRestants =0; else { compteEssaiRestants--; if (compteEssaiRestants == 0) { try { KalimuchoDNS dns = (KalimuchoDNS)ServicesRegisterManager.lookForService(Parameters.KALIMUCHO_DNS_MANAGER); dns.removeReference(new NetworkAddress(adresseIP)); } catch (ServiceClosedException sce) { } gestionnaireContexte.signalEvent(new ContextInformation("Error when sending PF message: IO")); } } } } if ((compteEssaiRestants == 0) && isPing) { // le ping a echoue => debloquer l'attente try { PingService pingService = (PingService) ServicesRegister.lookForService(Parameters.NETWORK_PING_SERVICE); pingService.abandonner(); } catch (ServiceClosedException sce) {} } } /** * Sends the messages for the PF */ @Override public void run() { // boucle de traitement des messages a envoyer termine = false; while (enMarche) { if (!arrete) traiterDemandes(); else { while ((messagesEnAttente.size() != 0) || (messagesUrgentsEnAttente.size() != 0)) traiterDemandes(); enMarche = false; } } terminer(); } private synchronized void terminer() { termine = true; notifyAll(); } /** * Stops this thread. It is necessary to wait until all pending messages heve beedn sent * before stopping this thread. */ public synchronized void stopThread() { arrete = true; notifyAll(); } /** * Waits until there is no more messages to send */ public synchronized void waitForBufferEmpty() { while (!termine) { try { wait(); } catch (InterruptedException ie) {} } } /** * Returns the number of bytes sent on network by the PF since the last call of this method. * @return the number of bytes sent on network by the PF since the last call of this method. */ public int getDataSize() { int ret = sendedData; sendedData = 0; return ret; } private int getMessageSize(NetworkPlatformMessage s) { int taille; SizeCountOutputStream bos = new SizeCountOutputStream(); try { ObjectOutputStream oos = new ObjectOutputStream(bos); oos.writeObject(s); taille = bos.getSize(); } catch (IOException ioe) { taille = 0; } return taille; } }