/* WebDownloader for X-Window
* Copyright (C) 1999-2002 Koshelev Maxim
* This Program is free but not GPL!!! You can't modify it
* without agreement with author. You can't distribute modified
* program but you can distribute unmodified program.
*
* 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.
*/
#if (defined(__unix__) || defined(unix)) && !defined(USG)
#include <sys/param.h>
#endif
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <netdb.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <errno.h>
#include <sys/time.h>
#include <fcntl.h>
#include "socket.h"
#include "var.h"
#include "signal.h"
#ifndef INADDR_NONE
#define INADDR_NONE ((unsigned long) -1)
#endif
int my_get_host_by_name(const char *host,int port,
sockaddr_in *info,
hostent *hp,
char *buf,
int bufsize,
int *rvalbuf){
info->sin_family=AF_INET;
if (host) {
info->sin_addr.s_addr = inet_addr(host);
if (info->sin_addr.s_addr == INADDR_NONE){
hostent *hpr=hp;
*rvalbuf=0;
#if !(defined(BSD) && (BSD >= 199306))
#if (defined(__sparc__) || defined(__mips__)) && !(defined(__linux__))
int tmpr=gethostbyname_r(host,hp,buf,bufsize,rvalbuf);
#else /* (defined(__sparc__) || defined(__mips__)) && !(defined(__linux__)) */
int tmpr=gethostbyname_r(host,hp,buf,bufsize,&hpr,rvalbuf);
#endif
if (tmpr!=0 && *rvalbuf) return -1;
memcpy((char *)&(info->sin_addr),hpr->h_addr_list[0],
(size_t) hpr->h_length);
#else /* !(defined(BSD) && (BSD >= 199306)) */
hostent *hpa=gethostbyname(host);
if (!hpa) return -1;
memcpy((char *)&(info->sin_addr),hpa->h_addr_list[0],
(size_t) hpa->h_length);
#endif /* !(defined(BSD) && (BSD >= 199306)) */
};
} else info->sin_addr.s_addr=INADDR_ANY;
info->sin_port=htons(port);
return sizeof(sockaddr_in);
};
/******************************************************************/
tSocket::tSocket() {
fd=-1;
RBytes=0;
SBytes=0;
buffer=NULL;
con_flag=0;
};
bool tSocket::constr_name(const char *host,guint16 port) {
info.sin_family=AF_INET;
if (host) {
d4x::USR1On2Off sig_locker_;
info.sin_addr.s_addr = inet_addr(host);
if (info.sin_addr.s_addr == INADDR_NONE){
if (!buffer) buffer=new char[MAX_LEN];
hostent *hpr=&hp;
temp_variable=0;
#if !(defined(BSD) && (BSD >= 199306))
#if (defined(__sparc__) || defined(__mips__)) && !(defined(__linux__))
gethostbyname_r(host,&hp,buffer,MAX_LEN,&temp_variable);
#else
gethostbyname_r(host,&hp,buffer,MAX_LEN,&hpr,&temp_variable);
#endif
if (temp_variable){
return false;
};
memcpy((char *)&info.sin_addr,hpr->h_addr_list[0],(size_t) hpr->h_length);
#else /* !(defined(BSD) && (BSD >= 199306)) */
/* It seems that reentrant variant
of gethostbyname is not available under BSD
*/
hostent *hpa=gethostbyname(host);
if (!hpa){
return false;
};
memcpy((char *)&info.sin_addr,hpa->h_addr_list[0],(size_t) hpa->h_length);
#endif /* !(defined(BSD) && (BSD >= 199306)) */
};
} else info.sin_addr.s_addr=INADDR_ANY;
info.sin_port=htons(port);
return true;
};
//***************************************************/
unsigned int tSocket::get_addr() {
unsigned int my_addr=0;
#if defined(__sparc__) && !(defined(__linux__)) && !(defined(BSD))
int len;
#else
socklen_t len;
#endif
len = sizeof(info);
if (getsockname(fd, (struct sockaddr* )&info,&len) == -1)
return 0;
memcpy(&my_addr, (char *)&info.sin_addr.s_addr,sizeof(my_addr));
my_addr=htonl(my_addr);
return my_addr;
}
unsigned short int tSocket::get_port() {
return htons(info.sin_port);
};
void set_nonblock_flag (int desc, int value){
int oldflags = fcntl (desc, F_GETFL, 0);
/* If reading the flags failed, return error indication now. */
if (oldflags == -1)
return;
/* Set just the flag we want to set. */
if (value != 0)
oldflags |= O_NONBLOCK;
else
oldflags &= ~O_NONBLOCK;
/* Store modified flag word in the descriptor. */
fcntl (desc, F_SETFL, oldflags);
};
bool tSocket::connect_impl(){
set_nonblock_flag(fd,1);
int len=sizeof(info);
connect(fd, (struct sockaddr *)&info, len);
if (wait_for_write(50))
return false;
int a;
len=sizeof(a);
if (getsockopt(fd,SOL_SOCKET,SO_ERROR,&a,(socklen_t*)&len) || a)
return false;
return true;
};
int tSocket::open_port(const char *host, guint16 port) {
DBC_RETVAL_IF_FAIL(host!=NULL,SOCKET_CANT_CONNECT);
d4x::USR1Off2On sig_unlocker_;
if (!constr_name(host,port)) return SOCKET_UNKNOWN_HOST;
if ((fd = socket(info.sin_family,SOCK_STREAM, 0)) < 0)
return(SOCKET_CANT_ALLOCATE);
int a=1;
setsockopt(fd,SOL_SOCKET,SO_KEEPALIVE,(char *)&a,sizeof(a));
setsockopt(fd,SOL_SOCKET,SO_KEEPALIVE,(char *)&a,sizeof(a));
size_t sl=2000; //set receive buffer to default+30% MTU size
setsockopt(fd,SOL_SOCKET,SO_RCVBUF,(char *)&sl,sizeof(sl));
if (!connect_impl())
return(SOCKET_CANT_CONNECT);
con_flag=1;
return 0;
}
int tSocket::open_port(int *ftp_addr) {
DBC_RETVAL_IF_FAIL(ftp_addr!=NULL,SOCKET_CANT_CONNECT);
unsigned char addr[6];
for (int i=0;i<6;i++) addr[i]=(unsigned char)(ftp_addr[i]&0xff);
unsigned long int host=0;
unsigned short int port=0;
memcpy((char *)&host,addr,4);
memcpy((char *)&port,addr+4,2);
return(open_port(host,port));
}
int tSocket::open_port(guint32 host,guint16 port) {
d4x::USR1Off2On sig_unlocker_;
port=htons(port);
// host=htonl(host);
if (!constr_name(NULL,port)) return SOCKET_UNKNOWN_HOST;
memcpy((char *)&info.sin_addr.s_addr,&host, sizeof(host));
if ((fd = socket(info.sin_family,SOCK_STREAM, 0)) < 0)
return(SOCKET_CANT_ALLOCATE);
int a=1;
setsockopt(fd,SOL_SOCKET,SO_KEEPALIVE,(char *)&a,sizeof(a));
if (!connect_impl())
return(SOCKET_CANT_CONNECT);
con_flag=1;
return 0;
}
int tSocket::open_any(const char *host) {
d4x::USR1Off2On sig_unlocker_;
DBC_RETVAL_IF_FAIL(host!=NULL,SOCKET_CANT_CONNECT);
constr_name(NULL,0);
if ((fd = socket(info.sin_family,SOCK_STREAM, 0)) < 0)
return(-1);
int a=1;
setsockopt(fd,SOL_SOCKET,SO_KEEPALIVE,(char *)&a,sizeof(a));
if (!constr_name(host,0)) return -2;
if (bind(fd, (struct sockaddr *)&info, (socklen_t)sizeof(info)) < 0)
return(-3);
if (listen(fd,1)) return(-4);
return 0;
};
int tSocket::open_any(guint32 host) {
d4x::USR1Off2On sig_unlocker_;
constr_name(NULL,0);
host=htonl(host);
memcpy((char *)&info.sin_addr.s_addr,&host, sizeof(host));
if ((fd = socket(info.sin_family,SOCK_STREAM, 0)) < 0)
return(-1);
int a=1;
setsockopt(fd,SOL_SOCKET,SO_KEEPALIVE,(char *)&a,sizeof(a));
if (bind(fd, (struct sockaddr *)&info, sizeof(info)) < 0)
return(-2);
if (listen(fd,1))
return(-3);
return 0;
};
int tSocket::wait_for_read(int len) {
FD_ZERO(&set);
FD_SET(fd,&set);
timeval tv;
tv.tv_sec=len;
tv.tv_usec=0;
if (select(fd+1,&set,NULL,NULL,&tv)>0) return 0;
con_flag=0;
return -1;
};
int tSocket::wait_for_write(int len) {
FD_ZERO(&set);
FD_SET(fd,&set);
timeval tv;
tv.tv_sec=len;
tv.tv_usec=0;
if (select(fd+1,NULL,&set,NULL,&tv)>0) return 0;
con_flag=0;
return -1;
};
void tSocket::flush(){
char *a;
FD_ZERO(&set);
FD_SET(fd,&set);
timeval tv;
tv.tv_sec=0;
tv.tv_usec=0;
while (select(1,&set,NULL,NULL,&tv)>0)
read(fd,&a,1);
};
int tSocket::accepting(const char * host) {
DBC_RETVAL_IF_FAIL(host!=NULL,-1);
sockaddr_in addr;
#if defined(__sparc__) && !(defined(__linux__)) && !(defined(BSD))
int len=sizeof(addr);
#else
socklen_t len=sizeof(addr);
#endif
int oldfd=fd;
if ((fd=accept(fd,(sockaddr *)&addr,&len))<0) {
return -1;
}
if (oldfd>0) {
close(oldfd);
};
con_flag=1;
return 0;
};
int tSocket::direct_send(char *what){
return(send(fd,what,strlen(what),0));
};
int tSocket::send_string(const char * what,int timeout) {
DBC_RETVAL_IF_FAIL(what!=NULL,-1);
int a=strlen(what);
int b=send(fd,what,a,0);
if (b<0) return -1;
if (wait_for_write(timeout)) {
return STATUS_TIMEOUT;
};
SBytes+=a-b;
return a-b;
};
fsize_t tSocket::lowlevel_read(char *where,fsize_t bytes){
return recv(fd,where,bytes,0);
};
fsize_t tSocket::rec_string(char * where,fsize_t len,int timeout) {
DBC_RETVAL_IF_FAIL(where!=NULL,-1);
d4x::USR1Off2On sig_unlocker_;
if (wait_for_read(timeout))
return STATUS_TIMEOUT;
tDownload **download=my_pthread_key_get();
fsize_t bytes;
if (download!=NULL && *download!=NULL && (CFG.SPEED_LIMIT!=3 || (*download)->SpeedLimit->base>0 || (*download)->SpeedLimit->base2>0))
bytes=(*download)->SpeedLimit->bytes >= len ? len: (*download)->SpeedLimit->bytes+1;
else
bytes=len;
fsize_t temp=lowlevel_read(where,bytes);
if (temp>0) {
d4x::USR1On2Off sig_locker_();
RBytes+=temp;
GVARS.MUTEX.lock();
GVARS.READED_BYTES+=temp;
GVARS.MUTEX.unlock();
if (download!=NULL && *download!=NULL){
tDownload *dwn=*download;
if (dwn->split && dwn->split->grandparent){
dwn->split->grandparent->SpeedCalc.inc(temp);
tDownload *par=dwn->split->grandparent;
if (par->myowner && par->myowner->PAPA)
par->myowner->PAPA->speed.inc(temp);
}else{
dwn->SpeedCalc.inc(temp);
if (dwn->myowner && dwn->myowner->PAPA)
dwn->myowner->PAPA->speed.inc(temp);
};
if (CFG.SPEED_LIMIT!=3 || dwn->SpeedLimit->base>0 || dwn->SpeedLimit->base2>0)
dwn->SpeedLimit->decrement(temp);
D4X_UPDATE.add(dwn);
};
};
return temp;
};
void tSocket::down() {
if (fd>=0) {
shutdown(fd,2);
close(fd);
};
fd=-1;
RBytes=SBytes=0;
};
int tSocket::connected(){
return(con_flag);
};
int tSocket::readed_bytes() {
return RBytes;
};
tSocket::~tSocket() {
if (buffer) delete[] buffer;
down();
};
syntax highlighted by Code2HTML, v. 0.9.1