zerolen.c (6886B)
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 * Test: zerolen.c 8 * 9 * Description: a test for Bugzilla bug #17699. We perform 10 * the same test for PR_Writev, PR_Write, and PR_Send. In 11 * each test the server thread first fills up the connection 12 * to the client so that the next write operation will fail 13 * with EAGAIN. Then it calls PR_Writev, PR_Write, or PR_Send 14 * with a zero-length buffer. The client thread initially 15 * does not read so that the connection can be filled up. 16 * Then it empties the connection so that the server thread's 17 * PR_Writev, PR_Write, or PR_Send call can succeed. 18 * 19 * Bug #17699 is specific to the pthreads version on Unix, 20 * so on other platforms this test does nothing. 21 */ 22 23 #ifndef XP_UNIX 24 25 # include <stdio.h> 26 27 int main(int argc, char** argv) { 28 printf("PASS\n"); 29 return 0; 30 } 31 32 #else /* XP_UNIX */ 33 34 # include "nspr.h" 35 # include "private/pprio.h" 36 37 # include <stdio.h> 38 # include <stdlib.h> 39 # include <string.h> 40 # include <errno.h> 41 # include <unistd.h> 42 43 static void ClientThread(void* arg) { 44 PRFileDesc* sock; 45 PRNetAddr addr; 46 PRUint16 port = (PRUint16)arg; 47 char buf[1024]; 48 PRInt32 nbytes; 49 50 sock = PR_NewTCPSocket(); 51 if (NULL == sock) { 52 fprintf(stderr, "PR_NewTCPSocket failed\n"); 53 exit(1); 54 } 55 if (PR_InitializeNetAddr(PR_IpAddrLoopback, port, &addr) == PR_FAILURE) { 56 fprintf(stderr, "PR_InitializeNetAddr failed\n"); 57 exit(1); 58 } 59 if (PR_Connect(sock, &addr, PR_INTERVAL_NO_TIMEOUT) == PR_FAILURE) { 60 fprintf(stderr, "PR_Connect failed\n"); 61 exit(1); 62 } 63 /* 64 * Sleep 5 seconds to force the server thread to get EAGAIN. 65 */ 66 if (PR_Sleep(PR_SecondsToInterval(5)) == PR_FAILURE) { 67 fprintf(stderr, "PR_Sleep failed\n"); 68 exit(1); 69 } 70 /* 71 * Then start reading. 72 */ 73 while (nbytes = PR_Read(sock, buf, sizeof(buf)) > 0) { 74 /* empty loop body */ 75 } 76 if (-1 == nbytes) { 77 fprintf(stderr, "PR_Read failed\n"); 78 exit(1); 79 } 80 if (PR_Close(sock) == PR_FAILURE) { 81 fprintf(stderr, "PR_Close failed\n"); 82 exit(1); 83 } 84 } 85 86 int main() { 87 PRFileDesc* listenSock; 88 PRFileDesc* acceptSock; 89 int osfd; 90 PRThread* clientThread; 91 PRNetAddr addr; 92 char buf[1024]; 93 PRInt32 nbytes; 94 PRIOVec iov; 95 96 memset(buf, 0, sizeof(buf)); /* Initialize the buffer. */ 97 listenSock = PR_NewTCPSocket(); 98 if (NULL == listenSock) { 99 fprintf(stderr, "PR_NewTCPSocket failed\n"); 100 exit(1); 101 } 102 if (PR_InitializeNetAddr(PR_IpAddrAny, 0, &addr) == PR_FAILURE) { 103 fprintf(stderr, "PR_InitializeNetAddr failed\n"); 104 exit(1); 105 } 106 if (PR_Bind(listenSock, &addr) == PR_FAILURE) { 107 fprintf(stderr, "PR_Bind failed\n"); 108 exit(1); 109 } 110 /* Find out what port number we are bound to. */ 111 if (PR_GetSockName(listenSock, &addr) == PR_FAILURE) { 112 fprintf(stderr, "PR_GetSockName failed\n"); 113 exit(1); 114 } 115 if (PR_Listen(listenSock, 5) == PR_FAILURE) { 116 fprintf(stderr, "PR_Listen failed\n"); 117 exit(1); 118 } 119 120 /* 121 * First test PR_Writev. 122 */ 123 clientThread = PR_CreateThread( 124 PR_USER_THREAD, ClientThread, (void*)PR_ntohs(PR_NetAddrInetPort(&addr)), 125 PR_PRIORITY_NORMAL, PR_GLOBAL_THREAD, PR_JOINABLE_THREAD, 0); 126 if (NULL == clientThread) { 127 fprintf(stderr, "PR_CreateThread failed\n"); 128 exit(1); 129 } 130 acceptSock = PR_Accept(listenSock, NULL, PR_INTERVAL_NO_TIMEOUT); 131 if (NULL == acceptSock) { 132 fprintf(stderr, "PR_Accept failed\n"); 133 exit(1); 134 } 135 osfd = PR_FileDesc2NativeHandle(acceptSock); 136 while (write(osfd, buf, sizeof(buf)) != -1) { 137 /* empty loop body */ 138 } 139 if ((errno != EAGAIN) && (errno != EWOULDBLOCK)) { 140 fprintf(stderr, "write failed\n"); 141 exit(1); 142 } 143 iov.iov_base = buf; 144 iov.iov_len = 0; 145 printf("calling PR_Writev with a zero-length buffer\n"); 146 fflush(stdout); 147 nbytes = PR_Writev(acceptSock, &iov, 1, PR_INTERVAL_NO_TIMEOUT); 148 if (nbytes != 0) { 149 fprintf(stderr, "PR_Writev should return 0 but returns %d\n", nbytes); 150 exit(1); 151 } 152 if (PR_Close(acceptSock) == PR_FAILURE) { 153 fprintf(stderr, "PR_Close failed\n"); 154 exit(1); 155 } 156 if (PR_JoinThread(clientThread) == PR_FAILURE) { 157 fprintf(stderr, "PR_JoinThread failed\n"); 158 exit(1); 159 } 160 161 /* 162 * Then test PR_Write. 163 */ 164 clientThread = PR_CreateThread( 165 PR_USER_THREAD, ClientThread, (void*)PR_ntohs(PR_NetAddrInetPort(&addr)), 166 PR_PRIORITY_NORMAL, PR_GLOBAL_THREAD, PR_JOINABLE_THREAD, 0); 167 if (NULL == clientThread) { 168 fprintf(stderr, "PR_CreateThread failed\n"); 169 exit(1); 170 } 171 acceptSock = PR_Accept(listenSock, NULL, PR_INTERVAL_NO_TIMEOUT); 172 if (NULL == acceptSock) { 173 fprintf(stderr, "PR_Accept failed\n"); 174 exit(1); 175 } 176 osfd = PR_FileDesc2NativeHandle(acceptSock); 177 while (write(osfd, buf, sizeof(buf)) != -1) { 178 /* empty loop body */ 179 } 180 if ((errno != EAGAIN) && (errno != EWOULDBLOCK)) { 181 fprintf(stderr, "write failed\n"); 182 exit(1); 183 } 184 printf("calling PR_Write with a zero-length buffer\n"); 185 fflush(stdout); 186 nbytes = PR_Write(acceptSock, buf, 0); 187 if (nbytes != 0) { 188 fprintf(stderr, "PR_Write should return 0 but returns %d\n", nbytes); 189 exit(1); 190 } 191 if (PR_Close(acceptSock) == PR_FAILURE) { 192 fprintf(stderr, "PR_Close failed\n"); 193 exit(1); 194 } 195 if (PR_JoinThread(clientThread) == PR_FAILURE) { 196 fprintf(stderr, "PR_JoinThread failed\n"); 197 exit(1); 198 } 199 200 /* 201 * Finally test PR_Send. 202 */ 203 clientThread = PR_CreateThread( 204 PR_USER_THREAD, ClientThread, (void*)PR_ntohs(PR_NetAddrInetPort(&addr)), 205 PR_PRIORITY_NORMAL, PR_GLOBAL_THREAD, PR_JOINABLE_THREAD, 0); 206 if (NULL == clientThread) { 207 fprintf(stderr, "PR_CreateThread failed\n"); 208 exit(1); 209 } 210 acceptSock = PR_Accept(listenSock, NULL, PR_INTERVAL_NO_TIMEOUT); 211 if (NULL == acceptSock) { 212 fprintf(stderr, "PR_Accept failed\n"); 213 exit(1); 214 } 215 osfd = PR_FileDesc2NativeHandle(acceptSock); 216 while (write(osfd, buf, sizeof(buf)) != -1) { 217 /* empty loop body */ 218 } 219 if ((errno != EAGAIN) && (errno != EWOULDBLOCK)) { 220 fprintf(stderr, "write failed\n"); 221 exit(1); 222 } 223 printf("calling PR_Send with a zero-length buffer\n"); 224 fflush(stdout); 225 nbytes = PR_Send(acceptSock, buf, 0, 0, PR_INTERVAL_NO_TIMEOUT); 226 if (nbytes != 0) { 227 fprintf(stderr, "PR_Send should return 0 but returns %d\n", nbytes); 228 exit(1); 229 } 230 if (PR_Close(acceptSock) == PR_FAILURE) { 231 fprintf(stderr, "PR_Close failed\n"); 232 exit(1); 233 } 234 if (PR_JoinThread(clientThread) == PR_FAILURE) { 235 fprintf(stderr, "PR_JoinThread failed\n"); 236 exit(1); 237 } 238 239 if (PR_Close(listenSock) == PR_FAILURE) { 240 fprintf(stderr, "PR_Close failed\n"); 241 exit(1); 242 } 243 printf("PASS\n"); 244 return 0; 245 } 246 247 #endif /* XP_UNIX */