LINUX.ORG.RU

[СИ]select и разрешение имен хостов

 


0

0

[СИ]select и разрешение имен хостов

Язык СИ
ОС UNIX

Продолжение темы.
На странице 811 был вопрос о select
и о разрешении имен хостов без подвисания.
Anonymous посоветовал libasyncns,
и я написал там, что все в порядке.

Я погорячился.
Мало того что сложно, так еще, как я понял,
там создается дополнительный процесс
для каждого запроса.
А это противоречит намерениям.

И мыслится подходящим делать прямые запросы
сервера DNS (из тех, что в файле /etc/resolv.conf)
через UDP-сокеты и подключать эти запросы
к центральному select-у.
Трудно только распарсить ответы DNS,
кроме самых простых.
Нет хорошего описания форматов ответов.
Пользуюсь пока этим:
http://www.crossplatform.ru/documentation/tcp_ip/glava14.php
но здесь не доходчивое и не исчерпывающее.

Не посоветует ли кто-нибудь описания получше?


Так может проще на отдельном треде/в отдельном процессе получать то что вам надо? Зачем реализовывать протокол, когда один лишний тред будет производить запросы, выбирая их из очереди и не останавливать выполнения основного процесса?

rymis ★★
()

Ну и гугл тоже открыть не помешает. Говорят, мощный инструмент. Особенно если в него вбить что-то на вроде 'Asynchronoys dns resolver'.

bibi
()

Это же стихи!

anonymous
()

Малопроцессный подразумевает: один процесс сервера обслуживает несколько клиентов.


Не пробывал для каждого щёлкать отдельный процесс?!

З.Ы. Хоть кусок кода показыл бы :)

Boy_from_Jungle ★★★★
()
Ответ на: комментарий от Alesh

proba





#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <sys/wait.h>
#include <errno.h>
#include <fcntl.h>
#include <time.h>
#include <signal.h>
#include <arpa/inet.h>
#include <pwd.h>
#include <unistd.h>
#include <sys/stat.h>
#include <unistd.h>
#include <sys/select.h>

#include <arpa/nameser.h>
//#include <resolv.h>

//#include <sys/resource.h>
#include <netdb.h>


//  gcc forum_my_dns.c -o forum_my_dns.cgi
//  ./forum_my_dns.cgi


int atoi_buf(int i, const char *buf, int len , int *ret);

int err=0, err0=0, Serr=300;
char cerr[300];


//-------------------------- main ---------------------------------

int main()

{

	const char *ip_dns="12.34.23.45";  //--- DNS-server ---


	const char *f="test.txt";

	int sd, fd;
    short id, flags;
    int k, dl;
    char buf[500], query[500], data[500];
    struct sockaddr_in  addr_dns, addr;
    unsigned long hostAddr;
    int type;
    struct hostent *hp;
    const char *pbuf;
    char dname[500];


    fd=open(f,O_RDWR|O_CREAT|O_TRUNC,00666);
    if(fd<0){ printf("fd=open(%s)=%d\n",f,fd); exit(0);}

    printf("\n--------------------------------------\n");

start:

    ftruncate(fd,0);

	pbuf=fgets(buf, sizeof(buf), stdin);
	if(pbuf==NULL){strcpy(buf,"pbuf=NULL\n");}

	//printf("Stroka:\n%s",buf);

	k=strlen(buf);
	if(k>0 && buf[k-1]=='\n')buf[k-1]=0;
    strcpy(dname,buf);


    hp=gethostbyname(dname);
    if(hp==NULL){ printf("hp==NULL\n"); exit(0);}
    memcpy(&addr.sin_addr, hp->h_addr_list[0], hp->h_length);
    printf(
		"gethostbyname()\n"
		"%s ==> %s\n\n"
		,hp->h_name, inet_ntoa(addr.sin_addr));


    type=1;

    k=res_mkquery(QUERY, dname, type, 1, data, sizeof(data), NULL, buf, sizeof(buf));
    //printf("k=res_mkquery()=%d\n",k);

    dl=k;
/*
    if(k>0){
        write(fd,buf,dl);
	}
*/
	dl=k;


	bzero(&addr_dns,sizeof(addr_dns));
	hostAddr=inet_addr(ip_dns);
	if((long)hostAddr!=(long)-1)bcopy(&hostAddr,&addr_dns.sin_addr,sizeof(hostAddr));
	else{ printf("hostAddr=%d\n",hostAddr); exit(0);}

    addr_dns.sin_port=htons(53);//htons конвертирует порядок байт
    addr_dns.sin_family=AF_INET;

	sd=socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
	//printf("\n\nsd=socket()=%d\n");
	if(sd<0){ printf("sd=make_socket_ip()=%d\n"); exit(0);}

	k=sendto(sd,buf,dl,0,(struct sockaddr*)&addr_dns,sizeof(addr_dns));
	printf("k=sendto()=%d\n",k);
	if(k<=0)exit(0);

	k=recvfrom(sd,buf,sizeof(buf),0,NULL,0);
    printf("k=recvfrom()=%d\n",k);

    if(k>0){
        write(fd,buf,k);
	    parser_dns(buf,k);
    }

	printf("\n--------------------------------------\n");

	goto start;

	exit(0);

}


