Article 9541 of comp.lang.perl:
Xref: feenix.metronet.com comp.lang.perl:9541
Path: feenix.metronet.com!news.ecn.bgu.edu!usenet.ins.cwru.edu!howland.reston.ans.net!math.ohio-state.edu!sdd.hp.com!sgiblab!idiom.berkeley.ca.us!idiom.berkeley.ca.us!not-for-mail
From: [email protected] (David Muir Sharnoff)
Newsgroups: comp.lang.perl
Subject: Re: perl code to listen/connect/etc to unix domain sockets ..
Date: 7 Jan 1994 12:20:29 -0800
Organization: Idiom Consulting / Berkeley, CA  USA
Lines: 284
Message-ID: <[email protected]>
References: <phone.757844874@cairo>
NNTP-Posting-Host: idiom.berkeley.ca.us
Keywords: perl, sockets, unix

In article <phone.757844874@cairo> [email protected] (matthew green) writes:
>i'm after some perl code to work with unix domain sockets.

I played with this a couple of months ago:

-------------------------------------------------

#  Copyright (c) 1993 David Muir Sharnoff
#  License at bottom of file

package sockets;

# hardcoded constants, should work fine for BSD-based systems
$AF_UNIX = 1;
$AF_INET = 2;
$SOCK_STREAM = 1;
$SOCK_DGRAM  = 2;
$SOCKADDR_IP = 'S n a4 x8';
$SOCKADDR_UN = 'S a108';

#
# &socket is a function that creates, binds, and connects
# sockets.
#
# Arguments:
# $S    - the name of the socket, eg 'SOC'.  Use <SOC> elsewhere.
# $type - datagram (dgram) or stream.
# $them - the remote address (optional)
# $us   - the local address (optional)
#
# Both $us and $them are in a flexible format.  If they look like a
# unix path (begins with /) then it is assumed you want a unix-domain
# socket.  Otherwise an IP socket is assumed.
#
# There is no default port number.   If you specify a $them IP address,
# be sure to specify a port number.
#
# IP $us and $them are in the format "$hostname/$port".  A symbolic
# port name will be looked up.
#

sub main'socket
{
       local($S,$type,$them,$us) = @_;
       local($t,$ip);

       if ("\L$type" eq 'stream' || "\L$type" eq 'tcp' || $type == $SOCK_STREAM) {
               $t = $SOCK_STREAM;
               $ip = 'tcp';
       } elsif ("\L$type" eq 'dgram' || "\L$type" eq 'udp' || $type == $SOCK_DGRAM) {
               $t = $SOCK_DGRAM;
               $ip = 'udp'
       } else {
               die "could not figure out socket type: $type";
       }

       if (($them =~ m,^/,) || ($us =~ m,^/,)) {
               &unix_socket($S,$t,$them,$us);
       } else {
               &ip_socket($S,$t,$ip,$them,$us);
       }
}

sub unix_socket
{
       local($S,$type,$them,$us) = @_;
       local($us_struct,$them_struct);

       print "unix socket $type, $them, $us\n" if $debug;
       socket($S, $AF_UNIX, $t, 0)
           || die "socket: $!";

       if ($us) {
               $us_struct = pack($SOCKADDR_UN, $AF_UNIX, $us);
               bind($S, $us_struct) || die "bind unix socket $us: $!";
       }
       if ($them) {
               $them_struct = pack($SOCKADDR_UN, $AF_UNIX, $them);
               connect($S, $them_struct) || die "connect unix socket $them: $!";
       }
       select((select($S),$| = 1)[0]); # don't buffer output
}

sub ip_socket
{
       local($S,$type,$protocol,$them,$us) = @_;

       local($their_port,$their_host);

       local($our_addr_struct) = &get_IP_addr_struct($protocol,$us);

       socket($S, $AF_INET, $t, &get_proto_number($protocol))
               || die "socket: $!";

       print "us $protocol,$us,$them: ",&unpack_IP_addr_struct($our_addr_struct),"\n" if $debug;
       bind($S, $our_addr_struct)
               || die "bind $hostname,0: $!";

       if ($them) {
               local($their_addr_struct) = &get_IP_addr_struct($protocol,$them);
               print "them $protocol,$us,$them: ",&unpack_IP_addr_struct($their_addr_struct),"\n" if $debug;
               connect($S, $their_addr_struct)
                       || die "connect $host: $!";
       }
       select((select($S),$| = 1)[0]); # don't buffer output
}

