ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/syncmail/syncmail
Revision: 1.3
Committed: Sat Oct 27 23:53:49 2001 UTC (22 years, 6 months ago) by root
Branch: MAIN
Changes since 1.2: +78 -396 lines
Log Message:
*** empty log message ***

File Contents

# Content
1 #!/usr/bin/perl
2
3 use Coro;
4 use Coro::Handle;
5 use Coro::Event;
6 use Coro::Semaphore;
7 use Coro::Channel;
8 use Coro::Signal;
9 use Coro::RWLock;
10
11 use Fcntl;
12 use MD5;
13
14 use constant PROTVERSION => 1;
15
16 $VERSION = 0.1;
17
18 require "config.pl";
19
20 use folder;
21 use vc;
22
23 $v = $VERBOSE;
24
25 # WARNING:
26 # Content-Length headers are deliberately being ignored. They
27 # are broken by design and will never be supported
28
29 # TODO: real message-id parsing
30
31 $|=1;
32
33 my $ecnt;
34
35 sub slog {
36 if ($_[0] <= $v) {
37 print STDERR "[$SLAVE] ", $_[1];
38 }
39 }
40
41 $lockdisk = new Coro::Semaphore;
42
43 # give up a/the timeslice
44 sub give {
45 Coro::Event::do_timer(after => 0);
46 }
47
48 my $quit = new Coro::RWLock;
49
50 sub rwlock::DESTROY {
51 $quit->unlock;
52 }
53
54 sub quit_guard {
55 $quit->rdlock;
56 bless [], rwlock;
57 }
58
59 sub find_folders {
60 my @folders;
61
62 opendir my $dh, $PREFIX
63 or die "$PREFIX: $!";
64
65 while (defined (my $folder = readdir $dh)) {
66 next if $folder =~ /^\./;
67 next unless -f "$PREFIX/$folder";
68 push @folders, $folder;
69 }
70
71 @folders;
72 }
73
74 my $sync_folder = new Coro::Semaphore 3; # max 3 folders in parallel
75
76 sub sync_folder {
77 my $name = $_[0];
78
79 my $quit_guard = quit_guard;
80 async {
81 my $guard = $sync_folder->guard;
82 my $vc = new vc;
83
84 my $folder = new folder name => $name;
85 #my ($rfid, $rmtime) = split /\s+/, (request open => $name)->[1];
86 ::give;
87
88 $vc->snd("open", $name);
89 $vc->snd("mtime");
90
91 $folder->check;
92 $folder->read_mdif;
93
94 my $mtime = $folder->{host}{$OTHERNAME};
95 my $rtime = $vc->rcv;
96
97 $vc->snd("diff", $rtime);
98 $folder->{host}{$OTHERNAME} = $folder->{mtime};
99
100 #request "update $rfid $folder->{mtime}";
101 #request "close $rfid";
102 undef $quit_guard;
103 }
104 }
105
106 sub main {
107 my $vc = new vc;
108
109 # time checking done symmetrically
110 {
111 my $time = time;
112 $vc->snd("time");
113 my $othertime = $vc->rcv;
114 abs (($time + time)*0.5 - $othertime) <= $::MAXTIMEDIFF
115 or die "ERROR: time difference between hosts larger than $::MAXTIMEDIFF";
116 }
117 #Coro::Event::do_timer(after => 60);#d#
118
119 $vc->snd("name");
120 $OTHERNAME = $vc->rcv;
121
122 if ($SLAVE) {
123 #
124 } else {
125 $vc->snd("list");
126 for (split /\0/, $vc->rcv) {
127 if (!-e "$PREFIX/$_") {
128 slog 2, "created new empty folder $_\n";
129 sysopen my $fh, "$PREFIX/$_", O_RDWR|O_CREAT, 0666;
130 }
131 }
132
133 for my $folder (find_folders) {
134 sync_folder $folder;
135 }
136
137 $quit->wrlock;
138
139 vc::snd_quit;
140 }
141 }
142
143 sub serve_folder {
144 my $vc = shift;
145 my $name = $vc->rcv;
146 my $folder = new folder name => $name;
147
148 slog 8, "serving folder $name\n";
149
150 $folder->check;
151 $folder->read_mdif;
152
153 while (my $msg = $vc->rcv) {
154 if ($msg eq "mtime") {
155 $vc->snd($folder->{mtime});
156 } elsif ($msg =~ /^update (\d+) (\d+)$/) {
157 #if ($folder[$1]->{host}{$OTHERNAME} != $2) {
158 # $folder[$1]->{host}{$OTHERNAME} = $2;
159 # $folder[$1]->dirty;
160 #}
161 #reply $id, 200, "ok";
162 } else {
163 die "protocol error, unknown folder command ($msg)\n";
164 }
165 }
166 }
167
168 sub serve {
169 my $vc = shift;
170
171 slog 8, "new connection $vc->{port}\n";
172
173 while (my $msg = $vc->rcv) {
174 if ($msg eq "name") {
175 $vc->snd($::MYNAME);
176 } elsif ($msg eq "pri") {
177 $self->{pri} = $vc->rcv;
178 } elsif ($msg eq "time") {
179 $vc->snd(time);
180 } elsif ($msg eq "list") {
181 $vc->snd(join "\0", find_folders);
182 } elsif ($msg eq "open") {
183 serve_folder($vc);
184 } else {
185 die "protocol error, unknown command ($msg)\n";
186 }
187 }
188 }
189
190 if ($SLAVE) {
191 $HOSTID = "slave";
192 async \&main;
193 vc::multiplex unblock \*STDIN, $SLAVE;
194 } else {
195 $HOSTID = "master";
196 {
197 use Socket;
198 socketpair S1, S2, AF_UNIX, SOCK_STREAM, PF_UNSPEC;
199 if (fork == 0) {
200 close S1;
201 open STDIN, "<&S2" or die;
202 open STDOUT, ">&S2" or die;
203 exec $0, "--slave";
204 exit 255;
205 }
206 close S2;
207 async \&main;
208 vc::multiplex unblock \*S1, $SLAVE;
209 }
210 }
211