//----------------------------- parser_dns ----------------------------

int parser_dns(const char *buf, int Lbuf)

{

    int i;

	int id;
	int fl;
	int st_qu;
	int st_res;
	int typ;
	int clas;

    char dname[500], dan[500];
    int j, k, n, stm;
    //int typ, clas;
    int ttl, dl;
    short ntmp;



    i=0;

    i=atoi_buf(i,buf,2,&id);
    i=atoi_buf(i,buf,2,&fl);
    i=atoi_buf(i,buf,2,&st_qu);
    i=atoi_buf(i,buf,2,&st_res);


    i=12;
    i=get_text(i,buf,dname);
    printf("dname=%s\n",dname);

    printf("id=%d; fl=%d; st_qu=%d; st_res=%d\n"
             ,id,fl,st_qu,st_res);

    i=atoi_buf(i,buf,2,&typ);
    i=atoi_buf(i,buf,2,&clas);
    printf("qtyp=%d; qclas=%d\n",typ,clas);


    n=st_res;
    k=1;
    while(k<=n){

        i=get_text(i,buf,dname);
        //printf("t1-%d: i=%d;  dname=%s ==> ",k,i,dname);

        i=atoi_buf(i,buf,2,&typ);
        i=atoi_buf(i,buf,2,&clas);
        i=atoi_buf(i,buf,4,&ttl);
        i=atoi_buf(i,buf,2,&dl);
        printf("rtyp=%d; rclas=%d; ttl=%d; dl=%d\n",typ,clas,ttl,dl);
        printf("t1-%d: i=%d;  dname=%s ==> ",k,i,dname);


        if(typ==1){
            i=print_ip(i,buf);
            printf("\n");
	    }
	    if(typ==5){
	    	i=get_text(i,buf,dname);
	    	printf("t2-%d: i=%d;  dname=%s",k,i,dname);
            printf("  (canon_name)\n");
	    }
	    if(typ !=1 && typ != 5)printf("\n");
	    k++;

    }
    return(0);
}



//----------------------- get_text ---------------------------------------

int get_text(int i, const char *buf, char dname[])

{
    int j, k, imem=-1, stm, ret;
    char  tmbuf[4];

    j=0;
    do{
        if((buf[i]&255)>=0 && (buf[i]&255)<=63){
	        	stm=(buf[i]&255);
	        	if((buf[i]&255)==0){ i++; goto m1;}
	        	i++;
	    }
	    else{
				if(imem<0)imem=i+2;
				tmbuf[0]=buf[i]&63;
				tmbuf[1]=buf[i+1];
				k=atoi_buf(0,tmbuf,2,&ret);
				i=ret;

				//printf("C0: i=%d\n",i);
				continue;
	    }

        k=0;
        while(k<stm){
                dname[j]=buf[i];
                i++;
                j++;
                k++;
	    }
	    dname[j]='.';
	    j++;

	}while(1);

m1:
    dname[j]=0;
    //printf("dname=%s\n",dname);

    if(imem>=0)return(imem);
    return(i);
}





//---------------------- atoi_buf --------------------------

int atoi_buf(int i, const char *buf, int len , int *ret)

{

    union _udan {
		char  dan[4];
		int   z;
		short s;
	} udan;
    memset(&udan,0,sizeof(udan));

#ifndef LOWBYTEFIRST

    if(len==2)goto m_2b;

m_4b:
    udan.dan[3]=buf[i];
    i++;
    udan.dan[2]=buf[i];
    i++;

m_2b:
    udan.dan[1]=buf[i];
    i++;
    udan.dan[0]=buf[i];
    i++;
    goto ret;

#else
    udan.dan[0]=buf[i];
    i++;
    udan.dan[1]=buf[i];
    i++;

    if(len==2)goto ret;
    udan.dan[2]=buf[i];
    i++;
    udan.dan[3]=buf[i];
    i++;

#endif

ret:
    *ret=udan.z;
//    printf("z=%d; s=%d\n",udan.z,(int)udan.s);

    return(i);
}

