home *** CD-ROM | disk | FTP | other *** search
/ Late Night VRML 2.0 with Java CD-ROM / code.zip / Ch19 / filter / UserServer.java < prev   
Encoding:
Java Source  |  1997-02-16  |  10.0 KB  |  465 lines

  1. // The Virtual Light Company 1996
  2. //
  3. // From Chapter 20: Late Night VRML 2.0 and java
  4. //
  5. // This is the Server That implements the user networking information..
  6. // At the moment the capabilites are very limited. The User is identified by
  7. // a hostname only. Thus if a user has two clients running on the one machine
  8. // then as soon as one closes it kills the sessions to all of the sessions
  9. // running on that machine. I will probably need to run a hostname/port number
  10. // combination.
  11.  
  12. package filter;
  13.  
  14. import java.net.*;
  15. import java.io.*;
  16. import java.util.*;
  17.  
  18. public class UserServer extends Thread
  19. {
  20.     private static final int BUFFER_LENGTH = 1024;
  21.     private static final int MAX_UPDATE_INTERVAL = 10000;  // 10 seconds
  22.     private static final int MAX_REFRESH_PERIOD = 10000;   // 10 seconds
  23.     
  24.     private boolean        server_available = false;
  25.     private Vector        user_list;
  26.     private Hashtable    address_list;
  27.  
  28.     private boolean        debug;
  29.             
  30.     public UserServer(ThreadGroup thread, boolean use_debug)
  31.     {
  32.         super(thread, "User Server Threadgroup");
  33.  
  34.         setPriority(7);
  35.  
  36.         System.out.println("Starting User server");
  37.         
  38.         user_list = new Vector(10, 2);
  39.         address_list = new Hashtable(10, 0.8f);
  40.         
  41.         server_available = true;
  42.  
  43.         debug = use_debug;
  44.     }
  45.  
  46.     public void run()
  47.     {
  48.         int    i;
  49.         long    start_time;
  50.         long    exec_time;
  51.         long    update_diff;
  52.         long    user_start;
  53.         User    user;
  54.  
  55.         // if the server failed to start then exit and do nothing.
  56.         if(!server_available)
  57.             return;
  58.  
  59.         // now process the input.
  60.         while(true)
  61.         {
  62.             start_time = System.currentTimeMillis();
  63.             
  64.             for(i = 0; i < user_list.size(); i++)
  65.             {
  66.                 user = (User)user_list.elementAt(i);
  67.  
  68.                 if((user.last_update - start_time) > MAX_UPDATE_INTERVAL)
  69.                 {
  70.                     synchronized (user_list)
  71.                     {
  72.                         user_list.removeElementAt(i);
  73.                     }
  74.                     synchronized (address_list)
  75.                     {
  76.                         address_list.remove(user.address.getHostName());
  77.                     }
  78.                     i--;
  79.                 }
  80.             }
  81.             
  82.             // if the execution time took less that the refresh period then
  83.             // sleep until the next 10 second bracket.
  84.             exec_time = System.currentTimeMillis() - start_time;
  85.             if(exec_time < MAX_REFRESH_PERIOD)
  86.             {
  87.                 try
  88.                 {
  89.                     sleep(MAX_REFRESH_PERIOD - exec_time);
  90.                 }
  91.                 catch(InterruptedException e)
  92.                 {
  93.                 }
  94.             }
  95.  
  96.             Thread.yield();
  97.         }
  98.     }
  99.  
  100.     // send the update information to the users. Since every users gets the same
  101.     // message we create the message once and then send it to the users.
  102.     public synchronized void send_update(String  hostname,
  103.                                          int     timestamp,
  104.                                          int     seq_num,
  105.                                          int     src_entid,
  106.                                          float[] position,
  107.                                          float[] rotation,
  108.                                          int     region,
  109.                                          float   size)
  110.     {
  111.         int    i;
  112.         float x, y, z;
  113.         float size_sqd = size * size;
  114.  
  115.         ByteArrayOutputStream    bytes = new ByteArrayOutputStream(BUFFER_LENGTH);
  116.         DataOutputStream out = new DataOutputStream(bytes);
  117.  
  118.         DatagramPacket    packet;
  119.         DatagramSocket    socket;
  120.         User    user;
  121.  
  122.         // firstly let's update the user
  123.         user = (User)address_list.get(hostname);
  124.  
  125.         // and check that this is a later sequence number if not discard.
  126.         if(seq_num < user.last_seq_num)
  127.             return;
  128.  
  129.         user.last_seq_num = seq_num;
  130.         user.entid = src_entid;
  131.         user.last_update = System.currentTimeMillis();
  132.         user.current_region = region;
  133.         user.size = size_sqd;
  134.         user.position = position;
  135.         user.rotation = rotation;
  136.  
  137.         if(debug)
  138.             System.out.println("Sending update");
  139.  
  140.         try
  141.         {
  142.             socket = new DatagramSocket();
  143.         }
  144.         catch(IOException e)
  145.         {
  146.             // ARGH, barf!
  147.             System.out.println("UserServer: unable to create outgoing update socket");
  148.             return;
  149.         }
  150.  
  151.         // create the output buffer once
  152.         try
  153.         {
  154.             // The RTP header octet 1 = 0x80, octet 2 = 79d
  155.             out.writeByte(0x80);
  156.             out.writeByte(79);
  157.             
  158.             // sequence number, timestamp, SSRC
  159.             out.writeShort(seq_num);
  160.             out.writeInt(timestamp);
  161.             out.writeInt(src_entid);
  162.  
  163.             // the position
  164.             out.writeFloat(position[0]);
  165.             out.writeFloat(position[1]);
  166.             out.writeFloat(position[2]);
  167.  
  168.             // the position
  169.             out.writeFloat(rotation[0]);
  170.             out.writeFloat(rotation[1]);
  171.             out.writeFloat(rotation[2]);
  172.             out.writeFloat(rotation[3]);
  173.  
  174.             // region, acuity, flags
  175.             out.writeInt(region);
  176.             out.writeFloat(size);
  177.             out.writeInt(0);
  178.             // when sending an update out it is 0
  179.         }
  180.         catch(IOException e)
  181.         {
  182.             System.out.println("User server: error writing update");
  183.             return;
  184.         }
  185.  
  186.         // all done for the message, now send it to the clients
  187.  
  188.         synchronized(user_list)
  189.         {
  190.             for(i = 0; i < user_list.size(); i++)
  191.             {
  192.                 user = (User)user_list.elementAt(i);
  193.                 x = user.position[0] - position[0];
  194.                 y = user.position[1] - position[1];
  195.                 z = user.position[2] - position[2];
  196.  
  197.                 // if the acuity is too small reject and try next client.
  198.                 if((size_sqd / (x*x + y*y + z*z)) < user.acuity)
  199.                     continue;
  200.  
  201.                 for(j = 0; j < user.regions.size; j++)
  202.                     if(user.regions[j] == region)
  203.                     {
  204.                         found = true;
  205.                         break;
  206.                     }
  207.  
  208.                 if(!found)
  209.                     continue;
  210.  
  211.                 packet = new DatagramPacket(bytes.toByteArray(),
  212.                                             bytes.size(),
  213.                                             user.address,
  214.                                             user.update_port);
  215.                 try
  216.                 {
  217.                     socket.send(packet);
  218.                 }
  219.                 catch(IOException e)
  220.                 {
  221.                     System.out.println("User server: " +
  222.                                        "error sending update packet");
  223.                 }
  224.             }
  225.         }
  226.  
  227.         socket.close();
  228.     }
  229.  
  230.     public void set_filter(String hostname,
  231.                            int update_port,
  232.                            float acuity,
  233.                            int horizon,
  234.                            int[] regions,
  235.                            int[] ports)
  236.     {
  237.         User user = (User)address_list.get(hostname);
  238.  
  239.         // if the hostname does not exist then add this to set the updates
  240.         if(user == null)
  241.         {
  242.             if(debug)
  243.                 System.out.println("Adding a new user");
  244.  
  245.             user = new User(update_port, acuity, horizon, regions, ports);
  246.             try
  247.             {
  248.                 user.address = InetAddress.getByName(hostname);
  249.             }
  250.             catch(UnknownHostException e)
  251.             {
  252.                 System.err.println("Unable to dereference host");
  253.                 return;
  254.             }
  255.             synchronized (address_list)
  256.             {
  257.                 address_list.put(hostname, user);
  258.             }
  259.             synchronized (user_list)
  260.             {
  261.                 user_list.addElement(user);
  262.             }
  263.         }
  264.         else
  265.         {
  266.             synchronized (user)
  267.             {
  268.                 user.update_port = update_port;
  269.                 user.acuity = acuity * acuity;
  270.                 user.horizon = horizon;
  271.                 user.regions = regions;
  272.                 user.ports = ports;
  273.                 user.last_update = System.currentTimeMillis();
  274.             }
  275.         }
  276.     }
  277.  
  278.     public void suspend(String hostname)
  279.     {
  280.         User user = (User)address_list.get(hostname);
  281.  
  282.         if(user == null)
  283.             return;
  284.  
  285.         synchronized (user_list)
  286.         {
  287.             user_list.removeElement(user);
  288.         }
  289.         synchronized (address_list)
  290.         {
  291.             address_list.remove(hostname);
  292.         }
  293.     }
  294.  
  295.     public void refresh(String address)
  296.     {
  297.         int    i;
  298.         ByteArrayOutputStream    bytes = new ByteArrayOutputStream(BUFFER_LENGTH);
  299.         DataOutputStream out = new DataOutputStream(bytes);
  300.  
  301.         DatagramPacket    packet;
  302.         DatagramSocket    socket;
  303.  
  304.         User user;
  305.         User me = (User)address_list.get(address);
  306.  
  307.         if(debug)
  308.             System.out.println("Sending refresh");
  309.  
  310.         try
  311.         {
  312.             socket = new DatagramSocket();
  313.         }
  314.         catch(IOException e)
  315.         {
  316.             // ARGH, barf!
  317.             System.out.println("UserServer: unable to create outgoing refresh socket");
  318.             return;
  319.         }
  320.  
  321.         for(i = 0; i < user_list.size(); i++)
  322.         {
  323.             user = (User)user_list.elementAt(i);
  324.  
  325.             // reset the stream to start from the beginning of the packet
  326.             bytes.reset();
  327.  
  328.             try
  329.             {
  330.                 // The RTP header octet 1 = 0x80, octet 2 = 79d
  331.                 out.writeByte(0x80);
  332.                 out.writeByte(80);
  333.  
  334.                 // sequence number, timestamp, SSRC
  335.                 out.writeShort(user.last_seq_num);
  336.                 out.writeInt((int)user.last_update);
  337.                 out.writeInt(user.entid);
  338.  
  339.                 // the position
  340.                 out.writeFloat(user.position[0]);
  341.                 out.writeFloat(user.position[1]);
  342.                 out.writeFloat(user.position[2]);
  343.  
  344.                 // the position
  345.                 out.writeFloat(user.rotation[0]);
  346.                 out.writeFloat(user.rotation[1]);
  347.                 out.writeFloat(user.rotation[2]);
  348.                 out.writeFloat(user.rotation[3]);
  349.  
  350.                 // region, acuity, flags
  351.                 out.writeInt(user.current_region);
  352.                 out.writeFloat(user.size);
  353.                 out.writeInt(0);
  354.                 // the flags are 0 for an update refresh
  355.             }
  356.             catch(IOException e)
  357.             {
  358.                 System.out.println("User server: error writing update");
  359.                 return;
  360.             }
  361.  
  362.             // all done for the message, now send it to the clients
  363.             packet = new DatagramPacket(bytes.toByteArray(),
  364.                             bytes.size(),
  365.                             me.address,
  366.                             me.update_port);
  367.             try
  368.             {
  369.                 socket.send(packet);
  370.             }
  371.             catch(IOException e)
  372.             {
  373.                 System.out.println("User server: error sending update packet");
  374.             }
  375.         }
  376.     }
  377.  
  378.     public synchronized void remove(String hostname)
  379.     {
  380.         User user = (User)address_list.get(hostname);
  381.  
  382.         synchronized(address_list)
  383.         {
  384.             address_list.remove(hostname);
  385.         }
  386.         synchronized(user_list)
  387.         {
  388.             user_list.removeElement(user);
  389.         }
  390.     }
  391.  
  392.     public synchronized void send_chat(int seq_num,
  393.                                        int mesg_type,
  394.                                        int text_id,
  395.                                        String msg_text)
  396.     {
  397.         int    i;
  398.         ByteArrayOutputStream    bytes = new ByteArrayOutputStream(BUFFER_LENGTH);
  399.         DataOutputStream out = new DataOutputStream(bytes);
  400.  
  401.         DatagramPacket    packet;
  402.         DatagramSocket    socket;
  403.  
  404.         User user;
  405.  
  406.         if(debug)
  407.             System.out.println("Sending chat message");
  408.  
  409.         try
  410.         {    
  411.             socket = new DatagramSocket();
  412.         }
  413.         catch(IOException e)
  414.         {
  415.             // ARGH, barf!
  416.             System.out.println("UserServer: unable to create outgoing update socket");
  417.             return;
  418.         }
  419.     
  420.     
  421.         // create the output buffer once
  422.         try
  423.         {
  424.             // The RTP header octet 1 = 0x80, octet 2 = 79d
  425.             out.writeByte(0x80);
  426.             out.writeByte(80);
  427.             
  428.             // sequence number, timestamp, SSRC
  429.             out.writeShort(seq_num);
  430.             out.writeInt(0);    // txt msg has timestamp 0
  431.             out.writeInt(text_id);
  432.  
  433.             // the position
  434.             out.writeShort(mesg_type);
  435.             out.writeShort(msg_text.length());
  436.  
  437.             // now write the message
  438.             out.writeBytes(msg_text);
  439.  
  440.         }
  441.         catch(IOException e)
  442.         {
  443.             System.out.println("User server: error writing update");
  444.             return;
  445.         }
  446.  
  447.         for(i = 0; i < user_list.size(); i++)
  448.         {
  449.             user = (User)user_list.elementAt(i);
  450.             packet = new DatagramPacket(bytes.toByteArray(),
  451.                             bytes.size(),
  452.                             user.address,
  453.                             user.update_port);
  454.             try
  455.             {
  456.                 socket.send(packet);
  457.             }
  458.             catch(IOException e)
  459.             {
  460.                 System.out.println("User server: error sending text packet");
  461.             }
  462.         }
  463.     }
  464. }
  465.