2012-03-16 22:30:51 +00:00
|
|
|
/*
|
|
|
|
Copyright (C) 2010-2012 Paul Gardner-Stephen, Serval Project.
|
|
|
|
|
|
|
|
This program is free software; you can redistribute it and/or
|
|
|
|
modify it under the terms of the GNU General Public License
|
|
|
|
as published by the Free Software Foundation; either version 2
|
|
|
|
of the License, or (at your option) any later version.
|
|
|
|
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
GNU General Public License for more details.
|
|
|
|
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
|
|
along with this program; if not, write to the Free Software
|
|
|
|
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "serval.h"
|
|
|
|
|
2012-03-17 02:32:09 +00:00
|
|
|
|
2012-03-16 22:30:51 +00:00
|
|
|
int mdp_abstract_socket=-1;
|
|
|
|
int mdp_named_socket=-1;
|
|
|
|
int overlay_mdp_setup_sockets()
|
|
|
|
{
|
|
|
|
struct sockaddr_un name;
|
|
|
|
int len;
|
|
|
|
|
|
|
|
name.sun_family = AF_UNIX;
|
|
|
|
|
|
|
|
#ifndef HAVE_LINUX_IF_H
|
|
|
|
/* Abstrack name space (i.e., non-file represented) unix domain sockets are a
|
|
|
|
linux-only thing. */
|
|
|
|
mdp_abstract_socket = -1;
|
|
|
|
#else
|
2012-03-17 02:32:09 +00:00
|
|
|
if (mdp_abstract_socket==-1) {
|
|
|
|
/* Abstract name space unix sockets is a special Linux thing, which is
|
|
|
|
convenient for us because Android is Linux, but does not have a shared
|
|
|
|
writable path that is on a UFS partition, so we cannot use traditional
|
|
|
|
named unix domain sockets. So the abstract name space gives us a solution. */
|
|
|
|
name.sun_path[0]=0;
|
|
|
|
/* XXX The 100 should be replaced with the actual maximum allowed.
|
|
|
|
Apparently POSIX requires it to be at least 100, but I would still feel
|
|
|
|
more comfortable with using the appropriate constant. */
|
|
|
|
snprintf(&name.sun_path[1],100,"org.servalproject.mesh.overlay.mdp");
|
|
|
|
len = 1+strlen(&name.sun_path[1]) + sizeof(name.sun_family);
|
|
|
|
|
2012-03-17 12:01:48 +00:00
|
|
|
mdp_abstract_socket = socket(AF_UNIX, SOCK_DGRAM, 0);
|
2012-03-17 02:32:09 +00:00
|
|
|
if (mdp_abstract_socket>-1) {
|
|
|
|
int dud=0;
|
|
|
|
int r=bind(mdp_abstract_socket, (struct sockaddr *)&name, len);
|
|
|
|
if (r) { dud=1; r=0; WHY("bind() of abstract name space socket failed (not an error on non-linux systems"); }
|
|
|
|
if (dud) {
|
|
|
|
close(mdp_abstract_socket);
|
|
|
|
mdp_abstract_socket=-1;
|
|
|
|
WHY("Could not open abstract name-space socket (only a problem on Linux).");
|
|
|
|
}
|
2012-03-16 22:30:51 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
2012-03-17 02:32:09 +00:00
|
|
|
if (mdp_named_socket==-1) {
|
|
|
|
char *instancepath=serval_instancepath();
|
2012-03-18 23:13:11 +00:00
|
|
|
if (strlen(instancepath)>85) return WHY("Instance path too long to allow construction of named unix domain socket.");
|
2012-03-17 02:32:09 +00:00
|
|
|
snprintf(&name.sun_path[0],100,"%s/mdp.socket",instancepath);
|
2012-03-18 23:13:11 +00:00
|
|
|
unlink(&name.sun_path[0]);
|
|
|
|
len = 0+strlen(&name.sun_path[0]) + sizeof(name.sun_family)+1;
|
2012-03-17 12:01:48 +00:00
|
|
|
mdp_named_socket = socket(AF_UNIX, SOCK_DGRAM, 0);
|
2012-03-17 02:32:09 +00:00
|
|
|
if (mdp_named_socket>-1) {
|
|
|
|
int dud=0;
|
|
|
|
int r=bind(mdp_named_socket, (struct sockaddr *)&name, len);
|
|
|
|
if (r) { dud=1; r=0; WHY("bind() of named unix domain socket failed"); }
|
|
|
|
if (dud) {
|
|
|
|
close(mdp_named_socket);
|
|
|
|
mdp_named_socket=-1;
|
|
|
|
WHY("Could not open named unix domain socket.");
|
|
|
|
}
|
2012-03-16 22:30:51 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2012-03-17 02:32:09 +00:00
|
|
|
int overlay_mdp_get_fds(struct pollfd *fds,int *fdcount,int fdmax)
|
|
|
|
{
|
|
|
|
/* Make sure sockets are open */
|
|
|
|
overlay_mdp_setup_sockets();
|
|
|
|
|
|
|
|
if ((*fdcount)>=fdmax) return -1;
|
|
|
|
if (mdp_abstract_socket>-1)
|
|
|
|
{
|
|
|
|
if (debug&DEBUG_IO) {
|
|
|
|
fprintf(stderr,"MDP abstract name space socket is poll() slot #%d (fd %d)\n",
|
|
|
|
*fdcount,mdp_abstract_socket);
|
|
|
|
}
|
|
|
|
fds[*fdcount].fd=mdp_abstract_socket;
|
|
|
|
fds[*fdcount].events=POLLIN;
|
|
|
|
(*fdcount)++;
|
|
|
|
}
|
|
|
|
if ((*fdcount)>=fdmax) return -1;
|
|
|
|
if (mdp_named_socket>-1)
|
|
|
|
{
|
|
|
|
if (debug&DEBUG_IO) {
|
|
|
|
fprintf(stderr,"MDP named unix domain socket is poll() slot #%d (fd %d)\n",
|
|
|
|
*fdcount,mdp_named_socket);
|
|
|
|
}
|
|
|
|
fds[*fdcount].fd=mdp_named_socket;
|
|
|
|
fds[*fdcount].events=POLLIN;
|
|
|
|
(*fdcount)++;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2012-03-16 22:30:51 +00:00
|
|
|
int overlay_saw_mdp_frame(int interface,overlay_frame *f,long long now)
|
|
|
|
{
|
|
|
|
return WHY("Not implemented");
|
|
|
|
}
|
2012-03-17 02:32:09 +00:00
|
|
|
|
|
|
|
int overlay_mdp_poll()
|
|
|
|
{
|
2012-03-19 05:36:34 +00:00
|
|
|
unsigned char buffer[16384];
|
|
|
|
int ttl;
|
|
|
|
struct sockaddr recvaddr;
|
|
|
|
socklen_t recvaddrlen=sizeof(recvaddr);
|
|
|
|
struct sockaddr_un *recvaddr_un=NULL;
|
|
|
|
|
|
|
|
if (mdp_named_socket>-1) {
|
|
|
|
ttl=-1;
|
|
|
|
bzero((void *)&recvaddr,sizeof(recvaddr));
|
|
|
|
fcntl(mdp_named_socket, F_SETFL,
|
|
|
|
fcntl(mdp_named_socket, F_GETFL, NULL)|O_NONBLOCK);
|
|
|
|
int len = recvwithttl(mdp_named_socket,buffer,sizeof(buffer),&ttl,
|
|
|
|
&recvaddr,&recvaddrlen);
|
|
|
|
if (len>0) {
|
|
|
|
dump("packet from unix domain socket",
|
|
|
|
buffer,len);
|
2012-03-19 05:53:05 +00:00
|
|
|
/* Look at overlay_mdp_frame we have received */
|
|
|
|
overlay_mdp_frame *mdp=(overlay_mdp_frame *)&buffer[0];
|
|
|
|
switch(mdp->packetTypeAndFlags) {
|
|
|
|
case MDP_TX: /* Send payload */
|
|
|
|
break;
|
|
|
|
case MDP_BIND: /* Bind to port */
|
|
|
|
WHY("MDP_BIND request");
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
/* Client is not allowed to send any other frame type */
|
2012-03-19 06:05:49 +00:00
|
|
|
WHY("Illegal frame type.");
|
2012-03-19 05:53:05 +00:00
|
|
|
mdp->packetTypeAndFlags=MDP_ERROR;
|
|
|
|
mdp->error.error=2;
|
|
|
|
snprintf(mdp->error.message,128,"Illegal request type. Clients may use only MDP_TX or MDP_BIND.");
|
|
|
|
int len=4+4+strlen(mdp->error.message)+1;
|
2012-03-19 06:05:49 +00:00
|
|
|
errno=0;
|
2012-03-19 05:53:05 +00:00
|
|
|
int e=sendto(mdp_named_socket,mdp,len,0,(struct sockaddr *)&recvaddr,recvaddrlen);
|
2012-03-19 06:05:49 +00:00
|
|
|
|
|
|
|
perror("sendto");
|
2012-03-19 05:53:05 +00:00
|
|
|
}
|
2012-03-19 05:36:34 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
recvaddr_un=(struct sockaddr_un *)&recvaddr;
|
|
|
|
fcntl(mdp_named_socket, F_SETFL,
|
|
|
|
fcntl(mdp_named_socket, F_GETFL, NULL)&(~O_NONBLOCK));
|
|
|
|
}
|
|
|
|
|
2012-03-19 05:53:05 +00:00
|
|
|
if (!(random()&0xff)) WHY("Not implemented");
|
|
|
|
return -1;
|
2012-03-19 05:36:34 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
int mdp_client_socket=-1;
|
|
|
|
int overlay_mdp_dispatch(overlay_mdp_frame *mdp,int flags,int timeout_ms)
|
|
|
|
{
|
2012-03-19 05:53:05 +00:00
|
|
|
int len=4;
|
2012-03-19 06:05:49 +00:00
|
|
|
char mdp_temporary_socket[1024];
|
|
|
|
mdp_temporary_socket[0]=0;
|
2012-03-19 05:53:05 +00:00
|
|
|
|
|
|
|
/* Minimise frame length to save work and prevent accidental disclosure of
|
|
|
|
memory contents. */
|
|
|
|
switch(mdp->packetTypeAndFlags)
|
|
|
|
{
|
|
|
|
case MDP_TX: len=4+sizeof(mdp->out)+mdp->out.payload_length; break;
|
|
|
|
case MDP_RX: len=4+sizeof(mdp->in)+mdp->out.payload_length; break;
|
|
|
|
case MDP_BIND: len=4+4; break;
|
|
|
|
case MDP_ERROR: len=4+4+strlen(mdp->error.message)+1; break;
|
|
|
|
default:
|
|
|
|
return WHY("Illegal MDP frame type.");
|
|
|
|
}
|
|
|
|
|
2012-03-19 05:36:34 +00:00
|
|
|
if (mdp_client_socket==-1) {
|
|
|
|
/* Open socket to MDP server (thus connection is always local) */
|
|
|
|
WHY("Use of abstract name space socket for Linux not implemented");
|
|
|
|
|
|
|
|
mdp_client_socket = socket(AF_UNIX, SOCK_DGRAM, 0);
|
|
|
|
if (mdp_client_socket < 0) {
|
|
|
|
perror("socket");
|
|
|
|
return WHY("Could not open socket to MDP server");
|
|
|
|
}
|
2012-03-19 06:05:49 +00:00
|
|
|
|
|
|
|
/* We must bind to a temporary file name */
|
|
|
|
snprintf(mdp_temporary_socket,1024,"%s/mdp-client.socket",serval_instancepath());
|
|
|
|
unlink(mdp_temporary_socket);
|
|
|
|
struct sockaddr_un name;
|
|
|
|
name.sun_family = AF_UNIX;
|
|
|
|
snprintf(&name.sun_path[0],100,mdp_temporary_socket);
|
|
|
|
int len = 1+strlen(&name.sun_path[0]) + sizeof(name.sun_family)+1;
|
|
|
|
int r=bind(mdp_client_socket, (struct sockaddr *)&name, len);
|
|
|
|
if (r) {
|
|
|
|
WHY("Could not bind MDP client socket to file name");
|
|
|
|
perror("bind");
|
|
|
|
return -1;
|
|
|
|
}
|
2012-03-19 05:36:34 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Construct name of socket to send to. */
|
|
|
|
char mdp_socket_name[101];
|
|
|
|
mdp_socket_name[100]=0;
|
|
|
|
snprintf(mdp_socket_name,100,"%s/mdp.socket",serval_instancepath());
|
|
|
|
if (mdp_socket_name[100]) {
|
2012-03-19 06:05:49 +00:00
|
|
|
if (mdp_temporary_socket[0]) unlink(mdp_temporary_socket);
|
2012-03-19 05:36:34 +00:00
|
|
|
return WHY("instance path is too long (unix domain named sockets have a short maximum path length)");
|
|
|
|
}
|
|
|
|
struct sockaddr_un name;
|
|
|
|
name.sun_family = AF_UNIX;
|
|
|
|
strcpy(name.sun_path, mdp_socket_name);
|
|
|
|
|
|
|
|
/* XXX Sends whole mdp structure, regardless of how much or little is used. */
|
2012-03-19 05:53:05 +00:00
|
|
|
int result=sendto(mdp_client_socket, mdp, len, 0,
|
2012-03-19 05:36:34 +00:00
|
|
|
(struct sockaddr *)&name, sizeof(struct sockaddr_un));
|
|
|
|
if (result<0) {
|
2012-03-19 05:53:05 +00:00
|
|
|
mdp->packetTypeAndFlags=MDP_ERROR;
|
|
|
|
mdp->error.error=1;
|
|
|
|
snprintf(mdp->error.message,128,"Error sending frame to MDP server.");
|
|
|
|
/* Clear socket so that we have the chance of reconnecting */
|
|
|
|
mdp_client_socket=-1;
|
2012-03-19 06:05:49 +00:00
|
|
|
if (mdp_temporary_socket[0]) unlink(mdp_temporary_socket);
|
2012-03-19 05:53:05 +00:00
|
|
|
return -1;
|
2012-03-19 05:36:34 +00:00
|
|
|
} else {
|
|
|
|
WHY("packet sent");
|
2012-03-19 06:05:49 +00:00
|
|
|
if (mdp_temporary_socket[0]) unlink(mdp_temporary_socket);
|
2012-03-19 05:36:34 +00:00
|
|
|
if (!(flags&MDP_AWAITREPLY)) return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Wait for a reply until timeout */
|
|
|
|
struct pollfd fds[1];
|
|
|
|
int fdcount=1;
|
|
|
|
fds[0].fd=mdp_client_socket; fds[0].events=POLLIN;
|
|
|
|
result = poll(fds,fdcount,timeout_ms);
|
|
|
|
if (result==0) {
|
|
|
|
/* Timeout */
|
|
|
|
mdp->packetTypeAndFlags=MDP_ERROR;
|
|
|
|
mdp->error.error=1;
|
|
|
|
snprintf(mdp->error.message,128,"Timeout waiting for reply to MDP packet (packet was successfully sent).");
|
2012-03-19 06:05:49 +00:00
|
|
|
if (mdp_temporary_socket[0]) unlink(mdp_temporary_socket);
|
2012-03-19 05:36:34 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Check if reply available */
|
2012-03-19 05:53:05 +00:00
|
|
|
|
2012-03-19 06:05:49 +00:00
|
|
|
if (mdp_temporary_socket[0]) unlink(mdp_temporary_socket);
|
2012-03-17 02:32:09 +00:00
|
|
|
return WHY("Not implemented");
|
|
|
|
}
|