//------------------------- print_ip -----------------------

int print_ip(int i, const char *buf)

{
    int k=0;
	while(k<3){
		printf("%d.",(buf[i]&255));
		i++;
		k++;
	}
	printf("%d",(buf[i]&255));
	i++;
	printf("\n");
	return(i);

}

//  gcc forum_my_dns.c -o forum_my_dns.cgi
//  ./forum_my_dns.cgi



oleg_2
() автор топика
Ответ на: комментарий от oleg_2

Boy_from_Jungle потребовал показать
кусок кода.
К сожалению код еще очень сырой.
Но покажу два куска.

Самодельный DNS-клиент:


Фрагмент сервера:


Я еще только нащупываю как сделать.
Первый кусок если кто-нибудь пожелает
запустить, то первым делом нужно константе
const char *ip_dns=«12.34.23.45»; //--- DNS-server ---
присвоить ip Вашего DNS-сервера.
Ввести можно характерные имена:
doc.agro.net.ua
yandex.ru
wikiru.wikusia.com
support.kharkiv.ukrtelecom.ua

Во втором фрагменте показано создание
второго сокета и ожидание его подключения (прокси-сервер).
Целевой сервер пока задан жестко.
А обработки тайм-аутов пока нет.

Пробовал для каждого отдельный процесс.
Очень простые серверы получаются.


oleg_2
() автор топика
Ответ на: комментарий от oleg_2

proba



#define  N               6      //--- число клиентов ---

typedef struct  {
	int sd1;
	int sd2;
	int flst;
	int fl_hdr;
	int fl_otvet;
	int fl_sd2;
	int len;
	int uk1;
	int analiz_i;
	char buf[8192];
} _lin;

//---------------------------------- server -------------------------------

int server()

