[Asterisk-Users] asterisk.ctl limitations

Tzafrir Cohen tzafrir at cohens.org.il
Tue Jan 17 11:08:42 MST 2006


Hi

I wrote a small patch to netcat to work with unix domain sockets to
enable me to communicate with an asterisk daemon through the 
unix-domain socket /var/run/asterisk/asterisk.ctl .

Only then I noticed that reading the code is done very differently than
a typical network protocol: it expects every command in a separate read.

Basically I used the following filter to pipe commands from the standard
input to netcat:

 while read line
 do 
   echo -n "$line"
   sleep 0.001
 done

This reads one text line and prints it to the output after stripping the 
linefeed in the end. Then it waits a bit (IIRC sleep is not an internal
bash command, and thus it actually takes some time to exec the process,
so the sleep is closer to 0.007 sec. on my system). This hints netcat to
send two lines in two seperate writes.


I am still left with one problem: there is no way for me to order the
termination of a connection. 'exit/quit' are implemented locally. 

So basically I have to change the filter there to detect an exit:

 while read line 
 do
   case "$line" in exit*)break;; esac
   echo -n "$line"
   sleep 0.001
 done

I wonder, though haven't really checked, what happens if I send some
randome data into this socket (specifically: some data that may have
some '\0' inside it).

I attach my patch to netcat, if anybody is interested. It applies to an 
already patched Debian source. Alternatively, you can try the small
programs I posted here a while ago that just write to the socket.

-- 
Tzafrir Cohen         | tzafrir at jbr.cohens.org.il | VIM is
http://tzafrir.org.il |                           | a Mutt's  
tzafrir at cohens.org.il |                           |  best
ICQ# 16849755         |                           | friend
-------------- next part --------------
#! /bin/sh /usr/share/dpatch/dpatch-run
## unix.dpatch by  <tzafrir@>
##
## All lines beginning with `## DP:' are a description of the patch.
## DP: unix-domain sockets support for netcat. Try:
## DP:
## DP:   nc -U /path/to/socket localhost 0
## DP:
## DP: listen mode (-l) should theoretically work, but is untested.

@DPATCH@
diff -urNad netcat-1.10/netcat.c /tmp/dpep.QmuQvQ/netcat-1.10/netcat.c
--- netcat-1.10/netcat.c	2006-01-04 22:11:40.000000000 +0200
+++ /tmp/dpep.QmuQvQ/netcat-1.10/netcat.c	2006-01-04 22:17:16.000000000 +0200
@@ -71,6 +71,7 @@
 #include <sys/time.h>		/* timeval, time_t */
 #include <setjmp.h>		/* jmp_buf et al */
 #include <sys/socket.h>		/* basics, SO_ and AF_ defs, sockaddr, ... */
+#include <sys/un.h>		/* UNIX-domain sockets */
 #include <netinet/in.h>		/* sockaddr_in, htons, in_addr */
 #include <netinet/in_systm.h>	/* misc crud that netinet/ip.h references */
 #include <netinet/ip.h>		/* IPOPT_LSRR, header stuff */
@@ -87,6 +88,7 @@
 
 /* handy stuff: */
 #define SA struct sockaddr	/* socket overgeneralization braindeath */
+#define SAU struct sockaddr_un  /*                                      */
 #define SAI struct sockaddr_in	/* ... whoever came up with this model */
 #define IA struct in_addr	/* ... should be taken out and shot, */
 				/* ... not that TLI is any better.  sigh.. */
@@ -149,12 +151,16 @@
 unsigned int wrote_net = 0;	/* total net bytes */
 static char wrote_txt[] = " sent %d, rcvd %d";
 static char hexnibs[20] = "0123456789abcdef  ";
+char * unixsock_name = NULL;	/* the filename for the unix domain socket to
+				   connect to or listen on, and also a flag
+				   to tell when in unixsock mode */
 
 /* will malloc up the following globals: */
 struct timeval * timer1 = NULL;
 struct timeval * timer2 = NULL;
 SAI * lclend = NULL;		/* sockaddr_in structs */
 SAI * remend = NULL;
