|
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: sendzlf.c |
|
8 * |
|
9 * Description: send a zero-length file with PR_SendFile and |
|
10 * PR_TransmitFile. |
|
11 */ |
|
12 |
|
13 #define ZERO_LEN_FILE_NAME "zerolen.tmp" |
|
14 #define HEADER_STR "Header" |
|
15 #define HEADER_LEN 6 /* length of HEADER_STR, not counting the null byte */ |
|
16 #define TRAILER_STR "Trailer" |
|
17 #define TRAILER_LEN 7 /* length of TRAILER_STR, not counting the null byte */ |
|
18 |
|
19 #include "nspr.h" |
|
20 |
|
21 #include <stdio.h> |
|
22 #include <stdlib.h> |
|
23 #include <string.h> |
|
24 |
|
25 static void ClientThread(void *arg) |
|
26 { |
|
27 PRFileDesc *sock; |
|
28 PRNetAddr addr; |
|
29 PRUint16 port = (PRUint16) arg; |
|
30 char buf[1024]; |
|
31 char *bufPtr; |
|
32 PRInt32 nbytes; |
|
33 PRInt32 ntotal; |
|
34 PRInt32 nexpected; |
|
35 |
|
36 sock = PR_NewTCPSocket(); |
|
37 if (NULL == sock) { |
|
38 fprintf(stderr, "PR_NewTCPSocket failed\n"); |
|
39 exit(1); |
|
40 } |
|
41 if (PR_InitializeNetAddr(PR_IpAddrLoopback, port, &addr) == PR_FAILURE) { |
|
42 fprintf(stderr, "PR_InitializeNetAddr failed\n"); |
|
43 exit(1); |
|
44 } |
|
45 if (PR_Connect(sock, &addr, PR_INTERVAL_NO_TIMEOUT) == PR_FAILURE) { |
|
46 fprintf(stderr, "PR_Connect failed\n"); |
|
47 exit(1); |
|
48 } |
|
49 ntotal = 0; |
|
50 bufPtr = buf; |
|
51 while ((nbytes = PR_Read(sock, bufPtr, sizeof(buf)-ntotal)) > 0) { |
|
52 ntotal += nbytes; |
|
53 bufPtr += nbytes; |
|
54 } |
|
55 if (-1 == nbytes) { |
|
56 fprintf(stderr, "PR_Read failed\n"); |
|
57 exit(1); |
|
58 } |
|
59 nexpected = HEADER_LEN+TRAILER_LEN+TRAILER_LEN+HEADER_LEN+HEADER_LEN; |
|
60 if (ntotal != nexpected) { |
|
61 fprintf(stderr, "total bytes read should be %d but is %d\n", |
|
62 nexpected, ntotal); |
|
63 exit(1); |
|
64 } |
|
65 if (memcmp(buf, HEADER_STR TRAILER_STR TRAILER_STR HEADER_STR HEADER_STR, |
|
66 nexpected) != 0) { |
|
67 fprintf(stderr, "wrong data is received\n"); |
|
68 exit(1); |
|
69 } |
|
70 if (PR_Close(sock) == PR_FAILURE) { |
|
71 fprintf(stderr, "PR_Close failed\n"); |
|
72 exit(1); |
|
73 } |
|
74 } |
|
75 |
|
76 static void ServerThread(void *arg) |
|
77 { |
|
78 PRFileDesc *listenSock = (PRFileDesc *) arg; |
|
79 PRFileDesc *acceptSock; |
|
80 PRFileDesc *file; |
|
81 PRSendFileData sfd; |
|
82 char header[1024], trailer[1024]; |
|
83 PRInt32 nbytes; |
|
84 |
|
85 /* Create a zero-length file */ |
|
86 file = PR_Open(ZERO_LEN_FILE_NAME, |
|
87 PR_CREATE_FILE|PR_TRUNCATE|PR_RDWR, 0666); |
|
88 if (NULL == file) { |
|
89 fprintf(stderr, "PR_Open failed\n"); |
|
90 exit(1); |
|
91 } |
|
92 sfd.fd = file; |
|
93 sfd.file_offset = 0; |
|
94 sfd.file_nbytes = 0; |
|
95 memcpy(header, HEADER_STR, HEADER_LEN); |
|
96 memcpy(trailer, TRAILER_STR, TRAILER_LEN); |
|
97 sfd.header = header; |
|
98 sfd.hlen = HEADER_LEN; |
|
99 sfd.trailer = trailer; |
|
100 sfd.tlen = TRAILER_LEN; |
|
101 acceptSock = PR_Accept(listenSock, NULL, PR_INTERVAL_NO_TIMEOUT); |
|
102 if (NULL == acceptSock) { |
|
103 fprintf(stderr, "PR_Accept failed\n"); |
|
104 exit(1); |
|
105 } |
|
106 /* Send both header and trailer */ |
|
107 nbytes = PR_SendFile(acceptSock, &sfd, PR_TRANSMITFILE_KEEP_OPEN, |
|
108 PR_INTERVAL_NO_TIMEOUT); |
|
109 if (HEADER_LEN+TRAILER_LEN != nbytes) { |
|
110 fprintf(stderr, "PR_SendFile should return %d but returned %d\n", |
|
111 HEADER_LEN+TRAILER_LEN, nbytes); |
|
112 exit(1); |
|
113 } |
|
114 /* Trailer only, no header */ |
|
115 sfd.hlen = 0; |
|
116 nbytes = PR_SendFile(acceptSock, &sfd, PR_TRANSMITFILE_KEEP_OPEN, |
|
117 PR_INTERVAL_NO_TIMEOUT); |
|
118 if (TRAILER_LEN != nbytes) { |
|
119 fprintf(stderr, "PR_SendFile should return %d but returned %d\n", |
|
120 TRAILER_LEN, nbytes); |
|
121 exit(1); |
|
122 } |
|
123 /* Header only, no trailer */ |
|
124 sfd.hlen = HEADER_LEN; |
|
125 sfd.tlen = 0; |
|
126 nbytes = PR_SendFile(acceptSock, &sfd, PR_TRANSMITFILE_KEEP_OPEN, |
|
127 PR_INTERVAL_NO_TIMEOUT); |
|
128 if (HEADER_LEN != nbytes) { |
|
129 fprintf(stderr, "PR_SendFile should return %d but returned %d\n", |
|
130 HEADER_LEN, nbytes); |
|
131 exit(1); |
|
132 } |
|
133 /* Try PR_TransmitFile */ |
|
134 nbytes = PR_TransmitFile(acceptSock, file, header, HEADER_LEN, |
|
135 PR_TRANSMITFILE_KEEP_OPEN, PR_INTERVAL_NO_TIMEOUT); |
|
136 if (HEADER_LEN != nbytes) { |
|
137 fprintf(stderr, "PR_TransmitFile should return %d but returned %d\n", |
|
138 HEADER_LEN, nbytes); |
|
139 exit(1); |
|
140 } |
|
141 if (PR_Close(acceptSock) == PR_FAILURE) { |
|
142 fprintf(stderr, "PR_Close failed\n"); |
|
143 exit(1); |
|
144 } |
|
145 if (PR_Close(file) == PR_FAILURE) { |
|
146 fprintf(stderr, "PR_Close failed\n"); |
|
147 exit(1); |
|
148 } |
|
149 if (PR_Delete(ZERO_LEN_FILE_NAME) == PR_FAILURE) { |
|
150 fprintf(stderr, "PR_Delete failed\n"); |
|
151 exit(1); |
|
152 } |
|
153 } |
|
154 |
|
155 int main(int argc, char **argv) |
|
156 { |
|
157 PRFileDesc *listenSock; |
|
158 PRThread *clientThread; |
|
159 PRThread *serverThread; |
|
160 PRNetAddr addr; |
|
161 PRThreadScope scope = PR_GLOBAL_THREAD; |
|
162 |
|
163 listenSock = PR_NewTCPSocket(); |
|
164 if (NULL == listenSock) { |
|
165 fprintf(stderr, "PR_NewTCPSocket failed\n"); |
|
166 exit(1); |
|
167 } |
|
168 if (PR_InitializeNetAddr(PR_IpAddrAny, 0, &addr) == PR_FAILURE) { |
|
169 fprintf(stderr, "PR_InitializeNetAddr failed\n"); |
|
170 exit(1); |
|
171 } |
|
172 if (PR_Bind(listenSock, &addr) == PR_FAILURE) { |
|
173 fprintf(stderr, "PR_Bind failed\n"); |
|
174 exit(1); |
|
175 } |
|
176 /* Find out what port number we are bound to. */ |
|
177 if (PR_GetSockName(listenSock, &addr) == PR_FAILURE) { |
|
178 fprintf(stderr, "PR_GetSockName failed\n"); |
|
179 exit(1); |
|
180 } |
|
181 if (PR_Listen(listenSock, 5) == PR_FAILURE) { |
|
182 fprintf(stderr, "PR_Listen failed\n"); |
|
183 exit(1); |
|
184 } |
|
185 |
|
186 clientThread = PR_CreateThread(PR_USER_THREAD, |
|
187 ClientThread, (void *) PR_ntohs(PR_NetAddrInetPort(&addr)), |
|
188 PR_PRIORITY_NORMAL, scope, PR_JOINABLE_THREAD, 0); |
|
189 if (NULL == clientThread) { |
|
190 fprintf(stderr, "PR_CreateThread failed\n"); |
|
191 exit(1); |
|
192 } |
|
193 serverThread = PR_CreateThread(PR_USER_THREAD, |
|
194 ServerThread, listenSock, |
|
195 PR_PRIORITY_NORMAL, scope, PR_JOINABLE_THREAD, 0); |
|
196 if (NULL == serverThread) { |
|
197 fprintf(stderr, "PR_CreateThread failed\n"); |
|
198 exit(1); |
|
199 } |
|
200 if (PR_JoinThread(clientThread) == PR_FAILURE) { |
|
201 fprintf(stderr, "PR_JoinThread failed\n"); |
|
202 exit(1); |
|
203 } |
|
204 if (PR_JoinThread(serverThread) == PR_FAILURE) { |
|
205 fprintf(stderr, "PR_JoinThread failed\n"); |
|
206 exit(1); |
|
207 } |
|
208 if (PR_Close(listenSock) == PR_FAILURE) { |
|
209 fprintf(stderr, "PR_Close failed\n"); |
|
210 exit(1); |
|
211 } |
|
212 printf("PASS\n"); |
|
213 return 0; |
|
214 } |