📄 tcp4u.c
字号:
/*
* Tcp4u v 3.30 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;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -