Upload Tizen:Base source
[toolchains/nspr.git] / mozilla / nsprpub / pr / tests / tmoacc.c
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* ***** BEGIN LICENSE BLOCK *****
3  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
4  *
5  * The contents of this file are subject to the Mozilla Public License Version
6  * 1.1 (the "License"); you may not use this file except in compliance with
7  * the License. You may obtain a copy of the License at
8  * http://www.mozilla.org/MPL/
9  *
10  * Software distributed under the License is distributed on an "AS IS" basis,
11  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12  * for the specific language governing rights and limitations under the
13  * License.
14  *
15  * The Original Code is the Netscape Portable Runtime (NSPR).
16  *
17  * The Initial Developer of the Original Code is
18  * Netscape Communications Corporation.
19  * Portions created by the Initial Developer are Copyright (C) 1998-2000
20  * the Initial Developer. All Rights Reserved.
21  *
22  * Contributor(s):
23  *
24  * Alternatively, the contents of this file may be used under the terms of
25  * either the GNU General Public License Version 2 or later (the "GPL"), or
26  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
27  * in which case the provisions of the GPL or the LGPL are applicable instead
28  * of those above. If you wish to allow use of your version of this file only
29  * under the terms of either the GPL or the LGPL, and not to allow others to
30  * use your version of this file under the terms of the MPL, indicate your
31  * decision by deleting the provisions above and replace them with the notice
32  * and other provisions required by the GPL or the LGPL. If you do not delete
33  * the provisions above, a recipient may use your version of this file under
34  * the terms of any one of the MPL, the GPL or the LGPL.
35  *
36  * ***** END LICENSE BLOCK ***** */
37
38 #include "nspr.h"
39
40 #include <stdlib.h>
41 #include <string.h>
42
43 #include "plerror.h"
44 #include "plgetopt.h"
45
46 #define BASE_PORT 9867
47 #define DEFAULT_THREADS 1
48 #define DEFAULT_BACKLOG 10
49 #define DEFAULT_TIMEOUT 10
50 #define RANDOM_RANGE 100  /* should be significantly smaller than RAND_MAX */
51
52 typedef enum {running, stopped} Status;
53
54 typedef struct Shared
55 {
56     PRLock *ml;
57     PRCondVar *cv;
58     PRBool passed;
59     PRBool random;
60     PRFileDesc *debug;
61     PRIntervalTime timeout;
62     PRFileDesc *listenSock;
63     Status status;
64 } Shared;
65
66 static PRIntervalTime Timeout(const Shared *shared)
67 {
68     PRIntervalTime timeout = shared->timeout;
69     if (shared->random)
70     {
71         PRIntervalTime half = timeout >> 1;  /* one half of the interval */
72         PRIntervalTime quarter = half >> 1;  /* one quarter of the interval */
73         /* something in [0..timeout / 2) */
74         PRUint32 random = (rand() % RANDOM_RANGE) * half / RANDOM_RANGE;
75         timeout = (3 * quarter) + random;  /* [75..125)% */
76     }
77     return timeout;
78 }  /* Timeout */
79
80 static void Accept(void *arg)
81 {
82     PRStatus rv;
83     char *buffer = NULL;
84     PRNetAddr clientAddr;
85     Shared *shared = (Shared*)arg;
86     PRInt32 recv_length = 0, flags = 0;
87     PRFileDesc *clientSock;
88     PRIntn toread, byte, bytes, loop = 0;
89     struct Descriptor { PRInt32 length; PRUint32 checksum; } descriptor;
90
91     do
92     {
93         PRUint32 checksum = 0;
94         if (NULL != shared->debug)
95             PR_fprintf(shared->debug, "[%d]accepting ... ", loop++);
96         clientSock = PR_Accept(
97             shared->listenSock, &clientAddr, Timeout(shared));
98         if (clientSock != NULL)
99         {
100             if (NULL != shared->debug)
101                 PR_fprintf(shared->debug, "reading length ... ");
102             bytes = PR_Recv(
103                 clientSock, &descriptor, sizeof(descriptor),
104                 flags, Timeout(shared));
105             if (sizeof(descriptor) == bytes)
106             {
107                 /* and, before doing something stupid ... */
108                 descriptor.length = PR_ntohl(descriptor.length);
109                 descriptor.checksum = PR_ntohl(descriptor.checksum);
110                 if (NULL != shared->debug)
111                     PR_fprintf(shared->debug, "%d bytes ... ", descriptor.length);
112                 toread = descriptor.length;
113                 if (recv_length < descriptor.length)
114                 {
115                     if (NULL != buffer) PR_DELETE(buffer);
116                     buffer = (char*)PR_MALLOC(descriptor.length);
117                     recv_length = descriptor.length;
118                 }
119                 for (toread = descriptor.length; toread > 0; toread -= bytes)
120                 {
121                     bytes = PR_Recv(
122                         clientSock, &buffer[descriptor.length - toread],
123                         toread, flags, Timeout(shared));
124                     if (-1 == bytes)
125                     {
126                         if (NULL != shared->debug)
127                             PR_fprintf(shared->debug, "read data failed...");
128                         bytes = 0;
129                     }
130                 }
131             }
132             else if (NULL != shared->debug)
133             {
134                 PR_fprintf(shared->debug, "read desciptor failed...");
135                 descriptor.length = -1;
136             }
137             if (NULL != shared->debug)
138                 PR_fprintf(shared->debug, "closing");
139             rv = PR_Shutdown(clientSock, PR_SHUTDOWN_BOTH);
140             if ((PR_FAILURE == rv) && (NULL != shared->debug))
141             {
142                 PR_fprintf(shared->debug, " failed");
143                 shared->passed = PR_FALSE;
144             }
145             rv = PR_Close(clientSock);
146             if (PR_FAILURE == rv) if (NULL != shared->debug)
147             {
148                 PR_fprintf(shared->debug, " failed");
149                 shared->passed = PR_FALSE;
150             }
151             if (descriptor.length > 0)
152             {
153                 for (byte = 0; byte < descriptor.length; ++byte)
154                 {
155                     PRUint32 overflow = checksum & 0x80000000;
156                     checksum = (checksum << 1);
157                     if (0x00000000 != overflow) checksum += 1;
158                     checksum += buffer[byte];
159                 }
160                 if ((descriptor.checksum != checksum) && (NULL != shared->debug))
161                 {
162                     PR_fprintf(shared->debug, " ... data mismatch");
163                     shared->passed = PR_FALSE;
164                 }
165             }
166             else if (0 == descriptor.length)
167             {
168                 PR_Lock(shared->ml);
169                 shared->status = stopped;
170                 PR_NotifyCondVar(shared->cv);
171                 PR_Unlock(shared->ml);
172             }
173             if (NULL != shared->debug)
174                 PR_fprintf(shared->debug, "\n");
175         }
176         else
177         {
178             if (PR_PENDING_INTERRUPT_ERROR != PR_GetError())
179             {
180                 if (NULL != shared->debug) PL_PrintError("Accept");
181                 shared->passed = PR_FALSE;
182             }
183         }        
184     } while (running == shared->status);
185     if (NULL != buffer) PR_DELETE(buffer);
186 }  /* Accept */
187
188 PRIntn Tmoacc(PRIntn argc, char **argv)
189 {
190     PRStatus rv;
191     PRIntn exitStatus;
192     PRIntn index;
193         Shared *shared;
194         PLOptStatus os;
195         PRThread **thread;
196     PRNetAddr listenAddr;
197     PRSocketOptionData sockOpt;
198     PRIntn timeout = DEFAULT_TIMEOUT;
199     PRIntn threads = DEFAULT_THREADS;
200     PRIntn backlog = DEFAULT_BACKLOG;
201     PRThreadScope thread_scope = PR_LOCAL_THREAD;
202
203         PLOptState *opt = PL_CreateOptState(argc, argv, "dGb:t:T:R");
204
205     shared = PR_NEWZAP(Shared);
206
207     shared->debug = NULL;
208     shared->passed = PR_TRUE;
209     shared->random = PR_TRUE;
210     shared->status = running;
211     shared->ml = PR_NewLock();
212     shared->cv = PR_NewCondVar(shared->ml);
213
214         while (PL_OPT_EOL != (os = PL_GetNextOpt(opt)))
215     {
216         if (PL_OPT_BAD == os) continue;
217         switch (opt->option)
218         {
219         case 'd':  /* debug mode */
220             shared->debug = PR_GetSpecialFD(PR_StandardError);
221             break;
222         case 'G':  /* use global threads */
223             thread_scope = PR_GLOBAL_THREAD;
224             break;
225         case 'b':  /* size of listen backlog */
226             backlog = atoi(opt->value);
227             break;
228         case 't':  /* number of threads doing accept */
229             threads = atoi(opt->value);
230             break;
231         case 'T':  /* timeout used for network operations */
232             timeout = atoi(opt->value);
233             break;
234         case 'R':  /* randomize the timeout values */
235             shared->random = PR_TRUE;
236             break;
237         default:
238             break;
239         }
240     }
241         PL_DestroyOptState(opt);
242     if (0 == threads) threads = DEFAULT_THREADS;
243     if (0 == backlog) backlog = DEFAULT_BACKLOG;
244     if (0 == timeout) timeout = DEFAULT_TIMEOUT;
245     
246     PR_STDIO_INIT();
247     memset(&listenAddr, 0, sizeof(listenAddr));
248     rv = PR_InitializeNetAddr(PR_IpAddrAny, BASE_PORT, &listenAddr);
249     PR_ASSERT(PR_SUCCESS == rv);
250
251     shared->timeout = PR_SecondsToInterval(timeout);
252
253     /* First bind to the socket */
254     shared->listenSock = PR_NewTCPSocket();
255     if (shared->listenSock)
256     {
257         sockOpt.option = PR_SockOpt_Reuseaddr;
258         sockOpt.value.reuse_addr = PR_TRUE;
259         rv = PR_SetSocketOption(shared->listenSock, &sockOpt);
260         PR_ASSERT(PR_SUCCESS == rv);
261         rv = PR_Bind(shared->listenSock, &listenAddr);
262         if (rv != PR_FAILURE)
263         {
264             rv = PR_Listen(shared->listenSock, threads + backlog);
265             if (PR_SUCCESS == rv)
266             {
267                 thread = (PRThread**)PR_CALLOC(threads * sizeof(PRThread*));
268                 for (index = 0; index < threads; ++index)
269                 {
270                     thread[index] = PR_CreateThread(
271                         PR_USER_THREAD, Accept, shared,
272                         PR_PRIORITY_NORMAL, thread_scope,
273                         PR_JOINABLE_THREAD, 0);
274                     PR_ASSERT(NULL != thread[index]);
275                 }
276
277                 PR_Lock(shared->ml);
278                 while (shared->status == running)
279                     PR_WaitCondVar(shared->cv, PR_INTERVAL_NO_TIMEOUT);
280                 PR_Unlock(shared->ml);
281                 for (index = 0; index < threads; ++index)
282                 {
283                     rv = PR_Interrupt(thread[index]);
284                     PR_ASSERT(PR_SUCCESS== rv);
285                     rv = PR_JoinThread(thread[index]);
286                     PR_ASSERT(PR_SUCCESS== rv);
287                 }
288                 PR_DELETE(thread);
289             }
290             else
291             {
292                 if (shared->debug) PL_PrintError("Listen");
293                 shared->passed = PR_FALSE;
294             }
295         }
296         else
297         {
298             if (shared->debug) PL_PrintError("Bind");
299             shared->passed = PR_FALSE;
300         }
301
302         PR_Close(shared->listenSock);
303     }
304     else
305     {
306         if (shared->debug) PL_PrintError("Create");
307         shared->passed = PR_FALSE;
308     }
309
310     PR_DestroyCondVar(shared->cv);
311     PR_DestroyLock(shared->ml);
312
313     PR_fprintf(
314         PR_GetSpecialFD(PR_StandardError), "%s\n",
315         ((shared->passed) ? "PASSED" : "FAILED"));
316
317     exitStatus = (shared->passed) ? 0 : 1;
318     PR_DELETE(shared);
319     return exitStatus;
320 }
321
322 int main(int argc, char **argv)
323 {
324     return (PR_VersionCheck(PR_VERSION)) ?
325         PR_Initialize(Tmoacc, argc, argv, 4) : -1;
326 }  /* main */
327
328 /* tmoacc */