|
Packit |
8f70b4 |
/*
|
|
Packit |
8f70b4 |
* lftp - file transfer program
|
|
Packit |
8f70b4 |
*
|
|
Packit |
8f70b4 |
* Copyright (c) 1996-2015 by Alexander V. Lukyanov (lav@yars.free.net)
|
|
Packit |
8f70b4 |
*
|
|
Packit |
8f70b4 |
* This program is free software; you can redistribute it and/or modify
|
|
Packit |
8f70b4 |
* it under the terms of the GNU General Public License as published by
|
|
Packit |
8f70b4 |
* the Free Software Foundation; either version 3 of the License, or
|
|
Packit |
8f70b4 |
* (at your option) any later version.
|
|
Packit |
8f70b4 |
*
|
|
Packit |
8f70b4 |
* This program is distributed in the hope that it will be useful,
|
|
Packit |
8f70b4 |
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
Packit |
8f70b4 |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
Packit |
8f70b4 |
* GNU General Public License for more details.
|
|
Packit |
8f70b4 |
*
|
|
Packit |
8f70b4 |
* You should have received a copy of the GNU General Public License
|
|
Packit |
8f70b4 |
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
Packit |
8f70b4 |
*/
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
#include <config.h>
|
|
Packit |
8f70b4 |
#include <stdio.h>
|
|
Packit |
8f70b4 |
#include <sys/types.h>
|
|
Packit |
8f70b4 |
#include <netdb.h>
|
|
Packit |
8f70b4 |
#include <errno.h>
|
|
Packit |
8f70b4 |
#include <unistd.h>
|
|
Packit |
8f70b4 |
#include <fcntl.h>
|
|
Packit |
8f70b4 |
#include <netinet/in.h>
|
|
Packit |
8f70b4 |
#ifdef HAVE_NETINET_IN_SYSTM_H
|
|
Packit |
8f70b4 |
# include <netinet/in_systm.h>
|
|
Packit |
8f70b4 |
#endif
|
|
Packit |
8f70b4 |
#ifdef HAVE_NETINET_IP_H
|
|
Packit |
8f70b4 |
# include <netinet/ip.h>
|
|
Packit |
8f70b4 |
#endif
|
|
Packit |
8f70b4 |
#ifdef HAVE_NETINET_TCP_H
|
|
Packit |
8f70b4 |
# include <netinet/tcp.h>
|
|
Packit |
8f70b4 |
#endif
|
|
Packit |
8f70b4 |
#ifdef HAVE_SYS_IOCTL_H
|
|
Packit |
8f70b4 |
# include <sys/ioctl.h>
|
|
Packit |
8f70b4 |
#endif
|
|
Packit |
8f70b4 |
#ifdef HAVE_TERMIOS_H
|
|
Packit |
8f70b4 |
# include <termios.h>
|
|
Packit |
8f70b4 |
#endif
|
|
Packit |
8f70b4 |
#include "SMTask.h"
|
|
Packit |
8f70b4 |
#include "network.h"
|
|
Packit |
8f70b4 |
#include "ResMgr.h"
|
|
Packit |
8f70b4 |
#include "ProtoLog.h"
|
|
Packit |
8f70b4 |
#include "xstring.h"
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
const char *sockaddr_u::address() const
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
#ifdef HAVE_GETNAMEINFO
|
|
Packit |
8f70b4 |
char *buf=xstring::tmp_buf(NI_MAXHOST);
|
|
Packit |
8f70b4 |
if(getnameinfo(&sa,addr_len(),buf,NI_MAXHOST,0,0,NI_NUMERICHOST)<0)
|
|
Packit |
8f70b4 |
return "????";
|
|
Packit |
8f70b4 |
return buf;
|
|
Packit |
8f70b4 |
#else
|
|
Packit |
8f70b4 |
static char buf[16];
|
|
Packit |
8f70b4 |
if(sa.sa_family!=AF_INET)
|
|
Packit |
8f70b4 |
return "????";
|
|
Packit |
8f70b4 |
unsigned char *a=(unsigned char *)&in.sin_addr;
|
|
Packit |
8f70b4 |
snprintf(buf,16,"%u.%u.%u.%u",a[0],a[1],a[2],a[3]);
|
|
Packit |
8f70b4 |
return buf;
|
|
Packit |
8f70b4 |
#endif
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
int sockaddr_u::port() const
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(sa.sa_family==AF_INET)
|
|
Packit |
8f70b4 |
return ntohs(in.sin_port);
|
|
Packit |
8f70b4 |
#if INET6
|
|
Packit |
8f70b4 |
if(sa.sa_family==AF_INET6)
|
|
Packit |
8f70b4 |
return ntohs(in6.sin6_port);
|
|
Packit |
8f70b4 |
#endif
|
|
Packit |
8f70b4 |
return 0;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
void sockaddr_u::set_port(int port)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(sa.sa_family==AF_INET)
|
|
Packit |
8f70b4 |
in.sin_port=htons(port);
|
|
Packit |
8f70b4 |
#if INET6
|
|
Packit |
8f70b4 |
if(sa.sa_family==AF_INET6)
|
|
Packit |
8f70b4 |
in6.sin6_port=htons(port);
|
|
Packit |
8f70b4 |
#endif
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
const xstring& sockaddr_u::to_xstring() const
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
return xstring::format("[%s]:%d",address(),port());
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
bool sockaddr_u::is_reserved() const
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(sa.sa_family==AF_INET)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
unsigned char *a=(unsigned char *)&in.sin_addr;
|
|
Packit |
8f70b4 |
return (a[0]==0)
|
|
Packit |
8f70b4 |
|| (a[0]==127 && !is_loopback())
|
|
Packit |
8f70b4 |
|| (a[0]>=240);
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
#if INET6
|
|
Packit |
8f70b4 |
if(family()==AF_INET6) {
|
|
Packit |
8f70b4 |
return IN6_IS_ADDR_UNSPECIFIED(&in6.sin6_addr)
|
|
Packit |
8f70b4 |
|| IN6_IS_ADDR_V4MAPPED(&in6.sin6_addr)
|
|
Packit |
8f70b4 |
|| IN6_IS_ADDR_V4COMPAT(&in6.sin6_addr);
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
#endif
|
|
Packit |
8f70b4 |
return false;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
bool sockaddr_u::is_multicast() const
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(sa.sa_family==AF_INET)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
unsigned char *a=(unsigned char *)&in.sin_addr;
|
|
Packit |
8f70b4 |
return (a[0]>=224 && a[0]<240);
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
#if INET6
|
|
Packit |
8f70b4 |
if(family()==AF_INET6)
|
|
Packit |
8f70b4 |
return IN6_IS_ADDR_MULTICAST(&in6.sin6_addr);
|
|
Packit |
8f70b4 |
#endif
|
|
Packit |
8f70b4 |
return false;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
bool sockaddr_u::is_private() const
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(sa.sa_family==AF_INET)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
unsigned char *a=(unsigned char *)&in.sin_addr;
|
|
Packit |
8f70b4 |
return (a[0]==10)
|
|
Packit |
8f70b4 |
|| (a[0]==172 && a[1]>=16 && a[1]<32)
|
|
Packit |
8f70b4 |
|| (a[0]==192 && a[1]==168)
|
|
Packit |
8f70b4 |
|| (a[0]==169 && a[1]==254); // self-assigned
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
#if INET6
|
|
Packit |
8f70b4 |
if(family()==AF_INET6) {
|
|
Packit |
8f70b4 |
return IN6_IS_ADDR_SITELOCAL(&in6.sin6_addr)
|
|
Packit |
8f70b4 |
|| IN6_IS_ADDR_LINKLOCAL(&in6.sin6_addr);
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
#endif
|
|
Packit |
8f70b4 |
return false;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
bool sockaddr_u::is_loopback() const
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(sa.sa_family==AF_INET)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
unsigned char *a=(unsigned char *)&in.sin_addr;
|
|
Packit |
8f70b4 |
return (a[0]==127 && a[1]==0 && a[2]==0 && a[3]==1);
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
#if INET6
|
|
Packit |
8f70b4 |
if(sa.sa_family==AF_INET6)
|
|
Packit |
8f70b4 |
return IN6_IS_ADDR_LOOPBACK(&in6.sin6_addr);
|
|
Packit |
8f70b4 |
#endif
|
|
Packit |
8f70b4 |
return false;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
bool sockaddr_u::is_compatible(const sockaddr_u& o) const
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
return family()==o.family()
|
|
Packit |
8f70b4 |
&& !is_multicast() && !o.is_multicast()
|
|
Packit |
8f70b4 |
&& !is_reserved() && !o.is_reserved()
|
|
Packit |
8f70b4 |
&& is_private()==o.is_private()
|
|
Packit |
8f70b4 |
&& is_loopback()==o.is_loopback();
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
bool sockaddr_u::set_compact(const char *c,size_t len)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(len==4) {
|
|
Packit |
8f70b4 |
sa.sa_family=AF_INET;
|
|
Packit |
8f70b4 |
memcpy(&in.sin_addr,c,4);
|
|
Packit |
8f70b4 |
in.sin_port=0;
|
|
Packit |
8f70b4 |
return true;
|
|
Packit |
8f70b4 |
#if INET6
|
|
Packit |
8f70b4 |
} else if(len==16) {
|
|
Packit |
8f70b4 |
sa.sa_family=AF_INET6;
|
|
Packit |
8f70b4 |
memcpy(&in6.sin6_addr,c,16);
|
|
Packit |
8f70b4 |
return true;
|
|
Packit |
8f70b4 |
#endif
|
|
Packit |
8f70b4 |
} else if(len==6) {
|
|
Packit |
8f70b4 |
sa.sa_family=AF_INET;
|
|
Packit |
8f70b4 |
memcpy(&in.sin_addr,c,4);
|
|
Packit |
8f70b4 |
in.sin_port=htons((c[5]&255)|((c[4]&255)<<8));
|
|
Packit |
8f70b4 |
return true;
|
|
Packit |
8f70b4 |
#if INET6
|
|
Packit |
8f70b4 |
} else if(len==18) {
|
|
Packit |
8f70b4 |
sa.sa_family=AF_INET6;
|
|
Packit |
8f70b4 |
memcpy(&in6.sin6_addr,c,16);
|
|
Packit |
8f70b4 |
in6.sin6_port=htons((c[17]&255)|((c[16]&255)<<8));
|
|
Packit |
8f70b4 |
return true;
|
|
Packit |
8f70b4 |
#endif
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
return false;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
const sockaddr_compact& sockaddr_u::compact() const
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
sockaddr_compact& c=compact_addr();
|
|
Packit |
8f70b4 |
int p=port();
|
|
Packit |
8f70b4 |
if(c.length() && p) {
|
|
Packit |
8f70b4 |
c.append(char(p>>8));
|
|
Packit |
8f70b4 |
c.append(char(p&255));
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
return c;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
sockaddr_compact& sockaddr_u::compact_addr() const
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
sockaddr_compact& c=sockaddr_compact::get_tmp();
|
|
Packit |
8f70b4 |
if(family()==AF_INET)
|
|
Packit |
8f70b4 |
c.append((const char*)&in.sin_addr,4);
|
|
Packit |
8f70b4 |
#if INET6
|
|
Packit |
8f70b4 |
else if(family()==AF_INET6)
|
|
Packit |
8f70b4 |
c.append((const char*)&in6.sin6_addr,16);
|
|
Packit |
8f70b4 |
#endif
|
|
Packit |
8f70b4 |
return c;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
void Networker::NonBlock(int fd)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
int fl=fcntl(fd,F_GETFL);
|
|
Packit |
8f70b4 |
fcntl(fd,F_SETFL,fl|O_NONBLOCK);
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
void Networker::CloseOnExec(int fd)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
fcntl(fd,F_SETFD,FD_CLOEXEC);
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
static int one=1;
|
|
Packit |
8f70b4 |
void Networker::KeepAlive(int sock)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
setsockopt(sock,SOL_SOCKET,SO_KEEPALIVE,(char*)&one,sizeof(one));
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
void Networker::MinimizeLatency(int sock)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
#ifdef IP_TOS
|
|
Packit |
8f70b4 |
int tos = IPTOS_LOWDELAY;
|
|
Packit |
8f70b4 |
setsockopt(sock, IPPROTO_IP, IP_TOS, (char *)&tos, sizeof(int));
|
|
Packit |
8f70b4 |
#endif
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
void Networker::MaximizeThroughput(int sock)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
#ifdef IP_TOS
|
|
Packit |
8f70b4 |
int tos = IPTOS_THROUGHPUT;
|
|
Packit |
8f70b4 |
setsockopt(sock, IPPROTO_IP, IP_TOS, (char *)&tos, sizeof(int));
|
|
Packit |
8f70b4 |
#endif
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
void Networker::ReuseAddress(int sock)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
setsockopt(sock,SOL_SOCKET,SO_REUSEADDR,(char*)&one,sizeof(one));
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
void Networker::SetSocketBuffer(int sock,int socket_buffer)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(socket_buffer==0)
|
|
Packit |
8f70b4 |
return;
|
|
Packit |
8f70b4 |
if(-1==setsockopt(sock,SOL_SOCKET,SO_SNDBUF,(char*)&socket_buffer,sizeof(socket_buffer)))
|
|
Packit |
8f70b4 |
ProtoLog::LogError(1,"setsockopt(SO_SNDBUF,%d): %s",socket_buffer,strerror(errno));
|
|
Packit |
8f70b4 |
if(-1==setsockopt(sock,SOL_SOCKET,SO_RCVBUF,(char*)&socket_buffer,sizeof(socket_buffer)))
|
|
Packit |
8f70b4 |
ProtoLog::LogError(1,"setsockopt(SO_RCVBUF,%d): %s",socket_buffer,strerror(errno));
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
void Networker::SetSocketMaxseg(int sock,int socket_maxseg)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
#ifndef SOL_TCP
|
|
Packit |
8f70b4 |
# define SOL_TCP IPPROTO_TCP
|
|
Packit |
8f70b4 |
#endif
|
|
Packit |
8f70b4 |
#ifdef TCP_MAXSEG
|
|
Packit |
8f70b4 |
if(socket_maxseg==0)
|
|
Packit |
8f70b4 |
return;
|
|
Packit |
8f70b4 |
if(-1==setsockopt(sock,SOL_TCP,TCP_MAXSEG,(char*)&socket_maxseg,sizeof(socket_maxseg)))
|
|
Packit |
8f70b4 |
ProtoLog::LogError(1,"setsockopt(TCP_MAXSEG,%d): %s",socket_maxseg,strerror(errno));
|
|
Packit |
8f70b4 |
#endif
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
int Networker::SocketCreateUnbound(int af,int type,int proto,const char *hostname)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
int s=socket(af,type,proto);
|
|
Packit |
8f70b4 |
if(s<0)
|
|
Packit |
8f70b4 |
return s;
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
NonBlock(s);
|
|
Packit |
8f70b4 |
CloseOnExec(s);
|
|
Packit |
8f70b4 |
SetSocketBuffer(s,ResMgr::Query("net:socket-buffer",hostname));
|
|
Packit |
8f70b4 |
return s;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
bool sockaddr_u::set_defaults(int af,const char *hostname,int port)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
memset(this,0,sizeof(*this));
|
|
Packit |
8f70b4 |
sa.sa_family=af;
|
|
Packit |
8f70b4 |
const char *b=0;
|
|
Packit |
8f70b4 |
if(af==AF_INET)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
b=ResMgr::Query("net:socket-bind-ipv4",hostname);
|
|
Packit |
8f70b4 |
if(!(b && b[0] && inet_pton(af,b,&in.sin_addr)))
|
|
Packit |
8f70b4 |
b=0;
|
|
Packit |
8f70b4 |
in.sin_port=htons(port);
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
#if INET6
|
|
Packit |
8f70b4 |
else if(af==AF_INET6)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
b=ResMgr::Query("net:socket-bind-ipv6",hostname);
|
|
Packit |
8f70b4 |
if(!(b && b[0] && inet_pton(af,b,&in6.sin6_addr)))
|
|
Packit |
8f70b4 |
b=0;
|
|
Packit |
8f70b4 |
in6.sin6_port=htons(port);
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
#endif
|
|
Packit |
8f70b4 |
return b || port;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
void Networker::SocketBindStd(int s,int af,const char *hostname,int port)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
sockaddr_u bind_addr;
|
|
Packit |
8f70b4 |
if(bind_addr.set_defaults(af,hostname,port))
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(bind_addr.bind_to(s)==-1)
|
|
Packit |
8f70b4 |
ProtoLog::LogError(0,"bind(%s): %s",bind_addr.to_string(),strerror(errno));
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
int Networker::SocketCreate(int af,int type,int proto,const char *hostname)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
int s=SocketCreateUnbound(af,type,proto,hostname);
|
|
Packit |
8f70b4 |
if(s<0)
|
|
Packit |
8f70b4 |
return s;
|
|
Packit |
8f70b4 |
SocketBindStd(s,af,hostname);
|
|
Packit |
8f70b4 |
return s;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
void Networker::SocketTuneTCP(int s,const char *hostname)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
KeepAlive(s);
|
|
Packit |
8f70b4 |
SetSocketMaxseg(s,ResMgr::Query("net:socket-maxseg",hostname));
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
int Networker::SocketCreateTCP(int af,const char *hostname)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
int s=SocketCreate(af,SOCK_STREAM,IPPROTO_TCP,hostname);
|
|
Packit |
8f70b4 |
if(s<0)
|
|
Packit |
8f70b4 |
return s;
|
|
Packit |
8f70b4 |
SocketTuneTCP(s,hostname);
|
|
Packit |
8f70b4 |
return s;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
int Networker::SocketCreateUnboundTCP(int af,const char *hostname)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
int s=SocketCreateUnbound(af,SOCK_STREAM,IPPROTO_TCP,hostname);
|
|
Packit |
8f70b4 |
if(s<0)
|
|
Packit |
8f70b4 |
return s;
|
|
Packit |
8f70b4 |
SocketTuneTCP(s,hostname);
|
|
Packit |
8f70b4 |
return s;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
int Networker::SocketConnect(int fd,const sockaddr_u *u)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
// some systems have wrong connect() prototype, so we have to cast off const.
|
|
Packit |
8f70b4 |
// in any case, connect does not alter the address.
|
|
Packit |
8f70b4 |
int res=connect(fd,(sockaddr*)&u->sa,SocketAddrLen(u));
|
|
Packit |
8f70b4 |
if(res!=-1)
|
|
Packit |
8f70b4 |
SMTask::UpdateNow(); // if non-blocking doesn't work
|
|
Packit |
8f70b4 |
return res;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
int Networker::SocketAccept(int fd,sockaddr_u *u,const char *hostname)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
socklen_t len=sizeof(*u);
|
|
Packit |
8f70b4 |
int a=accept(fd,&u->sa,&len;;
|
|
Packit |
8f70b4 |
if(a<0)
|
|
Packit |
8f70b4 |
return a;
|
|
Packit |
8f70b4 |
NonBlock(a);
|
|
Packit |
8f70b4 |
CloseOnExec(a);
|
|
Packit |
8f70b4 |
KeepAlive(a);
|
|
Packit |
8f70b4 |
SetSocketBuffer(a,ResMgr::Query("net:socket-buffer",hostname));
|
|
Packit |
8f70b4 |
SetSocketMaxseg(a,ResMgr::Query("net:socket-maxseg",hostname));
|
|
Packit |
8f70b4 |
return a;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
void Networker::SocketSinglePF(int s,int pf)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
#if INET6 && defined(IPV6_V6ONLY)
|
|
Packit |
8f70b4 |
if(pf==PF_INET6) {
|
|
Packit |
8f70b4 |
int on = 1;
|
|
Packit |
8f70b4 |
if(-1==setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY, (char *)&on, sizeof(on)))
|
|
Packit |
8f70b4 |
ProtoLog::LogError(1,"setsockopt(IPV6_V6ONLY): %s",strerror(errno));
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
#endif
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
#ifdef TIOCOUTQ
|
|
Packit |
8f70b4 |
static bool TIOCOUTQ_returns_free_space;
|
|
Packit |
8f70b4 |
static bool TIOCOUTQ_works;
|
|
Packit |
8f70b4 |
static bool TIOCOUTQ_tested;
|
|
Packit |
8f70b4 |
static void test_TIOCOUTQ()
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
int sock=socket(PF_INET,SOCK_STREAM,IPPROTO_TCP);
|
|
Packit |
8f70b4 |
if(sock==-1)
|
|
Packit |
8f70b4 |
return;
|
|
Packit |
8f70b4 |
TIOCOUTQ_tested=true;
|
|
Packit |
8f70b4 |
int avail=-1;
|
|
Packit |
8f70b4 |
socklen_t len=sizeof(avail);
|
|
Packit |
8f70b4 |
if(getsockopt(sock,SOL_SOCKET,SO_SNDBUF,(char*)&avail,&len)==-1)
|
|
Packit |
8f70b4 |
avail=-1;
|
|
Packit |
8f70b4 |
int buf=-1;
|
|
Packit |
8f70b4 |
if(ioctl(sock,TIOCOUTQ,&buf)==-1)
|
|
Packit |
8f70b4 |
buf=-1;
|
|
Packit |
8f70b4 |
if(buf>=0 && avail>0 && (buf==0 || buf==avail))
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
TIOCOUTQ_works=true;
|
|
Packit |
8f70b4 |
TIOCOUTQ_returns_free_space=(buf==avail);
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
close(sock);
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
#endif
|
|
Packit |
8f70b4 |
int Networker::SocketBuffered(int sock)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
#ifdef TIOCOUTQ
|
|
Packit |
8f70b4 |
if(!TIOCOUTQ_tested)
|
|
Packit |
8f70b4 |
test_TIOCOUTQ();
|
|
Packit |
8f70b4 |
if(!TIOCOUTQ_works)
|
|
Packit |
8f70b4 |
return 0;
|
|
Packit |
8f70b4 |
int buffer=0;
|
|
Packit |
8f70b4 |
if(TIOCOUTQ_returns_free_space)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
socklen_t len=sizeof(buffer);
|
|
Packit |
8f70b4 |
if(getsockopt(sock,SOL_SOCKET,SO_SNDBUF,(char*)&buffer,&len)==-1)
|
|
Packit |
8f70b4 |
return 0;
|
|
Packit |
8f70b4 |
int avail=buffer;
|
|
Packit |
8f70b4 |
if(ioctl(sock,TIOCOUTQ,&avail)==-1)
|
|
Packit |
8f70b4 |
return 0;
|
|
Packit |
8f70b4 |
if(avail>buffer)
|
|
Packit |
8f70b4 |
return 0; // something wrong
|
|
Packit |
8f70b4 |
buffer-=avail;
|
|
Packit |
8f70b4 |
buffer=buffer*3/4; // approx...
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
else
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(ioctl(sock,TIOCOUTQ,&buffer)==-1)
|
|
Packit |
8f70b4 |
return 0;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
return buffer;
|
|
Packit |
8f70b4 |
#else
|
|
Packit |
8f70b4 |
return 0;
|
|
Packit |
8f70b4 |
#endif
|
|
Packit |
8f70b4 |
}
|