Class: RStyx::Client::Connection

Inherits:
Object
  • Object
show all
Defined in:
lib/rstyx/client.rb

Overview

module StyxClient

Direct Known Subclasses

TCPConnection

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(auth = nil) ⇒ Connection

Returns a new instance of Connection.



194
195
196
197
198
199
200
201
202
203
204
205
# File 'lib/rstyx/client.rb', line 194

def initialize(auth=nil)
  @usedfids = []
  @pendingclunks = {}
  @rpendingclunks = {}
  @conn = nil
  @rootfid = nil
  @eventthread = nil
  @authenticator = auth
  @clunklock = Mutex.new
  @umask = ::File.umask
  @peerauth = nil
end

Instance Attribute Details

#connectstateObject (readonly)

Returns the value of attribute connectstate.



191
192
193
# File 'lib/rstyx/client.rb', line 191

def connectstate
  @connectstate
end

#msizeObject (readonly)

Returns the value of attribute msize.



191
192
193
# File 'lib/rstyx/client.rb', line 191

def msize
  @msize
end

#peerauthObject (readonly)

Returns the value of attribute peerauth.



192
193
194
# File 'lib/rstyx/client.rb', line 192

def peerauth
  @peerauth
end

#pendingclunksObject

Returns the value of attribute pendingclunks.



190
191
192
# File 'lib/rstyx/client.rb', line 190

def pendingclunks
  @pendingclunks
end

#rootdirectoryObject (readonly)

Returns the value of attribute rootdirectory.



192
193
194
# File 'lib/rstyx/client.rb', line 192

def rootdirectory
  @rootdirectory
end

#rootfidObject (readonly)

Returns the value of attribute rootfid.



192
193
194
# File 'lib/rstyx/client.rb', line 192

def rootfid
  @rootfid
end

#umaskObject

Returns the value of attribute umask.



190
191
192
# File 'lib/rstyx/client.rb', line 190

def umask
  @umask
end

#usedfidsObject

Returns the value of attribute usedfids.



190
191
192
# File 'lib/rstyx/client.rb', line 190

def usedfids
  @usedfids
end

#versionObject (readonly)

Returns the value of attribute version.



191
192
193
# File 'lib/rstyx/client.rb', line 191

def version
  @version
end

Instance Method Details

#connect(&block) ⇒ Object

Connect to a remote Styx server. If a block is passed, yield self to the block and then do a disconnect when the block finishes.



251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
# File 'lib/rstyx/client.rb', line 251

def connect(&block)
  prepare_connection()
  uname = ENV['USER']
  aname = ""

  # Do Inferno authentication if the @authenticator object is a
  # keyring authinfo object
  if @authenticator.is_a?(Keyring::Authinfo)
    @conn.keyringauth = Keyring::FileWrapper.new(@conn)
    @peerauth, secret = Keyring.auth(@conn.keyringauth,
                                     :client, @authenticator,
                                     ["none"])
    @conn.keyringauth = nil
  end

  # Connection has been established.  Begin the handshaking process
  # with the remote server.
  #
  # 1. Send a Tversion message and check the response from the
  #    remote Styx server.
  #
  rver = send_message(Message::Tversion.new(:msize => 8216,
                                            :version => "9P2000"))
  if (rver.version != "9P2000")
    raise StyxException.new("Server uses unsupported Styx version #{rver.version}")
  end
  @msize = rver.msize
  @version = rver.version
  rfid = nil
  # 2. Attach to the remote server
  if @auth.nil? || @authenticator.is_a?(Keyring::Authinfo)
    # unauthenticated connection
    rfid = get_free_fid
    rattach = send_message(Message::Tattach.new(:fid => rfid,
                                                :afid => NOFID,
                                                :uname => uname,
                                                :aname => aname))
  else
    #
    # 3. Perform authentication based on the passed authenticator
    #    object.
    #
    # If we have an authenticator object, we call its authenticator
    # method with ourself.
    #
    rfid = @auth.authenticate(self)
  end

  # If we get here, we're connected, and rfid represents the root
  # fid of the connection
  @rootfid = rfid

  if block_given?
    begin
      yield self
    ensure
      self.disconnect
    end
  else
    return(self)
  end