#
# Create IP address structures.
#
# The first argument must be 'tcp', or 'udp'.
# The second argument is the host (`hostname` if null) to connect to.
# The third argument is the port to bind to.   Pass 0 if any will do.
#
# The return arguments are a protocol value that can use by socket()
# and a port address that can be used by bind().
#
sub get_IP_addr_struct
{
       local($protocol,$host,$port) = @_;
       local($junk,$host_addr);

       if (! $port && ($host =~ s,([^/]+)/(.+),$1,)) {
               $port = $2;
       }
       $host = &hostname()
               if ! $host;
       ($junk,$junk,$junk,$junk,$host_addr) = gethostbyname($host);

       die "gethostbyname($host): $!"
               unless $host_addr;

       if ($port =~ /[^\d]/) {
               ($junk,$junk,$port) = getservbyname($port,$protocol);
               die "getservbyname($port,$protocol): $!"
                       unless $port;
       }

       return pack($SOCKADDR_IP, $AF_INET, $port, $host_addr);
}

sub get_proto_number
{
       local($protocol) = @_;
       local($junk,$proto);

       ($junk,$junk,$proto) = getprotobyname($protocol);

       die "getprotobyname($protocol): $!"
               unless $proto;

       return $proto;
}

sub hostname
{
       if (! $hostname) {
               chop($hostname = `hostname`);
               if (! $hostname) {
                       chop($hostname = `uname -n`);
                       if (! $hostname) {
                               die "cannot determine hostname";
                       }
               }
       }
       return $hostname;
}

#
# An extra...
#

sub unpack_IP_addr_struct
{
       local($addr) = @_;
       local($name,@junk);
       local($af,$port,$host) = unpack($SOCKADDR_IP,$addr);
       ($name,@junk) = gethostbyaddr($host,$AF_INET);
       if ($name) {
               return $name;
       } else {
               local(@IP) = unpack('C4',$host);
               return join('.',@IP)."/$port";
       }
}

#############################################################################
#
#  Copyright (c) 1993 David Muir Sharnoff
#  All rights reserved.
#
#  Redistribution and use in source and binary forms, with or without
#  modification, are permitted provided that the following conditions
#  are met:
#  1. Redistributions of source code must retain the above copyright
#     notice, this list of conditions and the following disclaimer.
#  2. Redistributions in binary form must reproduce the above copyright
#     notice, this list of conditions and the following disclaimer in the
#     documentation and/or other materials provided with the distribution.
#  3. All advertising materials mentioning features or use of this software
#     must display the following acknowledgement:
#       This product includes software developed by the David Muir Sharnoff.
#  4. The name of David Sharnoff may not be used to endorse or promote products
#     derived from this software without specific prior written permission.
#
#  THIS SOFTWARE IS PROVIDED BY THE DAVID MUIR SHARNOFF ``AS IS'' AND
#  ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
#  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
#  ARE DISCLAIMED.  IN NO EVENT SHALL DAVID MUIR SHARNOFF BE LIABLE
#  FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
#  DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
#  OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
#  HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
#  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
#  OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
#  SUCH DAMAGE.
#
# This copyright notice derrived from material copyrighted by the Regents
# of the University of California.
#
# Contributions accepted.
#
#############################################################################

1;

-------------------------------------------------

Here are some test routines that should show you how to use &socket().

$uport = ....

sub unix_stream_server
{
       &main'socket(ST,STREAM,"",$uport);
       listen(ST,5) || die "listen: $!";
       ($their_addr = accept(NST,ST)) || die "accept: $!";
       if ($debug) {
               ($junk,$their_path) = unpack($SOCKADDR_UN,$their_addr);
               print "Their address: $their_path\n";
       }
       select((select(NST),$| = 1)[0]); # don't buffer output
       print NST "Server here\n";
       $x = <NST>;
       print ($x eq "Client here\n" ? "ok 6\n" : "not ok 6\n");
       close(NST);
       close(ST);
       unlink($uport);
}

sub unix_stream_client
{
       &main'socket(CT,STREAM,$uport,"");
       $x = <CT>;
       print ($x eq "Server here\n" ? "ok 5\n" : "not ok 5\n");
       print CT "Client here\n";
       close(CT);
}

sub unix_dgram_server
{
       &main'socket(ST,DGRAM,"",$uport);
       $their_addr = recv(ST,$x,1024,0);
       if ($debug) {
               ($junk,$their_path) = unpack($SOCKADDR_UN,$their_addr);
               print "Their address: $their_path\n";
       }
       print "their-addr: $their_addr\n" if $debug;
       print ($x eq "Client here\n" ? "ok 7\n" : "not ok 7\n");
       send(ST,"Server here\n",0,$their_addr);
       close(ST);
       unlink($uport);
}

sub unix_dgram_client
{
       &main'socket(CT,DGRAM,$uport,"/tmp/us2.$$");
       print CT "Client here\n";
       $x = <CT>;
       print ($x eq "Server here\n" ? "ok 8\n" : "not ok 8\n");
       close(CT);
       unlink("/tmp/us2.$$");
}