{
    _lin lin[N];

    //....

    //--- ставим сокет на прослушку ---
    k=listen(sd0, 5);
    if(k<0){
		snprintf(cerr,Serr,"listen: %s",strerror(errno));
		if(cmd != 5)printf("%s\n",cerr);
		wrerr(0,cerr,"PIC-7-server");
		exit(5);
	}

    //--- закрываем всё ненужное ---
    close(pipe3);
    close(0);
    close(1);
    close(2);

    //--- делаем сокет не блокирующим ---
	flags=fcntl(sd0, F_GETFL, 0);
    if(flags<0){ close(lin[n].sd1); goto ERR;}
    k=fcntl(sd0, F_SETFL, flags | O_NONBLOCK);
    if(k<0){ close(lin[n].sd1); goto ERR;}

    //--- обнуляем ---
	n=0;
	while(n<N){
	    lin[n].flst=0;
	    lin[n].len=0;
	    lin[n].sd2=-1;
	    lin[n].uk1=0;
		n++;
	}

	//....

    n1=0;

start_t:

    //--- бесконечный главный цикл ---
    do{
        FD_ZERO( &rdsd );
        FD_ZERO( &wrsd );
        FD_SET( sd0, &rdsd );
        FD_SET( sd0, &wrsd );
	    sdmax=sd0;

        n=0;
		while(n<N){
			if(lin[n].flst==0){
				n++;
				continue;
			}
            if(lin[n].flst==1){
				FD_SET( lin[n].sd1, &rdsd );
				FD_SET( lin[n].sd2, &rdsd );
			}
            else if(lin[n].flst==2){
				FD_SET( lin[n].sd1, &rdsd );
			}
			else if(lin[n].flst==3){
				FD_SET( lin[n].sd1, &wrsd );
			}
			else if(lin[n].flst==4){
				FD_SET( lin[n].sd2, &wrsd );
			}

			else if(lin[n].flst==6){
				FD_SET( lin[n].sd2, &wrsd );
			}
			if(lin[n].sd1 > sdmax)sdmax=lin[n].sd1;
			if(lin[n].sd2 > sdmax)sdmax=lin[n].sd2;
            n++;
	    }

        tv.tv_sec =tmrd;
        tv.tv_usec=0;


        k=select(sdmax+1, &rdsd, &wrsd, NULL, NULL );

                //....

        if(k==0){ goto TIME;}                  //--- time-out ---

                //....

        if(FD_ISSET(sd0, &rdsd)){  //--- зашевелился слушающий сокет ---

			//--- создать новую линию ---
			n=0;
			while(n<N){
				if(lin[n].flst==0)break;
				n++;
			}
			if(n<N){
				k=sizeof(addr1);
				lin[n].sd1=accept(sd0, (struct sockaddr *)&addr1, &k);
				if(lin[n].sd1>=0){
					lin[n].len=0;
					lin[n].fl_sd2=0;
					lin[n].analiz_i=0;
					lin[n].uk1=0;
					lin[n].flst=2;
					lin[n].fl_otvet=1;
				}
			}
			if(n>=N){
				sd_pod=accept(sd0, (struct sockaddr *)&addr1, &k);
				close(sd_pod);
			}
		}  //--- end if(FD_ISSET(sd0, &rdsd)) ---

		//--- перебираем все линии (всех клиентов) ---
		n=0;
		do{
		    if(lin[n].flst==0){ n++; continue;}

            //....

		    if(lin[n].flst==2){
                if(FD_ISSET(lin[n].sd1, &rdsd)){
                    if(lin[n].fl_otvet==1){  //--- начало заголовка клиента ---
						lin[n].len=0;
						lin[n].fl_otvet==0;
						lin[n].fl_hdr=1;
						lin[n].uk1=0;
					}
                    k=read(lin[n].sd1, lin[n].buf+lin[n].len, Sbuf-lin[n].len);
                    if(k>0)lin[n].len=lin[n].len+k;
                    if(k<=0 && errno != EAGAIN){ goto ERR1;}
                    k=analiz_http_cli_proxy_njx(n, lin, tmrd, Sbuf);
                    if(k<0){ goto ERR1;}     //--- ошибка ---
                    if(k>0){           //--- заголовок набран ---

                        if(lin[n].fl_sd2==0){

                            //--- создаем второй сокет ---

	                        bzero(&srv_adr,sizeof(srv_adr));
	                        hostAddr=inet_addr(serv_name);
	                        if((long)hostAddr!=(long)-1)
	                            bcopy(&hostAddr,&srv_adr.sin_addr,sizeof(hostAddr));
                            else{ goto ERR1;}

                            srv_adr.sin_port=htons(port2);//htons конвертирует порядок байт
                            srv_adr.sin_family=AF_INET;
                            lin[n].sd2=socket(AF_INET,SOCK_STREAM,0);
                            if(lin[n].sd2<0){ goto ERR1;}

                            flags=fcntl(lin[n].sd2, F_GETFL, 0);
                            if(flags<0){ close(lin[n].sd1); goto ERR1;}
                            k=fcntl(lin[n].sd2, F_SETFL, flags | O_NONBLOCK);
                            if(k<0){ goto ERR1;}

                            k=connect(lin[n].sd2,(struct sockaddr *)&srv_adr, sizeof(srv_adr));

                            if(k!=0 && errno != EINPROGRESS){ goto ERR1;}
                            if(k==0){
								lin[n].flst=4;
							  	lin[n].fl_sd2=1;
							}
							else lin[n].flst=6;
							n++;
							continue;
						}
                        else lin[n].flst=4;
						    lin[n].fl_hdr=0;
						}
					}  //--- end if(k>0) ---
				}   //--- end if(FD_ISSET(lin[n].sd1, &rdsd)) ---
				n++;
				continue;
			}   //--- end if(lin[n].flst==2) ---

			//....

			if(lin[n].flst==6){
				if(lin[n].fl_sd2==0){
				    if(!(isconnected(lin[n].sd2, &rdsd, &wrsd, &errsd ))){ n++; continue;}
                    else{
                        lin[n].uk1=0;
                        lin[n].flst=4;
                        lin[n].fl_otvet=1;
                        lin[n].fl_sd2=1;
	                }
				}
				n++;
				continue;
            }   //--- end if(lin[n].flst==6) ---

			goto m1;

ERR1:

			close(lin[n].sd1);
			close(lin[n].sd2);
			lin[n].flst=0;

m1:
			n++;
		}while(n<N);  //--- конец перебора всех линий ---
	}while(1);  //--- конец главного цикла ---

    exit(0);

TIME:
    goto start_t;


}




proba

почему-то смещения строк не соответствуют

oleg_2
() автор топика
Ответ на: комментарий от oleg_2

В первом куске в функции main() после
k=recvfrom(sd,buf,sizeof(buf),0,NULL,0);
нужно написаь
close(sd);

oleg_2
() автор топика
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.