1 /*
2  * Mozilla Test
3  * Copyright (C) 2004 Filip Navara
4  */
5 
6 #include <winsock.h>
7 #include <stdio.h>
8 
9 ULONG DbgPrint(PCH Format,...);
10 
11 #undef DBG
12 #define DBG(x) \
13   printf("%s:%i - %s", __FILE__, __LINE__, x); \
14   DbgPrint("%s:%i - %s", __FILE__, __LINE__, x);
15 
16 int SocketTest()
17 {
18    /*
19     * A socket pair is often used for interprocess communication,
20     * so we need to make sure neither socket is associated with
21     * the I/O completion port; otherwise it can't be used by a
22     * child process.
23     *
24     * The default implementation below cannot be used for NT
25     * because PR_Accept would have associated the I/O completion
26     * port with the listening and accepted sockets.
27     */
28    SOCKET listenSock;
29    SOCKET osfd[2];
30    struct sockaddr_in selfAddr, peerAddr;
31    int addrLen;
32    WORD wVersionRequested;
33    WSADATA wsaData;
34    int err;
35 
36    /*
37     * Initialization.
38     */
39 
40    wVersionRequested = MAKEWORD( 2, 2 );
41 
42    DBG("Calling WSAStartup\n");
43    err = WSAStartup( wVersionRequested, &wsaData );
44    if ( err != 0 ) {
45        /* Tell the user that we could not find a usable */
46        /* WinSock DLL.                                  */
47        DBG("WSAStartup failed\n");
48        return 1;
49    }
50 
51    /* Confirm that the WinSock DLL supports 2.2.*/
52    /* Note that if the DLL supports versions greater    */
53    /* than 2.2 in addition to 2.2, it will still return */
54    /* 2.2 in wVersion since that is the version we      */
55    /* requested.                                        */
56 
57    if ( LOBYTE( wsaData.wVersion ) != 2 ||
58            HIBYTE( wsaData.wVersion ) != 2 ) {
59        /* Tell the user that we could not find a usable */
60        /* WinSock DLL.                                  */
61        DBG("WSAStartup version unacceptable\n");
62        WSACleanup( );
63        return 1;
64    }
65 
66    /* The WinSock DLL is acceptable. Proceed. */
67 
68    DBG("Calling socket\n");
69    osfd[0] = osfd[1] = INVALID_SOCKET;
70    listenSock = socket(AF_INET, SOCK_STREAM, 0);
71    if (listenSock == INVALID_SOCKET) {
72        DBG("socket failed\n");
73        goto failed;
74    }
75 
76    selfAddr.sin_family = AF_INET;
77    selfAddr.sin_port = 0;
78    selfAddr.sin_addr.s_addr = htonl(INADDR_LOOPBACK); /* BugZilla: 35408 */
79    addrLen = sizeof(selfAddr);
80    DBG("Calling bind\n");
81    if (bind(listenSock, (struct sockaddr *) &selfAddr,
82            addrLen) == SOCKET_ERROR) {
83        DBG("bind failed\n");
84        goto failed;
85    }
86 
87    DBG("Calling getsockname\n");
88    if (getsockname(listenSock, (struct sockaddr *) &selfAddr,
89            &addrLen) == SOCKET_ERROR) {
90        DBG("getsockname failed\n");
91        goto failed;
92    }
93 
94    DBG("Calling listen\n");
95    if (listen(listenSock, 5) == SOCKET_ERROR) {
96        DBG("listen failed\n");
97        goto failed;
98    }
99 
100    DBG("Calling socket\n");
101    osfd[0] = socket(AF_INET, SOCK_STREAM, 0);
102    if (osfd[0] == INVALID_SOCKET) {
103        DBG("socket failed\n");
104        goto failed;
105    }
106    selfAddr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
107 
108    /*
109     * Only a thread is used to do the connect and accept.
110     * I am relying on the fact that connect returns
111     * successfully as soon as the connect request is put
112     * into the listen queue (but before accept is called).
113     * This is the behavior of the BSD socket code.  If
114     * connect does not return until accept is called, we
115     * will need to create another thread to call connect.
116     */
117    DBG("Calling connect\n");
118    if (connect(osfd[0], (struct sockaddr *) &selfAddr,
119            addrLen) == SOCKET_ERROR) {
120        DBG("connect failed\n");
121        goto failed;
122    }
123 
124    /*
125     * A malicious local process may connect to the listening
126     * socket, so we need to verify that the accepted connection
127     * is made from our own socket osfd[0].
128     */
129    DBG("Calling getsockname\n");
130    if (getsockname(osfd[0], (struct sockaddr *) &selfAddr,
131            &addrLen) == SOCKET_ERROR) {
132        DBG("getsockname failed\n");
133        goto failed;
134    }
135 
136    DBG("Calling accept\n");
137    osfd[1] = accept(listenSock, (struct sockaddr *) &peerAddr, &addrLen);
138    if (osfd[1] == INVALID_SOCKET) {
139        DBG("accept failed\n");
140        goto failed;
141    }
142    if (peerAddr.sin_port != selfAddr.sin_port) {
143        /* the connection we accepted is not from osfd[0] */
144        DBG("peerAddr.sin_port != selfAddr.sin_port\n");
145        goto failed;
146    }
147 
148    DBG("Hurray!\n");
149 
150    closesocket(listenSock);
151 
152    closesocket(osfd[0]);
153    closesocket(osfd[1]);
154 
155    WSACleanup();
156 
157    return 0;
158 
159 failed:
160    if (listenSock != INVALID_SOCKET) {
161        closesocket(listenSock);
162    }
163    if (osfd[0] != INVALID_SOCKET) {
164        closesocket(osfd[0]);
165    }
166    if (osfd[1] != INVALID_SOCKET) {
167        closesocket(osfd[1]);
168    }
169 
170    WSACleanup();
171 
172    return 1;
173 }
174 
175 int VirtualTest()
176 {
177    DWORD dwErr;
178    SYSTEM_INFO si;
179    HANDLE hMap;
180    PBYTE pBufferStart;
181    PCHAR pszFileName = "test.txt";
182    ULONG dwMaxSize = strlen(pszFileName);
183 
184    DBG("Calling CreateFileMappingA\n");
185    hMap = CreateFileMappingA(INVALID_HANDLE_VALUE, NULL,
186       PAGE_READWRITE | SEC_RESERVE, 0, dwMaxSize, pszFileName);
187    if (!hMap)
188    {
189       DBG("CreateFileMappingA failed\n");
190       return 1;
191    }
192 
193    dwErr = GetLastError();
194    DBG("Calling MapViewOfFile\n");
195    pBufferStart = (BYTE *)MapViewOfFile(hMap, FILE_MAP_ALL_ACCESS, 0, 0, 0);
196    if (!pBufferStart)
197    {
198       DBG("MapViewOfFile failed\n");
199       return 1;
200    }
201 
202    GetSystemInfo(&si);
203 
204    if (dwErr == ERROR_ALREADY_EXISTS)
205    {
206       DBG("MapViewOfFile returned ERROR_ALREADY_EXISTS\n");
207       DBG("This really shouldn't happen, but it's not fatal.\n");
208       UnmapViewOfFile(pBufferStart);
209       CloseHandle(hMap);
210       return 1;
211    }
212    else
213    {
214       DBG("Calling VirtualAlloc\n");
215       if (!VirtualAlloc(pBufferStart, si.dwPageSize, MEM_COMMIT, PAGE_READWRITE))
216       {
217          DBG("VirtualAlloc failed\n");
218          UnmapViewOfFile(pBufferStart);
219          CloseHandle(hMap);
220          return 1;
221       }
222    }
223 
224    DBG("Hurray!\n");
225 
226    UnmapViewOfFile(pBufferStart);
227    CloseHandle(hMap);
228 
229    return 0;
230 }
231 
232 int main(int argc, char **argv)
233 {
234    if (argc != 2)
235    {
236       printf("Usage: %s test_name\n\n", argv[0]);
237       printf("Valid test names:\n");
238       printf("\tsocket\n");
239       printf("\tvirtual\n");
240       return 0;
241    }
242 
243    if (!_stricmp(argv[1], "socket"))
244       return SocketTest();
245    if (!_stricmp(argv[1], "virtual"))
246       return VirtualTest();
247 
248    printf("Test '%s' doesn't exist\n", argv[1]);
249 
250    return 0;
251 }
252