Class: RStyx::Server::Session

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

Overview

Session state of a Styx connection.

Constant Summary collapse

EXECUTE =

These constants are used by Session#permission? and should NOT be changed. The algorithm used depends on it!

0
WRITE =
1
READ =
2

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(conn) ⇒ Session

Create a new session.

conn

The connection object (Server mixin)



693
694
695
696
697
698
699
700
701
# File 'lib/rstyx/server.rb', line 693

def initialize(conn)
  @conn = conn
  @version_negotiated = false
  @msize = 0
  @user = nil
  @auth = false
  @fids = {}
  @tags = []
end

Instance Attribute Details

#authObject

Authenticated flag



664
665
666
# File 'lib/rstyx/server.rb', line 664

def auth
  @auth
end

#fidsObject

List of active fids on this session



667
668
669
# File 'lib/rstyx/server.rb', line 667

def fids
  @fids
end

#groupsObject

Group table



686
687
688
# File 'lib/rstyx/server.rb', line 686

def groups
  @groups
end

#iounitObject

Active iounit for this connection



682
683
684
# File 'lib/rstyx/server.rb', line 682

def iounit
  @iounit
end

#msizeObject

Maximum message size to be used by this session, based on the lesser of the server’s and the client’s msize.



661
662
663
# File 'lib/rstyx/server.rb', line 661

def msize
  @msize
end

#tagsObject

List of active tags on this session



670
671
672
# File 'lib/rstyx/server.rb', line 670

def tags
  @tags
end

#userObject

User this connection has authenticated against



678
679
680
# File 'lib/rstyx/server.rb', line 678

def user
  @user
end

#version_negotiatedObject

Flag which is true if version negotiation has been performed on this session



674
675
676
# File 'lib/rstyx/server.rb', line 674

def version_negotiated
  @version_negotiated
end

Instance Method Details

#[](fid) ⇒ Object

Gets the file associated with the indexed FID. Raises a FidNotFoundException if the fid is not present.

fid

the fid to obtain the associated SFile instance of



745
746
747
748
749
750
# File 'lib/rstyx/server.rb', line 745

def [](fid)
  unless has_fid?(fid)
    raise FidNotFoundException.new(fid)
  end
  return(@fids[fid])
end

#[]=(fid, file) ⇒ Object

Associates a FID with a file. The FID passed must be checked before using this or the old FID will be forgotten.

fid

the fid to be associated

file

the SFile to associate with fid



734
735
736
737
# File 'lib/rstyx/server.rb', line 734

def []=(fid, file)
  @fids.delete(fid)
  @fids[fid] = file
end

#add_tag(tag) ⇒ Object Also known as: <<

Adds the given tag to the list of tags in use, first checking to see if it is already in use. Raises a TagInUseException if tag is already in use.



810
811
812
813
814
815
# File 'lib/rstyx/server.rb', line 810

def add_tag(tag)
  if has_tag?(tag)
    raise TagInUseException.new(tag)
  end
  @tags << tag
end

#clunk(fid) ⇒ Object

Clunk fid, i.e. make the server forget about the fid assignment for this connection.



764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
# File 'lib/rstyx/server.rb', line 764

def clunk(fid)
  unless @fids.has_key?(fid)
    raise FidNotFoundException.new(fid)
  end
  sf = self[fid]
  sf.synchronize do
    # Get the client using this fid, and see whether the file
    # is requested to be deleted on clunk.
    sfc = sf.client(self, fid)
    if (!sfc.nil? && sfc.orclose?)
      begin
        sf.remove
      rescue Exception => e
        # if there was a problem removing the file, ignore it
      end
    end
    sf.remove_client(sfc)
    @fids.delete(fid)
  end
end

#clunk_allObject

Clunk all outstanding fids on this connection.



788
789
790
791
792
793
794
795
796
# File 'lib/rstyx/server.rb', line 788

def clunk_all
  @fids.each_key do |k|
    begin
      clunk(k)
    rescue FidNotFoundException => e
      # ignore this as we are closing down anyway...
    end
  end
end

#confirm_open(sf, mode) ⇒ Object

Checks that the given file can be opened with the given mode. Raises a StyxException if this is not possible.

sf

the SFile to be opened

mode

the open mode



901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
# File 'lib/rstyx/server.rb', line 901

