]> mj.ucw.cz Git - moe.git/blob - submit/MO/Submit.pm
4497eef41ea391637633141bc167cfcc2c473f07
[moe.git] / submit / MO / Submit.pm
1 # A Perl module for communicating with the MO Submit Server
2 # (c) 2007 Martin Mares <mj@ucw.cz>
3
4 package MO::Submit;
5
6 use strict;
7 use warnings;
8
9 use IO::Socket::INET;
10 use IO::Socket::SSL; # qw(debug3);
11 use Sherlock::Object;
12 use POSIX;
13
14 sub new($) {
15         my $user = $ENV{"USER"} or die "Environment variable USER not set\n";
16         my $home = $ENV{"HOME"} or die "Environment variable HOME not set\n";
17         my $mo = "$home/.mo";
18         my $root = $ENV{"MO_ROOT"} or die "Environment variable MO_ROOT not set\n";
19         my $self = {
20                 "Contest" => "CPSPC 2007",
21                 "Server" => "kamzice.ms.mff.cuni.cz:8888",
22                 "Key" => "$mo/key.pem",         # Keys and certificates
23                 "Cert" => "$mo/cert.pem",
24                 "CACert" => "$mo/ca-cert.pem",
25                 "Trace" => defined $ENV{"MO_SUBMIT_TRACE"},
26                 "Checks" => 1,
27 #               "History" => "$home/.history",  # Keep submission history in this directory
28                 "RefreshTimer" => 60000,        # How often GUI sends STATUS commands [ms]
29                 "root" => $root,
30                 "user" => $user,
31                 "sk" => undef,
32                 "error" => undef,
33         };
34         return bless $self;
35 }
36
37 sub DESTROY($) {
38         my $self = shift @_;
39         $self->disconnect;
40 }
41
42 sub log($$) {
43         my ($self, $msg) = @_;
44         print STDERR "SUBMIT: $msg\n" if $self->{"Trace"};
45 }
46
47 sub err($$) {
48         my ($self, $msg) = @_;
49         print STDERR "ERROR: $msg\n" if $self->{"Trace"};
50         $self->{"error"} = $msg;
51         $self->disconnect;
52 }
53
54 sub is_connected($) {
55         my $self = shift @_;
56         return defined $self->{"sk"};
57 }
58
59 sub disconnect($) {
60         my $self = shift @_;
61         if ($self->is_connected) {
62                 close $self->{"sk"};
63                 $self->{"sk"} = undef;
64                 $self->log("Disconnected");
65         }
66 }
67
68 sub connect($) {
69         my $self = shift @_;
70         $self->disconnect;
71         $self->log("Connecting to submit server");
72         my $sk = new IO::Socket::INET(
73                 PeerAddr => $self->{"Server"},
74                 Proto => "tcp",
75         );
76         if (!defined $sk) {
77                 $self->err("Cannot connect to server: $!");
78                 return undef;
79         }
80         my $z = <$sk>;
81         if (!defined $z) {
82                 $self->err("Server failed to send a welcome message");
83                 close $sk;
84                 return undef;
85         }
86         chomp $z;
87         if ($z !~ /^\+/) {
88                 $self->err("Server rejected the connection: $z");
89                 close $sk;
90                 return undef;
91         }
92         if ($z =~ /TLS/) {
93                 $self->log("Starting TLS");
94                 $sk = IO::Socket::SSL->start_SSL(
95                         $sk,
96                         SSL_version => 'TLSv1',
97                         SSL_use_cert => 1,
98                         SSL_key_file => $self->{"Key"},
99                         SSL_cert_file => $self->{"Cert"},
100                         SSL_ca_file => $self->{"CACert"},
101                         SSL_verify_mode => 3,
102                 );
103                 if (!defined $sk) {
104                         $self->err("Cannot establish TLS connection: " . IO::Socket::SSL::errstr());
105                         return undef;
106                 }
107         }
108         $self->{"sk"} = $sk;
109
110         $self->log("Logging in");
111         my $req = new Sherlock::Object("U" => $self->{"user"});
112         my $reply = $self->request($req);
113         my $err = $reply->get("-");
114         if (defined $err) {
115                 $self->err("Cannot log in: $err");
116                 return undef;
117         }
118
119         $self->log("Connected");
120         return 1;
121 }
122
123 sub request($$) {
124         my ($self, $obj) = @_;
125         my $sk = $self->{"sk"};
126         $obj->write($sk);       ### FIXME: Flushing
127         if ($sk->error) {
128                 $self->err("Connection broken");
129                 return undef;
130         }
131         print $sk "\n";
132         return $self->reply;
133 }
134
135 sub reply($) {
136         my ($self, $obj) = @_;
137         my $sk = $self->{"sk"};
138         my $reply = new Sherlock::Object;
139         if ($reply->read($sk)) {
140                 return $reply;
141         } else {
142                 $self->err("Connection broken");
143                 return undef;
144         }
145 }
146
147 sub send_file($$$) {
148         my ($self, $fh, $size) = @_;
149         my $sk = $self->{"sk"};
150         while ($size) {
151                 my $l = ($size < 4096 ? $size : 4096);
152                 my $buf = "";
153                 if ($fh->read($buf, $l) != $l) {
154                         $self->err("File shrunk during upload");
155                         return undef;
156                 }
157                 $sk->write($buf, $l);
158                 if ($sk->error) {
159                         $self->err("Connection broken");
160                         return undef;
161                 }
162                 $size -= $l;
163         }
164         return $self->reply;
165 }
166
167 sub local_submit($$$$$) {
168         my ($self, $task, $part, $ext, $filename) = @_;
169         my $hist = $self->{"History"};
170         -d $hist or mkdir $hist or return "Unable to create $hist: $!";
171         ### FIXME: Unfinished
172 }
173
174 1;