#!/usr/bin/perl -w use strict; use IO::File; use IO::Socket; use IO::Select; use Queue; my ($svr_shutdown, $verbose, $debug); my ($select, $log); my %conn_info; my $msg_id; my ($msg, @addr_list, $list_pos); my $qdir = "queue"; my $q = Queue->new($qdir); sub printlog; sub close_client; ######################################################### # # The %cmds hash keeps the protocol commands and their # associated subrefs. To add functionality, just # declare the sub and add a key to the hash. # ######################################################### my %cmds; sub next_addr(); sub succ_addr(); sub fail_addr(); sub get_msg(); sub svr_stat(); sub svr_down(); %cmds = ( 'next_addr' => \&next_addr, 'succ_addr' => \&succ_addr, 'fail_addr' => \&fail_addr, 'get_msg' => \&get_msg, 'quit' => \&close_client, 'stat' => \&svr_stat, 'svr_down' => \&svr_down, 'hup_log' => \&hup_log, ); ######################################################### # # The protocol handlers actually live here - don't forget # to map the sub to a command in the %cmds hash. # ######################################################### sub next_addr() { my ($clt) = @_; if (defined $msg && defined($conn_info{$clt->fileno}{"msg_id"}) && + $msg_id eq $conn_info{$clt->fileno}{"msg_id"}) { if ($list_pos < @addr_list) { chomp $addr_list[$list_pos]; if ($debug) {print("0: send_addr: $addr_list[$list_pos] " + . $clt->fileno . ": listpos: $list_pos : addrlist: " . scalar(@addr_ +list) . "\n")} snd($clt,$addr_list[$list_pos]); $list_pos++; } if ($list_pos >= @addr_list) { if ($debug) {print("0: flush:" . $clt->fileno . ": listpos +: $list_pos : addrlist: " . scalar(@addr_list) . "\n")} printlog("$msg_id.msg finished. flushing."); $msg = undef; $msg_id = undef; @addr_list = undef; $list_pos = -1; } } else { if ($debug) {print("0: FIN:" . $clt->fileno . "\n")} delete $conn_info{$clt->fileno}{"msg_id"}; snd($clt,"FIN"); } } sub succ_addr() { my ($clt,$addr) = @_; if (defined($addr)) { printlog("succ: $addr"); snd($clt,"OK"); } else { snd($clt,"ERR:no addr!"); } } sub fail_addr() { my ($clt,$addr) = @_; if (defined($addr)) { printlog("fail: $addr"); snd($clt,"OK"); } else { snd($clt,"ERR:no addr!"); } } sub get_msg() { my ($clt) = @_; if (!defined $msg) { my $msg_file = $q->next_by_ext(".msg"); if ($msg_file) { my $list_file = $msg_file; $list_file =~ s/\.msg$/\.list/g; $_ = $msg_file; ($msg_id) = /$qdir\/(.*)?\.msg/; if ($debug) { print "Setting msg_id: $msg_id\n" } open(MSG, "<$msg_file"); { local $/ = undef; $msg = <MSG>; } close(MSG); open(LIST, "<$list_file"); @addr_list = <LIST>; close(LIST); $list_pos = 0; $q->dequeue($msg_file); $q->dequeue($list_file); printlog("$msg_id.msg loaded; " . scalar @addr_list . " ad +dresses"); } else { $msg = undef; $msg_id = undef; } } if (defined $msg) { snd($clt,$msg); if ($debug) { print "conn:" . $clt->fileno . ": msg_id=$msg_id +\n" } $conn_info{$clt->fileno}{"msg_id"} = $msg_id; } else { snd($clt,"FIN"); if (exists $conn_info{$clt->fileno}{"msg_id"}) { delete $conn_ +info{$clt->fileno}{"msg_id"} } } } sub svr_stat() { my ($clt) = @_; if ($list_pos >= @addr_list) { snd($clt,"List finished - $list_pos addresses processed"); } elsif ($list_pos == 0) { snd($clt,"List ready. Waiting for client."); } else { snd($clt,$list_pos . " of " . (@addr_list)); } } sub svr_down() { my ($clt) = @_; $svr_shutdown = 1; snd($clt,"Bye!"); } sub hup_log() { my ($clt) = @_; $log->close(); $log = IO::File->new(">>log/ds2.log"); snd($clt,"log released"); } ################################ # # ################################ sub snd { my $sock = shift; my $msg = shift; my $len = length($msg); if ($debug) {print $sock->fileno . ": > $len : $msg\n"} $msg = pack('N', $len) . $msg; syswrite($sock, $msg, length($msg)); } sub rcv { my $sock = shift; my $buf; my ($bytes_read, $total_read, $bytes_to_read); $bytes_read = sysread($sock, $buf, 4); if ($! || ($bytes_read != 4)) { return undef; } else { $bytes_to_read = unpack('N',$buf); #if ($debug) { print "Read count: $bytes_to_read\n" } # Quick sanity check on our packet length # Bob help you if you're trying to read over 1MB packets :-) return undef if ($bytes_to_read <= 0 || $bytes_to_read > 10000 +00); $total_read = 0; my $buf2 = $buf = undef; while ($total_read < $bytes_to_read) { $bytes_read = sysread($sock, $buf, $bytes_to_read - $total +_read); $buf2 .= $buf; $total_read += $bytes_read; } $buf = $buf2; } return $buf; } sub printlog { my @date = localtime(time); my $timestamp = sprintf("%02d/%02d/%04d %02d:%02d:%02d", $date[4] ++ 1, $date[3], $date[5] + 1900, $date[2],$date[1], $date[0]); print $log "$timestamp: @_\n"; $log->flush(); } sub close_client { my $socket = shift; if ($debug) {print($socket->fileno . ": disconnected\n")} if (defined $conn_info{$socket->fileno}) { delete($conn_info{$sock +et->fileno}) } $select->remove($socket); $socket->close; } ######################################################### # # start_server - Sets up the server socket and handles # all I/O and command dispatching. # ######################################################### ######################################################### # # Start things running... # ######################################################### $| = 1; $list_pos = 0; $verbose = 0; $debug = 0; while (defined($_ = shift)) { if ($_ eq '-v' || $_ eq '--verbose') {$verbose = 1} elsif ($_ eq '-d' || $_ eq '--debug') {$debug = 1} } $svr_shutdown = 0; my $server = IO::Socket::INET->new( Proto => 'tcp', LocalPort => 6900, Listen => SOMAXCONN, Reuse => 1); $select = IO::Select->new($server); $log = IO::File->new(">>log/ds2.log"); my @ready; while (!$svr_shutdown && (@ready = $select->can_read)) { my $socket; for $socket (@ready) { if ($socket == $server) { my $new_clt = $server->accept(); $new_clt->autoflush(1); $select->add($new_clt); if ($debug) {print($new_clt->fileno . ": connected\n")} snd($new_clt,"HELO " . $new_clt->fileno); } else { my $msg; if (defined($msg = rcv($socket))) { chomp $msg; if ($debug) {print($socket->fileno . ": $msg\n")} $_ = $msg; my ($clt_cmd, $clt_args) = /^\s*(\w*)\s*(.*)/; if (exists($cmds{"$clt_cmd"})) { my $subref = $cmds{"$clt_cmd"}; &$subref($socket, $clt_args); } else { snd($socket,"Invalid command: $clt_cmd"); } } else { close_client($socket); } } } } $log->close();

