/*
* The Spread Toolkit.
*
* The contents of this file are subject to the Spread Open-Source
* License, Version 1.0 (the ``License''); you may not use
* this file except in compliance with the License. You may obtain a
* copy of the License at:
*
* http://www.spread.org/license/
*
* or in the file ``license.txt'' found in this distribution.
*
* Software distributed under the License is distributed on an AS IS basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Creators of Spread are:
* Yair Amir, Michal Miskin-Amir, Jonathan Stanton.
*
* Copyright (C) 1993-2004 Spread Concepts LLC <spread@spreadconcepts.com>
*
* All Rights Reserved.
*
* Major Contributor(s):
* ---------------
* Cristina Nita-Rotaru crisn@cs.purdue.edu - group communication security.
* Theo Schlossnagle jesus@omniti.com - Perl, skiplists, autoconf.
* Dan Schoenblum dansch@cnds.jhu.edu - Java interface.
* John Schultz jschultz@cnds.jhu.edu - contribution to process group membership.
*
*/
#include <stdlib.h>
#include "arch.h"
#ifndef ARCH_PC_WIN95
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/uio.h>
/* for select */
#include <sys/time.h>
#include <unistd.h>
#include <errno.h>
#else /* ARCH_PC_WIN95 */
#include <winsock.h>
#endif /* ARCH_PC_WIN95 */
#include <string.h>
#include <assert.h>
#include "data_link.h"
#include "status.h"
#include "alarm.h"
#include "sp_events.h" /* for sp_time */
channel DL_init_channel( int32 channel_type, int16 port, int32 mcast_address, int32 interface_address )
{
channel chan;
struct sockaddr_in soc_addr;
int on=1;
int i1,i2,i3,i4;
#ifdef IP_MULTICAST_TTL
unsigned char ttl_val;
#endif
if((chan = socket(AF_INET, SOCK_DGRAM, 0)) == -1)
Alarm( EXIT, "DL_init_channel: socket error for port %d\n", port );
if ( channel_type & SEND_CHANNEL )
{
if (setsockopt(chan, SOL_SOCKET, SO_BROADCAST, (char *)&on,
sizeof(on)) < 0)
Alarm( EXIT, "DL_init_channel: setsockopt error for port %d\n",port);
Alarm( DATA_LINK, "DL_init_channel: setsockopt for send and broadcast went ok\n");
#ifdef IP_MULTICAST_TTL
/* ### Isn't this for sending??? */
ttl_val = 1;
if (setsockopt(chan, IPPROTO_IP, IP_MULTICAST_TTL, (void *)&ttl_val,
sizeof(ttl_val)) < 0)
{
Alarm( DATA_LINK, "DL_init_channel: problem in setsockopt of multicast ttl %d - ignore in WinNT or Win95\n", ttl_val );
}
Alarm( DATA_LINK, "DL_init_channel: setting Mcast TTL to %d\n",ttl_val);
#endif
}
if ( channel_type & RECV_CHANNEL )
{
soc_addr.sin_family = AF_INET;
soc_addr.sin_port = htons(port);
memset(&soc_addr.sin_zero, 0, sizeof(soc_addr.sin_zero));
if (interface_address == 0)
soc_addr.sin_addr.s_addr= INADDR_ANY;
else
soc_addr.sin_addr.s_addr= htonl(interface_address);
if(bind( chan, (struct sockaddr *) &soc_addr,
sizeof(soc_addr)) == -1)
{
Alarm( EXIT, "DL_init_channel: bind error (%d): %s for port %d, with sockaddr (%d.%d.%d.%d: %d) probably already running \n", sock_errno, sock_strerror(sock_errno), port, IP1(soc_addr.sin_addr.s_addr),IP2(soc_addr.sin_addr.s_addr),IP3(soc_addr.sin_addr.s_addr),IP4(soc_addr.sin_addr.s_addr), soc_addr.sin_port );
}
Alarm( DATA_LINK, "DL_init_channel: bind for recv_channel for port %d with chan %d ok\n",
port, chan);
i1 = (mcast_address >> 24) & 0x000000ff;
i2 = (mcast_address >> 16) & 0x000000ff;
i3 = (mcast_address >> 8) & 0x000000ff;
i4 = mcast_address & 0x000000ff;
if( i1 >=224 && i1 < 240 )
{
#ifdef IP_MULTICAST_TTL
struct ip_mreq mreq;
mreq.imr_multiaddr.s_addr = htonl( mcast_address );
/* the interface could be changed to a specific interface if needed */
mreq.imr_interface.s_addr = INADDR_ANY;
if (setsockopt(chan, IPPROTO_IP, IP_ADD_MEMBERSHIP, (void *)&mreq,
sizeof(mreq)) < 0)
{
Alarm( EXIT, "DL_init_channel: problem in setsockopt to multicast address %d\n", mcast_address );
}
Alarm( DATA_LINK, "DL_init_channel: Joining multicast address %d.%d.%d.%d went ok\n",i1,i2,i3,i4);
#else /* no multicast support */
Alarm( EXIT, "DL_init_channel: Old SunOS architecture does not support IP multicast: %d.%d.%d.%d\n",i1,i2,i3,i4);
#endif
} else {
if (setsockopt(chan, SOL_SOCKET, SO_BROADCAST, (char *)&on,
sizeof(on)) < 0)
Alarm( EXIT, "DL_init_channel: setsockopt SO_BROADCAST error for port %d, socket %d\n",port,chan);
Alarm( DATA_LINK, "DL_init_channel: setsockopt for recv and broadcast went ok\n");
}
}
Alarm( DATA_LINK, "DL_init_channel: went ok on channel %d\n",chan);
return ( chan );
}
void DL_close_channel(channel chan)
{
if( -1 == close(chan))
{
Alarm(EXIT, "DL_close_channel: error closing channel %d\n", chan);
}
}
int DL_send( channel chan, int32 address, int16 port, sys_scatter *scat )
{
#ifndef ARCH_SCATTER_NONE
static struct msghdr msg;
#else /* ARCH_SCATTER_NONE */
static char pseudo_scat[MAX_PACKET_SIZE];
#endif /* ARCH_SCATTER_NONE */
static struct sockaddr_in soc_addr;
static sp_time select_delay = { 0, 10000 };
int ret;
int total_len;
int i;
int num_try;
char *send_errormsg = NULL; /* fool compiler */
/* Check that the scatter passed is small enough to be a valid system scatter */
assert(scat->num_elements <= ARCH_SCATTER_SIZE);
soc_addr.sin_family = AF_INET;
soc_addr.sin_addr.s_addr= htonl(address);
soc_addr.sin_port = htons(port);
#ifdef ARCH_PC_HOME
soc_addr.sin_addr.s_addr= htonl(-1073741814);
#endif /* ARCH_PC_HOME */
#ifndef ARCH_SCATTER_NONE
msg.msg_name = (caddr_t) &soc_addr;
msg.msg_namelen = sizeof(soc_addr);
msg.msg_iov = (struct iovec *)scat->elements;
msg.msg_iovlen = scat->num_elements;
#endif /* ARCH_SCATTER_NONE */
#ifdef ARCH_SCATTER_CONTROL
msg.msg_controllen = 0;
#endif /* ARCH_SCATTER_CONTROL */
#ifdef ARCH_SCATTER_ACCRIGHTS
msg.msg_accrightslen = 0;
#endif /* ARCH_SCATTER_ACCRIGHTS */
for( i=0, total_len=0; i < scat->num_elements; i++)
{
#ifdef ARCH_SCATTER_NONE
memcpy( &pseudo_scat[total_len], scat->elements[i].buf,
scat->elements[i].len );
#endif /* ARCH_SCATTER_NONE */
total_len+=scat->elements[i].len;
}
#if 0
#ifndef ARCH_SCATTER_NONE
if( msg.msg_iovlen > 16)
{
Alarm(EXIT, "Too Big iovec of size %d\n", msg.msg_iovlen);
}
#endif
#endif
for( ret=-10, num_try=0; ret < 0 && num_try < 10; num_try++ )
{
#ifndef ARCH_SCATTER_NONE
ret = sendmsg(chan, &msg, 0);
#else /* ARCH_SCATTER_NONE */
ret = sendto(chan, pseudo_scat, total_len, 0,
(struct sockaddr *)&soc_addr, sizeof(soc_addr) );
#endif /* ARCH_SCATTER_NONE */
if(ret < 0) {
/* delay for a short while */
send_errormsg = sock_strerror(sock_errno);
Alarm( DATA_LINK, "DL_send: delaying after failure in send to %d.%d.%d.%d, ret is %d\n",
IP1(address), IP2(address), IP3(address), IP4(address), ret);
select( 0, 0, 0, 0, (struct timeval *)&select_delay );
}
}
if (ret < 0)
{
for( i=0; i < scat->num_elements; i++)
Alarm( DATA_LINK, "DL_send: element[%d]: %d bytes\n",
i,scat->elements[i].len);
Alarm( DATA_LINK, "DL_send: error: %s\n sending %d bytes on channel %d to address %d.%d.%d.%d\n",
send_errormsg, total_len,chan,IP1(address), IP2(address), IP3(address), IP4(address) );
}else if(ret < total_len){
Alarm( DATA_LINK, "DL_send: partial sending %d out of %d\n",
ret,total_len);
}
Alarm( DATA_LINK, "DL_send: sent a message of %d bytes to (%d.%d.%d.%d,%d) on channel %d\n",
ret,IP1(address), IP2(address),IP3(address), IP4(address),port,chan);
return(ret);
}
int DL_recv( channel chan, sys_scatter *scat )
{
#ifndef ARCH_SCATTER_NONE
static struct msghdr msg;
struct sockaddr_in source_address;
#else /* ARCH_SCATTER_NONE */
static char pseudo_scat[MAX_PACKET_SIZE];
int bytes_to_copy;
int total_len;
int start;
int i;
#endif /* ARCH_SCATTER_NONE */
int ret;
/* check the scat is small enough to be a sys_scatter */
assert(scat->num_elements <= ARCH_SCATTER_SIZE);
#ifndef ARCH_SCATTER_NONE
msg.msg_name = (caddr_t) &source_address;
msg.msg_namelen = sizeof(source_address);
msg.msg_iov = (struct iovec *)scat->elements;
msg.msg_iovlen = scat->num_elements;
#endif /* ARCH_SCATTER_NONE */
#ifdef ARCH_SCATTER_CONTROL
msg.msg_control = (caddr_t) 0;
msg.msg_controllen = 0;
#endif /* ARCH_SCATTER_CONTROL */
#ifdef ARCH_SCATTER_ACCRIGHTS
msg.msg_accrights = (caddr_t) 0;
msg.msg_accrightslen = 0;
#endif /* ARCH_SCATTER_ACCRIGHTS */
#ifndef ARCH_SCATTER_NONE
ret = recvmsg( chan, &msg, 0 );
#else /* ARCH_SCATTER_NONE */
total_len = 0; /*This is for TCP, to not receive*/
for(i=0; i<scat->num_elements; i++) /*more than one packet. */
total_len += scat->elements[i].len;
if(total_len>MAX_PACKET_SIZE)
total_len = MAX_PACKET_SIZE;
ret = recvfrom( chan, pseudo_scat, total_len, 0, 0, 0 );
for( i=0, total_len = ret, start =0; total_len > 0; i++)
{
bytes_to_copy = scat->elements[i].len;
if( bytes_to_copy > total_len ) bytes_to_copy = total_len;
memcpy( scat->elements[i].buf, &pseudo_scat[start],
bytes_to_copy );
total_len-= scat->elements[i].len;
start += scat->elements[i].len;
}
#endif /* ARCH_SCATTER_NONE */
if (ret < 0)
{
Alarm( DATA_LINK, "DL_recv: error %d receiving on channel %d\n", ret, chan );
return( -1 );
}
#ifdef ARCH_SCATTER_CONTROL
else if (ret == 0)
{
char *sptr;
sptr = (char *) inet_ntoa(source_address.sin_addr);
Alarm( DATA_LINK, "DL_recv: received zero length packet on channel %d flags 0x%x\nfrom %s", chan, msg.msg_flags,sptr );
#ifdef MSG_BCAST
if ( msg.msg_flags & MSG_BCAST )
{
Alarm( DATA_LINK, "\t(BROADCAST)");
}
#endif
#ifdef MSG_MCAST
if ( msg.msg_flags & MSG_MCAST )
{
Alarm( DATA_LINK, "\t(MULTICAST)");
}
#endif
#ifdef MSG_TRUNC
if ( msg.msg_flags & MSG_TRUNC )
{
Alarm( DATA_LINK, "\t(Data TRUNCATED)");
}
#endif
#ifdef MSG_CTRUNC
if ( msg.msg_flags & MSG_CTRUNC )
{
Alarm( DATA_LINK, "\t(Control TRUNCATED)");
}
#endif
Alarm( DATA_LINK, "\n");
}
#endif
Alarm( DATA_LINK, "DL_recv: received %d bytes on channel %d\n",
ret, chan );
return(ret);
}
syntax highlighted by Code2HTML, v. 0.9.1