Atlas 0.7.0
Networking protocol for the Worldforge system.
negotiation.py
1#negotiation of codec
2
3#Copyright 2000, 2001 by Aloril
4
5#This library is free software; you can redistribute it and/or
6#modify it under the terms of the GNU Lesser General Public
7#License as published by the Free Software Foundation; either
8#version 2.1 of the License, or (at your option) any later version.
9
10#This library is distributed in the hope that it will be useful,
11#but WITHOUT ANY WARRANTY; without even the implied warranty of
12#MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13#Lesser General Public License for more details.
14
15#You should have received a copy of the GNU Lesser General Public
16#License along with this library; if not, write to the Free Software
17#Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18
19
20#initialization:
21#server:
22#neg = NegotiationServer(("Packed", "XML"), id="Joe server")
23#or with filepointer (socket or normal file):
24#neg = NegotiationServer(("Packed", "XML"), input_fp, id="foo")
25#client same as above, except mode is different:
26#neg = NegotiationClient(("Packed", "XML"), id="Joe's text client")
27
28#feeding data and getting result:
29#feed it input...
30#neg(input_string)
31#.. and send replies if any ...
32# (first check neg() return value, see after next line)
33#neg.get_send_str() returns what should be sent to other side
34#...until you get non empty result:
35#either "found" or "fail":
36#neg.str contains what is left over of negotiation
37#in case when "found", then neg.selected_codec contains selected codec
38# (string: currently only "XML" supported by Atlas-Python)
39#get_codec() returns codec object that can be used to
40# encode(obj) outgoing objects and decode(str) incoming objects
41# see codec.py for more docs
42
43#other info:
44#neg.other_codecs: list of codecs other side supports
45#neg.other_id: id -string of other side
46
47import string
48import atlas.codecs
49
51 state_done = 0
52 state_id = "id"
53 state_negotiation = "negotiation"
54 state_found = "found"
55 #when result to __call__ is:
56 #"": than state is one of above "string" states
57
58 #when result to __call__ is:
59 #"fail" or "found": then state is state_done
60 #and further calls are undefined
61 def __init__(self, mode, codecs_lst, fp=None, id=""):
62 #args stuff
63 self.mode = mode
64 if codecs_lst:
65 self.codecs = codecs_lst
66 else:
67 self.codecs = atlas.codecs.ids
68 self.fp = fp
69 if id: self.id = id
70 else: self.id = mode
71
72 #result stuff:
73 #reply to send: use get_send_str() to access
74 self.send_str = "ATLAS %s\n" % self.id
75 self.selected_codec = "" #what codec was selected
76 self.other_codecs = [] #list of codecs other side supports
77 #"found"/"fail" when result has been achieved
78 #result of __call__
79 self.result_code = ""
80 self.other_id = "" #id -string of other side
81
82 #internal state stuff:
83 self.str = ""
84 self.state = self.state_id
85
86 def get_send_str(self):
87 res = self.send_str
88 self.send_str = ""
89 return res
90
91 def __call__(self, str=""):
92 if str: self.str = self.str + str
93 if self.state == self.state_done: return self.result_code
94 line = self.collect_until_newline()
95 while line!=None:
96 res = self.process_line(line)
97 if res: return res
98 line = self.collect_until_newline()
99 return self.result_code
100
101 def process_line(self, line):
102 raise AttributeError("User NegotiationClient or NegotiationServer instead")
103
104 def collect_until_newline(self):
105 if self.fp:
106 ok = string.find(self.str, "\n")<0
107 while ok:
108 ok = read_str = self.fp.recv(1) # silence-py depends on this /Demitar
109 self.str = self.str + read_str
110 ok = read_str and string.find(self.str, "\n")<0
111 #print "neg:cun", `self.str`
112 newline_pos = string.find(self.str, "\n")
113 if newline_pos >= 0:
114 res = self.str[:newline_pos]
115 self.str = self.str[newline_pos+1:]
116 return res
117
118 def iwill(self, codecs):
119 return string.join(["IWILL %s\n" % c for c in codecs], "") + '\n' # Fixes negotiation /Demitar
120
121 def ican(self, codecs):
122 return string.join(["ICAN %s\n" % c for c in codecs], "") + '\n' # Fixes negotiation /Demitar
123
124 def analyse_line_codecs(self, line):
125 modes = string.split(line)
126 if len(modes)>=2 and modes[0]=="ICAN":
127 self.other_codecs.append(modes[1])
128 return modes
129
130 def fail(self, msg):
131 self.send_str = self.send_str + msg
132 self.state = self.state_done
133 self.result_code = "fail"
134 #print "neg:fail", msg
135 return self.result_code
136
137 def get_codec(self):
139 co.set_stream_mode()
140 return co
141
143 def __init__(self, codecs=(), fp=None, id=""):
144 Negotiation.__init__(self, "server", codecs, fp, id)
145
146 def process_line(self, line):
147 if self.statestate == self.state_id:
148 if line[:5]!="ATLAS":
149 return self.fail("Huh?\n\n")
150 self.other_idother_id = line[6:]
151 self.statestate = self.state_negotiation
152 elif self.statestate == self.state_negotiation:
153 if not line:
154 return self.fail(self.ican(self.codecs))
155 modes = self.analyse_line_codecs(line)
156 if len(modes)>=2 and modes[0]=="ICAN" and \
157 modes[1] in self.codecs:
158 self.selected_codecselected_codec = modes[1]
159 #print "neg:found"
160 self.statestate = self.state_found
161 else: #negotiation_found
162 self.analyse_line_codecs(line)
163 if not line or line=="\r":
164 #print "neg:ok"
165 self.send_strsend_str = self.send_strsend_str + \
167 self.statestate = self.state_done
168 self.result_coderesult_code = "found"
169 return self.result_coderesult_code
170
171
173 def __init__(self, codecs=(), fp=None, id=""):
174 Negotiation.__init__(self, "client", codecs, fp, id)
175
176 def process_line(self, line):
177 if self.statestate == self.state_id:
178 if line[:5]!="ATLAS":
179 return self.fail("Huh?\n\n")
180 self.other_idother_id = line[6:]
181 self.statestate = self.state_negotiation
182 self.send_strsend_str = self.send_strsend_str + self.ican(self.codecs)
183 elif self.statestate == self.state_negotiation:
184 if not line:
185 return self.fail("")
186 modes = self.analyse_line_codecs(line)
187 if len(modes)>=2 and modes[0]=="IWILL" and \
188 modes[1] in self.codecs:
189 self.other_codecs.append(modes[1])
190 self.selected_codecselected_codec = modes[1]
191 #print "neg:found"
192 self.statestate = self.state_found
193 else: #negotiation_found
194 self.analyse_line_codecs(line)
195 if not line:
196 #print "neg:ok"
197 self.statestate = self.state_done
198 self.result_coderesult_code = "found"
199 return self.result_coderesult_code
def get_codec(name)