/* * Tcp4u v 3.31 Created may 93 - Last Revision 20/10/1997 3.20 * *=========================================================================== * * Project: Tcp4u, Library for tcp protocol * File: tcp4u.c * Purpose: main functions for tcp management * *=========================================================================== * * This software is Copyright (c) 1996-1998 by Philippe Jounin * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library 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. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. * * * If you make modifications to this software that you feel * increases it usefulness for the rest of the community, please * email the changes, enhancements, bug fixes as well as any and * all ideas to me. This software is going to be maintained and * enhanced as deemed necessary by the community. * * * Philippe Jounin (ph.jounin@computer.org) */ #include "build.h" #define TCP4U_SENDTIMEOUT 3600l /* one hour */ /* ******************************************************************* */ /* */ /* Partie I : constructeurs /Destructeurs */ /* */ /* */ /* Tcp4uInit, Tcp4uCleanup */ /* */ /* */ /* ******************************************************************* */ /* ------------------------------------------------------------------ */ /* Initialisation */ /* ------------------------------------------------------------------ */ int API4U Tcp4uInit (void) { int Rc=0; Tcp4uLog (LOG4U_PROC, "Tcp4uInit"); Skt4uInit (); # ifdef _WINDOWS { /* enregistrement aupres de Winsock.Dll */ WSADATA WSAData; Tcp4uLog (LOG4U_CALL, "WSAStartup, Winsock 1.1 required"); Rc = WSAStartup (MAKEWORD (1,1), & WSAData); } # endif Tcp4uLog (LOG4U_EXIT, "Tcp4uInit"); return Rc==0 ? TCP4U_SUCCESS : TCP4U_ERROR; } /* Tcp4uInit */ /* ------------------------------------------------------------------ */ /* Destructeurs */ /* ------------------------------------------------------------------ */ int API4U Tcp4uCleanup (void) { int Rc; Tcp4uLog (LOG4U_PROC, "Tcp4uCleanup"); Rc = Skt4uCleanup (); Tcp4uLog (LOG4U_EXIT, "Tcp4uCleanup"); return Rc; } /* Tcp4wCleanup */ /* ------------------------------------------------------------------ */ /* WINDOWS : Fin de vie de la DLL */ /* ------------------------------------------------------------------ */ #ifdef TCP4W_DLL int API4U WEP (int nExitType) { Tcp4uLog (LOG4U_PROC, "WEP"); Skt4uCleanup (); nExitType=0; /* suppress warning */ Tcp4uLog (LOG4U_EXIT, "WEP"); return 1; /* definition Windows */ } /* WEP */ #endif /* ------------------------------------------------------------------ */ /* Aliases : Tcp4uxInit/Tcp4uxCleanup ; Tcp4wInit/Tcp4wCleanup */ /* ------------------------------------------------------------------ */ #ifdef _WINDOWS int API4U Tcp4wInit (void) { return Tcp4uInit (); } int API4U Tcp4wCleanup (void) { return Tcp4uCleanup (); } #endif #ifdef UNIX int API4U Tcp4uxInit (void) { return Tcp4uInit (); } int API4U Tcp4uxCleanup (void) { return Tcp4uCleanup (); } #endif /* ******************************************************************* */ /* */ /* Partie I : Fonctions de bas niveau TCP */ /* */ /* */ /* TcpAbort */ /* TcpAccept */ /* TcpConnect */ /* TcpClose */ /* TcpFlush */ /* TcpGetListenSocket */ /* TcpRecv */ /* TcpSend */ /* */ /* ******************************************************************* */ /* ------------------------------------------------------------ */ /* TcpAbort: Stoppe un appel bloquant */ /* Retourne TCP4U_SUCCESS */ /* ------------------------------------------------------------ */ int API4U TcpAbort (void) { Tcp4uLog (LOG4U_PROC, "TcpAbort"); if (WSAIsBlocking ()) { Tcp4uLog (LOG4U_CALL, "WSACancelBlockingCall"); WSACancelBlockingCall (); } else Tcp4uLog (LOG4U_ERROR, "TcpAbort: No calling process to cancel"); Tcp4uLog (LOG4U_EXIT, "TcpAbort"); return TCP4U_SUCCESS; } /* TcpAbort */ /* ------------------------------------------------------------ */ /* TcpAccept : itablissement d'une connexion TCP avec Timeout */ /* Retourne TCP4U_ERROR, TCP4U_TIMEOUT, TCP4U_SUCCESS */ /* ou TCP4U_BUFFERFREED si pConnectSock n'existe plus */ /* En cas de succes la variable pConnectSock est */ /* renseignee. */ /* ------------------------------------------------------------ */ int API4U TcpAccept (SOCKET far *pCSock, SOCKET ListenSock, UINT nTO) { struct timeval TO; /* Time Out structure */ fd_set ReadMask; /* select mask */ SOCKET ConSock; struct sockaddr_in saSockAddr; /* specifications pour le Accept */ struct linger sling = { TRUE, 5 }; /* 5-seconds timeout */ int nAddrLen = sizeof saSockAddr; int Rc; Tcp4uLog (LOG4U_PROC, "TcpAccept. Listen socket %d, Timeout %d", ListenSock, nTO); /* prepare select */ FD_ZERO (& ReadMask); /* mise a zero du masque */ FD_SET (ListenSock, & ReadMask); /* Attente d'evenement en lecture */ TO.tv_sec = (long) nTO; /* secondes */ TO.tv_usec = 0; /* microsecondes */ /* s+1 normally unused but better for a lot of bugged TCP Stacks */ Tcp4uLog (LOG4U_CALL, "select on socket %d", ListenSock); Rc = select (1+ListenSock, & ReadMask, NULL, NULL, nTO==0 ? NULL : & TO); if (Rc<0) { Tcp4uLog (LOG4U_ERROR, "select on socket %d", ListenSock); return IsCancelled() ? TCP4U_CANCELLED : TCP4U_ERROR; /* erreur reseau */ } if (Rc==0) { Tcp4uLog (LOG4U_ERROR, "select on socket %d: Timeout", ListenSock); return TCP4U_TIMEOUT; } Tcp4uLog (LOG4U_CALL, "accept on listen socket %d", ListenSock); ConSock = accept (ListenSock, (struct sockaddr far *) &saSockAddr, &nAddrLen); if (ConSock==INVALID_SOCKET) { Tcp4uLog (LOG4U_ERROR, "accept on socket %d", ListenSock); return IsCancelled() ? TCP4U_CANCELLED : TCP4U_ERROR; } Skt4uRcd (ConSock, STATE_SERVER); Tcp4uLog (LOG4U_CALL, "setsockopt SOL_LINGER on socket %d", ConSock); setsockopt (ConSock, SOL_SOCKET, SO_LINGER,(LPSTR) &sling, sizeof sling); /* validite des pointeurs */ if (IsBadWritePtr (pCSock, sizeof *pCSock)) { TcpClose (& ConSock); Tcp4uLog (LOG4U_ERROR, "TcpAccept. invalid pointer"); return TCP4U_BUFFERFREED; } else { *pCSock = ConSock; Tcp4uLog (LOG4U_EXIT, "TcpAccept"); return TCP4U_SUCCESS; } } /* TcpAccept */ /* ------------------------------------------------------------ */ /* TcpClose - Fermeture d'une socket */ /* La socket pointie par pS est fermie, *pS est */ /* mise ` INVALID_SOCKET. */ /* - Retourne 1 en cas de succhs, -1 sinon (en giniral */ /* du ` l'erreur WSAEINTR) */ /* constantes (TCP4U_SUCCESS et TCP4U_ERROR) */ /* ------------------------------------------------------------ */ int API4U TcpClose (SOCKET far *pS) { SOCKET s; struct timeval TO; /* Time Out structure */ struct S_HistoSocket *pStat; /* stats about socket */ Tcp4uLog (LOG4U_PROC, "TcpClose socket %d", *pS); if (*pS==(unsigned) INVALID_SOCKET) return TCP4U_SUCCESS; /* bien passe */ s = *pS; pStat = Skt4uGetStats (s); if (pStat!=NULL && pStat->nState==STATE_LISTEN) { /* Ici une petite tempo pour les winsockets qui n'apprecient */ /* pas la succession trop rapide Accept/Close */ TO.tv_sec = 0; TO.tv_usec = 100000l; /* microsecondes */ select (s+1, NULL, NULL, NULL, & TO); } /* pause */ /* Si on effectue un shutdown (s, 2), certaines winsocket */ /* n'envoie plus la trame de longueur 0 caracteristique */ /* de la fin de connexion. */ /* On le remplace donc par le TcpFlush */ if (pStat!=NULL && pStat->nState!=STATE_LISTEN) TcpFlush (s); Tcp4uLog (LOG4U_CALL, "closesocket socket %d", s); if (CloseSocket (s)==0) { Skt4uUnRcd (s); if (!IsBadWritePtr(pS, sizeof *pS)) *pS =(unsigned) INVALID_SOCKET; else Tcp4uLog (LOG4U_ERROR, "TcpClose: Invalid pointer"); Tcp4uLog (LOG4U_EXIT, "TcpClose"); return TCP4U_SUCCESS; } Tcp4uLog (LOG4U_ERROR, "closesocket socket %d", s); return TCP4U_ERROR; } /* TcpClose */ /* --------------------------------------------------------------------- */ /* TcpConnect : Tentative d'etablissemnt d'une connexion TCP */ /* Retourne TCP4U_ERROR, TCP4U_SUCCESS, TCP4U_HOSTUNKNONW */ /* --------------------------------------------------------------------- */ int API4U TcpConnect (SOCKET far *pS, LPCSTR szHost, LPCSTR szService, unsigned short far *lpPort) { int Rc; struct sockaddr_in saSockAddr; struct servent far * lpServEnt; SOCKET connect_skt; unsigned short Zero = 0; Tcp4uLog (LOG4U_PROC, "TcpConnect. Host %s, service %s, port %u", szHost, szService==NULL ? "none" : szService, lpPort==NULL ? -1 : *lpPort); *pS = INVALID_SOCKET; /* par defaut erreur */ if (lpPort==NULL) lpPort = & Zero; /* evite de tester sans arret */ /* --- 1er champ de saSockAddr : Port */ if (szService==NULL) lpServEnt = NULL ; else { Tcp4uLog (LOG4U_DBCALL, "getservbyname %s/tcp", szService); lpServEnt = getservbyname (szService, "tcp") ; } saSockAddr.sin_port = lpServEnt!=NULL ? lpServEnt->s_port : htons(*lpPort); if (saSockAddr.sin_port == 0) return TCP4U_BADPORT; /* erreur dans port */ /* --- 2eme champ de saSockAddr : Addresse serveur */ saSockAddr.sin_addr = Tcp4uGetIPAddr (szHost); if (saSockAddr.sin_addr.s_addr==INADDR_NONE) return TCP4U_HOSTUNKNOWN; /* --- Dernier champ : liaison connectie */ saSockAddr.sin_family = AF_INET; /* on utilise le mode connecte TCP */ /* --- creation de la socket */ Tcp4uLog (LOG4U_CALL, "socket PF_INET, SOCK_STREAM"); if ( (connect_skt = socket (PF_INET, SOCK_STREAM, 0))==SOCKET_ERROR) { Tcp4uLog (LOG4U_ERROR, "socket"); return TCP4U_NOMORESOCKET; } /* --- connect retourne INVALID_SOCKET ou numero valide */ Tcp4uLog (LOG4U_CALL, "connect on host %s", inet_ntoa (saSockAddr.sin_addr)); Rc = connect (connect_skt,(struct sockaddr far *) & saSockAddr, sizeof saSockAddr); /* --- enregistrement dans notre table */ if (Rc==SOCKET_ERROR) { Tcp4uLog (LOG4U_ERROR, "connect"); CloseSocket (connect_skt); /* release buffer */ } else Skt4uRcd (connect_skt, STATE_CLIENT); *lpPort = htons (saSockAddr.sin_port); if (IsBadWritePtr (pS, sizeof *pS)) { Tcp4uLog (LOG4U_ERROR, "TcpConnect: invalid pointer"); return TCP4U_BUFFERFREED; } else *pS = Rc==SOCKET_ERROR ? INVALID_SOCKET : connect_skt; Tcp4uLog (LOG4U_EXIT, "TcpConnect"); return Rc==SOCKET_ERROR ? TCP4U_CONNECTFAILED : TCP4U_SUCCESS; } /* TcpConnect */ /* ------------------------------------------------------------ */ /* TcpFlush: Vide le buffer relatif a une socket */ /* Retourne TCP4U_ERROR, TCP4U_SUCCESS, TCP4U_CLOSEDSOCKET */ /* ------------------------------------------------------------ */ int API4U TcpFlush (SOCKET s) { int nBR=-1; char szBuf[64]; Tcp4uLog (LOG4U_PROC, "TcpFlush on socket %d", s); if (s==INVALID_SOCKET) return TCP4U_ERROR; while ( TcpIsDataAvail (s) && (nBR=recv (s,szBuf,sizeof szBuf,0)) > 0 ) Tcp4uDump (szBuf, nBR, "Flushed"); while ( TcpIsOOBDataAvail (s) &&(nBR=recv (s,szBuf,sizeof szBuf,MSG_OOB))>0 ) Tcp4uDump (szBuf, nBR, "Flushed"); Tcp4uLog (LOG4U_EXIT, "TcpFlush"); if (nBR<0) return IsCancelled() ? TCP4U_CANCELLED : TCP4U_ERROR; if (nBR==0) return TCP4U_SOCKETCLOSED; return TCP4U_SUCCESS; } /* TcpFlush */ /* ------------------------------------------------------------ */ /* TcpGetListenSocket */ /* Retourne TCP4U_ERROR, TCP4U_SUCCESS */ /* ------------------------------------------------------------ */ int API4U TcpGetListenSocket (SOCKET far *pS, LPCSTR szService, unsigned short far *lpPort, int nPendingConnection) { struct sockaddr_in saSockAddr; /* specifications pour le Accept */ int nAddrLen; SOCKET ListenSock; int One=1; int Rc; unsigned short Zero = 0; struct servent far * lpServEnt; Tcp4uLog (LOG4U_PROC, "TcpGetListenSocket on service %s, port %u", szService==NULL ? "none" : szService, lpPort==NULL ? 0 : *lpPort); *pS = INVALID_SOCKET; if (lpPort==NULL) lpPort = & Zero; /* --- 1er champ de saSockAddr : Port */ if (szService==NULL) lpServEnt = NULL ; else { Tcp4uLog (LOG4U_DBCALL, "getservbyname %s/tcp", szService); lpServEnt = getservbyname (szService, "tcp") ; } saSockAddr.sin_port = (lpServEnt!=NULL) ? lpServEnt->s_port : htons(*lpPort); #ifdef CONTROL_EN_TROP if (saSockAddr.sin_port==0) return TCP4U_BADPORT; /* erreur attribution Port */ #endif /* create socket */ Tcp4uLog (LOG4U_CALL, "socket AF_INET, SOCK_STREAM"); ListenSock = socket (AF_INET, SOCK_STREAM, IPPROTO_TCP); if (ListenSock==INVALID_SOCKET) { Tcp4uLog (LOG4U_ERROR, "socket"); return TCP4U_NOMORESOCKET; } saSockAddr.sin_family = AF_INET; saSockAddr.sin_addr.s_addr=INADDR_ANY; /* set options ReuseAddress and Linger */ Tcp4uLog (LOG4U_CALL, "setsockopt SO_REUSEADDR on sock %d", ListenSock); setsockopt (ListenSock, SOL_SOCKET, SO_REUSEADDR, (char far *)&One, sizeof One); Tcp4uLog (LOG4U_CALL, "setsockopt SO_LINGER on sock %d", ListenSock); setsockopt (ListenSock, SOL_SOCKET, SO_LINGER,(char far *)&One, sizeof One); /* Bind name to socket */ Tcp4uLog (LOG4U_CALL, "bind socket %d to %s", ListenSock, inet_ntoa (saSockAddr.sin_addr)); Rc = bind (ListenSock,(struct sockaddr far *) & saSockAddr, sizeof(struct sockaddr)); if (Rc != SOCKET_ERROR) { Tcp4uLog (LOG4U_CALL, "listen on socket %d. %d pendind connections", ListenSock, nPendingConnection); Rc = listen (ListenSock, nPendingConnection); } if (Rc==SOCKET_ERROR) { Tcp4uLog (LOG4U_ERROR, "bind or listen on socket %d", WSAGetLastError (), ListenSock); CloseSocket (ListenSock); return TCP4U_BINDERROR; } /* Get port id with getsockname */ nAddrLen = sizeof saSockAddr; memset (& saSockAddr, 0, sizeof(struct sockaddr) ); Tcp4uLog (LOG4U_DBCALL, "getsockname on socket %d", ListenSock); getsockname (ListenSock, (struct sockaddr far *) &saSockAddr, &nAddrLen); *lpPort = htons (saSockAddr.sin_port); Skt4uRcd (ListenSock, STATE_LISTEN); if (IsBadWritePtr (pS, sizeof *pS)) { Tcp4uLog (LOG4U_ERROR, "TcpGetListenSocket: invalid pointer"); return TCP4U_BUFFERFREED; } else *pS = ListenSock; Tcp4uLog (LOG4U_EXIT, "TcpGetListenSocket"); return TCP4U_SUCCESS; } /* TcpGetListenSock */ /* ------------------------------------------------------------ */ /* TcpRecv - Lecture d'une trame avec Timeout */ /* TcpRecv recoit uBufSize octets de donnies */ /* la fonction s'arrjte avant si la socket est fermie */ /* ou si une timeout arrive. */ /* - Retourne le nombre d'octets lus, */ /* TCP4U_SOCKETCLOSED si la socket a iti fermie */ /* TCP4U_ERROR sur une erreur de lecture */ /* TCP4U_TIMEOUT sur un TO */ /* TCP4U_BUFFERFREED si libiration des buffers */ /* - Remarque : Pour iviter que le buffer appelant soit */ /* libere de manihre asynchrone, la fonction utilise */ /* ses propres buffers. */ /* - Ajout des modes TCP4U_WAITFOREVER et TCP4U_WAIT */ /* ------------------------------------------------------------ */ /* forme avec log */ int API4U TcpRecv (SOCKET s, LPSTR szBuf, unsigned uBufSize, unsigned uTimeOut, HFILE hLogFile) { int Rc; Tcp4uLog (LOG4U_PROC, "TcpRecv on socket %d. Timeout %d, bufsize %d", s, uTimeOut, uBufSize); Rc = InternalTcpRecv (s, szBuf, uBufSize, uTimeOut, hLogFile); if (Rc>=TCP4U_SUCCESS) Tcp4uDump (szBuf, Rc, DUMP4U_RCVD); Tcp4uLog (LOG4U_EXIT, "TcpRecv"); return Rc; } /* TcpRecv */ /* forme sans log */ int InternalTcpRecv (SOCKET s, LPSTR szBuf, unsigned uBufSize, unsigned uTimeOut, HFILE hLogFile) { char cBuf; LPSTR p = NULL; int Rc, nUpRc; /* Return Code of select and recv */ struct timeval TO; /* Time Out structure */ struct timeval *pTO; /* Time Out structure */ fd_set ReadMask; /* select mask */ if (s==INVALID_SOCKET) return TCP4U_ERROR; FD_ZERO (& ReadMask); /* mise a zero du masque */ FD_SET (s, & ReadMask); /* Attente d'evenement en lecture */ /* detail des modes */ switch (uTimeOut) { case TCP4U_WAITFOREVER : pTO = NULL; break; case TCP4U_DONTWAIT : TO.tv_sec = TO.tv_usec=0 ; pTO = & TO; break; /* Otherwise uTimeout is really the Timeout */ default : TO.tv_sec = (long) uTimeOut; TO.tv_usec=0; pTO = & TO; break; } /* s+1 normally unused but better for a lot of bugged TCP Stacks */ Tcp4uLog (LOG4U_CALL, "select on socket %d", s); Rc = select (s+1, & ReadMask, NULL, NULL, pTO); if (Rc<0) { Tcp4uLog (LOG4U_ERROR, "select on socket %d", s); return IsCancelled() ? TCP4U_CANCELLED : TCP4U_ERROR; } if (Rc==0) { Tcp4uLog (LOG4U_ERROR, "select on socket %d: Timeout", s); return TCP4U_TIMEOUT; /* timeout en reception */ } if (szBuf==NULL || uBufSize==0) { Tcp4uLog (LOG4U_EXIT, "TcpRecv"); return TCP4U_SUCCESS; } if (uBufSize==1) /* cas frequent : lecture caractere par caractere */ p = & cBuf; else { p = Calloc (uBufSize, 1); if (p==NULL) return TCP4U_INSMEMORY; } Tcp4uLog (LOG4U_CALL, "recv socket %d, buffer %d bytes", s, uBufSize); Rc = recv (s, p, uBufSize, 0); /* chgt 11/01/95 */ switch (Rc) { case SOCKET_ERROR : Tcp4uLog (LOG4U_ERROR, "recv socket %d", s); nUpRc = IsCancelled() ? TCP4U_CANCELLED : TCP4U_ERROR ; break; case 0 : Tcp4uLog (LOG4U_ERROR,"socket %d: Host has closed connection", s); nUpRc = TCP4U_SOCKETCLOSED ; break; default : if (hLogFile!=HFILE_ERROR) Write (hLogFile, p, Rc); if (IsBadWritePtr (szBuf, 1)) nUpRc = TCP4U_BUFFERFREED; else memcpy (szBuf, p, nUpRc=Rc); break; } /* translation des codes d'erreurs */ if (p!=NULL && uBufSize!=1) Free (p); return nUpRc; } /* TcpRecv */ /* ------------------------------------------------------------ */ /* TcpSend : Envoi de uBufSize octets vers le distant */ /* Retourne TCP4U_ERROR ou TCP4U_SUCCESS */ /* ------------------------------------------------------------ */ /* forme avec log */ int API4U TcpSend (SOCKET s, LPCSTR szBuf, unsigned uBufSize, BOOL bHighPriority, HFILE hLogFile) { int Rc; Tcp4uLog (LOG4U_PROC,"TcpSend on socket %d. %d bytes to be sent",s,uBufSize); Rc = InternalTcpSend (s, szBuf, uBufSize, bHighPriority, hLogFile); if (Rc==TCP4U_SUCCESS) Tcp4uDump (szBuf, uBufSize, DUMP4U_SENT); Tcp4uLog (LOG4U_EXIT, "TcpSend"); return Rc; } /* TcpSend */ /* forme sans log */ int InternalTcpSend (SOCKET s, LPCSTR szBuf, unsigned uBufSize, BOOL bHighPriority, HFILE hLogFile) { int Rc; unsigned Total; LPSTR p; if (s==INVALID_SOCKET) return TCP4U_ERROR; p = Calloc (uBufSize, 1); if (p==NULL) return TCP4U_INSMEMORY; memcpy (p, szBuf, uBufSize); if (hLogFile!=HFILE_ERROR) Write (hLogFile, p, uBufSize); for ( Total = 0, Rc = 1 ; Total < uBufSize && Rc > 0 ; Total += Rc) { Tcp4uLog (LOG4U_CALL, "send on socket %d. %d bytes to be sent", s, uBufSize-Total); Rc = send (s, & p[Total], uBufSize-Total, bHighPriority ? MSG_OOB : 0); if (Rc<=0) Tcp4uLog (LOG4U_ERROR, "send on socket %d.", s); } Free(p); return Total>=uBufSize ? TCP4U_SUCCESS : IsCancelled() ? TCP4U_CANCELLED : TCP4U_ERROR; } /* TcpSend */ /* ******************************************************************* */ /* */ /* Partie I (suite) : Fonctions d'information */ /* */ /* TcpGetLocalID */ /* TcpGetRemoteID */ /* TcpIsDataAvail */ /* */ /* ******************************************************************* */ /* ------------------------------------------------------------ */ /* TcpGetLocalID: Retourne nom et adresse IP de la station */ /* Retourne TCP4U_SUCCESS, TCP4U_ERROR */ /* ------------------------------------------------------------ */ int API4U TcpGetLocalID (LPSTR szStrName, int uNameSize, DWORD far *lpAddress) { char szName[128]; struct hostent far *lpHostEnt; int Rc; Tcp4uLog (LOG4U_PROC, "TcpGetLocalID"); if (lpAddress!=NULL) memset (lpAddress, 0, sizeof (DWORD)); /* on envisage 2 methodes pour obtenir le nom du PC */ /* d'abord un appel a gethostname */ Tcp4uLog (LOG4U_DBCALL, "gethostname"); if (gethostname (szName, sizeof szName)==SOCKET_ERROR) return TCP4U_ERROR; if (lpAddress != NULL) { Tcp4uLog (LOG4U_DBCALL, "gethostbyname on host %s", szName); lpHostEnt = gethostbyname (szName); if (lpHostEnt==NULL) return TCP4U_ERROR; memcpy (lpAddress, lpHostEnt->h_addr_list[0], lpHostEnt->h_length); } if (szStrName!=NULL) { Strcpyn (szStrName, szName, uNameSize); Rc = Strlen(szName)>Strlen(szStrName) ? TCP4U_OVERFLOW : TCP4U_SUCCESS; } else Rc = TCP4U_SUCCESS; Tcp4uLog (LOG4U_EXIT, "TcpGetLocalID"); return TCP4U_SUCCESS; } /* TcpGetLocalID */ /* ------------------------------------------------------------ */ /* TcpGetRemoteID: Retourne nom et adresse IP du distant */ /* Retourne TCP4U_SUCCESS, TCP4U_ERROR */ /* ------------------------------------------------------------ */ int API4U TcpGetRemoteID (SOCKET s, LPSTR szStrName, int uNameSize, DWORD far *lpAddress) { struct sockaddr_in SockAddr; int SockAddrLen=sizeof SockAddr; struct hostent far *lpHostEnt; Tcp4uLog (LOG4U_PROC, "TcpGetRemoteID on socket %d", s); /* determiner l'adress IP de la station distante */ Tcp4uLog (LOG4U_DBCALL, "getpeername on socket %d", s); if (getpeername (s, (struct sockaddr far *) & SockAddr, & SockAddrLen)==SOCKET_ERROR) { Tcp4uLog (LOG4U_ERROR, "getpeername on socket %d", s); return TCP4U_ERROR; } if (lpAddress!=NULL) memcpy (lpAddress, & SockAddr.sin_addr.s_addr, sizeof SockAddr.sin_addr.s_addr); if (szStrName!=NULL && uNameSize > 0) { /* determiner par gethostbyaddr le nom de la station */ szStrName[0]=0; /* si erreur */ Tcp4uLog (LOG4U_DBCALL, "gethostbyaddr on host %s", inet_ntoa (SockAddr.sin_addr)); lpHostEnt = gethostbyaddr ((LPSTR) & SockAddr.sin_addr.s_addr, 4, PF_INET); if (lpHostEnt!=NULL) Strcpyn (szStrName, lpHostEnt->h_name, uNameSize); else Tcp4uLog (LOG4U_ERROR, "gethostbyaddr"); } Tcp4uLog (LOG4U_EXIT, "TcpGetRemoteID"); return TCP4U_SUCCESS; } /* TcpGetRemoteID */ /* ------------------------------------------------------------- */ /* TcpIsDataAvail: Retourne VRAI si des donnees sont disponibles */ /* ------------------------------------------------------------- */ BOOL API4U TcpIsDataAvail (SOCKET s) { unsigned long ulData; int Rc; Tcp4uLog (LOG4U_PROC, "TcpIsDataAvail on socket %d", s); Tcp4uLog (LOG4U_CALL, "Ioctl FIONREAD on socket %d", s); Rc = IoctlSocket (s, FIONREAD, & ulData); Tcp4uLog (LOG4U_EXIT, "TcpIsDataAvail"); return Rc==0 && ulData>0; } /* TcpIsDataAvail */ /* ------------------------------------------------------------- */ /* TcpIsOOBDataAvail: Retourne VRAI si des donnees Out Of Band */ /* sont disponibles */ /* ------------------------------------------------------------- */ BOOL API4U TcpIsOOBDataAvail (SOCKET s) { unsigned long ulData; int Rc; Tcp4uLog (LOG4U_PROC, "TcpIsOOBDataAvail on socket %d", s); Rc = IoctlSocket (s, SIOCATMARK, & ulData); Tcp4uLog (LOG4U_EXIT, "TcpIsOOBDataAvail"); return Rc==0 && ! ulData; } /* TcpIsOOBDataAvail */ /* ******************************************************************* */ /* */ /* Partie II : Gestion d'un mini- protocole */ /* */ /* */ /* TcpPPSend - TcpPPRecv */ /* */ /* */ /* ******************************************************************* */ /* ------------------------------------------------------------ */ /* TcpPPRecv - Lecture d'une trame avec Timeout */ /* TcpPPRecv recoit uBufSize octets de donnies */ /* la fonction s'arrjte avant si la socket est fermie */ /* ou si un timeout arrive. */ /* - Retourne le nombre d'octets lus, */ /* TCP4U_SOCKETCLOSED si la socket a iti fermie */ /* TCP4U_ERROR sur une erreur de lecture */ /* TCP4U_TIMEOUT sur un TO */ /* TCP4U_BUFFERFREED si libiration des buffers */ /* - Remarque : Pour iviter que le buffer appelant soit */ /* libiri de manihre asynchrone, la fonction utilise */ /* ses propres buffers. */ /* ------------------------------------------------------------ */ int API4U TcpPPRecv (SOCKET s, LPSTR szBuf, unsigned uBufSize, unsigned uTimeOut, BOOL bExact, HFILE hLogFile) { LPSTR p, q; int Rc, nUpRc; /* Return Code of select and recv */ unsigned short nToBeReceived, nReceived; Tcp4uLog (LOG4U_PROC, "TcpPPRecv on socket %d. Timeout %d, buffer %d bytes", s, uTimeOut, uBufSize); if (s==INVALID_SOCKET) return TCP4U_ERROR; Rc = TcpRecv (s, (LPSTR) & nToBeReceived, 2, uTimeOut, hLogFile); if (Rc0 && nReceived= TCP4U_SUCCESS) { if (IsBadWritePtr (szBuf, nToBeReceived)) nUpRc = TCP4U_BUFFERFREED; else memcpy (szBuf, p, nUpRc=nToBeReceived); } Free (p); Tcp4uLog (LOG4U_EXIT, "TcpPPRecv"); return nUpRc; } /* TcpPPRecv */ /* -------------------------------------------------------------- */ /* TcpPPSend : Envoi de uBufSize octets vers le distant */ /* Retourne TCP4U_ERROR ou TCP4U_SUCCESS */ /* -------------------------------------------------------------- */ int API4U TcpPPSend (SOCKET s, LPCSTR szBuf, unsigned uBufSize, HFILE hLogFile) { int Rc; unsigned short Total; Tcp4uLog (LOG4U_PROC, "TcpPPSend on socket %d. %d bytes to send", s, uBufSize); if (s==INVALID_SOCKET) return TCP4U_ERROR; /* Envoi de la longueur de la trame sur 2 octets */ Total = htons ((unsigned short) uBufSize); Rc = TcpSend (s, (void far *) & Total, 2, FALSE, hLogFile); /* cas d'une sequence vide -> envoi de 0 OK: retour OK */ if (Rc>=TCP4U_SUCCESS && uBufSize>0) /* maintenant on envoie la sequence (qui n'est pas vide) */ Rc = TcpSend (s, szBuf, uBufSize, FALSE, hLogFile); Tcp4uLog (LOG4U_EXIT, "TcpPPSend"); return Rc; } /* TcpPPSend */ /* ******************************************************************* */ /* */ /* Partie III : Lecture Jusqu'a ... */ /* */ /* */ /* ******************************************************************* */ /* ------------------------------------------------------------ */ /* TcpRecvUntilStr */ /* Recois des donnees jusqu'a */ /* - Une erreur */ /* - Une Fermeture de socket */ /* - un timeout */ /* - la reception de la chaine szStop */ /* - le remplissage du buffer */ /* Le Retour soit un code d'erreur, soit TCP4U_SUCCESS */ /* Si c'est TCP4U_OVERFLOW, uBufSize octes ont iti lus, mais */ /* la chaine szStop n'a pas iti trouvie */ /* Si c'est TCP4U_SOCKETCLOSED, le distant a ferme la connexion */ /* La chaine szStop n'est pas ajoutie au buffer */ /* lpBufSize contient le nombre d'octets lus */ /* NOTE: Cette fonction est incompatible avec La pile de Novell */ /* LAN Workplace */ /* ------------------------------------------------------------ */ /* redeclaration de tolower: MSCV2 semble avoir des problemes avec */ static char ToLower (char c) { return (c>='A' && c<='Z') ? c + ('a' -'A') : c; } /* ToLower */ /* compare les chaines s1 et s2 sur nLength caracteres */ /* retourne TRUE si les deux chaines sont identiques */ static BOOL uMemcmp (LPSTR s1, LPSTR s2, int nLength, BOOL bCaseSensitive) { int Evan; if (bCaseSensitive) return memcmp (s1, s2, nLength)==0; else { for (Evan=0 ; Evan=ns2-*npProx && uMemcmp (s1, & s2[*npProx], ns2-*npProx, bCaseSensitive)) { return 0; } } /* traitement des antecedents */ for ( Ark=0, bNotFound=TRUE; Ark<=ns1-ns2 && (bNotFound= ! uMemcmp (& s1[Ark], s2, ns2, bCaseSensitive)) ; Ark++) ; /* recherche de s2 */ if (bNotFound) { for ( *npProx = min (ns1, ns2-1) ; *npProx>0 && !uMemcmp (& s1[ns1-*npProx], s2, *npProx, bCaseSensitive); (*npProx)-- ); } return bNotFound ? -1 : Ark; /* si bNotFounf, *npProx est positionne */ } /* FindPos */ int API4U TcpRecvUntilStr (SOCKET s, LPSTR szBuf,unsigned far *lpBufSize, LPSTR szStop, unsigned uStopSize, BOOL bCaseSensitive, unsigned uTimeOut, HFILE hLogFile) { int Rc; Tcp4uLog ( LOG4U_PROC, "TcpRecvUntilStr on socket %d. Timeout %d, buffer %d bytes", s, uTimeOut, *lpBufSize); Rc = InternalTcpRecvUntilStr (s, szBuf, lpBufSize, szStop, uStopSize, bCaseSensitive, uTimeOut, hLogFile); if (Rc==TCP4U_SUCCESS) Tcp4uDump (szBuf, *lpBufSize, DUMP4U_RCVD); if (Rc==TCP4U_OVERFLOW) Tcp4uDump (szBuf, *lpBufSize, "Overflow"); Tcp4uLog (LOG4U_EXIT, "TcpRecvUntilStr"); return Rc; } /* TcpRecvUntilStr */ int InternalTcpRecvUntilStr (SOCKET s, LPSTR szBuf,unsigned far *lpBufSize, LPSTR szStop, unsigned uStopSize, BOOL bCaseSensitive, unsigned uTimeOut, HFILE hLogFile) { unsigned uNbRecus; static int nProxy; /* Proxy sert si clef partagee sur 2 trames */ LPSTR pTest = NULL; int Rc; int Idx; #define XX_RETURN(x,s) \ { if (pTest!=NULL) Free(pTest); \ *lpBufSize=uNbRecus; \ Tcp4uLog (LOG4U_ERROR, IsCancelled() ? "call cancelled" : s); \ return IsCancelled() ? TCP4U_CANCELLED : x; } if (s==INVALID_SOCKET || *lpBufSize==0) return TCP4U_ERROR; /* On prend un buffer qui permet de lire la trame, */ /* la chaine de stop et qui soit toujours 0-terminee */ /* Le recv suivant est sur de ne pas bloquer, vu que */ /* le PEEK a rendu OK */ pTest = Calloc (*lpBufSize+uStopSize+1, 1); if (pTest==NULL) return TCP4U_INSMEMORY; uNbRecus = 0; do { Rc = InternalTcpRecv (s, NULL, 0, uTimeOut, HFILE_ERROR); /* ereur select */ if (Rc != TCP4U_SUCCESS) XX_RETURN (Rc, "Timeout"); /* Lecture en MSG_PEEK */ Tcp4uLog (LOG4U_CALL, "recv on socket %d. MSG_PEEK, buffer %d bytes", s, *lpBufSize + uStopSize - uNbRecus); Rc = recv (s, & pTest[uNbRecus], *lpBufSize+uStopSize-uNbRecus, MSG_PEEK); if (Rc<=0) XX_RETURN (Rc, "TcpRecvUntilStr"); /* --- Maintenant on distingue 2 cas: */ /* Cas 1 : la clef est dans le buffer, */ Idx = FindPos (& pTest[uNbRecus], Rc, szStop, uStopSize, & nProxy, bCaseSensitive); if (Idx!=-1) /* la clef est disponible -> pas de probleme */ { if ( IsBadWritePtr (& szBuf[uNbRecus], Idx) ) XX_RETURN (TCP4U_BUFFERFREED, "TcpRecvUntilStr: invalid pointer") else { if (Idx!=0) { InternalTcpRecv (s, & szBuf[uNbRecus], Idx, 0, hLogFile); uNbRecus += Idx; } else uNbRecus -= nProxy; *lpBufSize = uNbRecus; InternalTcpRecv (s, pTest, uStopSize - (Idx==0 ? nProxy:0), 0, hLogFile); nProxy = 0; /* pour la prochaine recherche */ Free (pTest); return TCP4U_SUCCESS; } } /* chaine trouvee */ else /* Cas 2 : la clef n'est pas dans le buffer */ {int nToBeReceived = min (Rc, (signed) (*lpBufSize-uNbRecus)); if (IsBadWritePtr (& szBuf[uNbRecus], nToBeReceived) ) { Free (pTest); Tcp4uLog (LOG4U_ERROR, "TcpRecvUntilStr: invalid pointer"); return TCP4U_BUFFERFREED; } else { InternalTcpRecv (s, & szBuf[uNbRecus], nToBeReceived , 0, hLogFile); uNbRecus += nToBeReceived; } } /* chaine pas trouvee */ } while (uNbRecus<*lpBufSize); Free (pTest); *lpBufSize = uNbRecus; #undef XX_RETURN return TCP4U_OVERFLOW; } /* InternalTcpRecvUntilStr */