Странная проблема с сокетами

Модератор: Модераторы разделов

frp
Сообщения: 1445
ОС: Debian Squeeze

Странная проблема с сокетами

Сообщение frp »

Сервер:

Код:

#include <unistd.h> #include <sys/socket.h> #include <sys/types.h> #include <netinet/in.h> #include <netdb.h> #include <string> #include <cstring> #include <iostream> #include <cstdio> #include <pthread.h> #include <sys/poll.h> #include <signal.h> #include <cstdlib> #include <errno.h> using namespace std; int readpipe[2],writepipe[2]; int sfd; int cfd; bool inst=true; void* recv_tcp_func(void* arg); void* recv_pipe_func(void* arg); int main() { sfd=socket(AF_INET,SOCK_STREAM,0); if(sfd<0){cout<<"socket";return 0;} int sdsffs=1; setsockopt(sfd,SOL_SOCKET,SO_REUSEADDR,&sdsffs,sizeof(sdsffs)); sockaddr_in addr,caddr; memset(&addr,sizeof(addr),0); addr.sin_family=AF_INET; addr.sin_port=htons(7905); addr.sin_addr.s_addr=htonl(INADDR_ANY); int br; br=bind(sfd,(sockaddr*)&addr,sizeof(addr)); if(br<0){cout<<"bind";return 0;} br=listen(sfd,5); if(br<0){cout<<"listen";return 0;} socklen_t cfdl; cfd=accept(sfd,(sockaddr*)&caddr,&cfdl); if(cfd<0) { /*perror("accept");return 0;*/ int e=errno; switch(e) { case EAGAIN:cout<<"AGAIN";break; case EBADF:cout<<"BADF";break; case ENOTSOCK:cout<<"NOTSOCK";break; case EOPNOTSUPP:cout<<"OPNOTSUPP";break; case EINTR:cout<<"INTR";break; case ECONNABORTED:cout<<"CONNABORTED";break; case EINVAL:cout<<"INVAL";break; case EMFILE:cout<<"MFILE";break; case ENFILE:cout<<"NFILE";break; case ENOMEM:cout<<"NOMEM";break; case ENOBUFS:cout<<"NOBUFS";break; case EPROTO:cout<<"PROTO";break; case EPERM:cout<<"PERM";break; } return 0; } pipe(readpipe); pipe(writepipe); char suffix[100]; sprintf(suffix,"<&%d >&%d",readpipe[0],writepipe[1]); string cmd="pppd nodetach notty noauth"; cmd+=suffix; int pid=fork(); if(pid==0) { system(cmd.c_str()); return 0; } pthread_t t1,t2; pthread_create(&t1,NULL,recv_tcp_func,NULL); pthread_create(&t2,NULL,recv_pipe_func,NULL); while(inst) { sleep(1); } close(cfd); close(sfd); kill(pid,SIGKILL); close(readpipe[0]);close(readpipe[1]); close(writepipe[0]);close(writepipe[1]); return 0; } void* recv_tcp_func(void* arg) { char buf[65536]; pollfd sfdp; while(1) { sfdp.fd=cfd; sfdp.events=POLLIN; poll(&sfdp,1,-1); if(sfdp.revents&POLLIN>0) { int bcnt=recv(cfd,buf,65536,0); if(bcnt<=0) { inst=false; return arg; } else write(readpipe[1],buf,bcnt); } } return arg; } void* recv_pipe_func(void* arg) { char buf[65536]; pollfd sfdp; while(inst) { sfdp.fd=writepipe[0]; sfdp.events=POLLIN; poll(&sfdp,1,-1); if(sfdp.revents&POLLIN>0) { int bcnt=read(writepipe[0],buf,65536); send(cfd,buf,bcnt,0); } } return arg; }

Клиент:

Код:

#include <unistd.h> #include <sys/socket.h> #include <sys/types.h> #include <netinet/in.h> #include <netdb.h> #include <string> #include <cstring> #include <iostream> #include <cstdio> #include <pthread.h> #include <sys/poll.h> #include <signal.h> #include <cstdlib> #include <netdb.h> #include <errno.h> using namespace std; int readpipe[2],writepipe[2]; int sfd; int cfd; bool inst=true; void* recv_tcp_func(void* arg); void* recv_pipe_func(void* arg); int main(int argc,char** argv) { if(argc==0)return -1; cfd=socket(AF_INET,SOCK_STREAM,0); if(cfd<0){cout<<"socket";return 0;} int br; addrinfo hints,*addr; memset(&hints,0,sizeof(hints)); hints.ai_family=AF_INET; hints.ai_socktype=SOCK_STREAM; hints.ai_flags=AI_ADDRCONFIG; getaddrinfo(argv[1],NULL,&hints,&addr); ((sockaddr_in*)(addr->ai_addr))->sin_port=htons(7905); br=connect(cfd,addr->ai_addr,addr->ai_addrlen); // if(br<0){cout<<"connect";return 0;} br=pipe(readpipe); if(br<0){cout<<"readpipe";return 0;} br=pipe(writepipe); if(br<0){cout<<"writepipe";return 0;} char suffix[100]; sprintf(suffix,"<&%d >&%d",readpipe[0],writepipe[1]); string cmd="pppd updetach noauth passive notty ipparam vpn 10.0.0.1:10.0.0.2"; cmd+=suffix; int pid=fork(); if(pid==0) { system(cmd.c_str()); return 0; } pthread_t t1,t2; pthread_create(&t1,NULL,recv_tcp_func,NULL); pthread_create(&t2,NULL,recv_pipe_func,NULL); while(inst) { sleep(1); } close(cfd); kill(pid,SIGKILL); close(readpipe[0]);close(readpipe[1]); close(writepipe[0]);close(writepipe[1]); return 0; } void* recv_tcp_func(void* arg) { char buf[65536]; pollfd sfdp; while(1) { sfdp.fd=cfd; sfdp.events=POLLIN; poll(&sfdp,1,-1); if(sfdp.revents&POLLIN>0) { int bcnt=recv(cfd,buf,65536,0); /* if(bcnt<=0) { inst=false; return arg; } else*/ write(readpipe[1],buf,bcnt); } } return arg; } void* recv_pipe_func(void* arg) { char buf[65536]; pollfd sfdp; while(inst) { sfdp.fd=writepipe[0]; sfdp.events=POLLIN; poll(&sfdp,1,-1); if(sfdp.revents&POLLIN>0) { int bcnt=read(writepipe[0],buf,65536); send(cfd,buf,bcnt,0); } } return arg; }


