| line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
|
1
|
|
|
|
|
|
|
package Citrix::SessOp; |
|
2
|
|
|
|
|
|
|
#use strict; |
|
3
|
|
|
|
|
|
|
#use warnings; |
|
4
|
|
|
|
|
|
|
|
|
5
|
|
|
|
|
|
|
our $VERSION = "0.25"; |
|
6
|
|
|
|
|
|
|
|
|
7
|
|
|
|
|
|
|
=head1 NAME |
|
8
|
|
|
|
|
|
|
|
|
9
|
|
|
|
|
|
|
Citrix::SessOp - Disconnect or Logoff from an existing Citrix Session. |
|
10
|
|
|
|
|
|
|
|
|
11
|
|
|
|
|
|
|
=head1 DESCRIPTION |
|
12
|
|
|
|
|
|
|
|
|
13
|
|
|
|
|
|
|
Control Citrix session state by launching associated command line utilities. |
|
14
|
|
|
|
|
|
|
The module user should take care of gaining authority to (by host/user, |
|
15
|
|
|
|
|
|
|
whatever) execute these commands successfully on Citrix Farm as the |
|
16
|
|
|
|
|
|
|
current process runtime user (It seems Citrix commands and associated protocol map the user |
|
17
|
|
|
|
|
|
|
1-to-1 to the server end). Lacking this permission the commands will fail. |
|
18
|
|
|
|
|
|
|
|
|
19
|
|
|
|
|
|
|
Module aims to provide proper return values and error messages |
|
20
|
|
|
|
|
|
|
when things fail, but this is not a substitute for first taking care of |
|
21
|
|
|
|
|
|
|
of proper permissions (for lauching Citrix commands) with your local Citrix Admin. |
|
22
|
|
|
|
|
|
|
|
|
23
|
|
|
|
|
|
|
=head1 SYNOPSIS |
|
24
|
|
|
|
|
|
|
|
|
25
|
|
|
|
|
|
|
use Citrix::SessOp; |
|
26
|
|
|
|
|
|
|
my $fms = Citrix::getfarms('idx' => 1); |
|
27
|
|
|
|
|
|
|
my $farmctx = $fms->{'cairo'}; |
|
28
|
|
|
|
|
|
|
my $csop = Citrix::SessOp->new($farmctx); |
|
29
|
|
|
|
|
|
|
|
|
30
|
|
|
|
|
|
|
# Disconnect (leaves session idle, to "returnable" state) |
|
31
|
|
|
|
|
|
|
$err = $csop->disconnect("the-cx-host-12:8879"); |
|
32
|
|
|
|
|
|
|
|
|
33
|
|
|
|
|
|
|
# Log Off Completely (Terminating UNIX X-Windows session) |
|
34
|
|
|
|
|
|
|
$err = $csop->logoff("the-cx-host-12:8879"); |
|
35
|
|
|
|
|
|
|
|
|
36
|
|
|
|
|
|
|
=head1 METHODS |
|
37
|
|
|
|
|
|
|
|
|
38
|
|
|
|
|
|
|
=head2 $csop = Citrix::SessOp->new($farmctx); |
|
39
|
|
|
|
|
|
|
|
|
40
|
|
|
|
|
|
|
Create a new Citrix session operation by L context ($farmctx). |
|
41
|
|
|
|
|
|
|
The ops available later are disconnect() / logoff() (See method docs on each for details). |
|
42
|
|
|
|
|
|
|
Return session operation instance. |
|
43
|
|
|
|
|
|
|
|
|
44
|
|
|
|
|
|
|
=cut |
|
45
|
|
|
|
|
|
|
sub new { |
|
46
|
0
|
|
|
0
|
1
|
|
my ($class, $fc) = @_; |
|
47
|
|
|
|
|
|
|
#my ($h, $sid) = split(/:/, $hostsess); |
|
48
|
0
|
0
|
|
|
|
|
if (!$fc) {return(undef);} |
|
|
0
|
|
|
|
|
|
|
|
49
|
0
|
|
|
|
|
|
return(bless({ 'fc' => $fc}, $class)); # 'hs' => $hostsess, |
|
50
|
|
|
|
|
|
|
} |
|
51
|
|
|
|
|
|
|
|
|
52
|
|
|
|
|
|
|
|
|
53
|
|
|
|
|
|
|
=head2 $err = $cop->disconnect("the-cx-host-12:8879"); |
|
54
|
|
|
|
|
|
|
|
|
55
|
|
|
|
|
|
|
Disconnect a Citrix session By Host Session ID ($hostsess in format "$hostname:$sessid"). |
|
56
|
|
|
|
|
|
|
Disconnect persists the session state (leaves applications in the state they were before disconnect). |
|
57
|
|
|
|
|
|
|
Return 0 for success, 1 (and up) for errors. |
|
58
|
|
|
|
|
|
|
|
|
59
|
|
|
|
|
|
|
=cut |
|
60
|
|
|
|
|
|
|
|
|
61
|
|
|
|
|
|
|
sub disconnect { |
|
62
|
0
|
|
|
0
|
1
|
|
my ($op, $hostsess) = @_; |
|
63
|
0
|
|
|
|
|
|
opexec($op, $hostsess, 'ctxdisconnect'); |
|
64
|
|
|
|
|
|
|
|
|
65
|
|
|
|
|
|
|
} |
|
66
|
|
|
|
|
|
|
|
|
67
|
|
|
|
|
|
|
=head2 $err = $cop->logoff("the-cx-host-12:8879"); |
|
68
|
|
|
|
|
|
|
|
|
69
|
|
|
|
|
|
|
Logoff from a Citrix session By Host Session ID ($hostsess in format "$hostname:$sessid"). |
|
70
|
|
|
|
|
|
|
Logging off completely destroys the session state (closes apps and terminates X-Windows session). |
|
71
|
|
|
|
|
|
|
Return 0 for success, 1 (and up) for errors. |
|
72
|
|
|
|
|
|
|
|
|
73
|
|
|
|
|
|
|
=cut |
|
74
|
|
|
|
|
|
|
sub logoff { |
|
75
|
0
|
|
|
0
|
1
|
|
my ($op, $hostsess) = @_; |
|
76
|
0
|
|
|
|
|
|
opexec($op, $hostsess, 'ctxlogoff'); |
|
77
|
|
|
|
|
|
|
} |
|
78
|
|
|
|
|
|
|
|
|
79
|
|
|
|
|
|
|
# Internal accessor to Get/Set Farm context of a Citrix Operation. |
|
80
|
|
|
|
|
|
|
sub fc { |
|
81
|
0
|
|
|
0
|
0
|
|
my ($op, $fc) = @_; |
|
82
|
0
|
0
|
|
|
|
|
if ($fc) {$op->{'fc'} = $fc;} |
|
|
0
|
|
|
|
|
|
|
|
83
|
0
|
|
|
|
|
|
$op->{'fc'}; |
|
84
|
|
|
|
|
|
|
} |
|
85
|
|
|
|
|
|
|
|
|
86
|
|
|
|
|
|
|
# Internal method for executing Citrix Operation by launching associated command $cmd. |
|
87
|
|
|
|
|
|
|
# Not part of public API, do not use this directly. Please use the wrapper methods disconnect() and |
|
88
|
|
|
|
|
|
|
# logoff() as operations. |
|
89
|
|
|
|
|
|
|
# Return 0 for success, 1 for failure. |
|
90
|
|
|
|
|
|
|
sub opexec { |
|
91
|
0
|
|
|
0
|
0
|
|
my ($op, $hostsess, $cmd) = @_; |
|
92
|
|
|
|
|
|
|
#my ($h, $sid) = split(/:/, $hostsess); |
|
93
|
|
|
|
|
|
|
#my ($h, $sid) = split(/:/, $op->{'hs'}); |
|
94
|
0
|
|
|
|
|
|
my $tout = $Citrix::touts->{'op'}; # 5; |
|
95
|
0
|
|
|
|
|
|
my $fc = $op->fc(); |
|
96
|
|
|
|
|
|
|
#if (!$fc) {die("No Farm Context for operation");} |
|
97
|
0
|
|
|
|
|
|
my $mh = $fc->masterhost(); # OLD: {'mh'} |
|
98
|
|
|
|
|
|
|
#if (!$mh) {die("No Master host for Farm");} |
|
99
|
0
|
0
|
|
|
|
|
if (!$Citrix::binpath) {die("Citrix binary path is NOT set !!!");} |
|
|
0
|
|
|
|
|
|
|
|
100
|
0
|
|
|
|
|
|
my $clcmd = "$Citrix::binpath/$cmd"; |
|
101
|
|
|
|
|
|
|
# Allow configuring Command to be local |
|
102
|
0
|
|
|
|
|
|
my $wcmd = "rsh $mh $clcmd $hostsess"; |
|
103
|
|
|
|
|
|
|
#OLD:system($wcmd); |
|
104
|
0
|
|
|
|
|
|
eval { |
|
105
|
0
|
|
|
0
|
|
|
local $SIG{'ALRM'} = sub {die("Error Controlling session '$hostsess' within timelimit ($tout s.)\n");}; |
|
|
0
|
|
|
|
|
|
|
|
106
|
0
|
|
|
|
|
|
alarm($tout); |
|
107
|
0
|
|
|
|
|
|
$op->{'msg'} = `$wcmd`; |
|
108
|
|
|
|
|
|
|
}; |
|
109
|
0
|
|
|
|
|
|
alarm(0); |
|
110
|
0
|
0
|
0
|
|
|
|
if ($? || $@) {$op->{'msg'} = "Error $? / $! ($op->{'msg'}) Executing Session command '$wcmd'\n";return(1);} |
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
111
|
|
|
|
|
|
|
#else {$op->{'msg'} = "$op->{'msg'}";} |
|
112
|
|
|
|
|
|
|
# Consider the Error Indicators (Any others ?) |
|
113
|
0
|
0
|
|
|
|
|
if ($op->{'msg'} =~ /^Access/) {return(1);} |
|
|
0
|
|
|
|
|
|
|
|
114
|
|
|
|
|
|
|
# If no message is gotten expect it to be successful (is this correct assumption ?). |
|
115
|
|
|
|
|
|
|
# One of commands does not return any message |
|
116
|
0
|
0
|
|
|
|
|
if (!$op->{'msg'}) {$op->{'msg'} = "Operation Successful";} |
|
|
0
|
|
|
|
|
|
|
|
117
|
0
|
|
|
|
|
|
return(0); |
|
118
|
|
|
|
|
|
|
} |
|
119
|
|
|
|
|
|
|
|
|
120
|
|
|
|
|
|
|
1; |