--- a/src/netcon.cpp
+++ b/src/netcon.cpp
@@ -31,8 +31,8 @@
#include <unistd.h>
#include <fcntl.h>
#include <sys/time.h>
-
#include <sys/socket.h>
+#include <sys/un.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <arpa/inet.h>
@@ -61,6 +61,15 @@
#ifndef SOCKLEN_T
#define SOCKLEN_T socklen_t
+#endif
+
+// Size of path buffer in sockaddr_un (AF_UNIX socket
+// addr). Mysteriously it's 108 (explicit value) under linux, no
+// define accessible. Let's take a little margin as it appears that
+// some systems use 92. I believe we could also malloc a variable size
+// struct but why bother.
+#ifndef UNIX_PATH_MAX
+#define UNIX_PATH_MAX 90
#endif
// Need &one, &zero for setsockopt...
@@ -615,33 +624,57 @@
closeconn();
- struct sockaddr_in saddr;
- memset(&saddr, 0, sizeof(saddr));
- saddr.sin_family = AF_INET;
- saddr.sin_port = htons(port);
-
- // Server name may be host name or IP address
- int addr;
- if ((addr = inet_addr(host)) != -1) {
- memcpy(&saddr.sin_addr, &addr, sizeof(addr));
+ struct sockaddr *saddr;
+ socklen_t addrsize;
+
+ struct sockaddr_in ip_addr;
+ struct sockaddr_un unix_addr;
+ if (host[0] != '/') {
+ memset(&ip_addr, 0, sizeof(ip_addr));
+ ip_addr.sin_family = AF_INET;
+ ip_addr.sin_port = htons(port);
+
+ // Server name may be host name or IP address
+ int addr;
+ if ((addr = inet_addr(host)) != -1) {
+ memcpy(&ip_addr.sin_addr, &addr, sizeof(addr));
+ } else {
+ struct hostent *hp;
+ if ((hp = gethostbyname(host)) == 0) {
+ LOGERR(("NetconCli::openconn: gethostbyname(%s) failed\n",
+ host));
+ return -1;
+ }
+ memcpy(&ip_addr.sin_addr, hp->h_addr, hp->h_length);
+ }
+
+ if ((m_fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
+ LOGSYSERR("NetconCli::openconn", "socket", "");
+ return -1;
+ }
+ addrsize = sizeof(ip_addr);
+ saddr = (sockaddr*)&ip_addr;
} else {
- struct hostent *hp;
- if ((hp = gethostbyname(host)) == 0) {
- LOGERR(("NetconCli::openconn: gethostbyname(%s) failed\n", host));
- return -1;
- }
- memcpy(&saddr.sin_addr, hp->h_addr, hp->h_length);
- }
-
- if ((m_fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
- LOGSYSERR("NetconCli::openconn", "socket", "");
- return -1;
+ memset(&unix_addr, 0, sizeof(unix_addr));
+ unix_addr.sun_family = AF_UNIX;
+ if (strlen(host) > UNIX_PATH_MAX - 1) {
+ LOGERR(("NetconCli::openconn: name too long: %s\n", host));
+ return -1;
+ }
+ strcpy(unix_addr.sun_path, host);
+
+ if ((m_fd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) {
+ LOGSYSERR("NetconCli::openconn", "socket", "");
+ return -1;
+ }
+ addrsize = sizeof(unix_addr);
+ saddr = (sockaddr*)&unix_addr;
}
if (timeo > 0) {
set_nonblock(1);
}
- if (connect(m_fd, (struct sockaddr *) &saddr, sizeof(saddr)) < 0) {
+ if (connect(m_fd, saddr, addrsize) < 0) {
if (timeo > 0) {
if (errno != EINPROGRESS) {
goto out;
@@ -676,17 +709,21 @@
}
// Same as previous, but get the port number from services
-int NetconCli::openconn(const char *host, char *serv, int timeo)
+int NetconCli::openconn(const char *host, const char *serv, int timeo)
{
LOGDEB2(("Netconcli::openconn: host %s, serv %s\n", host, serv));
- struct servent *sp;
- if ((sp = getservbyname(serv, "tcp")) == 0) {
- LOGERR(("NetconCli::openconn: getservbyname failed for %s\n", serv));
- return -1;
- }
- // Callee expects the port number in host byte order
- return openconn(host, ntohs(sp->s_port), timeo);
+ if (host[0] != '/') {
+ struct servent *sp;
+ if ((sp = getservbyname(serv, "tcp")) == 0) {
+ LOGERR(("NetconCli::openconn: getservbyname failed for %s\n",serv));
+ return -1;
+ }
+ // Callee expects the port number in host byte order
+ return openconn(host, ntohs(sp->s_port), timeo);
+ } else {
+ return openconn(host, (unsigned int)0, timeo);
+ }
}
@@ -727,22 +764,64 @@
#endif
// Set up service.
-int NetconServLis::openservice(char *serv, int backlog)
+int NetconServLis::openservice(const char *serv, int backlog)
{
int port;
struct servent *servp;
+ if (!serv) {
+ LOGERR(("NetconServLis::openservice: null serv??\n"));
+ return -1;
+ }
LOGDEB1(("NetconServLis::openservice: serv %s\n", serv));
#ifdef NETCON_ACCESSCONTROL
if (initperms(serv) < 0) {
return -1;
}
#endif
- if ((servp = getservbyname(serv, "tcp")) == 0) {
- LOGERR(("NetconServLis::openservice: getservbyname failed for %s\n", serv));
- return -1;
- }
- port = (int)ntohs((short)servp->s_port);
- return openservice(port, backlog);
+
+ m_serv = serv;
+ if (serv[0] != '/') {
+ if ((servp = getservbyname(serv, "tcp")) == 0) {
+ LOGERR(("NetconServLis::openservice: getservbyname failed for %s\n",
+ serv));
+ return -1;
+ }
+ port = (int)ntohs((short)servp->s_port);
+ return openservice(port, backlog);
+ } else {
+ if (strlen(serv) > UNIX_PATH_MAX - 1) {
+ LOGERR(("NetconServLis::openservice: too long for AF_UNIX: %s\n",
+ serv));
+ return -1;
+ }
+ int ret = -1;
+ struct sockaddr_un addr;
+ if ((m_fd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) {
+ LOGSYSERR("NetconServLis", "socket", "");
+ return -1;
+ }
+ memset(&addr, 0, sizeof(addr));
+ addr.sun_family = AF_UNIX;
+ strcpy(addr.sun_path, serv);
+
+ if (::bind(m_fd, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
+ LOGSYSERR("NetconServLis", "bind", "");
+ goto out;
+ }
+ if (listen(m_fd, backlog) < 0) {
+ LOGSYSERR("NetconServLis", "listen", "");
+ goto out;
+ }
+
+ LOGDEB1(("NetconServLis::openservice: service opened ok\n"));
+ ret = 0;
+ out:
+ if (ret < 0 && m_fd >= 0) {
+ close(m_fd);
+ m_fd = -1;
+ }
+ return ret;
+ }
}
// Port is a natural host integer value
@@ -800,7 +879,7 @@
}
// Get authorized address lists from parameter file. This is disabled for now
-int NetconServLis::initperms(char *serv)
+int NetconServLis::initperms(const char *serv)
{
if (permsinit) {
return 0;
@@ -868,31 +947,47 @@
NetconServCon *con = 0;
int newfd = -1;
struct sockaddr_in who;
- SOCKLEN_T clilen = (SOCKLEN_T)sizeof(who);
- if ((newfd = ::accept(m_fd, (struct sockaddr *)&who, &clilen)) < 0) {
- LOGSYSERR("NetconServCon::accept", "accept", "");
- goto out;
- }
+ struct sockaddr_un uwho;
+ if (m_serv.empty() || m_serv[0] != '/') {
+ SOCKLEN_T clilen = (SOCKLEN_T)sizeof(who);
+ if ((newfd = ::accept(m_fd, (struct sockaddr *)&who, &clilen)) < 0) {
+ LOGSYSERR("NetconServCon::accept", "accept", "");
+ goto out;
+ }
#ifdef NETCON_ACCESSCONTROL
- if (checkperms(&who, clilen) < 0) {
- goto out;
- }
+ if (checkperms(&who, clilen) < 0) {
+ goto out;
+ }
#endif
+ } else {
+ SOCKLEN_T clilen = (SOCKLEN_T)sizeof(uwho);
+ if ((newfd = ::accept(m_fd, (struct sockaddr *)&uwho, &clilen)) < 0) {
+ LOGSYSERR("NetconServCon::accept", "accept", "");
+ goto out;
+ }
+ }
+
con = new NetconServCon(newfd);
if (con == 0) {
LOGERR(("NetconServLis::accept: new NetconServCon failed\n"));
goto out;
}
+
// Retrieve peer's host name. Errors are non fatal
- struct hostent *hp;
- if ((hp = gethostbyaddr((char *) & (who.sin_addr), sizeof(struct in_addr),
- AF_INET)) == 0) {
- LOGERR(("NetconServLis::accept: gethostbyaddr failed for addr 0x%lx\n",
+ if (m_serv.empty() || m_serv[0] != '/') {
+ struct hostent *hp;
+ if ((hp = gethostbyaddr((char *) & (who.sin_addr),
+ sizeof(struct in_addr), AF_INET)) == 0) {
+ LOGERR(("NetconServLis::accept: gethostbyaddr failed for addr 0x%lx\n",
who.sin_addr.s_addr));
- con->setpeer(inet_ntoa(who.sin_addr));
+ con->setpeer(inet_ntoa(who.sin_addr));
+ } else {
+ con->setpeer(hp->h_name);
+ }
} else {
- con->setpeer(hp->h_name);
- }
+ con->setpeer(m_serv.c_str());
+ }
+
LOGDEB2(("NetconServLis::accept: setting keepalive\n"));
if (setsockopt(newfd, SOL_SOCKET, SO_KEEPALIVE,
(char *)&one, sizeof(one)) < 0) {
@@ -1106,7 +1201,10 @@
fprintf(stderr, "new NetconCli failed\n");
return 1;
}
- if (clicon->openconn(host, serv) < 0) {
+ int port = atoi(serv);
+ int ret = port > 0 ?
+ clicon->openconn(host, port) : clicon->openconn(host, serv);
+ if (ret < 0) {
fprintf(stderr, "openconn(%s, %s) failed\n", host, serv);
return 1;
}
@@ -1135,7 +1233,7 @@
SelectLoop myloop;
myloop.addselcon(con, Netcon::NETCONPOLL_WRITE);
fprintf(stderr, "client ready\n");
- int ret = myloop.doLoop();
+ ret = myloop.doLoop();
if (ret < 0) {
fprintf(stderr, "selectloop failed\n");
exit(1);
@@ -1237,7 +1335,10 @@
sigaction(SIGQUIT, &sa, 0);
sigaction(SIGTERM, &sa, 0);
- if (servlis->openservice(serv) < 0) {
+ int port = atoi(serv);
+ int ret = port > 0 ?
+ servlis->openservice(port) : servlis->openservice(serv);
+ if (ret < 0) {
fprintf(stderr, "openservice(%s) failed\n", serv);
return 1;
}