1 // SPDX-License-Identifier: GPL-2.0
3 * Copyright (c) 2000-2003 Silicon Graphics, Inc.
8 * Synchronized byte range lock exerciser
18 #include <sys/socket.h>
19 #include <netinet/in.h>
20 #include <netinet/tcp.h>
23 #include <sys/types.h>
29 #define HEX_2_ASC(x) ((x) > 9) ? (x)-10+'a' : (x)+'0'
30 #define FILE_SIZE 1024
31 #define PLATFORM_INIT() /*no-op*/
32 #define PLATFORM_CLEANUP() /*no-op*/
37 #define inet_aton(STRING, INADDRP) \
38 (((INADDRP)->s_addr = inet_addr(STRING)) == -1 ? 0 : 1)
40 /* this assumes 32 bit pointers */
41 #define PTR_TO_U64(P) ((unsigned __int64)(unsigned int)(P))
42 #define U64_TO_PTR(T,U) ((T)(void *)(unsigned int)(U))
44 #if __BYTE_ORDER == __LITTLE_ENDIAN
45 #define bswap_uint16(x) (uint16_t)bswap_16(x)
46 #define bswap_uint32(x) (uint32_t)bswap_32(x)
47 #define bswap_uint64(x) (uint64_t)bswap_64(x)
49 #define bswap_uint16(x) x
50 #define bswap_uint32(x) x
51 #define bswap_uint64(x) x
55 #define SOCKET_READ read
56 #define SOCKET_WRITE write
57 #define SOCKET_CLOSE(S) (close(S))
58 #define INVALID_SOCKET -1
63 #define INVALID_HANDLE -1
64 #define SEEK(H, O) (lseek(H, O, SEEK_SET))
65 #define READ(H, B, L) (read(H, B, L))
66 #define WRITE(H, B, L) (write(H, B, L))
67 #define CLOSE(H) (close(H))
69 #define RAND() (rand())
70 #define SRAND(s) (srand(s))
72 #define MIN(A,B) (((A)<(B))?(A):(B))
73 #define MAX(A,B) (((A)>(B))?(A):(B))
75 #define ALLOC_ALIGNED(S) (memalign(65536, S))
76 #define FREE_ALIGNED(P) (free(P))
79 static char *filename = 0;
81 static int server = 1;
83 static int testnumber = -1;
84 static int saved_errno = 0;
86 static SOCKET s_fd = -1; /* listen socket */
87 static SOCKET c_fd = -1; /* IPC socket */
88 static HANDLE f_fd = INVALID_HANDLE; /* shared file */
110 #define FLAGS 2 /* index 2 is also used for do_open() flag, see below */
113 * flags for Mac OS X do_open()
130 * When adding tests be sure to add to both the descriptions AND tests array.
131 * Also, be sure to undo whatever is set for each test (eg unlock any locks)
132 * There is no need to have a matching client command for each server command
136 char *descriptions[] = {
137 /* 1 */"Add a lock to an empty lock list",
138 /* 2 */"Add a lock to the start and end of a list - no overlaps",
139 /* 3 */"Add a lock to the middle of a list - no overlap",
140 /* 4 */"Add different lock types to middle of the list - overlap exact match",
141 /* 5 */"Add new lock which completely overlaps any old lock in the list",
142 /* 6 */"Add new lock which itself is completely overlaped by any old lock in the list",
143 /* 7 */"Add new lock which starts before any old lock in the list",
144 /* 8 */"Add new lock which starts in the middle of any old lock in the list and ends after",
145 /* 9 */"Add different new lock types which completely overlaps any old lock in the list",
146 /* 10 */"Add different new locks which are completely overlaped by an old lock in the list",
147 /* 11 */"Add different new lock types which start before the old lock in the list",
148 /* 12 */"Add different new lock types which start in the middle of an old lock in the list and end after",
149 /* 13 */"Add new lock, differing types and processes, to middle of the list - exact overlap match",
150 /* 14 */"Add new lock, differing types and processes, which completely overlap any of the locks in the list",
151 /* 15 */"Add new lock, differing types and processes, which are completely overlaped by locks in the list",
152 /* 16 */"Add new lock, differing types and processes, which start before a lock in the list",
153 /* 17 */"Add new lock, differing types and processes, which starts in the middle of a lock, and ends after",
154 /* 18 */"Acquire write locks with overlapping ranges",
155 /* 19 */"Acquire write locks with non-overlapping ranges extending beyond EOF",
156 /* 20 */"Acquire write locks with overlapping ranges extending beyond EOF",
157 /* 21 */"Acquire write locks on whole files",
158 /* 22 */"Acquire write lock on whole file and range write lock",
159 /* 23 */"Acquire read locks with non-overlapping ranges",
160 /* 24 */"Acquire read locks with overlapping ranges",
161 /* 25 */"Acquire read and write locks with no overlapping ranges",
162 /* 26 */"Acquire read and write locks with overlapping ranges",
163 /* 27 */"Acquire whole file write lock and then close without unlocking (and attempt a lock)",
164 /* 28 */"Acquire two read locks, close and reopen the file, and test if the inital lock is still there",
165 /* 29 */"Verify that F_GETLK for F_WRLCK doesn't require that file be opened for write",
167 /* 30 */"Close the opened file and open the file with SHLOCK, other client will try to open with SHLOCK too",
168 /* 31 */"Close the opened file and open the file with SHLOCK, other client will try to open with EXLOCK",
169 /* 32 */"Close the opened file and open the file with EXLOCK, other client will try to open with EXLOCK too"
173 static int64_t tests[][6] =
174 /* test # Action [offset|flags] length expected server/client */
176 /* Various simple tests exercising the list */
178 /* SECTION 1: WRITE and CMD_UNLOCK with the same process (SERVER) */
179 /* Add a lock to an empty list */
180 {1, CMD_WRLOCK, 1, 10, PASS, SERVER },
181 {1, CMD_UNLOCK, 1, 10, PASS, SERVER },
183 /* Add a lock to the start and end of a list - 1, 13 - no overlap */
184 {2, CMD_WRLOCK, 10, 10, PASS, SERVER },
185 {2, CMD_WRLOCK, 30, 10, PASS, SERVER },
186 {2, CMD_WRLOCK, 50, 10, PASS, SERVER },
187 {2, CMD_WRLOCK, 1, 5, PASS, SERVER },
188 {2, CMD_WRLOCK, 70, 5, PASS, SERVER },
190 {2, CMD_UNLOCK, 10, 10, PASS, SERVER },
191 {2, CMD_UNLOCK, 30, 10, PASS, SERVER },
192 {2, CMD_UNLOCK, 50, 10, PASS, SERVER },
193 {2, CMD_UNLOCK, 1, 5, PASS, SERVER },
194 {2, CMD_UNLOCK, 70, 5, PASS, SERVER },
196 /* Add a lock to the middle of a list - no overlap */
197 {3, CMD_WRLOCK, 10, 10, PASS, SERVER },
198 {3, CMD_WRLOCK, 30, 10, PASS, SERVER },
199 {3, CMD_WRLOCK, 50, 10, PASS, SERVER },
200 {3, CMD_WRLOCK, 42, 5, PASS, SERVER },
202 {3, CMD_UNLOCK, 10, 10, PASS, SERVER },
203 {3, CMD_UNLOCK, 30, 10, PASS, SERVER },
204 {3, CMD_UNLOCK, 50, 10, PASS, SERVER },
205 {3, CMD_UNLOCK, 42, 5, PASS, SERVER },
207 /* Add different lock types to middle of the list - overlap exact match - 3 */
208 {4, CMD_WRLOCK, 10, 10, PASS, SERVER },
209 {4, CMD_WRLOCK, 30, 10, PASS, SERVER },
210 {4, CMD_WRLOCK, 50, 10, PASS, SERVER },
211 /* Exact match - same lock type */
212 {4, CMD_WRLOCK, 30, 10, PASS, SERVER },
213 /* Exact match - different lock type */
214 {4, CMD_RDLOCK, 30, 10, PASS, SERVER },
215 /* Exact match - unlock */
216 {4, CMD_UNLOCK, 30, 10, PASS, SERVER },
217 /* New lock - as above, inserting in the list again */
218 {4, CMD_WRLOCK, 30, 10, PASS, SERVER },
220 {4, CMD_UNLOCK, 10, 10, PASS, SERVER },
221 {4, CMD_UNLOCK, 30, 10, PASS, SERVER },
222 {4, CMD_UNLOCK, 50, 10, PASS, SERVER },
224 /* Add new lock which completely overlaps any old lock in the list - 4,5,6 */
225 {5, CMD_WRLOCK, 10, 10, PASS, SERVER },
226 {5, CMD_WRLOCK, 30, 10, PASS, SERVER },
227 {5, CMD_WRLOCK, 50, 10, PASS, SERVER },
228 /* The start is the same, end overlaps */
229 {5, CMD_WRLOCK, 30, 15, PASS, SERVER },
230 /* The start is before, end is the same */
231 {5, CMD_WRLOCK, 25, 20, PASS, SERVER },
232 /* Both start and end overlap */
233 {5, CMD_WRLOCK, 22, 26, PASS, SERVER },
235 {5, CMD_UNLOCK, 10, 10, PASS, SERVER },
236 {5, CMD_UNLOCK, 22, 26, PASS, SERVER },
237 {5, CMD_UNLOCK, 50, 10, PASS, SERVER },
239 /* Add new lock which itself is completely overlaped by any old lock in the list - 7,8,10 */
240 {6, CMD_WRLOCK, 10, 10, PASS, SERVER },
241 {6, CMD_WRLOCK, 30, 10, PASS, SERVER },
242 {6, CMD_WRLOCK, 50, 10, PASS, SERVER },
243 /* The start is the same, end is in the middle of old lock - NOP */
244 {6, CMD_WRLOCK, 30, 5, PASS, SERVER },
245 /* The start and end are in the middle of old lock - NOP */
246 {6, CMD_WRLOCK, 32, 6, PASS, SERVER },
247 /* Start in the middle and end is the same - NOP */
248 {6, CMD_WRLOCK, 32, 8, PASS, SERVER },
250 {6, CMD_UNLOCK, 10, 10, PASS, SERVER },
251 {6, CMD_UNLOCK, 30, 10, PASS, SERVER },
252 {6, CMD_UNLOCK, 32, 8, PASS, SERVER },
253 {6, CMD_UNLOCK, 50, 10, PASS, SERVER },
255 /* Add new lock which starts before any old lock in the list - 2,9 */
256 {7, CMD_WRLOCK, 10, 10, PASS, SERVER },
257 {7, CMD_WRLOCK, 30, 10, PASS, SERVER },
258 {7, CMD_WRLOCK, 50, 10, PASS, SERVER },
259 /* Here is the new lock */
260 {7, CMD_WRLOCK, 27, 10, PASS, SERVER },
261 /* Go again with the end of the new lock matching the start of old lock */
262 {7, CMD_WRLOCK, 25, 2, PASS, SERVER },
264 {7, CMD_UNLOCK, 10, 10, PASS, SERVER },
265 {7, CMD_UNLOCK, 25, 15, PASS, SERVER },
266 {7, CMD_UNLOCK, 50, 10, PASS, SERVER },
268 /* Add new lock which starts in the middle of any old lock in the list and ends after - 11,12 */
269 {8, CMD_WRLOCK, 10, 10, PASS, SERVER },
270 {8, CMD_WRLOCK, 30, 10, PASS, SERVER },
271 {8, CMD_WRLOCK, 50, 10, PASS, SERVER },
272 /* Here is the new lock */
273 {8, CMD_WRLOCK, 35, 10, PASS, SERVER },
274 /* Go again with the end of the new lock matching the start of old lock */
275 {8, CMD_WRLOCK, 45, 2, PASS, SERVER },
277 {8, CMD_UNLOCK, 10, 10, PASS, SERVER },
278 {8, CMD_UNLOCK, 30, 17, PASS, SERVER },
279 {8, CMD_UNLOCK, 50, 10, PASS, SERVER },
280 /* SECTION 2: Overlapping READ and WRITE and CMD_UNLOCK with the same process (SERVER) */
281 /* Add different new lock types which completely overlaps any old lock in the list - 4,5,6 */
282 {9, CMD_WRLOCK, 10, 10, PASS, SERVER },
283 {9, CMD_WRLOCK, 30, 10, PASS, SERVER },
284 {9, CMD_WRLOCK, 50, 10, PASS, SERVER },
285 /* The start is the same, end overlaps */
286 {9, CMD_RDLOCK, 30, 15, PASS, SERVER },
287 /* The start is before, end is the same */
288 {9, CMD_WRLOCK, 25, 20, PASS, SERVER },
289 /* Both start and end overlap */
290 {9, CMD_RDLOCK, 22, 26, PASS, SERVER },
292 {9, CMD_UNLOCK, 10, 10, PASS, SERVER },
293 {9, CMD_UNLOCK, 22, 26, PASS, SERVER },
294 {9, CMD_UNLOCK, 50, 10, PASS, SERVER },
296 /* Add different new locks which are completely overlaped by an old lock in the list - 7,8,10 */
297 {10, CMD_WRLOCK, 10, 10, PASS, SERVER },
298 {10, CMD_WRLOCK, 30, 10, PASS, SERVER },
299 {10, CMD_WRLOCK, 50, 10, PASS, SERVER },
300 /* The start is the same, end is in the middle of old lock */
301 {10, CMD_RDLOCK, 30, 5, PASS, SERVER },
302 /* The start and end are in the middle of a lock */
303 {10, CMD_WRLOCK, 32, 2, PASS, SERVER },
304 /* Start in the middle and end is the same */
305 {10, CMD_RDLOCK, 36, 5, PASS, SERVER },
307 {10, CMD_UNLOCK, 10, 10, PASS, SERVER },
308 {10, CMD_UNLOCK, 30, 11, PASS, SERVER },
309 {10, CMD_UNLOCK, 50, 10, PASS, SERVER },
311 /* Add different new lock types which start before the old lock in the list - 2,9 */
312 {11, CMD_WRLOCK, 10, 10, PASS, SERVER },
313 {11, CMD_WRLOCK, 30, 10, PASS, SERVER },
314 {11, CMD_WRLOCK, 50, 10, PASS, SERVER },
315 /* Here is the new lock */
316 {11, CMD_RDLOCK, 27, 10, PASS, SERVER },
317 /* Go again with the end of the new lock matching the start of lock */
318 {11, CMD_WRLOCK, 25, 3, PASS, SERVER },
320 {11, CMD_UNLOCK, 10, 10, PASS, SERVER },
321 {11, CMD_UNLOCK, 25, 15, PASS, SERVER },
322 {11, CMD_UNLOCK, 50, 10, PASS, SERVER },
324 /* Add different new lock types which start in the middle of an old lock in the list and end after - 11,12 */
325 {12, CMD_WRLOCK, 10, 10, PASS, SERVER },
326 {12, CMD_WRLOCK, 30, 10, PASS, SERVER },
327 {12, CMD_WRLOCK, 50, 10, PASS, SERVER },
328 /* Here is the new lock */
329 {12, CMD_RDLOCK, 35, 10, PASS, SERVER },
330 /* Go again with the end of the new lock matching the start of old lock */
331 {12, CMD_WRLOCK, 44, 3, PASS, SERVER },
333 {12, CMD_UNLOCK, 10, 10, PASS, SERVER },
334 {12, CMD_UNLOCK, 30, 18, PASS, SERVER },
335 {12, CMD_UNLOCK, 50, 10, PASS, SERVER },
337 /* SECTION 3: Overlapping READ and WRITE and CMD_UNLOCK with the different processes (CLIENT/SERVER) */
338 /* Add new lock, differing types and processes, to middle of the list - exact overlap match - 3 */
339 {13, CMD_WRLOCK, 10, 10, PASS, SERVER },
340 {13, CMD_WRLOCK, 30, 10, PASS, SERVER },
341 {13, CMD_RDLOCK, 50, 10, PASS, SERVER },
342 /* Same lock type, different process */
343 {13, CMD_WRLOCK, 30, 10, FAIL, CLIENT },
344 {13, CMD_RDLOCK, 50, 10, PASS, CLIENT },
345 /* Exact match - different lock type, different process */
346 {13, CMD_RDLOCK, 30, 10, FAIL, CLIENT },
347 /* Exact match - unlock */
348 {13, CMD_UNLOCK, 30, 10, PASS, CLIENT },
349 /* New lock - as above, inserting in the list again */
350 {13, CMD_UNLOCK, 30, 10, PASS, SERVER },
351 /* Exact match - same lock type, different process */
352 {13, CMD_WRLOCK, 30, 10, PASS, CLIENT },
354 {13, CMD_UNLOCK, 10, 10, PASS, SERVER },
355 {13, CMD_UNLOCK, 30, 10, PASS, CLIENT },
356 {13, CMD_UNLOCK, 50, 10, PASS, SERVER },
358 /* Add new lock, differing types and processes, which completely overlap any of the locks in the list - 4,5,6 */
359 {14, CMD_WRLOCK, 10, 10, PASS, SERVER },
360 {14, CMD_WRLOCK, 30, 10, PASS, SERVER },
361 {14, CMD_RDLOCK, 50, 10, PASS, SERVER },
362 /* The start is the same, end overlaps */
363 {14, CMD_RDLOCK, 30, 15, FAIL, CLIENT },
364 {14, CMD_WRLOCK, 30, 15, FAIL, CLIENT },
365 /* The start is before, end is the same */
366 {14, CMD_RDLOCK, 25, 20, FAIL, CLIENT },
367 {14, CMD_WRLOCK, 25, 20, FAIL, CLIENT },
368 /* Both start and end overlap */
369 {14, CMD_RDLOCK, 22, 26, FAIL, CLIENT },
370 {14, CMD_WRLOCK, 22, 26, FAIL, CLIENT },
372 /* The start is the same, end overlaps */
373 {14, CMD_RDLOCK, 50, 15, PASS, CLIENT },
374 {14, CMD_WRLOCK, 50, 17, FAIL, CLIENT },
375 /* The start is before, end is the same */
376 {14, CMD_RDLOCK, 45, 20, PASS, CLIENT },
377 {14, CMD_WRLOCK, 43, 22, FAIL, CLIENT },
378 /* Both start and end overlap */
379 {14, CMD_RDLOCK, 42, 26, PASS, CLIENT },
380 {14, CMD_WRLOCK, 41, 28, FAIL, CLIENT },
382 {14, CMD_UNLOCK, 10, 10, PASS, SERVER },
383 {14, CMD_UNLOCK, 22, 26, PASS, SERVER },
384 {14, CMD_UNLOCK, 42, 26, PASS, CLIENT },
386 /* Add new lock, differing types and processes, which are completely overlaped by an old lock in the list - 7,8,10 */
387 {15, CMD_WRLOCK, 10, 10, PASS, SERVER },
388 {15, CMD_RDLOCK, 30, 10, PASS, SERVER },
389 {15, CMD_WRLOCK, 50, 10, PASS, SERVER },
390 /* The start is the same, end is in the middle of old lock */
391 {15, CMD_RDLOCK, 50, 5, FAIL, CLIENT },
392 {15, CMD_WRLOCK, 50, 5, FAIL, CLIENT },
393 /* The start and end are in the middle of old lock */
394 {15, CMD_RDLOCK, 52, 6, FAIL, CLIENT },
395 {15, CMD_WRLOCK, 52, 6, FAIL, CLIENT },
396 /* Start in the middle and end is the same */
397 {15, CMD_RDLOCK, 52, 8, FAIL, CLIENT },
398 {15, CMD_WRLOCK, 52, 8, FAIL, CLIENT },
399 /* The start is the same, end is in the middle of old lock */
400 {15, CMD_RDLOCK, 30, 5, PASS, CLIENT },
401 {15, CMD_WRLOCK, 30, 5, FAIL, CLIENT },
402 /* The start and end are in the middle of old lock */
403 {15, CMD_RDLOCK, 32, 6, PASS, CLIENT },
404 {15, CMD_WRLOCK, 32, 6, FAIL, CLIENT },
405 /* Start in the middle and end is the same */
406 {15, CMD_RDLOCK, 32, 8, PASS, CLIENT },
407 {15, CMD_WRLOCK, 32, 8, FAIL, CLIENT },
409 {15, CMD_UNLOCK, 10, 10, PASS, SERVER },
410 {15, CMD_UNLOCK, 30, 10, PASS, SERVER },
411 {15, CMD_UNLOCK, 50, 10, PASS, SERVER },
412 /* Add new lock, differing types and processes, which start before a lock in the list - 2,9 */
413 {16, CMD_RDLOCK, 10, 10, PASS, SERVER },
414 {16, CMD_WRLOCK, 50, 10, PASS, SERVER },
415 /* Start is before, end is the start of the old lock in list */
416 {16, CMD_RDLOCK, 5, 6, PASS, CLIENT },
417 {16, CMD_WRLOCK, 5, 6, FAIL, CLIENT },
418 /* Start is before, end is in the middle of the old lock */
419 {16, CMD_RDLOCK, 5, 10, PASS, CLIENT },
420 {16, CMD_WRLOCK, 5, 10, FAIL, CLIENT },
421 /* Start is before, end is the start of the old lock in list */
422 {16, CMD_RDLOCK, 45, 6, FAIL, CLIENT },
423 {16, CMD_WRLOCK, 45, 6, FAIL, CLIENT },
424 /* Start is before, end is in the middle of the old lock */
425 {16, CMD_RDLOCK, 45, 10, FAIL, CLIENT },
426 {16, CMD_WRLOCK, 45, 10, FAIL, CLIENT },
428 {16, CMD_UNLOCK, 5, 15, PASS, CLIENT },
429 {16, CMD_UNLOCK, 30, 10, PASS, SERVER },
430 {16, CMD_UNLOCK, 50, 10, PASS, SERVER },
432 /* Add new lock, differing types and processes, which starts in the middle of a lock, and ends after - 11,12 */
433 {17, CMD_WRLOCK, 10, 10, PASS, SERVER },
434 {17, CMD_RDLOCK, 30, 10, PASS, SERVER },
435 {17, CMD_WRLOCK, 50, 10, PASS, SERVER },
436 /* Start in the middle, end after lock in list */
437 {17, CMD_WRLOCK, 35, 10, FAIL, CLIENT },
438 /* Start matches end of lock in list */
439 {17, CMD_RDLOCK, 35, 10, PASS, CLIENT },
440 {17, CMD_RDLOCK, 44, 2, PASS, CLIENT },
441 /* Start in the middle, end after lock in list */
442 {17, CMD_RDLOCK, 55, 10, FAIL, CLIENT },
443 {17, CMD_WRLOCK, 55, 10, FAIL, CLIENT },
444 /* Start matches end of lock in list */
445 {17, CMD_RDLOCK, 59, 5, FAIL, CLIENT },
446 {17, CMD_WRLOCK, 59, 5, FAIL, CLIENT },
448 {17, CMD_UNLOCK, 10, 10, PASS, SERVER },
449 {17, CMD_UNLOCK, 30, 16, PASS, CLIENT },
450 {17, CMD_UNLOCK, 50, 10, PASS, SERVER },
452 /* SECTION 4: overlapping and EOF tests */
453 /* Acquire overlapping ranges */
454 {18, CMD_WRLOCK, 11, 7, PASS, SERVER },
455 {18, CMD_WRLOCK, 13, 8, FAIL, CLIENT },
456 {18, CMD_UNLOCK, 11, 7, PASS, SERVER },
457 /* Acquire different ranges beyond EOF */
458 {19, CMD_WRLOCK, 10, FILE_SIZE, PASS, SERVER },
459 {19, CMD_WRLOCK, FILE_SIZE + 10, 10, PASS, CLIENT },
460 {19, CMD_UNLOCK, 10, FILE_SIZE, PASS, SERVER },
461 {19, CMD_UNLOCK, FILE_SIZE + 10, 10, PASS, CLIENT },
462 /* Acquire same range beyong EOF */
463 {20, CMD_WRLOCK, 10, FILE_SIZE, PASS, SERVER, },
464 {20, CMD_WRLOCK, 10, FILE_SIZE, FAIL, CLIENT, },
465 {20, CMD_UNLOCK, 10, FILE_SIZE, PASS, SERVER, },
466 /* Acquire whole file lock */
467 {21, CMD_WRLOCK, 0, 0, PASS, SERVER, },
468 {21, CMD_WRLOCK, 0, 0, FAIL, CLIENT, },
469 {21, CMD_UNLOCK, 0, 0, PASS, SERVER, },
470 /* Acquire whole file lock, then range */
471 {22, CMD_WRLOCK, 0, 0, PASS, SERVER, },
472 {22, CMD_WRLOCK, 1, 5, FAIL, CLIENT, },
473 {22, CMD_UNLOCK, 0, 0, PASS, SERVER, },
474 /* Acquire non-overlapping read locks */
475 {23, CMD_RDLOCK, 1, 5, PASS, SERVER, },
476 {23, CMD_RDLOCK, 7, 6, PASS, CLIENT, },
477 {23, CMD_UNLOCK, 1, 5, PASS, SERVER, },
478 {23, CMD_UNLOCK, 7, 6, PASS, CLIENT, },
479 /* Acquire overlapping read locks */
480 {24, CMD_RDLOCK, 1, 5, PASS, SERVER, },
481 {24, CMD_RDLOCK, 2, 6, PASS, CLIENT, },
482 {24, CMD_UNLOCK, 1, 5, PASS, SERVER, },
483 {24, CMD_UNLOCK, 1, 7, PASS, CLIENT, },
484 /* Acquire non-overlapping read and write locks */
485 {25, CMD_RDLOCK, 1, 5, PASS, SERVER, },
486 {25, CMD_WRLOCK, 7, 6, PASS, CLIENT, },
487 {25, CMD_UNLOCK, 1, 5, PASS, SERVER, },
488 {25, CMD_UNLOCK, 7, 6, PASS, CLIENT, },
489 /* Acquire overlapping read and write locks */
490 {26, CMD_RDLOCK, 1, 5, PASS, SERVER, },
491 {26, CMD_WRLOCK, 2, 6, FAIL, CLIENT, },
492 {26, CMD_UNLOCK, 1, 5, PASS, SERVER, },
493 /* Acquire whole file lock, then close (without unlocking) */
494 {27, CMD_WRLOCK, 0, 0, PASS, SERVER, },
495 {27, CMD_WRLOCK, 1, 5, FAIL, CLIENT, },
496 {27, CMD_CLOSE,0, 0, PASS, SERVER, },
497 {27, CMD_WRLOCK, 1, 5, PASS, CLIENT, },
498 {27, CMD_OPEN, O_RDWR, 0, PASS, SERVER, },
499 {27, CMD_UNLOCK, 1, 5, PASS, CLIENT, },
500 /* Acquire two read locks, close one file and then reopen to check that first lock still exists */
501 {28, CMD_RDLOCK, 1, 5, PASS, SERVER, },
502 {28, CMD_RDLOCK, 1, 5, PASS, CLIENT, },
503 {28, CMD_CLOSE,0, 0, PASS, SERVER, },
504 {28, CMD_OPEN, O_RDWR, 0, PASS, SERVER, },
505 {28, CMD_WRLOCK, 0, 0, FAIL, SERVER, },
506 {28, CMD_UNLOCK, 1, 5, PASS, SERVER, },
507 /* Verify that F_GETLK for F_WRLCK doesn't require that file be opened for write */
508 {29, CMD_CLOSE, 0, 0, PASS, SERVER, },
509 {29, CMD_OPEN, O_RDONLY, 0, PASS, SERVER, },
510 {29, CMD_WRTEST, 0, 0, PASS, SERVER, },
511 {29, CMD_CLOSE,0, 0, PASS, SERVER, },
512 {29, CMD_OPEN, O_RDWR, 0, PASS, SERVER, },
514 /* Close the opened file and open the file with SHLOCK, other client will try to open with SHLOCK too */
515 {30, CMD_CLOSE,0, 0, PASS, SERVER, },
516 {30, CMD_OPEN, O_RDWR|O_SHLOCK|O_NONBLOCK, 0, PASS, SERVER, },
517 {30, CMD_CLOSE,0, 0, PASS, CLIENT, },
518 {30, CMD_OPEN, O_RDWR|O_SHLOCK|O_NONBLOCK, 0, PASS, CLIENT, },
519 /* Close the opened file and open the file with SHLOCK, other client will try to open with EXLOCK */
520 {31, CMD_CLOSE,0, 0, PASS, SERVER, },
521 {31, CMD_CLOSE,0, 0, PASS, CLIENT, },
522 {31, CMD_OPEN, O_RDWR|O_SHLOCK|O_NONBLOCK, 0, PASS, SERVER, },
523 {31, CMD_OPEN, O_RDWR|O_EXLOCK|O_NONBLOCK, 0, FAIL, CLIENT, },
524 /* Close the opened file and open the file with EXLOCK, other client will try to open with EXLOCK too */
525 {32, CMD_CLOSE,0, 0, PASS, SERVER, },
526 {32, CMD_CLOSE,0, 0, FAIL, CLIENT, },
527 {32, CMD_OPEN, O_RDWR|O_EXLOCK|O_NONBLOCK, 0, PASS, SERVER, },
528 {32, CMD_OPEN, O_RDWR|O_EXLOCK|O_NONBLOCK, 0, FAIL, CLIENT, },
529 {32, CMD_CLOSE,0, 0, PASS, SERVER, },
530 {32, CMD_CLOSE,0, 0, FAIL, CLIENT, },
531 {32, CMD_OPEN, O_RDWR, 0, PASS, SERVER, },
532 {32, CMD_OPEN, O_RDWR, 0, PASS, CLIENT, },
534 /* indicate end of array */
547 int32_t padding; /* So mac and irix have the same size struct (bloody alignment) */
554 fprintf(stderr, "Usage: %s [options] sharedfile\n\
557 -p port TCP/IP port number for client-server communication\n\
558 -d enable debug tracing\n\
559 -n # test number to run\n\
560 -h host run as client and connect to server on remote host\n\
561 [default run as server]\n", prog);
565 #define INIT_BUFSZ 512
568 initialize(HANDLE fd)
574 int togo = FILE_SIZE;
576 ibuf = (char*)malloc(INIT_BUFSZ);
577 memset(ibuf, ':', INIT_BUFSZ);
582 j = togo > INIT_BUFSZ ? INIT_BUFSZ : togo;
584 if ((nwrite = WRITE(fd, ibuf, j)) != j) {
586 perror("initialize write:");
588 fprintf(stderr, "initialize: write() returns %d, not %d as expected\n",
598 int do_open(int flag)
600 int flags = flag|O_CREAT|O_BINARY;
603 fprintf(stderr, "do_open %s 0x%x\n", filename, flags);
605 if ((f_fd = open(filename, flags, 0666)) == INVALID_HANDLE) {
606 perror("shared file create");
613 static int do_lock(int cmd, int type, int start, int length)
620 fprintf(stderr, "do_lock: cmd=%d type=%d start=%d, length=%d\n", cmd, type, start, length);
628 fl.l_whence = SEEK_SET;
634 ret = fcntl(filedes, cmd, &fl);
638 fprintf(stderr, "do_lock: ret = %d, errno = %d (%s)\n", ret, errno, strerror(errno));
640 return(ret==0?PASS:FAIL);
646 fprintf(stderr, "do_close\n");
651 f_fd = INVALID_HANDLE;
666 fprintf(stderr, "send_ctl: test=%d, command=%d offset=%"LL"d, length=%"LL"d, result=%d, error=%d\n",
667 ctl.test, ctl.command, (long long)ctl.offset, (long long)ctl.length,ctl.result, ctl.error);
670 ctl.test= bswap_uint32(ctl.test);
671 ctl.command = bswap_uint32(ctl.command);
672 ctl.offset = bswap_uint64(ctl.offset);
673 ctl.length = bswap_uint64(ctl.length);
674 ctl.result = bswap_uint32(ctl.result);
675 ctl.index= bswap_uint32(ctl.index);
676 ctl.error = bswap_uint32(ctl.error);
677 nwrite = SOCKET_WRITE(c_fd, (char*)&ctl, sizeof(ctl));
679 ctl.test= bswap_uint32(ctl.test);
680 ctl.command = bswap_uint32(ctl.command);
681 ctl.offset = bswap_uint64(ctl.offset);
682 ctl.length = bswap_uint64(ctl.length);
683 ctl.result = bswap_uint32(ctl.result);
684 ctl.index= bswap_uint32(ctl.index);
685 ctl.error= bswap_uint32(ctl.error);
686 if (nwrite != sizeof(ctl)) {
688 perror("send_ctl: write");
690 fprintf(stderr, "send_ctl[%d]: write() returns %d, not %zu as expected\n",
691 ctl.test, nwrite, sizeof(ctl));
701 if ((nread = SOCKET_READ(c_fd, (char*)&ctl, sizeof(ctl))) != sizeof(ctl)) {
703 perror("recv_ctl: read");
705 fprintf(stderr, "recv_ctl[%d]: read() returns %d, not %zu as expected\n",
706 ctl.test, nread, sizeof(ctl));
707 fprintf(stderr, "socket might has been closed by other locktest\n");
712 ctl.test= bswap_uint32(ctl.test);
713 ctl.command = bswap_uint32(ctl.command);
714 ctl.offset = bswap_uint64(ctl.offset);
715 ctl.length = bswap_uint64(ctl.length);
716 ctl.result = bswap_uint32(ctl.result);
717 ctl.index= bswap_uint32(ctl.index);
718 ctl.error= bswap_uint32(ctl.error);
721 fprintf(stderr, "recv_ctl: test=%d, command=%d offset=%"LL"d, length=%"LL"d, result=%d, error=%d\n",
722 ctl.test, ctl.command, (long long)ctl.offset, (long long)ctl.length, ctl.result, ctl.error);
742 main(int argc, char *argv[])
746 struct sockaddr_in myAddr;
747 struct linger noLinger = {1, 0};
760 /* trim command name of leading directory components */
762 for (p = prog; *p; p++) {
767 while ((c = getopt(argc, argv, "dn:h:p:?")) != EOF) {
770 case 'd': /* debug flag */
774 case 'h': /* (server) hostname */
780 testnumber = atoi(optarg);
783 case 'p': /* TCP/IP port */
784 port = (int)strtol(optarg, &endnum, 10);
785 if (*endnum != '\0') {
786 fprintf(stderr, "%s: -p argument must be a numeric\n",
800 if (errflag || optind != argc-1) {
805 filename=argv[optind];
806 if (do_open(O_RDWR) == FAIL)
809 setbuf(stderr, NULL);
814 s_fd = socket(AF_INET, SOCK_STREAM, 0);
815 if (s_fd == INVALID_SOCKET) {
820 if (setsockopt(s_fd, IPPROTO_TCP, TCP_NODELAY, (char*)&one, sizeof(one)) < 0) {
821 perror("setsockopt(nodelay)");
825 if (setsockopt(s_fd, SOL_SOCKET, SO_REUSEADDR, (char*)&one, sizeof(one))<0) {
826 perror("setsockopt(reuseaddr)");
831 if (setsockopt(s_fd, SOL_SOCKET, SO_REUSEPORT, (char*)&one, sizeof(one))<0) {
832 perror("setsockopt(reuseport)");
838 memset(&myAddr, 0, sizeof(myAddr));
839 myAddr.sin_family = AF_INET;
840 myAddr.sin_addr.s_addr = htonl(INADDR_ANY);
841 myAddr.sin_port = htons((short)port);
842 sts = bind(s_fd, (struct sockaddr*)&myAddr, sizeof(myAddr));
849 sts = listen(s_fd, 5); /* Max. of 5 pending connection requests */
857 socklen_t addr_len = sizeof(myAddr);
859 if (getsockname(s_fd, &myAddr, &addr_len)) {
860 perror("getsockname");
864 port = ntohs(myAddr.sin_port);
867 printf("server port: %d\n", port);
870 c_fd = accept(s_fd, NULL, NULL);
871 if (c_fd == INVALID_SOCKET) {
877 if (debug) fprintf(stderr, "Client accepted\n");
881 struct hostent *servInfo;
883 if ((servInfo = gethostbyname(host)) == NULL) {
884 printf("Couldn't get hostbyname for %s", host);
885 if (h_errno == HOST_NOT_FOUND)
886 printf(": host not found");
892 c_fd = socket(AF_INET, SOCK_STREAM, 0);
893 if (c_fd == INVALID_SOCKET) {
898 /* avoid 200 ms delay */
899 if (setsockopt(c_fd, IPPROTO_TCP, TCP_NODELAY, (char *)&i, sizeof(i)) < 0) {
900 perror("setsockopt(nodelay)");
904 /* Don't linger on close */
905 if (setsockopt(c_fd, SOL_SOCKET, SO_LINGER, (char *)&noLinger, sizeof(noLinger)) < 0) {
906 perror("setsockopt(nolinger)");
911 memset(&myAddr, 0, sizeof(myAddr)); /* Arrgh! &myAddr, not myAddr */
912 myAddr.sin_family = AF_INET;
913 memcpy(&myAddr.sin_addr, servInfo->h_addr, servInfo->h_length);
914 myAddr.sin_port = htons((short)port);
916 if (connect(c_fd, (struct sockaddr*)&myAddr, sizeof(myAddr)) < 0) {
917 perror("unable to connect");
918 fprintf(stderr, "Server might still initializing the shared file\n ");
923 if (debug) fprintf(stderr, "Connected to server\n");
928 /* only server need do shared file */
932 * TCP/IP connection to be established, safe to proceed.
934 * real work is in here ...
947 last_test = testnumber - 1;
948 while(tests[index][TEST_NUM] != testnumber && tests[index][TEST_NUM] != 0) {
952 /* If we have a server command, deal with it */
953 if(tests[index][WHO] == SERVER) {
955 fprintf(stderr, "Got a server command (%d)\n", index);
956 if(tests[index][TEST_NUM] == 0) {
960 memset(&ctl, 0, sizeof(ctl));
961 ctl.test = tests[index][TEST_NUM];
963 if(tests[index][TEST_NUM] != 0) {
964 switch(tests[index][COMMAND]) {
966 result = do_lock(F_SETLK, F_WRLCK, tests[index][OFFSET], tests[index][LENGTH]);
969 result = do_lock(F_SETLK, F_RDLCK, tests[index][OFFSET], tests[index][LENGTH]);
972 result = do_lock(F_SETLK, F_UNLCK, tests[index][OFFSET], tests[index][LENGTH]);
978 result = do_open(tests[index][FLAGS]);
981 result = do_lock(F_GETLK, F_WRLCK, tests[index][OFFSET], tests[index][LENGTH]);
984 result = do_lock(F_GETLK, F_RDLCK, tests[index][OFFSET], tests[index][LENGTH]);
987 if( result != tests[index][RESULT]) {
989 /* We have a failure */
991 fprintf(stderr, "Server failure in test %d, while %sing using offset %lld, length %lld - err = %d:%s\n",
992 ctl.test, tests[index][COMMAND]==CMD_WRLOCK?"write lock":
993 tests[index][COMMAND]==CMD_RDLOCK?"read lock":
994 tests[index][COMMAND]==CMD_UNLOCK?"unlock":
995 tests[index][COMMAND]==CMD_OPEN?"open":"clos",
996 (long long)tests[index][OFFSET],
997 (long long)tests[index][LENGTH],
998 saved_errno, strerror(saved_errno));
999 fprintf(stderr, "Server failure in %lld:%s\n",
1000 (long long)tests[index][TEST_NUM],
1001 descriptions[tests[index][TEST_NUM] - 1]);
1004 /* else send it off to the client */
1005 } else if (tests[index][WHO] == CLIENT) {
1006 if(tests[index][TEST_NUM] == 0) {
1011 fprintf(stderr, "Sending command to client (%d) - %s - %lld:%lld\n",
1012 index, tests[index][COMMAND]==CMD_WRLOCK?"write lock":
1013 tests[index][COMMAND]==CMD_RDLOCK?"read lock":
1014 tests[index][COMMAND]==CMD_UNLOCK?"unlock":
1015 tests[index][COMMAND]==CMD_OPEN?"open":"clos",
1016 (long long)tests[index][OFFSET],
1017 (long long)tests[index][LENGTH]);
1018 /* get the client to do something */
1022 /* Get the clients response */
1024 /* this is the whether the test passed or failed,
1025 * not what the command returned */
1026 if( ctl.result == FAIL ) {
1029 fprintf(stderr, "Client failure in test %d, while %sing using offset %lld, length %lld - err = %d:%s\n",
1030 ctl.test, ctl.command==CMD_WRLOCK?"write lock":
1031 ctl.command==CMD_RDLOCK?"read lock":
1032 ctl.command==CMD_UNLOCK?"unlock":
1033 ctl.command==CMD_OPEN?"open":"clos",
1034 (long long)ctl.offset, (long long)ctl.length,
1035 ctl.error, strerror(ctl.error));
1036 fprintf(stderr, "Client failure in %lld:%s\n",
1037 (long long)tests[index][TEST_NUM],
1038 descriptions[tests[index][TEST_NUM] - 1]);
1042 if(tests[index][TEST_NUM] != 0) {
1043 if(last_test != tests[index][TEST_NUM]) {
1050 last_test = tests[index][TEST_NUM];
1054 } else { /* CLIENT */
1056 fprintf(stderr,"client: waiting...\n");
1057 /* wait for the server to do something */
1060 /* check for a client command */
1062 if (tests[index][WHO] != CLIENT) {
1063 fprintf(stderr, "not a client command index (%d)\n", index);
1073 ctl.command = tests[index][COMMAND];
1074 ctl.offset = tests[index][OFFSET];
1075 ctl.length = tests[index][LENGTH];
1076 switch(tests[index][COMMAND]) {
1078 result = do_lock(F_SETLK, F_WRLCK, tests[index][OFFSET], tests[index][LENGTH]);
1081 result = do_lock(F_SETLK, F_RDLCK, tests[index][OFFSET], tests[index][LENGTH]);
1084 result = do_lock(F_SETLK, F_UNLCK, tests[index][OFFSET], tests[index][LENGTH]);
1087 result = do_close();
1090 result = do_open(tests[index][FLAGS]);
1093 result = do_lock(F_GETLK, F_WRLCK, tests[index][OFFSET], tests[index][LENGTH]);
1096 result = do_lock(F_GETLK, F_RDLCK, tests[index][OFFSET], tests[index][LENGTH]);
1099 if( result != tests[index][RESULT] ) {
1101 fprintf(stderr,"Got %d, wanted %lld\n", result,
1102 (long long)tests[index][RESULT]);
1104 ctl.error = saved_errno;
1110 fprintf(stderr,"client: sending result to server (%d)\n", ctl.index);
1111 /* Send result to the server */
1113 if(tests[index][TEST_NUM] != 0) {
1114 if(last_test != tests[index][TEST_NUM])
1116 last_test = tests[index][TEST_NUM];
1121 printf("%d tests run, %d failed\n", test_count, fail_count);