1
2
3
4
5
6 import socket
7 import mdinterface
8 import time
9 from mdinterface import CommandException, MDInterface
10
11 DEBUG = False
12
13 try:
14 import tlslite
15 USE_TLSLITE = True
16 from tlslite.api import *
17 if DEBUG: print "Using tlslite"
18 except ImportError, e:
19 USE_TLSLITE = False
20
21
23 - def __init__(self, host, port,
24 login='anonymous', password = '',
25 keepalive = True):
26
27 self.connected = 0
28 self.host = host
29 self.port = port
30 self.login = login
31 self.password = password
32 self.keepalive = keepalive
33 self.buffer = ''
34 self.reqSSL = False
35 self.sslSock = 0
36 self.sslOptions = None
37 self.sessionID = 0
38 self.session = None
39 self.greetings = ''
40 self.protocolVersion = 0
41 self.currentCommand = ""
42 self.siteCache = {}
43 self.idCache = {}
44
45
47 self.reqSSL=True
48 self.keyFile=key
49 self.certFile=cert
50 if USE_TLSLITE:
51 self.sslOptions = tlslite.HandshakeSettings.HandshakeSettings
52 self.sslOptions.minVersion = (3,0)
53 self.sslOptions.maxVersion = (3,1)
54
55
57 if USE_TLSLITE:
58 self.sslSock=TLSConnection(self.s)
59 if session:
60 if DEBUG: print "Doing SSL resuming session using TLSLite"
61 self.sslSock.handshakeClientCert(session=session)
62 return
63 if DEBUG: print "Doing SSL handshake using TLSLite"
64 cert = None
65 key = None
66 if self.certFile:
67 s = open(self.certFile).read()
68 x509 = X509()
69 x509.parse(s)
70 cert = X509CertChain([x509])
71 if self.keyFile:
72 s = open(self.keyFile).read()
73 key = parsePEMKey(s, private=True)
74 self.sslSock.handshakeClientCert(cert, key,
75 self.session, None, None, False)
76 self.sslSock.closeSocket = False
77 else:
78 if DEBUG: print "Doing SSL handshake using builtin SSL"
79 self.sslSock=socket.ssl(self.s, self.keyFile, self.certFile)
80
81
83 self.s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
84 TCP_NODELAY = 1
85 self.s.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1)
86 self.s.connect((self.host, self.port))
87
88 self.greetings = ""
89
90 while self.greetings.count('\n') < 3:
91 line=self.s.recv(1024)
92 if not line:
93 raise CommandException(-1, "Cannot connect")
94 self.greetings += line
95
96 pos = self.greetings.find('\nProtocol ')
97 if pos > -1:
98 self.protocolVersion = int(self.greetings[pos+10])
99
100 if self.sessionID:
101 if DEBUG: print "Trying to resume session ", self.sessionID
102
103 if self.reqSSL:
104 self.s.send('resumeSSL%u\n\n' % self.sessionID)
105 line = self.s.recv(1024)
106 self.__doSSLHandshake(self.session)
107 else:
108 self.s.send('resume%d\n\n' % self.sessionID)
109 self.connected=True
110 self.buffer=''
111 self.attr=0
112 return 0
113 else:
114 if self.reqSSL:
115 self.s.send('ssl\n\n')
116 line = self.s.recv(1024)
117 self.__doSSLHandshake()
118 else:
119 self.s.send('plain\n\n')
120 line = self.s.recv(1024)
121
122
123 context = '0 '+self.login
124 if len(self.password):
125 context = context + '\n5 ' + self.password
126 context = context + '\n\n'
127
128 if not self.sessionID:
129 if self.sslSock:
130 self.sslSock.write(context)
131 else:
132 self.s.send(context)
133
134 self.connected=True
135 self.buffer=''
136 self.attr=0
137
138
140 if saveSession and self.sslSock:
141 if USE_TLSLITE:
142 self.session = self.sslSock.session
143 else:
144 self.session = None
145 if self.connected:
146 if self.sslSock:
147 if USE_TLSLITE:
148 self.sslSock.close()
149 else:
150 del self.sslSock
151 self.s.close()
152 self.connected = False
153
154
161
162
167
181
182
184 self.EOT = 0
185 self.buffer = "";
186 line = self.__fetchRow()
187 if line == None:
188 raise IOError("Server sent empty response")
189 pos=line.find(' ')
190 msg = ""
191 if(pos>-1):
192 retValue, msg=int(line[:pos]), line[pos+1:]
193 else:
194 retValue = int(line)
195 if retValue != 0:
196
197
198 while not self.EOT:
199 if self.__fetchData()<0:
200 break
201 self.buffer = ""
202 msg = msg + ". Command was: " + self.currentCommand
203 raise CommandException(retValue, msg)
204
205
222
223
226
227
229 pos=self.buffer.find('\n')
230 if pos>-1:
231 line=self.buffer[:pos]
232 self.buffer=self.buffer[pos+1:]
233 if not len(self.buffer) and not self.EOT:
234 if self.__fetchData() < 0: return None
235 return line
236 if self.EOT:
237 return None
238 if self.__fetchData() <=0:
239 return None
240 return self.__fetchRow()
241
242
244 while 1:
245
246 pos = self.buffer.find('\004')
247 if pos >-1:
248
249 while self.protocolVersion >1 and self.buffer.find('\004', pos + 1) <0:
250 if self.sslSock:
251 line=self.sslSock.read(1024)
252 else:
253 line=self.s.recv(1024)
254 if not line: break
255 self.buffer += line
256 break
257
258 pos = self.buffer.find('\n')
259 if pos>-1 and pos<len(self.buffer)-1: break
260
261
262 if self.sslSock:
263 line=self.sslSock.read(1024)
264 else:
265 line=self.s.recv(1024)
266 if not line: break
267 self.buffer += line
268 pos=self.buffer.find('\004')
269 if pos>-1:
270 self.sessionID = 0
271 if pos < len(self.buffer)-8 and self.buffer[pos+1:pos+8] == 'session':
272 pos2 = self.buffer.find('\004', pos+1)
273 self.sessionID = long(self.buffer[pos+8:pos2])
274 self.disconnect(True)
275 if DEBUG: print "Session ID", self.sessionID
276 self.buffer=self.buffer[:pos]
277 self.EOT=1
278 if not line:
279 return -1
280 return len(line)
281
282
284 gotSomething=1
285 self.s.setblocking(0)
286 try:
287 self.s.recv(1, MSG_PEEK)
288 except Exception, e:
289 gotSomething=0
290 self.s.setblocking(1)
291 return gotSomething
292
293
295 if type(value) == type(str()):
296 value = value.replace('\'', '\\\'')
297 value = "'" + value + "'"
298 return value
299
300
302 if len(self.buffer): return 0
303 if self.EOT: return 1
304 if self.__fetchData() <=0: return 1
305 return not len(self.buffer)
306
307
308 - def getattr(self, file, attributes):
314
315
316 - def getEntry(self):
317 file = self.__fetchRow()
318 attributes=[]
319 for i in range(0, self.nattrs):
320 attribute=self.__fetchRow()
321 attributes.append(attribute)
322 return file, attributes
323
324
325 - def setAttr(self, file, keys, values):
332
333
334 - def addEntry(self, file, keys, values):
335 command='addentry '+file
336 for i in range(len(keys)):
337 command += ' '+keys[i]
338 values[i] = self.__quoteValue(str(values[i]))
339 command += ' ' +values[i]
340 self.execute(command)
341
342
348
349
353
354
358
359
363
364
369
370
374
375
387
388
392
393
397
398
402
403
404 - def rm(self, path):
407
408
409 - def find(self, pattern, query):
415
416
424
425
427 attributes=[]
428 for i in range(0, self.nattrs):
429 attribute=self.__fetchRow()
430 attributes.append(attribute)
431 return attributes
432
433
434 - def updateAttr(self, pattern, updateExpr, condition):
441
442
443 - def update(self, pattern, updateExpr, condition):
450
451
452 - def upload(self, collection, attributes):
458
459
460 - def put(self, file, values):
467
468
472
473
477
478
483
484
489
490
494
495
499
500
504
505
509
510
515
516
520
521
525
526
528 command='constraint_list '+directory
529 self.execute(command)
530 constraints=[]
531 while not self.eot():
532 constraint = self.__fetchRow()
533 constraints.append(constraint)
534 return constraints
535
536
540
541
543 command='execute ' + remoteCommand
544 self.execute(command)
545 result = ''
546 while not self.eot():
547 result = result + self.__fetchRow() +'\n'
548 return result
549
550
551 - def siteAdd(self, site, server=''):
556
557
561
562
575
576
583
584
587
588
600
601
602 - def replicaList(self, files, resolveSites = True, isLFN = False):
603 if resolveSites and not len(self.idCache):
604 self.siteList()
605 command = 'replica_list'
606 if isLFN:
607 command += ' -l'
608 for f in files:
609 command += ' ' + f
610 self.execute(command)
611 res = {}
612 while not self.eot():
613 l = self.__fetchRow()
614 try:
615 (file, s) = l.split(' ', 1)
616 except ValueError:
617 file = l
618 s = ''
619 sites = map(int, s.split())
620 if resolveSites:
621 sites = map(self.idCache.get, sites)
622 res[file] = sites
623 return res
624