de6ea186e42a0a629b0da94a273fd28cd9363831
[doldaconnect.git] / lib / java / dolda / dolcon / Session.java
1 package dolda.dolcon;
2
3 import java.util.*;
4 import dolda.dolcon.protocol.*;
5
6 public class Session implements NotifyListener {
7     private Connection conn;
8     private String state;
9     private Set<HubListener> hubls = new HashSet<HubListener>();
10     private boolean listening = false;
11     private String[] hubstate = {"none"};
12     private String[][] states = {hubstate};
13     private Map<Integer, Hub> hubs = new TreeMap<Integer, Hub>();
14     
15     public Session(String aspec, String username, List<Authenticator> auth) throws AuthException, ProtocolException, InterruptedException {
16         state = "connecting";
17         conn = new Connection(aspec);
18         conn.expectVersion(2);
19         try {
20             conn.syncConnect();
21         } catch(ConnectException e) {
22             throw(new ProtocolException(e));
23         }
24         state = "auth";
25         authenticate(username, auth);
26         state = "";
27     }
28     
29     public Session(String aspec, String username, Authenticator... auth) throws AuthException, ProtocolException, InterruptedException {
30         this(aspec, username, Arrays.asList(auth));
31     }
32     
33     private void authenticate(String username, List<Authenticator> auth) throws AuthException, ProtocolException, InterruptedException {
34         Response resp;
35         
36         try {
37             resp = ResponseException.check(conn.ecmd("lsauth"), 200);
38             List<String> mechs = new LinkedList<String>();
39             for(List<String> mech : resp.lines)
40                 mechs.add(mech.get(0).intern());
41             String use = null;
42             Authenticator au = null;
43             for(Authenticator a : auth) {
44                 System.out.println(a);
45                 use = a.handles(mechs);
46                 if(use != null) {
47                     au = a;
48                     break;
49                 }
50             }
51             if(use == null)
52                 throw(new NoMechException());
53             resp = conn.ecmd("login", use, username);
54             while(true) {
55                 if(resp.code == 200) {
56                     return;
57                 } else if((resp.code / 100) == 3) {
58                     resp = conn.ecmd(au.step(resp));
59                 } else if((resp.code / 100) == 5) {
60                     throw(new AuthException(resp.token(0, 0)));
61                 } else {
62                     throw(new ResponseException(resp, 0));
63                 }
64             }
65         } catch(ClosedException e) {
66             throw(new ProtocolException(e));
67         }
68     }
69     
70     private void checkstates() {
71         boolean active = false;
72         for(String[] sp : states) {
73             if(sp[0] != "none") {
74                 active = true;
75                 break;
76             }
77         }
78         if(listening && !active)
79             conn.removeNotifyListener(this);
80         else if(!listening && active)
81             conn.addNotifyListener(this);
82     }
83
84     private int atoi(String a) {
85         return(Integer.parseInt(a));
86     }
87
88     private void fetchhubs() {
89         synchronized(hubstate) {
90             if(hubstate[0] != "none")
91                 return;
92             hubstate[0] = "fetch";
93         }
94         Command cmd = new Command("lsnodes");
95         cmd.new Listener() {
96                 public void done(Response r) {
97                     if(r.code != 200)
98                         return;
99                     for(List<String> line : r.lines) {
100                         Hub h = new Hub(atoi(line.get(0)));
101                         h.fnet = line.get(1).intern();
102                         h.name = line.get(2);
103                         h.numpeers = atoi(line.get(3));
104                         h.state = new String[] {"syn", "hs", "est", "dead"}[atoi(line.get(4))];
105                         h.gid = line.get(5);
106                         hubs.put(h.id, h);
107                     }
108                 }
109                 
110                 public void error(Exception e) {
111                 }
112             };
113         conn.qcmd(new Command("notify fn:act on"), cmd);
114     }
115     
116     public void addHubListener(HubListener hl, boolean addexisting) {
117         fetchhubs();
118         synchronized(hubls) {
119             hubls.add(hl);
120         }
121     }
122     
123     public void removeHubListener(HubListener hl) {
124         synchronized(hubls) {
125             hubls.remove(hl);
126             if(hubls.isEmpty()) {
127                 hubs.clear();
128                 hubstate[0] = "none";
129                 checkstates();
130             }
131         }
132     }
133
134     public void notified(Response resp) {
135     }
136     
137     public void close() {
138         conn.close();
139         state = "closed";
140     }
141     
142     protected void finalize() {
143         if(state != "closed")
144             close();
145     }
146 }