net-snmp 5.7
winpipe.c
00001 /*
00002   Copyright (c) Fabasoft R&D Software GmbH & Co KG, 2003
00003   oss@fabasoft.com
00004   Author: Bernhard Penz <bernhard.penz@fabasoft.com>
00005 
00006   Redistribution and use in source and binary forms, with or without
00007   modification, are permitted provided that the following conditions are met:
00008 
00009   *  Redistributions of source code must retain the above copyright notice,
00010      this list of conditions and the following disclaimer.
00011 
00012   *  Redistributions in binary form must reproduce the above copyright
00013      notice, this list of conditions and the following disclaimer in the
00014      documentation and/or other materials provided with the distribution.
00015 
00016   *  The name of Fabasoft R&D Software GmbH & Co KG or any of its subsidiaries, 
00017      brand or product names may not be used to endorse or promote products 
00018      derived from this software without specific prior written permission.
00019 
00020   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER ``AS IS'' AND ANY
00021   EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00022   IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
00023   PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT HOLDER BE
00024   LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
00025   CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
00026   SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
00027   BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
00028   WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
00029   OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
00030   IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00031 */
00032 
00033 #ifdef WIN32
00034 
00035 #include <net-snmp/net-snmp-config.h>
00036 #include <net-snmp/types.h>
00037 #include <net-snmp/library/snmp_assert.h>
00038 #include <net-snmp/library/winpipe.h>
00039 #include <io.h>
00040 
00041 static int InitUPDSocket(SOCKET *sock, struct sockaddr_in *socketaddress)
00042 {
00043         *sock = 0;
00044         memset(socketaddress, 0, sizeof(struct sockaddr_in));
00045 
00046         if( (*sock = socket(AF_INET, SOCK_DGRAM, 0)) == SOCKET_ERROR)
00047         {
00048                 netsnmp_assert(GetLastError() != WSANOTINITIALISED);
00049                 return -1;
00050         }
00051         socketaddress->sin_family = AF_INET;
00052         socketaddress->sin_addr.S_un.S_addr = htonl(INADDR_LOOPBACK);
00053         socketaddress->sin_port = 0;
00054 
00055         if(bind(*sock, (struct sockaddr *) socketaddress, sizeof(struct sockaddr)) == SOCKET_ERROR)
00056         {
00057                 return -1;
00058         }
00059 
00060         return 0;
00061 }
00062 
00063 static int ConnectUDPSocket(SOCKET *sock, struct sockaddr_in *socketaddress, SOCKET *remotesocket)
00064 {
00065         int size = sizeof(struct sockaddr);
00066         if (getsockname(*sock, (struct sockaddr *) socketaddress, &size) == SOCKET_ERROR)
00067         {
00068                 return -1;
00069         }
00070 
00071         if(size != sizeof(struct sockaddr))
00072         {
00073                 return -1;
00074         }
00075 
00076         if (connect(*remotesocket, (struct sockaddr *) socketaddress, sizeof(struct sockaddr)) == SOCKET_ERROR)
00077         {
00078                 return -1;
00079         }
00080 
00081         return 0;
00082 }
00083 
00084 static int TestUDPSend(SOCKET *sock, struct sockaddr_in *socketaddress)
00085 {
00086         unsigned short port = socketaddress->sin_port;
00087 
00088         int bytessent = sendto(*sock, (char *) &port, sizeof(port), 0, NULL, 0);
00089         if(bytessent != sizeof(port))
00090         {
00091                 return -1;
00092         }
00093 
00094         return 0;
00095 }
00096 
00097 static int TestUDPReceive(SOCKET *sock, SOCKET *remotesocket, struct sockaddr_in *remotesocketaddress)
00098 {
00099         struct sockaddr_in recvfromaddress;
00100         unsigned short readbuffer[2];
00101         int size = sizeof(struct sockaddr);
00102 
00103         int bytesreceived = recvfrom(*sock,(char *) &readbuffer, sizeof(readbuffer), 0, (struct sockaddr *) &recvfromaddress, &size) ;
00104         if(bytesreceived != sizeof(unsigned short) || size != sizeof(struct sockaddr) || readbuffer[0] != (unsigned short) remotesocketaddress->sin_port || recvfromaddress.sin_family != remotesocketaddress->sin_family || recvfromaddress.sin_addr.S_un.S_addr != remotesocketaddress->sin_addr.S_un.S_addr || recvfromaddress.sin_port != remotesocketaddress->sin_port)
00105         {
00106                 return -1;
00107         }
00108 
00109         return 0;
00110 }
00111 
00112 static void CloseUDPSocketPair(SOCKET *socketpair)
00113 {
00114         if(socketpair[0] != INVALID_SOCKET)
00115         {
00116                 closesocket(socketpair[0]);
00117         }
00118         if(socketpair[1] != INVALID_SOCKET)
00119         {
00120                 closesocket(socketpair[1]);
00121         }
00122 }
00123 
00124 /*
00125         Windows unnamed pipe emulation, used to enable select()
00126         on a Windows machine for the CALLBACK (pipe-based) transport domain.
00127 */
00128 int create_winpipe_transport(int *pipefds)
00129 {
00130         SOCKET socketpair[2];
00131         struct sockaddr_in socketaddress[2];
00132 
00133         struct timeval waittime = {0, 200000};
00134         fd_set readset;
00135 
00136         if (InitUPDSocket(&socketpair[0], &socketaddress[0]))
00137         {
00138                 CloseUDPSocketPair(socketpair);
00139                 return -1;
00140         }
00141         if (InitUPDSocket(&socketpair[1], &socketaddress[1]))
00142         {
00143                 CloseUDPSocketPair(socketpair);
00144                 return -1;
00145         }
00146 
00147         /*
00148                 I have two UDP sockets - now lets connect them to each other.
00149         */
00150 
00151         if (ConnectUDPSocket(&socketpair[0], &socketaddress[0], &socketpair[1]))
00152         {
00153                 CloseUDPSocketPair(socketpair);
00154                 return -1;
00155         }
00156         if(ConnectUDPSocket(&socketpair[1], &socketaddress[1], &socketpair[0]))
00157         {
00158                 CloseUDPSocketPair(socketpair);
00159                 return -1;
00160         }
00161 
00162         /*
00163                 The two sockets are connected to each other, now lets test the connection
00164                 by sending the own port number.
00165         */
00166         if(TestUDPSend(&socketpair[0], &socketaddress[0]))
00167         {
00168                 CloseUDPSocketPair(socketpair);
00169                 return -1;
00170         }
00171         if(TestUDPSend(&socketpair[1], &socketaddress[1]))
00172         {
00173                 CloseUDPSocketPair(socketpair);
00174                 return -1;
00175         }
00176 
00177         /*
00178                 Port numbers sent, now lets select() on the socketpair and check that 
00179                 both messages got through
00180         */
00181         FD_ZERO(&readset);
00182         FD_SET(socketpair[0], &readset);
00183         FD_SET(socketpair[1], &readset);
00184 
00185         /*
00186                 For some unknown reason the timeout setting in the select call does not have
00187                 the desired effect, and for yet another unknown reason a Sleep(1) solves this
00188                 problem.
00189         */
00190         Sleep(1);
00191         if(select(0, &readset, NULL, NULL, &waittime) != 2 || !FD_ISSET(socketpair[0], &readset) || !FD_ISSET(socketpair[1], &readset))
00192         {
00193                 CloseUDPSocketPair(socketpair);
00194                 return -1;
00195         }
00196 
00197         /*
00198                 Check if the packets I receive were really sent by me, and nobody else
00199                 tried to sneak.
00200         */
00201     if(TestUDPReceive(&socketpair[0], &socketpair[1], &socketaddress[1]))
00202         {
00203                 CloseUDPSocketPair(socketpair);
00204                 return -1;
00205         }
00206         if(TestUDPReceive(&socketpair[1], &socketpair[0], &socketaddress[0]))
00207         {
00208                 CloseUDPSocketPair(socketpair);
00209                 return -1;
00210         }
00211 
00212         /*
00213                 All sanity checks passed, I can return a "UDP pipe"
00214         */
00215         pipefds[0] = (int) socketpair[0];
00216         pipefds[1] = (int) socketpair[1];
00217 
00218         return 0;
00219 }
00220 
00221 #endif /* WIN32 */
00222