/* * Tcp4u v 3.31 Last Revision 09/03/1997 3.31-00 * *=========================================================================== * * Project: Tcp4u, Library for tcp protocol * File: udp4u.c * Purpose: main functions for udp protocol 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" static char szWhat[] ="@(#)Udp4u by Ph. Jounin version 3.31"; /* ------------------------------------------------------------------------- */ /* Fonction de traduction Service -> port */ /* ------------------------------------------------------------------------- */ unsigned short API4U Udp4uServiceToPort (LPCSTR szService) { unsigned short uPort = 0; struct servent far * lpServEnt; if (szService!=NULL) { Tcp4uLog (LOG4U_CALL, "getservbyname service %s", szService); lpServEnt = getservbyname (szService, "udp") ; if (lpServEnt==NULL) Tcp4uLog (LOG4U_ERROR, "getservbyname service %s", szService); else uPort = ntohs (lpServEnt->s_port); } return uPort; } /* Udp4uServiceToPort */ /* ------------------------------------------------------------------------- */ /* initialisation UDP */ /* ------------------------------------------------------------------------- */ int API4U UdpInit (LPUDPSOCK far *pUdp, LPCSTR szHost, unsigned short uRemotePort, unsigned short uLocalPort) { int Rc; SOCKET UdpSock = INVALID_SOCKET; struct sockaddr_in saSendAddr; /* structure identifiant le destinataire */ struct sockaddr_in saBindAddr; /* structure limitant les clients */ Tcp4uLog (LOG4U_PROC, "UdpInit, host %s", szHost); memset (& saBindAddr, 0, sizeof saBindAddr); memset (& saSendAddr, 0, sizeof saSendAddr); /* --- 1. calcul de saSendAddr : RemoteService et szHost */ saSendAddr.sin_family = AF_INET; saSendAddr.sin_port = htons (uRemotePort) ; if (szHost!=NULL) { saSendAddr.sin_addr = Tcp4uGetIPAddr (szHost); if (saSendAddr.sin_addr.s_addr==INADDR_NONE) { Tcp4uLog (LOG4U_ERROR, "UdpInit: host Unknown"); return TCP4U_HOSTUNKNOWN; } } /* szHost is specified */ /* --- autres champs de saBindAddr */ saBindAddr.sin_port = htons (uLocalPort); saBindAddr.sin_family = AF_INET; saBindAddr.sin_addr.s_addr = INADDR_ANY; /* --- Allocation de la socket */ Tcp4uLog (LOG4U_CALL, "socket PF_INET SOCK_DGRAM"); UdpSock = socket (PF_INET, SOCK_DGRAM, 0); if (UdpSock<0) { Tcp4uLog (LOG4U_ERROR, "socket PF_INET SOCK_DGRAM"); return TCP4U_NOMORESOCKET; } /* --- do a bind, thus all packets to be received will come on given port */ Tcp4uLog (LOG4U_CALL, "bind to %s", inet_ntoa (saBindAddr.sin_addr)); Rc = bind (UdpSock, (struct sockaddr far *) & saBindAddr, sizeof(struct sockaddr)); if (Rc<0) { Tcp4uLog (LOG4U_ERROR, "bind to %s", inet_ntoa (saBindAddr.sin_addr)); CloseSocket (UdpSock); return TCP4U_BINDERROR; } /* --- Allocation de la structure */ *pUdp = Calloc (sizeof (UDPSOCK), 1); if (*pUdp==NULL) { CloseSocket (UdpSock); return TCP4U_INSMEMORY; } (*pUdp)->UdpSock = UdpSock; (*pUdp)->saSendAddr = saSendAddr; (*pUdp)->bSemiConnected = FALSE; /* can receive data from any host */ Tcp4uLog (LOG4U_EXIT, "UdpInit"); return TCP4U_SUCCESS; } /* UdpInit */ /* ------------------------------------------------------------------------ */ /* UdpBind: Restrict socket to listen only from previous client */ /* ------------------------------------------------------------------------ */ int API4U UdpBind (LPUDPSOCK pUdp, BOOL bFilter, int nMode) { Tcp4uLog (LOG4U_PROC, "UdpBind Mode %s", nMode==UDP4U_CLIENT ? "client" : "server"); if (bFilter) { switch (nMode) { /* le client ne peut recevoir que de la machine serveur */ /* le serveur que depuis la machine d'ou il a deja recu des infos */ /* en mode serveur, l'adresse de destination devient l'adresse */ /* du dernier host. */ case UDP4U_CLIENT : pUdp->saFilter = pUdp->saSendAddr.sin_addr ; break; case UDP4U_SERVER : pUdp->saFilter = pUdp->saRecvAddr.sin_addr; pUdp->saSendAddr = pUdp->saRecvAddr; break; default : return TCP4U_ERROR; } /* selon mode */ } /* si filtre positionne */ /* filtre ou pas filtre */ pUdp->bSemiConnected = bFilter; Tcp4uLog (LOG4U_EXIT, "UdpBind"); return TCP4U_SUCCESS; } /* UdpBind */ /* ------------------------------------------------------------------------- */ /* destructeur : UdpCleanup */ /* ------------------------------------------------------------------------- */ int API4U UdpCleanup (LPUDPSOCK Udp) { int Rc; Tcp4uLog (LOG4U_PROC, "UdpCleanup sock %d", Udp->UdpSock); Tcp4uLog (LOG4U_CALL, "closesocket sock %d", Udp->UdpSock); Rc = CloseSocket (Udp->UdpSock); if (Rc!=0) { Tcp4uLog (LOG4U_ERROR, "closesocket sock %d", Udp->UdpSock); return TCP4U_ERROR; } Free (Udp); Tcp4uLog (LOG4U_EXIT, "UdpCleanup"); return TCP4U_SUCCESS; } /* UdpCleanup */ /* ------------------------------------------------------------------------- */ /* Envoi d'une trame UDP */ /* ------------------------------------------------------------------------- */ int API4U UdpSend (LPUDPSOCK Udp, LPCSTR sData, int nDataSize, BOOL bHighPriority, HFILE hLogFile) { int Rc; Tcp4uLog (LOG4U_PROC, "UdpSend sock %d, %d bytes to be sent ", Udp->UdpSock, nDataSize); Rc = InternalUdpSend (Udp, sData, nDataSize, bHighPriority, hLogFile); if (Rc==TCP4U_SUCCESS) Tcp4uDump (sData, nDataSize, DUMP4U_SENT); Tcp4uLog (LOG4U_EXIT, "UdpSend"); return Rc; } /* UdpSend */ int InternalUdpSend (LPUDPSOCK Udp,LPCSTR sData, int nDataSize, BOOL bHighPriority, HFILE hLogFile) { int Rc; Tcp4uLog (LOG4U_CALL, "sendto host %s sock %d, %d bytes to be sent ", inet_ntoa (Udp->saSendAddr.sin_addr), Udp->UdpSock, nDataSize); Rc = sendto ( Udp->UdpSock, sData, nDataSize, bHighPriority ? MSG_OOB : 0, (struct sockaddr far *) &Udp->saSendAddr, sizeof Udp->saSendAddr); /* --- Analyser la valeur retounee */ if (Rc<0) { Tcp4uLog (LOG4U_ERROR, "sendto host %s", inet_ntoa (Udp->saSendAddr.sin_addr) ); return TCP4U_ERROR; } if (hLogFile!=HFILE_ERROR) Write (hLogFile, sData, Rc); return Rc==nDataSize ? TCP4U_SUCCESS : TCP4U_OVERFLOW; } /* InternalUdpSend */ /* ------------------------------------------------------------------------- */ /* La fonction reciproque : UdpRecv */ /* ------------------------------------------------------------------------- */ int API4U UdpRecv (LPUDPSOCK pUdp, LPSTR sData, int nDataSize, unsigned uTimeOut, HFILE hLogFile) { int Rc; Tcp4uLog (LOG4U_PROC, "UdpRecv sock %d, buffer %d bytes", pUdp->UdpSock, nDataSize); Rc = InternalUdpRecv (pUdp, sData, nDataSize, uTimeOut, hLogFile); if (Rc>=TCP4U_SUCCESS) Tcp4uDump (sData, Rc, DUMP4U_RCVD); Tcp4uLog (LOG4U_EXIT, "UdpRecv %d bytes received", Rc); return Rc; } /* UdpRecv */ int InternalUdpRecv (LPUDPSOCK pUdp, LPSTR sData, int nDataSize, unsigned uTimeOut, HFILE hLogFile) { int Rc; struct timeval TO; fd_set ReadMask; /* select mask */ int Len = sizeof (struct sockaddr_in); if (pUdp->UdpSock==INVALID_SOCKET) return TCP4U_ERROR; /* bug 1 : Timeout kept in Loop, should be decremented */ /* (can be done by the select function) */ /* bug 2 : some frames are read even if they do not concern this process */ TO.tv_sec = (long) uTimeOut; /* secondes */ TO.tv_usec = 0; /* microsecondes */ do { FD_ZERO (& ReadMask); /* mise a zero du masque */ FD_SET (pUdp->UdpSock, & ReadMask); /* Attente d'evenement en lecture */ /* s+1 normally unused but better for a lot of bugged TCP Stacks */ Tcp4uLog (LOG4U_CALL, "select Timeout %d", uTimeOut); Rc = select ( pUdp->UdpSock+1, & ReadMask, NULL, NULL, uTimeOut==0? NULL: &TO); if (Rc<0) { Tcp4uLog (LOG4U_ERROR, "select"); return IsCancelled() ? TCP4U_CANCELLED : TCP4U_ERROR; } if (Rc==0) { Tcp4uLog (LOG4U_ERROR, "select: Timeout"); return TCP4U_TIMEOUT; /* timeout en reception */ } Tcp4uLog (LOG4U_CALL, "recvfrom host %s", inet_ntoa (pUdp->saRecvAddr.sin_addr)); Rc = recvfrom (pUdp->UdpSock, sData, nDataSize, 0, (struct sockaddr far *) & pUdp->saRecvAddr, & Len); if (Rc<0) { Tcp4uLog (LOG4U_ERROR, "recvfrom"); return TCP4U_ERROR; } } while ( pUdp->bSemiConnected && memcmp (& pUdp->saRecvAddr.sin_addr, & pUdp->saFilter, sizeof pUdp->saFilter) != 0); if (hLogFile!=HFILE_ERROR) Write (hLogFile, sData, Rc); return Rc; } /* InternalUdpRecv */