+SAU * unixsock = NULL;
 HINF ** gates = NULL;		/* LSRR hop hostpoop */
 char * optbuf = NULL;		/* LSRR or sockopts */
 char * bigbuf_in;		/* data buffers */
@@ -660,10 +666,17 @@
 
 /* grab a socket; set opts */
 newskt:
-  if (o_udpmode)
-    nnetfd = socket (AF_INET, SOCK_DGRAM, IPPROTO_UDP);
-  else
-    nnetfd = socket (AF_INET, SOCK_STREAM, IPPROTO_TCP);
+  if (unixsock_name) {
+    if (o_udpmode)
+      nnetfd = socket (AF_LOCAL, SOCK_DGRAM, 0);
+    else
+      nnetfd = socket (AF_LOCAL, SOCK_STREAM, 0);
+  } else {
+    if (o_udpmode)
+      nnetfd = socket (AF_INET, SOCK_DGRAM, IPPROTO_UDP);
+    else
+      nnetfd = socket (AF_INET, SOCK_STREAM, IPPROTO_TCP);
+  }
   if (nnetfd < 0)
     bail ("Can't get socket");
   if (nnetfd == 0)		/* if stdin was closed this might *be* 0, */
@@ -692,14 +705,20 @@
   rr = setsockopt(nnetfd, SOL_SOCKET, SO_RCVBUF, &o_rcvbuf, sizeof o_rcvbuf);
   rr = setsockopt(nnetfd, SOL_SOCKET, SO_SNDBUF, &o_sndbuf, sizeof o_sndbuf);
 #endif
-  
-  /* fill in all the right sockaddr crud */
+ 
+  if (unixsock_name) {
+    unixsock->sun_family = AF_LOCAL;
+    strncpy(unixsock->sun_path, unixsock_name, sizeof(unixsock->sun_path)-1);
+    //strncpy(unixsock->sun_path, unixsock_name, 108-1);
+    //unixsock->sun_path[sizeof(unixsock->sun_path)-1] = '\0';
+  } else {
+    /* fill in all the right sockaddr crud */
     lclend->sin_family = AF_INET;
 
-/* fill in all the right sockaddr crud */
-  lclend->sin_family = AF_INET;
-  remend->sin_family = AF_INET;
-
+    /* fill in all the right sockaddr crud */
+    lclend->sin_family = AF_INET;
+    remend->sin_family = AF_INET;
+  }
 /* if lad/lp, do appropriate binding */
   if (lad)
     memcpy (&lclend->sin_addr.s_addr, lad, sizeof (IA));
