/* tcpopen.c * Copyright Acquisition group, GANIL Caen, France. * * Fonction : Ouvre un socket de communication TCP/IP * * Si ip_adrs =0 et *sid_pt = 0 : - mode SERVEUR - * Un socket est cree puis on sort * TcpOpen retourne l'id du socket dans le pointeur sid_pt. * * Si ip_adrs !=0 : - mode CLIENT - * Un socket est cree, et on cherche a effectuer une connection * avec le serveur dont on a specifie l'adresse dans ip_adrs. * (Dans la limite du timeout). * * Si ip_adrs =0 et *sid_pt != 0 : - mode CLONE - * Attente d'une connexion distante sur le socket specifie * TcpOpen cree un socket clone et retourne son id dans sid_pt * Attention, il est de la responsabilite de l'utilisatuer de sau- * vegarder le precedent sid_pt pour fermer le processus. * * Si une attente depasse le timeout, TcpOpen retourne R_TIMOUT. * * * Syntaxe :int TcpOpen(sid_pt,ip_adrs,SourcePort,DestPort,timeout). * * Entree :int *sid_pt, identificateur du socket. Passe par adresse. * * :char *ip_adrs, nom ou adresse du service distant * (sous forme d'une chaine de caracteres). * * :int SourcePort, numero de port du socket source. * Utilise seulement dans les modes SERVEUR et CLIENT. * * :int DestPort, numero de port de la machine distante * Utilise seulement dans le mode CLIENT. * * :long timeout, time_out de connection (accept et connect). * * Modifications : * B. Raine le 11 mars 1999 * close(*sid_pt); si erreur sur bind ou connect * */ #define _TCPOPEN_ #include #include #include #include #include #include #include #ifdef __Lynx__ #include #include #include #else #include #include #include #endif #include #include #include #include #include #ifndef __Lynx__ #include #else #include #endif #include "TCP.h" #include "TCP_err.h" int TcpWind = WINDOW; /* taille buffer TCP/IP */ long nbsig; /* compte les intervales de 0.2 ms */ int TcpOpen ( int * sid_pt, char * ip_adrs, int SourcePort, int DestPort, long timeout ) { int mode; /* mode d'utilisation de TcpOpen. */ int err; struct hostent *host_addr; unsigned long tmp; int rcvsiz,sndsiz; int one; int sid_clone; struct sockaddr_in sin_me, sin_him; struct sockaddr_in sin_from; /* description de l'appelant -CLONE-*/ int from_len; fd_set ready; /* pour select */ struct timeval tout; one = 1; if (timeout < 0) timeout = 0; /* Les valeurs negatives sont interdites */ /* init la longueur des buffers de TCP/IP */ rcvsiz = TcpWind; /* definit dans TcpC.h */ sndsiz = TcpWind; /* Determine le mode d'utilisation de TcpOpen: SERVEUR, CLONE ou CLIENT */ mode = (ip_adrs? CLIENT: (*sid_pt? CLONE: SERVEUR)); err = 0; /* branchement suivant le mode */ switch(mode) { case SERVEUR: /* RECEIVE ip_adrs =0 et *sid_pt = 0 */ /* on cree un socket pere */ if ((*sid_pt = socket(AF_INET,SOCK_STREAM,0)) < 0) return(R_TCP_SOCK); setsockopt(*sid_pt,SOL_SOCKET,SO_RCVBUF,(char *)&rcvsiz,sizeof(rcvsiz)); setsockopt(*sid_pt,SOL_SOCKET,SO_SNDBUF,(char *)&sndsiz,sizeof(sndsiz)); setsockopt(*sid_pt,SOL_SOCKET,SO_REUSEADDR,(char *)&one,sizeof(one)); /* nomme le socket -initialisation de sin_me */ memset((char *)&sin_me, 0, sizeof(sin_me)); sin_me.sin_family = AF_INET; sin_me.sin_addr.s_addr = INADDR_ANY; sin_me.sin_port = htons(SourcePort); if (bind(*sid_pt,(struct sockaddr *)&sin_me, sizeof(sin_me)) < 0) { close(*sid_pt); /* B. Raine le 11 mars 1999 */ return(R_TCP_BIND); } /* met le socket a l'ecoute et cree une queue */ if (listen(*sid_pt,5) == -1L) { close(*sid_pt); /* B. Raine le 11 mars 1999 */ return(R_TCP_LISTEN); } else { return (0); } break; /* Fin de SERVEUR */ /* ++++++++++++++++++++++++++++++++++ */ case CLONE: /* On attent une connexion sur le socket specifie */ /* extrait une demande de connection de la queue */ from_len = sizeof(sin_from); err = -1; do { if (timeout != 0) { FD_ZERO(&ready); FD_SET(*sid_pt,&ready); tout.tv_sec = timeout / 5; tout.tv_usec = (timeout % 5) * 200 * 1000; if (select((*sid_pt)+1, &ready, (fd_set *)0, (fd_set *)0, &tout) < 0) return(R_TCP_TIMEOUT); if (!(FD_ISSET(*sid_pt,&ready))) return(R_TCP_TIMEOUT); } sid_clone = accept(*sid_pt,(struct sockaddr*)&sin_from,&from_len); /* traite l'erreur */ if (sid_clone < 0) /* -1 >> erreur */ { if (errno != EWOULDBLOCK) err = R_TCP_CLONE; /* on sort en erreur */ } else /* pas d'erreur - on a une demande de connection */ /* sid_clone contient le nouveau numero de socket sur lequel */ /* on va continuer la conversation avec le site distant */ { *sid_pt = sid_clone; err = 0; } } while (err == -1); return(err); break; /* Fin de CLONE */ /* ++++++++++++++++++++++++++++++++++ */ case CLIENT: /* TRANSMIT */ /* initialise sin_me */ memset((char *)&sin_me, 0, sizeof(sin_me)); sin_me.sin_port = 0; /* free choice */ /* initialise sin_him */ memset((char *)&sin_him, 0, sizeof(sin_him)); /* fabrique l'@ du host que l'on veut appeler */ if (atoi(ip_adrs) > 0) /* le 1er caractere de ip_adrs est numerique */ { /* l'@ est passee sous forme 192.93.218.100 */ sin_him.sin_family = AF_INET; tmp = inet_addr(ip_adrs); /* calcul @ 32 bits */ sin_him.sin_addr.s_addr = tmp; } else { /* l'@ est passee sous forme de nom */ if ((host_addr = gethostbyname(ip_adrs)) == NULL) { return(R_TCP_HOST); } sin_him.sin_family = host_addr->h_addrtype; memcpy((char *)&tmp,host_addr->h_addr,host_addr->h_length); sin_him.sin_addr.s_addr = tmp; } sin_him.sin_port = htons(DestPort); /* on cree un socket et on effectue la connexion */ if ((*sid_pt = socket(AF_INET,SOCK_STREAM,0)) < 0) return(R_TCP_SOCK); setsockopt(*sid_pt,SOL_SOCKET,SO_SNDBUF,(char *)&sndsiz,sizeof(sndsiz)); setsockopt(*sid_pt,SOL_SOCKET,SO_RCVBUF,(char *)&rcvsiz,sizeof(rcvsiz)); setsockopt(*sid_pt,SOL_SOCKET,SO_REUSEADDR,(char *)&one,sizeof(one)); if (bind(*sid_pt, (struct sockaddr *)&sin_me, sizeof(sin_me)) < 0) { close(*sid_pt); /* B. Raine le 11 mars 1999 */ return(R_TCP_BIND); } /* effectue la connection sur le serveur distant */ err = -1; do { if (connect(*sid_pt,(struct sockaddr *)&sin_him,sizeof(sin_him)) < 0 ) { /* traite l'erreur */ close(*sid_pt); /* B. Raine le 11 mars 1999 */ err = R_TCP_CONNECT; /* retour si erreur */ } else { err = 0; } } while (err == -1); return(err); break; /* Fin de CASE:CLIENT. */ } /* fin de switch */ return 0; }