Почему-то постоянно у сервера EINVAL на accept (странно, что сервер ожидает соединений, а потом при соединении у сервера ошибка, а у клиента в connect при этом ошибки не происходит). В чем причина странного поведения? Как исправить?
Когда я только начинал писать прогру, то глюка не было.
Если важно, то программа должна создавать PPP-соединение через tcp.Когда я только начинал писать прогру, то глюка не было
PS. Для испытания использовался компьютер с VirtualBox и tap-интерфейс как сеть. Клиент запускаля в VirtualBox, сервер - просто на компьютере.
Спасибо сказали:
Аватара пользователя
Red User
Сообщения: 229
ОС: Debian

Re: Странная проблема с сокетами

Сообщение Red User »

(man 2 accept) писал(а):EINVAL Socket is not listening for connections, or addrlen is invalid (e.g., is negative).
cfdl надо инициализировать.
А ведь когда-то не боялись мы программы любой,
И с одним лишь debug'ом выходили на бой,
И искусно написанный вирус встречали как брата
Спасибо сказали:
frp
Сообщения: 1445
ОС: Debian Squeeze

Re: Странная проблема с сокетами

Сообщение frp »

Спасибо. Все работает. Но возникла одна проблема - как потом убить pppd?
PS. У меня в man не так написано:
EINVAL Сокет не слушает соединения.
Спасибо сказали:
Аватара пользователя
Red User
Сообщения: 229
ОС: Debian

Re: Странная проблема с сокетами

Сообщение Red User »

frp писал(а):
20.04.2009 11:13
Но возникла одна проблема - как потом убить pppd?

Наверное, надо отправить ему сигнал.
А ведь когда-то не боялись мы программы любой,
И с одним лишь debug'ом выходили на бой,
И искусно написанный вирус встречали как брата
Спасибо сказали:
frp
Сообщения: 1445
ОС: Debian Squeeze

Re: Странная проблема с сокетами

Сообщение frp »

Само собой понятно. Но для этого желательно узнать его PID. Есть еще одна идея:

Код: Выделить всё

system("killall pppd");
Спасибо сказали:
Аватара пользователя
Red User
Сообщения: 229
ОС: Debian

Re: Странная проблема с сокетами

Сообщение Red User »

frp писал(а):
20.04.2009 16:20
Но для этого желательно узнать его PID.

fork возвращает pid. Если запускать pppd с nodetach, то он вроде бы должен убиваться по SIGTERM или SIGINT.
Вот как-то так надо:

Код: Выделить всё

pid = fork();
switch (pid)
{
case 0:
    execlp("pppd", "pppd", "nodetach", "notty", "noauth", NULL);
    perror("execlp");
    return 1;
case -1:
    perror("fork");
    return 1;
}
kill(pid, SIGINT);
wait(NULL);
А ведь когда-то не боялись мы программы любой,
И с одним лишь debug'ом выходили на бой,
И искусно написанный вирус встречали как брата
Спасибо сказали:
frp
Сообщения: 1445
ОС: Debian Squeeze

Re: Странная проблема с сокетами

Сообщение frp »

Я и так убиваю процесс, порожденный fork(), но pppd при этом не умирает.
У меня возникла еще одна проблема - мне нужно, чтобы клиент через мою программу мог соединятся не только с сервером, а и с другими компьютерами (чтобы моя программа действовала как VPN). Как такое сделать?
Спасибо сказали:
Аватара пользователя
Red User
Сообщения: 229
ОС: Debian

Re: Странная проблема с сокетами

Сообщение Red User »

frp писал(а):
20.04.2009 22:04
Я и так убиваю процесс, порожденный fork(), но pppd при этом не умирает.

Ты пробовал запускать pppd с помощью exec*?
А ведь когда-то не боялись мы программы любой,
И с одним лишь debug'ом выходили на бой,
И искусно написанный вирус встречали как брата
Спасибо сказали:
frp
Сообщения: 1445
ОС: Debian Squeeze

Re: Странная проблема с сокетами

Сообщение frp »

Ты пробовал запускать pppd с помощью exec*?

Нет.

Если прописать route add default gw 10.0.0.1 на стороне клиента, то можно получить доступ к серверу по адресу из любого интерфейса. Как получить доступ к другим компьютерам?
Этот вопрос больше относиться к маршрутизации, чем к программированию.
Спасибо сказали:
frp
Сообщения: 1445
ОС: Debian Squeeze

Re: Странная проблема с сокетами

Сообщение frp »

Проблему решил с помощью NAT.
Спасибо сказали:
Ism
Сообщения: 1261
Статус: Никто, по сути быдло

Re: Странная проблема с сокетами

Сообщение Ism »

route add -net 10.0.0.0 netmask 255.0.0.0 gw *.*.*.*(your default gateway) 10.0.0.0 твоя подсеть
Спасибо сказали: