1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5
6 /*
7 * File: multiacc.c
8 *
9 * Description:
10 * This test creates multiple threads that accept on the
11 * same listening socket.
12 */
13
14 #include "nspr.h"
15
16 #include <stdio.h>
17 #include <stdlib.h>
18 #include <string.h>
19
20 #define NUM_SERVER_THREADS 10
21
22 static int num_server_threads = NUM_SERVER_THREADS;
23 static PRThreadScope thread_scope = PR_GLOBAL_THREAD;
24 static PRBool exit_flag = PR_FALSE;
25
ServerThreadFunc(void * arg)26 static void ServerThreadFunc(void *arg)
27 {
28 PRFileDesc *listenSock = (PRFileDesc *) arg;
29 PRFileDesc *acceptSock;
30 PRErrorCode err;
31 PRStatus status;
32
33 while (!exit_flag) {
34 acceptSock = PR_Accept(listenSock, NULL, PR_INTERVAL_NO_TIMEOUT);
35 if (NULL == acceptSock) {
36 err = PR_GetError();
37 if (PR_PENDING_INTERRUPT_ERROR == err) {
38 printf("server thread is interrupted\n");
39 fflush(stdout);
40 continue;
41 }
42 fprintf(stderr, "PR_Accept failed: %d\n", err);
43 exit(1);
44 }
45 status = PR_Close(acceptSock);
46 if (PR_FAILURE == status) {
47 fprintf(stderr, "PR_Close failed\n");
48 exit(1);
49 }
50 }
51 }
52
main(int argc,char ** argv)53 int main(int argc, char **argv)
54 {
55 PRNetAddr serverAddr;
56 PRFileDesc *dummySock;
57 PRFileDesc *listenSock;
58 PRFileDesc *clientSock;
59 PRThread *dummyThread;
60 PRThread **serverThreads;
61 PRStatus status;
62 PRUint16 port;
63 int idx;
64 PRInt32 nbytes;
65 char buf[1024];
66
67 serverThreads = (PRThread **)
68 PR_Malloc(num_server_threads * sizeof(PRThread *));
69 if (NULL == serverThreads) {
70 fprintf(stderr, "PR_Malloc failed\n");
71 exit(1);
72 }
73
74 /*
75 * Create a dummy listening socket and have the first
76 * (dummy) thread listen on it. This is to ensure that
77 * the first thread becomes the I/O continuation thread
78 * in the pthreads implementation (see ptio.c) and remains
79 * so throughout the test, so that we never have to
80 * recycle the I/O continuation thread.
81 */
82 dummySock = PR_NewTCPSocket();
83 if (NULL == dummySock) {
84 fprintf(stderr, "PR_NewTCPSocket failed\n");
85 exit(1);
86 }
87 memset(&serverAddr, 0, sizeof(serverAddr));
88 status = PR_InitializeNetAddr(PR_IpAddrAny, 0, &serverAddr);
89 if (PR_FAILURE == status) {
90 fprintf(stderr, "PR_InitializeNetAddr failed\n");
91 exit(1);
92 }
93 status = PR_Bind(dummySock, &serverAddr);
94 if (PR_FAILURE == status) {
95 fprintf(stderr, "PR_Bind failed\n");
96 exit(1);
97 }
98 status = PR_Listen(dummySock, 5);
99 if (PR_FAILURE == status) {
100 fprintf(stderr, "PR_Listen failed\n");
101 exit(1);
102 }
103
104 listenSock = PR_NewTCPSocket();
105 if (NULL == listenSock) {
106 fprintf(stderr, "PR_NewTCPSocket failed\n");
107 exit(1);
108 }
109 memset(&serverAddr, 0, sizeof(serverAddr));
110 status = PR_InitializeNetAddr(PR_IpAddrAny, 0, &serverAddr);
111 if (PR_FAILURE == status) {
112 fprintf(stderr, "PR_InitializeNetAddr failed\n");
113 exit(1);
114 }
115 status = PR_Bind(listenSock, &serverAddr);
116 if (PR_FAILURE == status) {
117 fprintf(stderr, "PR_Bind failed\n");
118 exit(1);
119 }
120 status = PR_GetSockName(listenSock, &serverAddr);
121 if (PR_FAILURE == status) {
122 fprintf(stderr, "PR_GetSockName failed\n");
123 exit(1);
124 }
125 port = PR_ntohs(serverAddr.inet.port);
126 status = PR_Listen(listenSock, 5);
127 if (PR_FAILURE == status) {
128 fprintf(stderr, "PR_Listen failed\n");
129 exit(1);
130 }
131
132 printf("creating dummy thread\n");
133 fflush(stdout);
134 dummyThread = PR_CreateThread(PR_USER_THREAD,
135 ServerThreadFunc, dummySock, PR_PRIORITY_NORMAL,
136 thread_scope, PR_JOINABLE_THREAD, 0);
137 if (NULL == dummyThread) {
138 fprintf(stderr, "PR_CreateThread failed\n");
139 exit(1);
140 }
141 printf("sleeping one second before creating server threads\n");
142 fflush(stdout);
143 PR_Sleep(PR_SecondsToInterval(1));
144 for (idx = 0; idx < num_server_threads; idx++) {
145 serverThreads[idx] = PR_CreateThread(PR_USER_THREAD,
146 ServerThreadFunc, listenSock, PR_PRIORITY_NORMAL,
147 thread_scope, PR_JOINABLE_THREAD, 0);
148 if (NULL == serverThreads[idx]) {
149 fprintf(stderr, "PR_CreateThread failed\n");
150 exit(1);
151 }
152 }
153
154 memset(&serverAddr, 0, sizeof(serverAddr));
155 PR_InitializeNetAddr(PR_IpAddrLoopback, port, &serverAddr);
156 clientSock = PR_NewTCPSocket();
157 if (NULL == clientSock) {
158 fprintf(stderr, "PR_NewTCPSocket failed\n");
159 exit(1);
160 }
161 printf("sleeping one second before connecting\n");
162 fflush(stdout);
163 PR_Sleep(PR_SecondsToInterval(1));
164 status = PR_Connect(clientSock, &serverAddr, PR_INTERVAL_NO_TIMEOUT);
165 if (PR_FAILURE == status) {
166 fprintf(stderr, "PR_Connect failed\n");
167 exit(1);
168 }
169 nbytes = PR_Read(clientSock, buf, sizeof(buf));
170 if (nbytes != 0) {
171 fprintf(stderr, "expected 0 bytes but got %d bytes\n", nbytes);
172 exit(1);
173 }
174 status = PR_Close(clientSock);
175 if (PR_FAILURE == status) {
176 fprintf(stderr, "PR_Close failed\n");
177 exit(1);
178 }
179 printf("sleeping one second before shutting down server threads\n");
180 fflush(stdout);
181 PR_Sleep(PR_SecondsToInterval(1));
182
183 exit_flag = PR_TRUE;
184 status = PR_Interrupt(dummyThread);
185 if (PR_FAILURE == status) {
186 fprintf(stderr, "PR_Interrupt failed\n");
187 exit(1);
188 }
189 status = PR_JoinThread(dummyThread);
190 if (PR_FAILURE == status) {
191 fprintf(stderr, "PR_JoinThread failed\n");
192 exit(1);
193 }
194 for (idx = 0; idx < num_server_threads; idx++) {
195 status = PR_Interrupt(serverThreads[idx]);
196 if (PR_FAILURE == status) {
197 fprintf(stderr, "PR_Interrupt failed\n");
198 exit(1);
199 }
200 status = PR_JoinThread(serverThreads[idx]);
201 if (PR_FAILURE == status) {
202 fprintf(stderr, "PR_JoinThread failed\n");
203 exit(1);
204 }
205 }
206 PR_Free(serverThreads);
207 status = PR_Close(dummySock);
208 if (PR_FAILURE == status) {
209 fprintf(stderr, "PR_Close failed\n");
210 exit(1);
211 }
212 status = PR_Close(listenSock);
213 if (PR_FAILURE == status) {
214 fprintf(stderr, "PR_Close failed\n");
215 exit(1);
216 }
217
218 printf("PASS\n");
219 return 0;
220 }
221