[Kroupware] /openpkg...

Lutz Badenheuer kroupware@mail.kde.org
Thu, 28 Nov 2002 21:57:41 +0100


Hi, 

Am Mittwoch, 27. November 2002 16:04 schrieb Tassilo Erlewein:
> Am Mittwoch, 27. November 2002 11:49 schrieb Lutz Badenheuer:
> > I've had a short look at kolab.ldif and discovered that there are
> > several "config-dir:"-Attributes which contain /openpkg pathes.
> > Shouldn't we use /kolab?
>
> Yes, you're right. That setting needs to be chosen according to
> your openpkg prefix.
> 
> BTW we have already fixed the installation procedure for the beta,
> now the ldap entries are generated during rpm install.
>
> the beta looks good but we're fighting with some nasty perl habits.
> It seems the openpkg perl behaves differently from "regular"
> packages. 
> 
> Could anybody provide me code snippets which successfully use
> IO::Select to block on a tcp socket ?

Maybe I didn't get you right, but you want to *block*? If my 
understanding of the select(2) system call and its OO-Perl wrapper 
IO::Select is correct, then you would use this to _avoid_ blocking 
I/O. 

If you specify a timeout to the can_read() method, the program will 
stop at this point for the duration of that timeout. If you do not 
specify a timeout to can_read(), then the program will wait forever. 

A simple TCP server listening to two ports could look like this: 

--snip-----
#!/usr/bin/perl -w
use strict;

use IO::Select;
use IO::Socket::INET;

my $IO_Handle_0 =  IO::Socket::INET->new( Listen    => 1,
                                          LocalAddr => '127.0.0.1',
                                          LocalPort => '9090',
                                          Proto     => 'tcp',
                                          Type      => SOCK_STREAM )
    or die 'couldn\'t create socket';

my $IO_Handle_1 =  IO::Socket::INET->new( Listen    => 1,
                                          LocalAddr => 'localhost',
                                          LocalPort => '9091',
                                          Proto     => 'tcp',
                                          Type      => SOCK_STREAM )
    or die 'couldn\'t create socket';

my $Selection = IO::Select->new();
$Selection->add($IO_Handle_0);
$Selection->add($IO_Handle_1);

my $line = '';
while( my @can_read_from = $Selection->can_read(50) ) {
    foreach my $handle (@can_read_from) {
        my $client = $handle->accept;
        $line = <$client>;
        chomp $line;
        print $client "Thanks for \"$line\"\n";
        print "client sent: \"" . $line . "\"\n\n";
        close($client);
    }
}
--snap-----

In this very simple example, the program will terminate after 50 
seconds if no connect takes place during this time, or 50 seconds 
after the last connect has been made (look at the timeout param to 
can_read()). If can_read() would have been called without parameter, 
the program would wait forever for connects. 

> Any of you used Convert::ASN1 ?

I did not understand why you want to use Convert::ASN1. As far as 
I've read and understood your code at this time, you simply use it to 
connect to the LDAP server and access its data. There are Perl 
modules like Net::LDAP, why not use these or own objects inheriting 
from these? 

> another thing is non-blocking IO on a fifo ...

This should be done with IO::Socket::UNIX in a way similar to the one 
described above. 

> (code examples would be nice, the O'Reilly stuff doesn't seem to
> work for me)
>
> I have attached the two supposedly buggy perl programs.
> The beta very much depends on that stuff to get running and I would
> appreciate every help I could get.

Well, I've had a very close look at the code, but at the moment I've 
got no machine I could test this on: my good 18GB 10kRPM U2W-SCSI 
disk produces I/O- and SCSI-errors and, from time to time, makes some 
horrible sounds. Unfortunately, this is exactly the disk with all the 
kolab stuff on it... 

But from my short look, there are some things I'd like to mention: 
first of all, mixing function definitions with the main program flow 
makes it a little.. hard to read the code. I would prefer to put all 
that configuration and initialization stuff into some simple, easy to 
maintain and extensible objects. This would not only make the code 
much cleaner, simpler to read and maintain, but also provide an API 
to our kolab server which can later be easily used to extend the 
functionality of the kolab server. 

Second, I do not understand why you do not fork() when a connet has 
taken place. Thus, every client would be handled by an own proces, so 
you don't have to worry with IO::Select. 

Third, I do not understand who had the idea to write the config files 
line by line with print() statements. We should use Text::Template 
instead of this <censored> idea. The e-Smith guys work with this 
technique, and as for my tests I did some months ago, it all works 
perfectly great. 

This provides us with big advantages: if there is one configuration 
option a user needs, but which is not covered by the web frontend, 
the user can simply add this option to the template without touching 
the code of any of our perl scripts. Additionally, this approach is 
much easier to write, debug and maintain than the current 
implementation. So we could put the configuration of each subsystem 
(apache, Courier, ProFTP, Postfix, OpenLDAP etc.) into an own object 
which is a child of, lets say, KolabConfig. 

I've added an oo-style pseudocode idea how to improve the scripts. 

Kind regards, 
Lutz 

PS: pseudocode
--snip-----
#!/usr/bin/perl -w
use strict;

use Kolab::Config;

my $Config = new Kolab::Config($cfgfile);
exit $Config->writeFiles();
--snap-----

--snip-----
package Kolab::Config;
use strict;

sub new {
    my $proto = shift;
    my $class = ref($proto) || $proto;
    my $self  = {};

    open(CFG, "</kolab/etc/kolab/kolab.conf") 
        or die "Couldn't open /kolab/etc/kolab/kolab.conf: $!";
    my $line = '';
    while( $line = <CFG> ) {
        chomp $line;
        $line =~ s/#.*$//g;
        $line =~ m/^(.*) : (.*)$/;
        $self->{$1} = $2;
    }
    if( ( !defined($self->{base_dn}) ) 
        || ( !defined($self->{bind_dn}) ) 
        || ( !defined($self->{bind_pw}) ) 
        || ( !defined($self->{bind_dn}) ) 
        || ( !defined($self->{ldap_uri}) ) {
        die "syntax error in /kolab/etc/kolab/kolab.conf";
    }

    # here a little inheritance to push PostfixConfig, ApacheConfig
    # into several modules and references to inctances into an array 

    bless ($self, $class);
    return $self;
}

1;
--snap-----

Just some ideas... 
---LB 

-- 
Lutz Badenheuer     | IT--Consulting, Development, Networksolutions
luke@the-web-ac.com | C/C++, OO-Perl, sh | Linux, SCO UNIX, Solaris