@@ -710,13 +729,21 @@
     x = (int) lp;
 /* try a few times for the local bind, a la ftp-data-port... */
     for (y = 4; y > 0; y--) {
-      rr = bind (nnetfd, (SA *)lclend, sizeof (SA));
+      if (unixsock_name) {
+	rr = bind (nnetfd, (SA *)unixsock, sizeof (SA));
+      } else {
+	rr = bind (nnetfd, (SA *)lclend, sizeof (SA));
+      }
       if (rr == 0)
 	break;
       if (errno != EADDRINUSE)
 	break;
       else {
-	holler ("retrying local %s:%d", inet_ntoa (lclend->sin_addr), lp);
+	if (unixsock_name) {
+	  holler ("retrying local socket %s", unixsock_name);
+	} else {
+	  holler ("retrying local %s:%d", inet_ntoa (lclend->sin_addr), lp);
+	}
 	sleep (2);
 	errno = 0;			/* clear from sleep */
       } /* if EADDRINUSE */
@@ -729,9 +756,10 @@
   if (o_listen)
     return (nnetfd);			/* thanks, that's all for today */
 
-  memcpy (&remend->sin_addr.s_addr, rad, sizeof (IA));
-  remend->sin_port = htons (rp);
-
+  if (! unixsock_name) {
+    memcpy (&remend->sin_addr.s_addr, rad, sizeof (IA));
+    remend->sin_port = htons (rp);
+  }
 /* rough format of LSRR option and explanation of weirdness.
 Option comes after IP-hdr dest addr in packet, padded to *4, and ihl > 5.
 IHL is multiples of 4, i.e. real len = ip_hl << 2.
@@ -805,14 +833,22 @@
   arm_timer (1, o_wait);
 #ifdef POSIX_SETJMP
   if (sigsetjmp (jbuf,1) == 0) {
-    rr = connect (nnetfd, (SA *)remend, sizeof (SA));
+    if (unixsock_name) {
+      rr = connect (nnetfd, (SA *)unixsock, sizeof (SAU));
+    } else {
+      rr = connect (nnetfd, (SA *)remend, sizeof (SA));
+    }
   } else {				/* setjmp: connect failed... */
     rr = -1;
     errno = ETIMEDOUT;			/* fake it */
   }
 #else
   if (setjmp (jbuf) == 0) {
-    rr = connect (nnetfd, (SA *)remend, sizeof (SA));
+    if (unixsock_name) {
+      rr = connect (nnetfd, (SA *)unixsock, sizeof (SAU));
+    } else {
+      rr = connect (nnetfd, (SA *)remend, sizeof (SA));
+    }
   } else {				/* setjmp: connect failed... */
     rr = -1;
     errno = ETIMEDOUT;			/* fake it */
@@ -1435,6 +1471,7 @@
 /* round up the usual suspects, i.e. malloc up all the stuff we need */
   lclend = (SAI *) Hmalloc (sizeof (SA));
   remend = (SAI *) Hmalloc (sizeof (SA));
+  unixsock=(SAU *) Hmalloc (sizeof (SA));
   bigbuf_in = Hmalloc (BIGSIZ);
   bigbuf_net = Hmalloc (BIGSIZ);
   ding1 = (fd_set *) Hmalloc (sizeof (fd_set));
@@ -1503,7 +1540,7 @@
 
 /* If your shitbox doesn't have getopt, step into the nineties already. */
 /* optarg, optind = next-argv-component [i.e. flag arg]; optopt = last-char */
-  while ((x = getopt (argc, argv, "abc:e:g:G:hi:lno:p:q:rs:tuvw:z")) != EOF) {
+  while ((x = getopt (argc, argv, "abc:e:g:G:hi:lno:p:q:rs:tuU:vw:z")) != EOF) {
 /* Debug (("in go: x now %c, optarg %x optind %d", x, optarg, optind)) */
     switch (x) {
       case 'a':
@@ -1579,6 +1616,8 @@
 #endif /* TELNET */
       case 'u':				/* use UDP */
 	o_udpmode++; break;
+      case 'U':				/* UNIX-domain socket */
+        unixsock_name = optarg;
       case 'v':				/* verbose */
 	o_verbose++; break;
       case 'w':				/* wait time */
@@ -1642,7 +1681,7 @@
     curport = 0;			/* rem port *can* be zero here... */
     if (argv[optind]) {			/* any rem-port-arg? */
       curport = getportpoop (argv[optind], 0);
-      if (curport == 0)			/* if given, demand correctness */
+      if ((curport == 0) && (unixsock_name==NULL) )/* if given, demand correctness */
 	bail ("invalid port %s", argv[optind]);
     } /* if port-arg */
     netfd = dolisten (themaddr, curport, ouraddr, o_lport);
@@ -1689,13 +1728,13 @@
         *cp = '\0';
         unescape(++cp); /* turn \-'s into -'s */
         hiport = getportpoop (cp, 0);
-        if (hiport == 0)
+        if ((hiport == 0) && (unixsock_name==NULL) )
           bail ("invalid port %s", cp);
       }
       unescape(argv[optind]); /* turn \-'s into -'s */
     } /* if found a dash */
     loport = getportpoop (argv[optind], 0);
-    if (loport == 0)
+    if ((loport == 0) && (unixsock_name==NULL) )
       bail ("invalid port %s", argv[optind]);
     if (hiport > loport) {		/* was it genuinely a range? */
       Single = 0;			/* multi-mode, case B */


More information about the asterisk-users mailing list