Proxy Wrapper: Оцените программку (proxy example socket)
Ключевые слова: proxy , example , socket , (найти похожие документы )
_ RU.UNIX (2:5077/15.22) _____________________________________________ RU.UNIX _
From : Alexei Yesipenko 2:5061/109.61 18 Jun 99 09:34:54
Subj : Proxy Wrapper: Оцените программку
________________________________________________________________________________
Hello All.
Хочу услышать ваше мнение по поводу первой моей программки под Unix.
Ситуация такая: имеется proxy c выходом в инет; имеется машинка
под Linux box, которой позволено ходить на proxy;
Цель программы: программа должна позволять хождение с моей машины
(Win95) в инет, с использованием IE или NN, при
условии если я имею логин на машину с Linuxом.
Перенаправление пакетов через ядро реализовать нельзя, т.к. ядро
старое - 2.0.30.
Вот собственно, какую программку я для этого придумал.
=== Cut ===
#define PORT_IN 8983
#define PORT_OUT 8080
#include <string.h>
#include <sys/types.h>
#include <sys/time.h>
#include <sys/wait.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <fcntl.h>
#include <netdb.h>
#include <unistd.h>
#include <errno.h>
#include <netinet/in.h>
#include <stdlib.h>
#include <unistd.h>
#include <pbmplus.h>
#include <signal.h>
int connect_proxy(char *name)
{
struct hostent *host;
struct sockaddr_in s_addr;
int sock;
host = gethostbyname(name);
if (!host)
return -1;
if ( (sock = socket(AF_INET,SOCK_STREAM,0)) == -1 )
return -1;
s_addr.sin_family = AF_INET;
s_addr.sin_port = htons( PORT_OUT );
memcpy((char*)&s_addr.sin_addr,host->h_addr_list[0],host->h_length);
if ( connect(sock,(struct sockaddr*)&s_addr,sizeof(s_addr)) == -1 ) {
close(sock);
return -1;
}
return sock;
}
int setup_server()
{
int sock;
struct sockaddr_in s_addr;
if ( (sock=socket(AF_INET,SOCK_STREAM,0)) == -1 ) {
perror("call socket() error");
return -1;
}
memset(&s_addr,0,sizeof(s_addr));
s_addr.sin_family = AF_INET;
s_addr.sin_addr.s_addr = INADDR_ANY;
s_addr.sin_port = htons(PORT_IN);
if ( bind(sock,(struct sockaddr *)&s_addr,sizeof(s_addr)) == -1 ) {
perror("call bind() error");
Err:
close(sock);
return -1;
}
if ( listen(sock,5) == -1 ) {
perror("call listen() error");
goto Err;
}
puts("Server ready...");
return sock;
}
int run_server(int sock,char* proxy)
{
struct timeval tv;
int p_sock = connect_proxy(proxy);
int fl_quit = 0,r;
char *buff_pr = malloc(8*1024);
char *buff_cl = malloc(8*1024);
int blen_pr, blen_cl;
if ( (p_sock != -1) && buff_pr && buff_cl ) {
fcntl(sock, F_SETFL, O_NONBLOCK);
fcntl(p_sock, F_SETFL, O_NONBLOCK);
while (!fl_quit) {
r = 0;
blen_cl = recv(sock,buff_cl,8*1024,0);
if ( blen_cl == 0 ) fl_quit = 1;
if ( blen_cl == -1 && errno == EWOULDBLOCK )
blen_cl = 0, r++;
blen_pr = recv(p_sock,buff_pr,8*1024,0);
if ( blen_pr == 0 ) fl_quit = 1;
if ( blen_pr == -1 && errno == EWOULDBLOCK )
blen_pr = 0, r++;
if ( r == 2 ) {
tv.tv_sec = 0;
tv.tv_usec = 100;
select(0,NULL,NULL,NULL,&tv);
} else {
if (blen_cl)
if ( blen_cl == -1 ||
send( p_sock,buff_cl,blen_cl,0) == -1)
fl_quit = 1;
if (blen_pr)
if ( blen_pr == -1 ||
send( sock,buff_pr,blen_pr,0) == -1)
fl_quit = 1;
}
}
close(p_sock);
}
if (buff_pr) free(buff_pr);
if (buff_cl) free(buff_cl);
close(sock);
}
int main(int argc, char **argv)
{
int sock,c_sock,s_addr_len,pid;
struct sockaddr_in s_addr;
if (argc == 2) {
if ( (sock=setup_server()) != -1 ) {
for(;;) {
memset(&s_addr,0,s_addr_len = sizeof(s_addr));
if ( (c_sock = accept(sock,
(struct sockaddr*)&s_addr,
&s_addr_len)) == -1) {
perror("call accept() error");
return 1;
}
fprintf(stderr,"Connect from %s\n",
inet_ntoa(s_addr.sin_addr));
while ( (waitpid(-1,&pid,WNOHANG) != -1)
&& WIFEXITED(pid) );
if ( (pid = fork()) == -1 ) {
perror("call fork() error");
return 1;
}
if ( !pid ) {
close(sock);
run_server(c_sock,argv[1]);
exit(0);
}
close(c_sock);
}
}
} else puts("Usage: proxysrv <proxy_host_name>");
return 0;
}
=== Cut ===
Правильно ли я избавляюсь от зомби?
При работе с IE иногда вылетает странная ошибка:
call accept() error: Connection reset by peer
Как правильно и проще закрывать порты при Ctrl-C?
WBR, Alexei.
---
* Origin: -= YesAl station =- (2:5061/109.61)
_ RU.UNIX (2:5077/15.22) _____________________________________________ RU.UNIX _
From : Oleg Derevenetz 2:5025/3.4 18 Jun 99 13:13:28
Subj : Proxy Wrapper: Оцените программку
________________________________________________________________________________
Hello Alexei!
At 18 Jun 99 09:34:54, Alexei Yesipenko wrote to All:
AY> Правильно ли я избавляюсь от зомби?
Вообще-то говоря, совсем правильно было бы повесить следующий обработчик на
SIGCHLD :
void KillZombies (int)
{
int Status;
waitpid (-1, &Status, WHOHANG);
signal (SIGCHLD, KillZombies);
}
AY> При работе с IE иногда вылетает странная ошибка:
AY> call accept() error: Connection reset by peer
С чьей стороны ? IE или твоей программы ?
AY> Как правильно и проще закрывать порты при Ctrl-C?
Повесить обработчик на SIGINT.
> [KILL THE YANKEE TEAM] [Team 5 колонну давить]
--- QDed beta v1.3 under FreeBSD 3.1-STABLE
* Origin: Взялся за гуж - полезай в кузов... (2:5025/3.4)
_ RU.UNIX (2:5077/15.22) _____________________________________________ RU.UNIX _
From : Michael Kondrashin 2:5020/128 24 Jun 99 13:00:02
Subj : Re: Proxy Wrapper: Оцените программку
________________________________________________________________________________
From: aplog@corbina.ru (Michael Kondrashin)
> > Плохо. Hекотоpые системы (не буду упоминать) стpадают тем, что могут выдать
> > положительный pезультат по select() и затем заблокиpовать recv(). Так что
> > безусловно лучше даже пpи select'е пользовать NONBLOCK.
>
Hадо попробывать сформулировать здесь "идеальный" цикл для этой задачи.
Всем кто может чего-либо посоветовать: подправте и опубликуйте.
Мой вариант:
for(;;) {
FD_ZERO(&fdset);
FD_SET(s1, &fdset);
FD_SET(s2, &fdset);
rc = select(max, &fdset, 0, 0, 0);
if( rc == -1 ) {
if( errno == EINTR ) continue;
printf("Error calling select: %s\n", strerror(errno));
return 1;
}
if( FD_ISSET(s, &fdset) ) {
int err = copy(s1, s2);
switch( err ) {
case 1:
puts("1 closed connection")
return 0;
case 0:
if( rc == 1) continue;
default:
return err;
}
}
if( FD_ISSET(s2, &fdset) ) {
int err = copy(s2, s1);
switch( err ) {
case 1:
puts("2 closed connection")
return 0;
case 0:
continue;
default:
return err;
}
}
puts("Select cycle internal error");
return 1;
}
--------------------
int copy(int from, int to)
{
int i_sz, o_sz;
char buf[BUF_SIZE];
i_sz = recv(from, buf, BUF_SIZE, 0);
if( i_sz == 0 ) return 1; // Connection closed
if( i_sz == -1 ) {
if( errno == ECONNRESET ) return 1; // Is it right?
printf("Error calling recv: %s\n", strerror(errno));
return 2;
}
o_sz = send(to, buf, i_sz, 0);
if( o_sz == -1 ) {
printf("Error calling send: %s\n", strerror(errno));
return 3;
}
if( i_sz != o_sz ) { // How this can heaped?
printf("Read %d bytes, wrote %d", i_sz, o_sz);
return 4;
}
return 0;
}
Здесь не хватает
-учета продлемы поднятой в цитате
-send то же может быть заблокирован.
-Что еще?
--- ifmail v.2.10dev
* Origin: Applied Logistics (2:5020/128@fidonet)
_ RU.UNIX (2:5077/15.22) _____________________________________________ RU.UNIX _
From : Valentin Nechayev 2:5020/400 25 Jun 99 12:44:14
Subj : Re: Proxy Wrapper: Оцените программку
________________________________________________________________________________
From: "Valentin Nechayev" <nx@nn.kiev.ua >
Reply-To: nx@nn.kiev.ua
Hello Michael Kondrashin!
At 24-Jun-99 12:00, Michael Kondrashin wrote:
> rc = select(max, &fdset, 0, 0, 0);
> if( rc == -1 ) {
> if( errno == EINTR ) continue;
> printf("Error calling select: %s\n", strerror(errno));
> return 1;
А вот pугаться тут незачем - ошибка в select'е некpитична
> }
>
> if( FD_ISSET(s, &fdset) ) {
Кто такой s?
> int err = copy(s1, s2);
> switch( err ) {
[skip]
Ох вы боги мои...
#define BS 1000
char lr_buf[BS], rl_buf[BS];
int leof, reof, lr_pos, rl_pos, lr_cnt, rl_cnt;
leof = reof = lr_pos = rl_pos = lr_cnt = rl_cnt = 0;
for(;;) {
if( leof && reof ) return "total eof";
if( fdLeft < FD_SETSIZE && fdRight < FD_SETSIZE ) {
fd_set fdr, fdw; struct timeval tv;
int maxfd = fdLeft > fdRight ? fdLeft : fdRight;
int got;
/* Ожидание */
FD_ZERO( &fdr ); FD_ZERO( &fdw );
if( lr_cnt < BS ) FD_SET( fdLeft, &fdr );
if( lr_cnt > 0 ) FD_SET( fdRight, &fdw );
if( rl_cnt < BS ) FD_SET( fdRight, &fdr );
if( rl_cnt > 0 ) FD_SET( fdLeft, &fdw );
tv.tv_sec = 4; tv.tv_usec = 0;
select( maxfd+1, &fdr, &fdw, NULL, &tv );
/* Hоpмализация буфеpов */
if( lr_pos > 0 ) {
memmove( lr_buf, lr_buf + lr_pos, lr_cnt );
lr_pos = 0;
}
if( rl_pos > 0 ) {
memmove( rl_buf, rl_buf + rl_pos, rl_cnt );
rl_pos = 0;
}
/* Чтение/запись */
if( FD_ISSET( fdLeft, &fdr ) ) {
rc = read( fdLeft, lr_buf + lr_pos + lr_cnt, BS - lr_buf - lr_cnt );
if( rc == -1 && errno != EINTR && errno != EWOULDBLOCK &&
errno != EAGAIN )
return "error";
if( rc == 0 ) l_eof = 1;
if( rc > 0 ) lr_cnt += rc;
}
if( FD_ISSET( fdRight, &fdr ) ) {
rc = read( fdRight, rl_buf + rl_pos + rl_cnt, BS - rl_buf - rl_cnt );
if( rc == -1 && errno != EINTR && errno != EWOULDBLOCK && errno
!= EAGAIN )
return "error";
if( rc == 0 ) r_eof = 1;
if( rc > 0 ) rl_cnt += rc;
}
if( FD_ISSET( fdLeft, &fdw ) ) {
rc = write( fdLeft, rl_buf + rl_pos, rl_cnt );
if( rc == -1 && errno != EINTR && errno != EWOULDBLOCK && errno
!= EAGAIN )
return "error";
if( rc > 0 ) rl_pos += rc, rl_cnt -= rc;
}
if( FD_ISSET( fdRight, &fdw ) ) {
rc = write( fdRight, lr_buf + lr_pos, lr_cnt );
if( rc == -1 && errno != EINTR && errno != EWOULDBLOCK && errno
!= EAGAIN )
return "error";
if( rc > 0 ) lr_pos += rc, lr_cnt -= rc;
}
Все. Отлаживайте и пускайте.
--
NN
--- ifmail v.2.14dev3
* Origin: unknown (2:5020/400)
_ RU.UNIX (2:5077/15.22) _____________________________________________ RU.UNIX _
From : Alexei Yesipenko 2:5061/109.61 28 Jun 99 09:48:44
Subj : Proxy Wrapper: Оцените программку
________________________________________________________________________________
Hello Valentin.
Пят Июн 25 1999 12:44, Valentin Nechayev wrote to Michael Kondrashin:
VN> /* Hоpмализация буфеpов */
VN> if( lr_pos > 0 ) {
VN> memmove( lr_buf, lr_buf + lr_pos, lr_cnt );
VN> lr_pos = 0;
VN> }
VN> }
Что так сложно-то?
Попробую предложить второй ошибочный вариант, но попроще...
=== Cut ===
#define CP_BUFF_SZ 2048
int cp_sock(int to, int from)
{
struct timeval tv;
char buf[CP_BUFF_SZ];
fd_set fdr,fdw;
int r,sz;
FD_ZERO(&fdr);
FD_SET(to,&fdr);
FD_SET(from,&fdr);
tv.tv_sec = 10;
tv.tv_usec = 0;
if ( r = select( (from>to?from:to)+1, &fdr, NULL, NULL, &tv) ) {
if (r<0) return 1;
if ( FD_ISSET(from, &fdr) ) {
sz = recv(from,buf,CP_BUFF_SZ,0);
if (sz<=0) return 2;
FD_ZERO(&fdw);
FD_SET(to,&fdw);
tv.tv_sec = 10;
tv.tv_usec = 0;
if ( select(to+1, NULL, &fdw, NULL, &tv) <= 0
|| send(to,buf,sz,0) <= 0 )
return 3;
}
}
return 0;
}
// А вот цикл:
while( !(cp_sock(p_sock,sock)
||cp_sock(sock,p_sock)) );
=== Cut ===
Вообще то, это не критично.
Меня другая проблема интересует. Как корректно выйти из этой программки?
Shutdown с последующим close не работает.
Если был хоть один коннект со стороны клиента, то последующий запуск
сервера (после Ctrl-C) вылетает c ошибкой bind(), что данный сокет
уже используется.
Хотя это тоже не критично, секунд через 30 сокет сам освобождается,
но хотелось бы знать как это в принципе работает.
И еще. А есть ли книга или faq типа "Программирование под UNIX для
программистов под DOS"?
В Unixe прекрасный инструментарий, например strace.
WBR, Alexei.
---
* Origin: -= YesAl station =- (FidoNet 2:5061/109.61)
1 , Аноним (1 ), 16:15, 16/12/2002 [ответить ]
+ /–
try to set SO_REUSEADDR socket option
2 , Senka (? ), 22:34, 23/03/2003 [ответить ]
+ /–
Условие такое же, но стоит NT у нее закрыты все порты (кроме системных). Нужно что бы эта прога коннектилась из под Linux к тачке, открывала порт, а затем его слушала. Если начинают поступать запросы , она начинает передавать данные (запросы могут быть как от браузера, так и от ssh клиента).