def confirm_open(sf, mode)
  if sf.exclusive? && sf.num_clients != 0
    raise StyxException.new("can't open locked file")
  end
  openmode = mode & 0x03
  case openmode
  when OREAD
    unless permission?(sf, READ)
      raise StyxException.new("read permission denied")
    end
  when OWRITE
    unless permission?(sf, WRITE)
      raise StyxException.new("write permission denied")
    end
  when ORDWR
    unless permission?(sf, READ)
      raise StyxException.new("read permission denied")
    end
    unless permission?(sf, WRITE)
      raise StyxException.new("write permission denied")
    end
  when OEXEC
    unless permission?(sf, EXECUTE)
      raise StyxException.new("execute permission denied")
    end
  else
    # shouldn't happen
    raise StyxException.new("internal Styx error openmode = #{openmode}: should be between 0 and 3")
  end

  # Execute permission is required for a directory in order to
  # do anything with it
  if sf.directory? && !execute?(sf)
    raise StyxException("directory execute permission denied")
  end

  if (mode & OTRUNC) != 0
    # can't truncate a directory
    if sf.directory?
      raise StyxException.new("cannot truncate a directory")
    end
    unless permission?(sf, WRITE)
      raise StyxException.new("need write permissions to truncate a file")
    end
  end

  if (mode & ORCLOSE) != 0
    # can't delete a directory on closing
    if sf.directory?
      raise StyxException.new("cannot automatically delete a directory")
    end
    # we must have write permissions on the parent directory and the file
    # itself to delete the file on clunking its fid
    unless permission?(sf.parent, WRITE)
      raise StyxException.new("need write permissions on the parent directory to delete the file when the fid is clunked")
    end
    # TODO: do we need write permissions on the file itself?
  end
end

#execute?(sf) ⇒ Boolean

Check for executable permission for the SFile sf.

Returns:

  • (Boolean)


884
885
886
# File 'lib/rstyx/server.rb', line 884

def execute?(sf)
  return(permission?(sf, EXECUTE))
end

#flush_allObject

Flush all outstanding tags on this session.



832
833
834
835
836
# File 'lib/rstyx/server.rb', line 832

def flush_all
  @tags.each do |f|
    flush_tag(t)
  end
end

#has_fid?(fid) ⇒ Boolean

Returns true if fid is associated with some file on this session.

Returns:

  • (Boolean)


756
757
758
# File 'lib/rstyx/server.rb', line 756

def has_fid?(fid)
  return(@fids.has_key?(fid))
end

#has_tag?(tag) ⇒ Boolean

Returns true if tag is associated with some active message

Returns:

  • (Boolean)


801
802
803
# File 'lib/rstyx/server.rb', line 801

def has_tag?(tag)
  return(!@tags.index(tag).nil?)
end

#permission?(sf, mode) ⇒ Boolean

Check the permissions for a given mode

sf

the file to check against

mode

the mode to check (EXEC, WRITE, or READ)

Returns:

  • (Boolean)


850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
# File 'lib/rstyx/server.rb', line 850

def permission?(sf, mode)
  if mode < 0 || mode > 2
    raise "Internal error: mode should be 0, 1, or 2"
  end
  # We bit shift the permissions value so that the mode is
  # represented by the last bit (all) the fourth to last bit
  # (group), and the seventh-to-last bit (user).  For example,
  # if we started with a mode of 0755 (binary 111101101,
  # rwxrwxrwx), and we want to check write permissions, we
  # shift by one bit so that the value of perms is 1110110, or
  # (rwxrwxrw).
  perms = sf.permissions >> mode
  # Check permissions for 'all' -- the low-order bit
  unless perms & 0b000_000_001 == 0
    return(true)
  end

  # Group permissions
  unless (perms & 0b000_001_000) == 0
    # The group has the correct permissions; now we have to find if
    # the user is a member of the group in question.
    ug = @groups[@user]
    unless ug.index(sf.gid).nil?
      return(true)
    end
  end

  # Owner permissions.  This is the final fallback.
  return(((perms & 0b001_000_000) != 0) && (@user == sf.uid))
end

#release_tag(tag) ⇒ Object Also known as: flush_tag

Called when a message is replied to, releasing tag so it can be used again.



823
824
825
# File 'lib/rstyx/server.rb', line 823

def release_tag(tag)
  @tags.delete(tag)
end

#reset_session(msize) ⇒ Object

Reset the session, setting version negotiation flag and iounit.

– FIXME: should clunk all outstanding fids and release all outstanding tags on this connection ++

msize

the maximum message size for this connection



721
722
723
724
725
# File 'lib/rstyx/server.rb', line 721

def reset_session(msize)
  # XXX: clunk all outstanding fids and release all outstanding tags
  @version_negotiated = true
  @iounit = msize
end

#version_negotiated?Boolean

Return true if the session peer has completed version negotiation

Returns:

  • (Boolean)


706
707
708
# File 'lib/rstyx/server.rb', line 706

def version_negotiated?
  return(@version_negotiated)
end

#writable?(sf) ⇒ Boolean

Check for write permission for the SFile sf.

Returns:

  • (Boolean)


890
891
892
# File 'lib/rstyx/server.rb', line 890

def writable?(sf)
  return(permission?(sf, WRITE))
end