Docjar: A Java Source and Docuemnt Enginecom.*    java.*    javax.*    org.*    all    new    plug-in

Quick Search    Search Deep

Source code: com/neuron/jaffer/AFP_Server.java


1   /* 
2    * Copyright (c) 2003 Stewart Allen <stewart@neuron.com>. All rights reserved.
3    * This program is free software. See the 'License' file for details.
4    */
5   
6   package com.neuron.jaffer;
7   
8   import java.io.*;
9   import java.net.*;
10  import java.util.*;
11  import com.strangeberry.rendezvous.*;
12  
13  /* TODO: request/reply queues
14   *   * command 0x7a - client going to sleep?
15   *
16   * AFP BUGS:
17   *   * sending truncated list for GetVolParams bitmap results in kernel panic / crash
18   *   * Login (0x12) is *not* sending pad byte after command)
19   *   * failure to reply to DSI_TICKLE results in kernel panic
20   *   * AFP31 p. 32 - offspring count is 2 bytes, NOT 4 bytes
21   *   * sending TICKLE with 'reply' flag panics kernel
22   *   * failing to complete an enumerate_ext2 call will panic/hang the system
23   *   * responding to DSI_WRITE with mirror reply panics kernel
24   */
25  public abstract class AFP_Server implements AFP_Constants, Runnable
26  {
27    static boolean DEBUG_DEBUG = true;
28    static boolean DEBUG_DSI = true;
29    static boolean DEBUG_DSI_REQUEST = true && DEBUG_DSI;
30    static boolean DEBUG_DSI_REPLY = true && DEBUG_DSI;
31    static boolean DEBUG_DSI_LINE = true && DEBUG_DSI;
32    static boolean DEBUG_PRINT = DEBUG_DEBUG | DEBUG_DSI;
33  
34    private final static String[] protoStrings = {
35      "AFP3.1" ,
36      "AFP2.3"
37    };
38  
39    private int port;
40    private String bind;
41    private ServerSocket socket;
42    private String serverName;
43    private Thread thread;
44    private int nextVolID = 1;
45    private Hashtable volumesByID;
46    private Hashtable volumesByName;
47    private Rendezvous rendezvous;
48    private AFP_ServerInfo serverInfo;
49  
50    public AFP_Server()
51      throws IOException
52    {
53      this(TCP_PORT);
54    }
55  
56    public AFP_Server(int port)
57      throws IOException
58    {
59      this(null, port);
60    }
61  
62    public AFP_Server(String rname, int port)
63      throws IOException
64    {
65      this(rname, null, port);
66    }
67  
68    public AFP_Server(String rname, String bind, int port)
69      throws IOException
70    {
71      this.bind = bind;
72      this.port = port;
73      this.rendezvous = new Rendezvous();
74      this.volumesByID = new Hashtable();
75      this.volumesByName = new Hashtable();
76      // set debug level
77      String dl = System.getProperty("debug.afp");
78      if (dl != null && dl.length() > 0)
79      {
80        setDebugLevel(Integer.parseInt(dl));
81      }
82      // register server with Rendezvous
83      InetAddress addr = InetAddress.getLocalHost();
84      serverName = rname != null ? rname : addr.getHostName();
85      if (rname == null && serverName.indexOf('.') > 0)
86      {
87        serverName = serverName.substring(0, serverName.indexOf('.'));
88      }
89      rendezvous.registerService(new ServiceInfo(
90        "_afpovertcp._tcp.local.", serverName+"._afpovertcp._tcp.local.", addr, port, 1, 1, "Java AFP Server"
91      ));
92    }
93  
94    public void setDebugLevel(int lvl)
95    {
96      DEBUG_DEBUG = true;
97      DEBUG_DSI = true;
98      DEBUG_DSI_REQUEST = DEBUG_DSI;
99      DEBUG_DSI_REPLY = DEBUG_DSI;
100     DEBUG_DSI_LINE = DEBUG_DSI;
101     DEBUG_PRINT = DEBUG_DEBUG | DEBUG_DSI;
102 
103     switch (lvl)
104     {
105       case 0:
106         DEBUG_DEBUG=false;
107         DEBUG_PRINT=false;
108         DEBUG_DSI=false;
109         break;
110       case 1:
111         DEBUG_DSI_REQUEST=false;
112         DEBUG_DSI_REPLY=false;
113         break;
114       default:
115         break;
116     }
117 
118     DEBUG_DSI_REQUEST &= DEBUG_DSI;
119     DEBUG_DSI_REPLY &= DEBUG_DSI;
120     DEBUG_DSI_LINE &= DEBUG_DSI;
121   }
122 
123   public synchronized int addVolume(AFP_Volume vol)
124   {
125     int id = nextVolID++;
126     volumesByID.put(new Integer(id), vol);
127     volumesByName.put(vol.getName(), vol);
128     vol.setID(id);
129     return id;
130   }
131 
132   public AFP_Volume getVolume(int vid)
133   {
134     return (AFP_Volume)volumesByID.get(new Integer(vid));
135   }
136 
137   public AFP_Volume getVolume(String vname)
138   {
139     return (AFP_Volume)volumesByName.get(vname);
140   }
141 
142   public synchronized AFP_Volume[] getVolumes()
143   {
144     Object k[] = volumesByName.keySet().toArray();
145     AFP_Volume v[] = new AFP_Volume[k.length];
146     for (int i=0; i<k.length; i++)
147     {
148       v[i] = (AFP_Volume)volumesByName.get(k[i]);
149     }
150     return v;
151   }
152 
153   public synchronized void delVolume(AFP_Volume vol)
154   {
155     if (vol == null)
156     {
157       return;
158     }
159     volumesByName.remove(vol.getName());
160     volumesByID.remove(new Integer(vol.getID()));
161   }
162 
163   public void delVolume(String vname)
164   {
165     delVolume((AFP_Volume)volumesByName.get(vname));
166   }
167 
168   public void delVolume(int vid)
169   {
170     delVolume((AFP_Volume)volumesByID.get(new Integer(vid)));
171   }
172 
173   public synchronized void start()
174     throws IOException
175   {
176     if (thread != null)
177     {
178       return;
179     }
180     socket = bind != null ?
181       new ServerSocket(port, 10, InetAddress.getByName(bind)) :
182       new ServerSocket(port);
183     thread = new Thread(this, "AFP Server");
184     thread.start();
185   }
186 
187   public void run()
188   {
189     try
190     {
191       System.out.println(
192         "Jaffer AFP/TCP Server v"+Main.VERSION+
193         " ready on port "+socket.getLocalPort()+" as "+serverName);
194       while (true)
195       {
196         acceptConnection();
197       }
198     }
199     catch (Exception ex)
200     {
201       ex.printStackTrace();
202     }
203   }
204 
205   public abstract boolean hasCleartextPasswords()
206     ;
207 
208   public abstract boolean hasUser(String userName)
209     ;
210 
211   public abstract boolean checkPassword(String userName, String password)
212     ;
213 
214   public abstract boolean setThreadOwner(String userName)
215     ;
216 
217   public abstract String getPassword(String userName)
218     ;
219 
220   public abstract String getGuestUser()
221     ;
222 
223   public AFP_ServerInfo getServerInfo()
224   {
225     if (serverInfo == null)
226     {
227       serverInfo = new AFP_ServerInfo(serverName, protoStrings,
228         hasCleartextPasswords() ?
229           new String[] { UAM_STR_GUEST, UAM_STR_CLEARTEXT, UAM_STR_RANDOM_NUM1, UAM_STR_DHX_128 } :
230           new String[] { UAM_STR_GUEST, UAM_STR_CLEARTEXT, UAM_STR_DHX_128 },
231         0
232       );
233     }
234     return serverInfo;
235   }
236 
237   private void acceptConnection()
238     throws IOException
239   {
240     Socket s = socket.accept();
241     s.setTcpNoDelay(true);
242     System.out.println("AFP_Server: connect from "+s.getInetAddress());
243     AFP_Session session = new AFP_Session(this, s);
244     session.start();
245   }
246 }
247