end

#disconnectObject

Disconnect from the remote server.



317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
# File 'lib/rstyx/client.rb', line 317

def disconnect
  # Clunk all outstanding fids in reverse order so the root fid
  # gets clunked last.
  while (@usedfids.length > 0)
    begin
      rclunk = tclunk(@usedfids[-1], true)
    rescue
      # An error is most likely a no such fid error.  Return the fid
      # manually in this case.
      return_fid(@usedfids[-1])
    end
  end

  @conn.disconnect
  @eventthread.kill
end

#get_free_fidObject

Get a new free FID.



210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
# File 'lib/rstyx/client.rb', line 210

def get_free_fid
  found = false
  val = nil
  0.upto(MAX_FID) do |i|
    unless @usedfids.include?(i)
      val = i
      break
    end
  end

  if val.nil?
    raise StyxException.new("No more free fids")
  end
  @usedfids << val
  return(val)
end

#open(path, mode = "r", perm = 0666, &block) ⇒ Object

Open a file on the remote server, throwing a StyxException if the file can’t be found or opened in a given mode.

path

The path of the file relative to the server root.

mode

Integer representing the mode, or one of “r”, “r+”, “w”, “w+”, “a”, “a+”, “e” as aliases

return

A File object representing the opened file, or

possibly a Directory object if the file was a directory.

If a block is passed, it will yield the file object to the block and close the file when the block finishes (actually it will pass the block on to the StyxFile#open method, which does just that).



401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
# File 'lib/rstyx/client.rb', line 401

def open(path, mode="r", perm=0666, &block)
  file = File.new(self, path)

  append = false
  create = false
  numeric_mode = nil
  if mode.is_a?(Integer)
    numeric_mode = mode
  else
    case mode.to_s
    when "r"
      numeric_mode = OREAD
    when "r+"
      numeric_mode = ORDWR
    when "w"
      numeric_mode = OTRUNC | OWRITE
      create = true
    when "w+"
      numeric_mode = OTRUNC | ORDWR
      create = true
    when "a"
      numeric_mode = OWRITE
      append = true
      create = true
    when "a+"
      numeric_mode = ORDWR
      append = true
      create = true
    when "e"
      numeric_mode = OEXEC
    end
  end

  fp = file.open(numeric_mode, perm, create, &block)
  if append
    fp.seek(0, 2)
  end
  return(fp)
end

#return_fid(fid) ⇒ Object

Returns a fid after we’re done using it.



230
231
232
# File 'lib/rstyx/client.rb', line 230

def return_fid(fid)
  @usedfids.delete(fid)
end

#send_message(msg, timeout = 0) ⇒ Object

Send a message, and return the response. Delegates to @conn#send_message. Do not use this method to send Tclunk messages!



339
340
341
# File 'lib/rstyx/client.rb', line 339

def send_message(msg, timeout=0)
  @conn.send_message(msg, timeout)
end

#tclunk(fid, sync = false) ⇒ Object

Fire and forget a Tclunk for some fid. When the Rclunk is received, return the fid. USE THIS METHOD, AND THIS METHOD ONLY, to send Tclunk messages.



348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
# File 'lib/rstyx/client.rb', line 348

def tclunk(fid, sync=false)
  if @rpendingclunks.has_key?(fid)
    return
  end
  q = nil
  if sync
    q = Queue.new
  end
  tag = @conn.send_message_async(Message::Tclunk.new(:fid => fid)) do |tx,rx|
    # Test whether the response is an Rclunk.
    if rx.class != Message::Rclunk
      # this is an error condition, but it will only get reported
      # if Thread.abort_on_exception is set to true, or if
      # the tclunk is synchronous
      exc = StyxException.new("#{tx.to_s} received #{rx.to_s}")
      if sync
        q << exc
      else
        raise exc
      end
    end
    # return the FID
    fid = @pendingclunks.delete(tag)
    @rpendingclunks.delete(fid)
    return_fid(fid)
    if sync
      q << fid
    end
  end
  @pendingclunks[tag] = fid
  @rpendingclunks[fid] = tag
  if sync
    res = q.shift
    if res.class == StyxException
      raise res
    end
  end
end