In reply to Tool for sending out newsletters by vxp

Title:
Use:  <p> text here (a paragraph) </p>
and:  <code> code here </code>
to format your post, it's "PerlMonks-approved HTML":



  • Posts are HTML formatted. Put <p> </p> tags around your paragraphs. Put <code> </code> tags around your code and data!
  • Titles consisting of a single word are discouraged, and in most cases are disallowed outright.
  • Read Where should I post X? if you're not absolutely sure you're posting in the right place.
  • Please read these before you post! —
  • Posts may use any of the Perl Monks Approved HTML tags:
    a, abbr, b, big, blockquote, br, caption, center, col, colgroup, dd, del, details, div, dl, dt, em, font, h1, h2, h3, h4, h5, h6, hr, i, ins, li, ol, p, pre, readmore, small, span, spoiler, strike, strong, sub, summary, sup, table, tbody, td, tfoot, th, thead, tr, tt, u, ul, wbr
  • You may need to use entities for some characters, as follows. (Exception: Within code tags, you can put the characters literally.)
            For:     Use:
    & &amp;
    < &lt;
    > &gt;
    [ &#91;
    ] &#93;
  • Link using PerlMonks shortcuts! What shortcuts can I use for linking?
  • See Writeup Formatting Tips and other pages linked from there for more info.