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 OPEN(N,F) (open(N, F|O_CREAT|O_BINARY, 0644))
65 #define SEEK(H, O) (lseek(H, O, SEEK_SET))
66 #define READ(H, B, L) (read(H, B, L))
67 #define WRITE(H, B, L) (write(H, B, L))
68 #define CLOSE(H) (close(H))
70 #define RAND() (rand())
71 #define SRAND(s) (srand(s))
72 #define SLEEP(s) (sleep(s))
74 #define MIN(A,B) (((A)<(B))?(A):(B))
75 #define MAX(A,B) (((A)>(B))?(A):(B))
77 #define ALLOC_ALIGNED(S) (memalign(65536, S))
78 #define FREE_ALIGNED(P) (free(P))
81 static char *filename = 0;
83 static int server = 1;
84 static int maxio = 8192;
86 static int testnumber = -1;
87 static int saved_errno = 0;
89 static SOCKET s_fd = -1; /* listen socket */
90 static SOCKET c_fd = -1; /* IPC socket */
91 static HANDLE f_fd = INVALID_HANDLE; /* shared file */
92 static char *buf; /* I/O buffer */
114 #define FLAGS 2 /* index 2 is also used for do_open() flag, see below */
117 * flags for Mac OS X do_open()
134 * When adding tests be sure to add to both the descriptions AND tests array.
135 * Also, be sure to undo whatever is set for each test (eg unlock any locks)
136 * There is no need to have a matching client command for each server command
140 char *descriptions[] = {
141 /* 1 */"Add a lock to an empty lock list",
142 /* 2 */"Add a lock to the start and end of a list - no overlaps",
143 /* 3 */"Add a lock to the middle of a list - no overlap",
144 /* 4 */"Add different lock types to middle of the list - overlap exact match",
145 /* 5 */"Add new lock which completely overlaps any old lock in the list",
146 /* 6 */"Add new lock which itself is completely overlaped by any old lock in the list",
147 /* 7 */"Add new lock which starts before any old lock in the list",
148 /* 8 */"Add new lock which starts in the middle of any old lock in the list and ends after",
149 /* 9 */"Add different new lock types which completely overlaps any old lock in the list",
150 /* 10 */"Add different new locks which are completely overlaped by an old lock in the list",
151 /* 11 */"Add different new lock types which start before the old lock in the list",
152 /* 12 */"Add different new lock types which start in the middle of an old lock in the list and end after",
153 /* 13 */"Add new lock, differing types and processes, to middle of the list - exact overlap match",
154 /* 14 */"Add new lock, differing types and processes, which completely overlap any of the locks in the list",
155 /* 15 */"Add new lock, differing types and processes, which are completely overlaped by locks in the list",
156 /* 16 */"Add new lock, differing types and processes, which start before a lock in the list",
157 /* 17 */"Add new lock, differing types and processes, which starts in the middle of a lock, and ends after",
158 /* 18 */"Acquire write locks with overlapping ranges",
159 /* 19 */"Acquire write locks with non-overlapping ranges extending beyond EOF",
160 /* 20 */"Acquire write locks with overlapping ranges extending beyond EOF",
161 /* 21 */"Acquire write locks on whole files",
162 /* 22 */"Acquire write lock on whole file and range write lock",
163 /* 23 */"Acquire read locks with non-overlapping ranges",
164 /* 24 */"Acquire read locks with overlapping ranges",
165 /* 25 */"Acquire read and write locks with no overlapping ranges",
166 /* 26 */"Acquire read and write locks with overlapping ranges",
167 /* 27 */"Acquire whole file write lock and then close without unlocking (and attempt a lock)",
168 /* 28 */"Acquire two read locks, close and reopen the file, and test if the inital lock is still there",
169 /* 29 */"Verify that F_GETLK for F_WRLCK doesn't require that file be opened for write",
171 /* 30 */"Close the opened file and open the file with SHLOCK, other client will try to open with SHLOCK too",
172 /* 31 */"Close the opened file and open the file with SHLOCK, other client will try to open with EXLOCK",
173 /* 32 */"Close the opened file and open the file with EXLOCK, other client will try to open with EXLOCK too"
177 static int64_t tests[][6] =
178 /* test # Action offset length expected server/client */
180 /* Various simple tests exercising the list */
182 /* SECTION 1: WRITE and UNLOCK with the same process (SERVER) */
183 /* Add a lock to an empty list */
184 {1, WRLOCK, 1, 10, PASS, SERVER },
185 {1, UNLOCK, 1, 10, PASS, SERVER },
187 /* Add a lock to the start and end of a list - 1, 13 - no overlap */
188 {2, WRLOCK, 10, 10, PASS, SERVER },
189 {2, WRLOCK, 30, 10, PASS, SERVER },
190 {2, WRLOCK, 50, 10, PASS, SERVER },
191 {2, WRLOCK, 1, 5, PASS, SERVER },
192 {2, WRLOCK, 70, 5, PASS, SERVER },
194 {2, UNLOCK, 10, 10, PASS, SERVER },
195 {2, UNLOCK, 30, 10, PASS, SERVER },
196 {2, UNLOCK, 50, 10, PASS, SERVER },
197 {2, UNLOCK, 1, 5, PASS, SERVER },
198 {2, UNLOCK, 70, 5, PASS, SERVER },
200 /* Add a lock to the middle of a list - no overlap */
201 {3, WRLOCK, 10, 10, PASS, SERVER },
202 {3, WRLOCK, 30, 10, PASS, SERVER },
203 {3, WRLOCK, 50, 10, PASS, SERVER },
204 {3, WRLOCK, 42, 5, PASS, SERVER },
206 {3, UNLOCK, 10, 10, PASS, SERVER },
207 {3, UNLOCK, 30, 10, PASS, SERVER },
208 {3, UNLOCK, 50, 10, PASS, SERVER },
209 {3, UNLOCK, 42, 5, PASS, SERVER },
211 /* Add different lock types to middle of the list - overlap exact match - 3 */
212 {4, WRLOCK, 10, 10, PASS, SERVER },
213 {4, WRLOCK, 30, 10, PASS, SERVER },
214 {4, WRLOCK, 50, 10, PASS, SERVER },
215 /* Exact match - same lock type */
216 {4, WRLOCK, 30, 10, PASS, SERVER },
217 /* Exact match - different lock type */
218 {4, RDLOCK, 30, 10, PASS, SERVER },
219 /* Exact match - unlock */
220 {4, UNLOCK, 30, 10, PASS, SERVER },
221 /* New lock - as above, inserting in the list again */
222 {4, WRLOCK, 30, 10, PASS, SERVER },
224 {4, UNLOCK, 10, 10, PASS, SERVER },
225 {4, UNLOCK, 30, 10, PASS, SERVER },
226 {4, UNLOCK, 50, 10, PASS, SERVER },
228 /* Add new lock which completely overlaps any old lock in the list - 4,5,6 */
229 {5, WRLOCK, 10, 10, PASS, SERVER },
230 {5, WRLOCK, 30, 10, PASS, SERVER },
231 {5, WRLOCK, 50, 10, PASS, SERVER },
232 /* The start is the same, end overlaps */
233 {5, WRLOCK, 30, 15, PASS, SERVER },
234 /* The start is before, end is the same */
235 {5, WRLOCK, 25, 20, PASS, SERVER },
236 /* Both start and end overlap */
237 {5, WRLOCK, 22, 26, PASS, SERVER },
239 {5, UNLOCK, 10, 10, PASS, SERVER },
240 {5, UNLOCK, 22, 26, PASS, SERVER },
241 {5, UNLOCK, 50, 10, PASS, SERVER },
243 /* Add new lock which itself is completely overlaped by any old lock in the list - 7,8,10 */
244 {6, WRLOCK, 10, 10, PASS, SERVER },
245 {6, WRLOCK, 30, 10, PASS, SERVER },
246 {6, WRLOCK, 50, 10, PASS, SERVER },
247 /* The start is the same, end is in the middle of old lock - NOP */
248 {6, WRLOCK, 30, 5, PASS, SERVER },
249 /* The start and end are in the middle of old lock - NOP */
250 {6, WRLOCK, 32, 6, PASS, SERVER },
251 /* Start in the middle and end is the same - NOP */
252 {6, WRLOCK, 32, 8, PASS, SERVER },
254 {6, UNLOCK, 10, 10, PASS, SERVER },
255 {6, UNLOCK, 30, 10, PASS, SERVER },
256 {6, UNLOCK, 32, 8, PASS, SERVER },
257 {6, UNLOCK, 50, 10, PASS, SERVER },
259 /* Add new lock which starts before any old lock in the list - 2,9 */
260 {7, WRLOCK, 10, 10, PASS, SERVER },
261 {7, WRLOCK, 30, 10, PASS, SERVER },
262 {7, WRLOCK, 50, 10, PASS, SERVER },
263 /* Here is the new lock */
264 {7, WRLOCK, 27, 10, PASS, SERVER },
265 /* Go again with the end of the new lock matching the start of old lock */
266 {7, WRLOCK, 25, 2, PASS, SERVER },
268 {7, UNLOCK, 10, 10, PASS, SERVER },
269 {7, UNLOCK, 25, 15, PASS, SERVER },
270 {7, UNLOCK, 50, 10, PASS, SERVER },
272 /* Add new lock which starts in the middle of any old lock in the list and ends after - 11,12 */
273 {8, WRLOCK, 10, 10, PASS, SERVER },
274 {8, WRLOCK, 30, 10, PASS, SERVER },
275 {8, WRLOCK, 50, 10, PASS, SERVER },
276 /* Here is the new lock */
277 {8, WRLOCK, 35, 10, PASS, SERVER },
278 /* Go again with the end of the new lock matching the start of old lock */
279 {8, WRLOCK, 45, 2, PASS, SERVER },
281 {8, UNLOCK, 10, 10, PASS, SERVER },
282 {8, UNLOCK, 30, 17, PASS, SERVER },
283 {8, UNLOCK, 50, 10, PASS, SERVER },
284 /* SECTION 2: Overlapping READ and WRITE and UNLOCK with the same process (SERVER) */
285 /* Add different new lock types which completely overlaps any old lock in the list - 4,5,6 */
286 {9, WRLOCK, 10, 10, PASS, SERVER },
287 {9, WRLOCK, 30, 10, PASS, SERVER },
288 {9, WRLOCK, 50, 10, PASS, SERVER },
289 /* The start is the same, end overlaps */
290 {9, RDLOCK, 30, 15, PASS, SERVER },
291 /* The start is before, end is the same */
292 {9, WRLOCK, 25, 20, PASS, SERVER },
293 /* Both start and end overlap */
294 {9, RDLOCK, 22, 26, PASS, SERVER },
296 {9, UNLOCK, 10, 10, PASS, SERVER },
297 {9, UNLOCK, 22, 26, PASS, SERVER },
298 {9, UNLOCK, 50, 10, PASS, SERVER },
300 /* Add different new locks which are completely overlaped by an old lock in the list - 7,8,10 */
301 {10, WRLOCK, 10, 10, PASS, SERVER },
302 {10, WRLOCK, 30, 10, PASS, SERVER },
303 {10, WRLOCK, 50, 10, PASS, SERVER },
304 /* The start is the same, end is in the middle of old lock */
305 {10, RDLOCK, 30, 5, PASS, SERVER },
306 /* The start and end are in the middle of a lock */
307 {10, WRLOCK, 32, 2, PASS, SERVER },
308 /* Start in the middle and end is the same */
309 {10, RDLOCK, 36, 5, PASS, SERVER },
311 {10, UNLOCK, 10, 10, PASS, SERVER },
312 {10, UNLOCK, 30, 11, PASS, SERVER },
313 {10, UNLOCK, 50, 10, PASS, SERVER },
315 /* Add different new lock types which start before the old lock in the list - 2,9 */
316 {11, WRLOCK, 10, 10, PASS, SERVER },
317 {11, WRLOCK, 30, 10, PASS, SERVER },
318 {11, WRLOCK, 50, 10, PASS, SERVER },
319 /* Here is the new lock */
320 {11, RDLOCK, 27, 10, PASS, SERVER },
321 /* Go again with the end of the new lock matching the start of lock */
322 {11, WRLOCK, 25, 3, PASS, SERVER },
324 {11, UNLOCK, 10, 10, PASS, SERVER },
325 {11, UNLOCK, 25, 15, PASS, SERVER },
326 {11, UNLOCK, 50, 10, PASS, SERVER },
328 /* Add different new lock types which start in the middle of an old lock in the list and end after - 11,12 */
329 {12, WRLOCK, 10, 10, PASS, SERVER },
330 {12, WRLOCK, 30, 10, PASS, SERVER },
331 {12, WRLOCK, 50, 10, PASS, SERVER },
332 /* Here is the new lock */
333 {12, RDLOCK, 35, 10, PASS, SERVER },
334 /* Go again with the end of the new lock matching the start of old lock */
335 {12, WRLOCK, 44, 3, PASS, SERVER },
337 {12, UNLOCK, 10, 10, PASS, SERVER },
338 {12, UNLOCK, 30, 18, PASS, SERVER },
339 {12, UNLOCK, 50, 10, PASS, SERVER },
341 /* SECTION 3: Overlapping READ and WRITE and UNLOCK with the different processes (CLIENT/SERVER) */
342 /* Add new lock, differing types and processes, to middle of the list - exact overlap match - 3 */
343 {13, WRLOCK, 10, 10, PASS, SERVER },
344 {13, WRLOCK, 30, 10, PASS, SERVER },
345 {13, RDLOCK, 50, 10, PASS, SERVER },
346 /* Same lock type, different process */
347 {13, WRLOCK, 30, 10, FAIL, CLIENT },
348 {13, RDLOCK, 50, 10, PASS, CLIENT },
349 /* Exact match - different lock type, different process */
350 {13, RDLOCK, 30, 10, FAIL, CLIENT },
351 /* Exact match - unlock */
352 {13, UNLOCK, 30, 10, PASS, CLIENT },
353 /* New lock - as above, inserting in the list again */
354 {13, UNLOCK, 30, 10, PASS, SERVER },
355 /* Exact match - same lock type, different process */
356 {13, WRLOCK, 30, 10, PASS, CLIENT },
358 {13, UNLOCK, 10, 10, PASS, SERVER },
359 {13, UNLOCK, 30, 10, PASS, CLIENT },
360 {13, UNLOCK, 50, 10, PASS, SERVER },
362 /* Add new lock, differing types and processes, which completely overlap any of the locks in the list - 4,5,6 */
363 {14, WRLOCK, 10, 10, PASS, SERVER },
364 {14, WRLOCK, 30, 10, PASS, SERVER },
365 {14, RDLOCK, 50, 10, PASS, SERVER },
366 /* The start is the same, end overlaps */
367 {14, RDLOCK, 30, 15, FAIL, CLIENT },
368 {14, WRLOCK, 30, 15, FAIL, CLIENT },
369 /* The start is before, end is the same */
370 {14, RDLOCK, 25, 20, FAIL, CLIENT },
371 {14, WRLOCK, 25, 20, FAIL, CLIENT },
372 /* Both start and end overlap */
373 {14, RDLOCK, 22, 26, FAIL, CLIENT },
374 {14, WRLOCK, 22, 26, FAIL, CLIENT },
376 /* The start is the same, end overlaps */
377 {14, RDLOCK, 50, 15, PASS, CLIENT },
378 {14, WRLOCK, 50, 17, FAIL, CLIENT },
379 /* The start is before, end is the same */
380 {14, RDLOCK, 45, 20, PASS, CLIENT },
381 {14, WRLOCK, 43, 22, FAIL, CLIENT },
382 /* Both start and end overlap */
383 {14, RDLOCK, 42, 26, PASS, CLIENT },
384 {14, WRLOCK, 41, 28, FAIL, CLIENT },
386 {14, UNLOCK, 10, 10, PASS, SERVER },
387 {14, UNLOCK, 22, 26, PASS, SERVER },
388 {14, UNLOCK, 42, 26, PASS, CLIENT },
390 /* Add new lock, differing types and processes, which are completely overlaped by an old lock in the list - 7,8,10 */
391 {15, WRLOCK, 10, 10, PASS, SERVER },
392 {15, RDLOCK, 30, 10, PASS, SERVER },
393 {15, WRLOCK, 50, 10, PASS, SERVER },
394 /* The start is the same, end is in the middle of old lock */
395 {15, RDLOCK, 50, 5, FAIL, CLIENT },
396 {15, WRLOCK, 50, 5, FAIL, CLIENT },
397 /* The start and end are in the middle of old lock */
398 {15, RDLOCK, 52, 6, FAIL, CLIENT },
399 {15, WRLOCK, 52, 6, FAIL, CLIENT },
400 /* Start in the middle and end is the same */
401 {15, RDLOCK, 52, 8, FAIL, CLIENT },
402 {15, WRLOCK, 52, 8, FAIL, CLIENT },
403 /* The start is the same, end is in the middle of old lock */
404 {15, RDLOCK, 30, 5, PASS, CLIENT },
405 {15, WRLOCK, 30, 5, FAIL, CLIENT },
406 /* The start and end are in the middle of old lock */
407 {15, RDLOCK, 32, 6, PASS, CLIENT },
408 {15, WRLOCK, 32, 6, FAIL, CLIENT },
409 /* Start in the middle and end is the same */
410 {15, RDLOCK, 32, 8, PASS, CLIENT },
411 {15, WRLOCK, 32, 8, FAIL, CLIENT },
413 {15, UNLOCK, 10, 10, PASS, SERVER },
414 {15, UNLOCK, 30, 10, PASS, SERVER },
415 {15, UNLOCK, 50, 10, PASS, SERVER },
416 /* Add new lock, differing types and processes, which start before a lock in the list - 2,9 */
417 {16, RDLOCK, 10, 10, PASS, SERVER },
418 {16, WRLOCK, 50, 10, PASS, SERVER },
419 /* Start is before, end is the start of the old lock in list */
420 {16, RDLOCK, 5, 6, PASS, CLIENT },
421 {16, WRLOCK, 5, 6, FAIL, CLIENT },
422 /* Start is before, end is in the middle of the old lock */
423 {16, RDLOCK, 5, 10, PASS, CLIENT },
424 {16, WRLOCK, 5, 10, FAIL, CLIENT },
425 /* Start is before, end is the start of the old lock in list */
426 {16, RDLOCK, 45, 6, FAIL, CLIENT },
427 {16, WRLOCK, 45, 6, FAIL, CLIENT },
428 /* Start is before, end is in the middle of the old lock */
429 {16, RDLOCK, 45, 10, FAIL, CLIENT },
430 {16, WRLOCK, 45, 10, FAIL, CLIENT },
432 {16, UNLOCK, 5, 15, PASS, CLIENT },
433 {16, UNLOCK, 30, 10, PASS, SERVER },
434 {16, UNLOCK, 50, 10, PASS, SERVER },
436 /* Add new lock, differing types and processes, which starts in the middle of a lock, and ends after - 11,12 */
437 {17, WRLOCK, 10, 10, PASS, SERVER },
438 {17, RDLOCK, 30, 10, PASS, SERVER },
439 {17, WRLOCK, 50, 10, PASS, SERVER },
440 /* Start in the middle, end after lock in list */
441 {17, WRLOCK, 35, 10, FAIL, CLIENT },
442 /* Start matches end of lock in list */
443 {17, RDLOCK, 35, 10, PASS, CLIENT },
444 {17, RDLOCK, 44, 2, PASS, CLIENT },
445 /* Start in the middle, end after lock in list */
446 {17, RDLOCK, 55, 10, FAIL, CLIENT },
447 {17, WRLOCK, 55, 10, FAIL, CLIENT },
448 /* Start matches end of lock in list */
449 {17, RDLOCK, 59, 5, FAIL, CLIENT },
450 {17, WRLOCK, 59, 5, FAIL, CLIENT },
452 {17, UNLOCK, 10, 10, PASS, SERVER },
453 {17, UNLOCK, 30, 16, PASS, CLIENT },
454 {17, UNLOCK, 50, 10, PASS, SERVER },
456 /* SECTION 4: overlapping and EOF tests */
457 /* Acquire overlapping ranges */
458 {18, WRLOCK, 11, 7, PASS, SERVER },
459 {18, WRLOCK, 13, 8, FAIL, CLIENT },
460 {18, UNLOCK, 11, 7, PASS, SERVER },
461 /* Acquire different ranges beyond EOF */
462 {19, WRLOCK, 10, FILE_SIZE, PASS, SERVER },
463 {19, WRLOCK, FILE_SIZE + 10, 10, PASS, CLIENT },
464 {19, UNLOCK, 10, FILE_SIZE, PASS, SERVER },
465 {19, UNLOCK, FILE_SIZE + 10, 10, PASS, CLIENT },
466 /* Acquire same range beyong EOF */
467 {20, WRLOCK, 10, FILE_SIZE, PASS, SERVER, },
468 {20, WRLOCK, 10, FILE_SIZE, FAIL, CLIENT, },
469 {20, UNLOCK, 10, FILE_SIZE, PASS, SERVER, },
470 /* Acquire whole file lock */
471 {21, WRLOCK, 0, 0, PASS, SERVER, },
472 {21, WRLOCK, 0, 0, FAIL, CLIENT, },
473 {21, UNLOCK, 0, 0, PASS, SERVER, },
474 /* Acquire whole file lock, then range */
475 {22, WRLOCK, 0, 0, PASS, SERVER, },
476 {22, WRLOCK, 1, 5, FAIL, CLIENT, },
477 {22, UNLOCK, 0, 0, PASS, SERVER, },
478 /* Acquire non-overlapping read locks */
479 {23, RDLOCK, 1, 5, PASS, SERVER, },
480 {23, RDLOCK, 7, 6, PASS, CLIENT, },
481 {23, UNLOCK, 1, 5, PASS, SERVER, },
482 {23, UNLOCK, 7, 6, PASS, CLIENT, },
483 /* Acquire overlapping read locks */
484 {24, RDLOCK, 1, 5, PASS, SERVER, },
485 {24, RDLOCK, 2, 6, PASS, CLIENT, },
486 {24, UNLOCK, 1, 5, PASS, SERVER, },
487 {24, UNLOCK, 1, 7, PASS, CLIENT, },
488 /* Acquire non-overlapping read and write locks */
489 {25, RDLOCK, 1, 5, PASS, SERVER, },
490 {25, WRLOCK, 7, 6, PASS, CLIENT, },
491 {25, UNLOCK, 1, 5, PASS, SERVER, },
492 {25, UNLOCK, 7, 6, PASS, CLIENT, },
493 /* Acquire overlapping read and write locks */
494 {26, RDLOCK, 1, 5, PASS, SERVER, },
495 {26, WRLOCK, 2, 6, FAIL, CLIENT, },
496 {26, UNLOCK, 1, 5, PASS, SERVER, },
497 /* Acquire whole file lock, then close (without unlocking) */
498 {27, WRLOCK, 0, 0, PASS, SERVER, },
499 {27, WRLOCK, 1, 5, FAIL, CLIENT, },
500 {27, F_CLOSE,0, 0, PASS, SERVER, },
501 {27, WRLOCK, 1, 5, PASS, CLIENT, },
502 {27, F_OPEN, O_RDWR, 0, PASS, SERVER, },
503 {27, UNLOCK, 1, 5, PASS, CLIENT, },
504 /* Acquire two read locks, close one file and then reopen to check that first lock still exists */
505 {28, RDLOCK, 1, 5, PASS, SERVER, },
506 {28, RDLOCK, 1, 5, PASS, CLIENT, },
507 {28, F_CLOSE,0, 0, PASS, SERVER, },
508 {28, F_OPEN, O_RDWR, 0, PASS, SERVER, },
509 {28, WRLOCK, 0, 0, FAIL, SERVER, },
510 {28, UNLOCK, 1, 5, PASS, SERVER, },
511 /* Verify that F_GETLK for F_WRLCK doesn't require that file be opened for write */
512 {29, F_CLOSE, 0, 0, PASS, SERVER, },
513 {29, F_OPEN, O_RDONLY, 0, PASS, SERVER, },
514 {29, WRTEST, 0, 0, PASS, SERVER, },
515 {29, F_CLOSE,0, 0, PASS, SERVER, },
516 {29, F_OPEN, O_RDWR, 0, PASS, SERVER, },
518 /* Close the opened file and open the file with SHLOCK, other client will try to open with SHLOCK too */
519 {30, F_CLOSE,0, 0, PASS, SERVER, },
520 {30, F_OPEN, O_RDWR|O_SHLOCK|O_NONBLOCK, 0, PASS, SERVER, },
521 {30, F_CLOSE,0, 0, PASS, CLIENT, },
522 {30, F_OPEN, O_RDWR|O_SHLOCK|O_NONBLOCK, 0, PASS, CLIENT, },
523 /* Close the opened file and open the file with SHLOCK, other client will try to open with EXLOCK */
524 {31, F_CLOSE,0, 0, PASS, SERVER, },
525 {31, F_CLOSE,0, 0, PASS, CLIENT, },
526 {31, F_OPEN, O_RDWR|O_SHLOCK|O_NONBLOCK, 0, PASS, SERVER, },
527 {31, F_OPEN, O_RDWR|O_EXLOCK|O_NONBLOCK, 0, FAIL, CLIENT, },
528 /* Close the opened file and open the file with EXLOCK, other client will try to open with EXLOCK too */
529 {32, F_CLOSE,0, 0, PASS, SERVER, },
530 {32, F_CLOSE,0, 0, FAIL, CLIENT, },
531 {32, F_OPEN, O_RDWR|O_EXLOCK|O_NONBLOCK, 0, PASS, SERVER, },
532 {32, F_OPEN, O_RDWR|O_EXLOCK|O_NONBLOCK, 0, FAIL, CLIENT, },
533 {32, F_CLOSE,0, 0, PASS, SERVER, },
534 {32, F_CLOSE,0, 0, FAIL, CLIENT, },
535 {32, F_OPEN, O_RDWR, 0, PASS, SERVER, },
536 {32, F_OPEN, O_RDWR, 0, PASS, CLIENT, },
538 /* indicate end of array */
551 int32_t padding; /* So mac and irix have the same size struct (bloody alignment) */
558 fprintf(stderr, "Usage: %s [options] sharedfile\n\
561 -p port TCP/IP port number for client-server communication\n\
562 -d enable debug tracing\n\
563 -n # test number to run\n\
564 -h host run as client and connect to server on remote host\n\
565 [default run as server]\n", prog);
569 #define INIT_BUFSZ 512
572 initialize(HANDLE fd)
578 int togo = FILE_SIZE;
580 ibuf = (char*)malloc(INIT_BUFSZ);
581 memset(ibuf, ':', INIT_BUFSZ);
586 j = togo > INIT_BUFSZ ? INIT_BUFSZ : togo;
588 if ((nwrite = WRITE(fd, ibuf, j)) != j) {
590 perror("initialize write:");
592 fprintf(stderr, "initialize: write() returns %d, not %d as expected\n",
602 int do_open(int flag)
604 if ((f_fd = OPEN(filename, flag)) == INVALID_HANDLE) {
605 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)
810 * +10 is slop for the iteration number if do_write() ... never
811 * needed unless maxio is very small
813 if ((buf = (char *)malloc(maxio + 10)) == NULL) {
814 perror("malloc buf");
819 setbuf(stderr, NULL);
824 s_fd = socket(AF_INET, SOCK_STREAM, 0);
825 if (s_fd == INVALID_SOCKET) {
830 if (setsockopt(s_fd, IPPROTO_TCP, TCP_NODELAY, (char*)&one, sizeof(one)) < 0) {
831 perror("setsockopt(nodelay)");
835 if (setsockopt(s_fd, SOL_SOCKET, SO_REUSEADDR, (char*)&one, sizeof(one))<0) {
836 perror("setsockopt(reuseaddr)");
841 if (setsockopt(s_fd, SOL_SOCKET, SO_REUSEPORT, (char*)&one, sizeof(one))<0) {
842 perror("setsockopt(reuseport)");
848 memset(&myAddr, 0, sizeof(myAddr));
849 myAddr.sin_family = AF_INET;
850 myAddr.sin_addr.s_addr = htonl(INADDR_ANY);
851 myAddr.sin_port = htons((short)port);
852 sts = bind(s_fd, (struct sockaddr*)&myAddr, sizeof(myAddr));
859 sts = listen(s_fd, 5); /* Max. of 5 pending connection requests */
867 socklen_t addr_len = sizeof(myAddr);
869 if (getsockname(s_fd, &myAddr, &addr_len)) {
870 perror("getsockname");
874 port = ntohs(myAddr.sin_port);
877 printf("server port: %d\n", port);
880 c_fd = accept(s_fd, NULL, NULL);
881 if (c_fd == INVALID_SOCKET) {
887 if (debug) fprintf(stderr, "Client accepted\n");
891 struct hostent *servInfo;
893 if ((servInfo = gethostbyname(host)) == NULL) {
894 printf("Couldn't get hostbyname for %s", host);
895 if (h_errno == HOST_NOT_FOUND)
896 printf(": host not found");
902 c_fd = socket(AF_INET, SOCK_STREAM, 0);
903 if (c_fd == INVALID_SOCKET) {
908 /* avoid 200 ms delay */
909 if (setsockopt(c_fd, IPPROTO_TCP, TCP_NODELAY, (char *)&i, sizeof(i)) < 0) {
910 perror("setsockopt(nodelay)");
914 /* Don't linger on close */
915 if (setsockopt(c_fd, SOL_SOCKET, SO_LINGER, (char *)&noLinger, sizeof(noLinger)) < 0) {
916 perror("setsockopt(nolinger)");
921 memset(&myAddr, 0, sizeof(myAddr)); /* Arrgh! &myAddr, not myAddr */
922 myAddr.sin_family = AF_INET;
923 memcpy(&myAddr.sin_addr, servInfo->h_addr, servInfo->h_length);
924 myAddr.sin_port = htons((short)port);
926 if (connect(c_fd, (struct sockaddr*)&myAddr, sizeof(myAddr)) < 0) {
927 perror("unable to connect");
928 fprintf(stderr, "Server might still initializing the shared file\n ");
933 if (debug) fprintf(stderr, "Connected to server\n");
938 /* only server need do shared file */
942 * TCP/IP connection to be established, safe to proceed.
944 * real work is in here ...
957 last_test = testnumber - 1;
958 while(tests[index][TEST_NUM] != testnumber && tests[index][TEST_NUM] != 0) {
962 /* If we have a server command, deal with it */
963 if(tests[index][WHO] == SERVER) {
965 fprintf(stderr, "Got a server command (%d)\n", index);
966 if(tests[index][TEST_NUM] == 0) {
970 memset(&ctl, 0, sizeof(ctl));
971 ctl.test = tests[index][TEST_NUM];
973 if(tests[index][TEST_NUM] != 0) {
974 switch(tests[index][COMMAND]) {
976 result = do_lock(F_SETLK, F_WRLCK, tests[index][OFFSET], tests[index][LENGTH]);
979 result = do_lock(F_SETLK, F_RDLCK, tests[index][OFFSET], tests[index][LENGTH]);
982 result = do_lock(F_SETLK, F_UNLCK, tests[index][OFFSET], tests[index][LENGTH]);
988 result = do_open(tests[index][FLAGS]);
991 result = do_lock(F_GETLK, F_WRLCK, tests[index][OFFSET], tests[index][LENGTH]);
994 result = do_lock(F_GETLK, F_RDLCK, tests[index][OFFSET], tests[index][LENGTH]);
997 if( result != tests[index][RESULT]) {
999 /* We have a failure */
1001 fprintf(stderr, "Server failure in test %d, while %sing using offset %lld, length %lld - err = %d:%s\n",
1002 ctl.test, tests[index][COMMAND]==WRLOCK?"write lock":
1003 tests[index][COMMAND]==RDLOCK?"read lock":
1004 tests[index][COMMAND]==UNLOCK?"unlock":
1005 tests[index][COMMAND]==F_OPEN?"open":"clos",
1006 (long long)tests[index][OFFSET],
1007 (long long)tests[index][LENGTH],
1008 saved_errno, strerror(saved_errno));
1009 fprintf(stderr, "Server failure in %lld:%s\n",
1010 (long long)tests[index][TEST_NUM],
1011 descriptions[tests[index][TEST_NUM] - 1]);
1014 /* else send it off to the client */
1015 } else if (tests[index][WHO] == CLIENT) {
1016 if(tests[index][TEST_NUM] == 0) {
1021 fprintf(stderr, "Sending command to client (%d) - %s - %lld:%lld\n",
1022 index, tests[index][COMMAND]==WRLOCK?"write lock":
1023 tests[index][COMMAND]==RDLOCK?"read lock":
1024 tests[index][COMMAND]==UNLOCK?"unlock":
1025 tests[index][COMMAND]==F_OPEN?"open":"clos",
1026 (long long)tests[index][OFFSET],
1027 (long long)tests[index][LENGTH]);
1028 /* get the client to do something */
1032 /* Get the clients response */
1034 /* this is the whether the test passed or failed,
1035 * not what the command returned */
1036 if( ctl.result == FAIL ) {
1039 fprintf(stderr, "Client failure in test %d, while %sing using offset %lld, length %lld - err = %d:%s\n",
1040 ctl.test, ctl.command==WRLOCK?"write lock":
1041 ctl.command==RDLOCK?"read lock":
1042 ctl.command==UNLOCK?"unlock":
1043 ctl.command==F_OPEN?"open":"clos",
1044 (long long)ctl.offset, (long long)ctl.length,
1045 ctl.error, strerror(ctl.error));
1046 fprintf(stderr, "Client failure in %lld:%s\n",
1047 (long long)tests[index][TEST_NUM],
1048 descriptions[tests[index][TEST_NUM] - 1]);
1053 fprintf(stderr, "server sleeping ...\n");
1056 if(tests[index][TEST_NUM] != 0) {
1057 if(last_test != tests[index][TEST_NUM]) {
1064 last_test = tests[index][TEST_NUM];
1068 } else { /* CLIENT */
1070 fprintf(stderr,"client: waiting...\n");
1071 /* wait for the server to do something */
1074 /* check for a client command */
1076 if (tests[index][WHO] != CLIENT) {
1077 fprintf(stderr, "not a client command index (%d)\n", index);
1087 ctl.command = tests[index][COMMAND];
1088 ctl.offset = tests[index][OFFSET];
1089 ctl.length = tests[index][LENGTH];
1090 switch(tests[index][COMMAND]) {
1092 result = do_lock(F_SETLK, F_WRLCK, tests[index][OFFSET], tests[index][LENGTH]);
1095 result = do_lock(F_SETLK, F_RDLCK, tests[index][OFFSET], tests[index][LENGTH]);
1098 result = do_lock(F_SETLK, F_UNLCK, tests[index][OFFSET], tests[index][LENGTH]);
1101 result = do_close();
1104 result = do_open(tests[index][FLAGS]);
1107 result = do_lock(F_GETLK, F_WRLCK, tests[index][OFFSET], tests[index][LENGTH]);
1110 result = do_lock(F_GETLK, F_RDLCK, tests[index][OFFSET], tests[index][LENGTH]);
1113 if( result != tests[index][RESULT] ) {
1115 fprintf(stderr,"Got %d, wanted %lld\n", result,
1116 (long long)tests[index][RESULT]);
1118 ctl.error = saved_errno;
1124 fprintf(stderr,"client: sending result to server (%d)\n", ctl.index);
1125 /* Send result to the server */
1127 if(tests[index][TEST_NUM] != 0) {
1128 if(last_test != tests[index][TEST_NUM])
1130 last_test = tests[index][TEST_NUM];
1135 printf("%d tests run, %d failed\n", test_count, fail_count);