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 */
112 static char *get_cmd_str(int cmd)
115 case CMD_WRLOCK: return "write lock"; break;
116 case CMD_RDLOCK: return "read lock"; break;
117 case CMD_UNLOCK: return "unlock"; break;
118 case CMD_CLOSE: return "close"; break;
119 case CMD_OPEN: return "open"; break;
120 case CMD_WRTEST: return "Wait for SIGIO"; break;
121 case CMD_RDTEST: return "Truncate"; break;
126 * flags for Mac OS X do_open()
143 * When adding tests be sure to add to both the descriptions AND tests array.
144 * Also, be sure to undo whatever is set for each test (eg unlock any locks)
145 * There is no need to have a matching client command for each server command
149 char *descriptions[] = {
150 /* 1 */"Add a lock to an empty lock list",
151 /* 2 */"Add a lock to the start and end of a list - no overlaps",
152 /* 3 */"Add a lock to the middle of a list - no overlap",
153 /* 4 */"Add different lock types to middle of the list - overlap exact match",
154 /* 5 */"Add new lock which completely overlaps any old lock in the list",
155 /* 6 */"Add new lock which itself is completely overlaped by any old lock in the list",
156 /* 7 */"Add new lock which starts before any old lock in the list",
157 /* 8 */"Add new lock which starts in the middle of any old lock in the list and ends after",
158 /* 9 */"Add different new lock types which completely overlaps any old lock in the list",
159 /* 10 */"Add different new locks which are completely overlaped by an old lock in the list",
160 /* 11 */"Add different new lock types which start before the old lock in the list",
161 /* 12 */"Add different new lock types which start in the middle of an old lock in the list and end after",
162 /* 13 */"Add new lock, differing types and processes, to middle of the list - exact overlap match",
163 /* 14 */"Add new lock, differing types and processes, which completely overlap any of the locks in the list",
164 /* 15 */"Add new lock, differing types and processes, which are completely overlaped by locks in the list",
165 /* 16 */"Add new lock, differing types and processes, which start before a lock in the list",
166 /* 17 */"Add new lock, differing types and processes, which starts in the middle of a lock, and ends after",
167 /* 18 */"Acquire write locks with overlapping ranges",
168 /* 19 */"Acquire write locks with non-overlapping ranges extending beyond EOF",
169 /* 20 */"Acquire write locks with overlapping ranges extending beyond EOF",
170 /* 21 */"Acquire write locks on whole files",
171 /* 22 */"Acquire write lock on whole file and range write lock",
172 /* 23 */"Acquire read locks with non-overlapping ranges",
173 /* 24 */"Acquire read locks with overlapping ranges",
174 /* 25 */"Acquire read and write locks with no overlapping ranges",
175 /* 26 */"Acquire read and write locks with overlapping ranges",
176 /* 27 */"Acquire whole file write lock and then close without unlocking (and attempt a lock)",
177 /* 28 */"Acquire two read locks, close and reopen the file, and test if the inital lock is still there",
178 /* 29 */"Verify that F_GETLK for F_WRLCK doesn't require that file be opened for write",
180 /* 30 */"Close the opened file and open the file with SHLOCK, other client will try to open with SHLOCK too",
181 /* 31 */"Close the opened file and open the file with SHLOCK, other client will try to open with EXLOCK",
182 /* 32 */"Close the opened file and open the file with EXLOCK, other client will try to open with EXLOCK too"
186 static int64_t tests[][6] =
187 /* test # Action [offset|flags] length expected server/client */
189 /* Various simple tests exercising the list */
191 /* SECTION 1: WRITE and CMD_UNLOCK with the same process (SERVER) */
192 /* Add a lock to an empty list */
193 {1, CMD_WRLOCK, 1, 10, PASS, SERVER },
194 {1, CMD_UNLOCK, 1, 10, PASS, SERVER },
196 /* Add a lock to the start and end of a list - 1, 13 - no overlap */
197 {2, CMD_WRLOCK, 10, 10, PASS, SERVER },
198 {2, CMD_WRLOCK, 30, 10, PASS, SERVER },
199 {2, CMD_WRLOCK, 50, 10, PASS, SERVER },
200 {2, CMD_WRLOCK, 1, 5, PASS, SERVER },
201 {2, CMD_WRLOCK, 70, 5, PASS, SERVER },
203 {2, CMD_UNLOCK, 10, 10, PASS, SERVER },
204 {2, CMD_UNLOCK, 30, 10, PASS, SERVER },
205 {2, CMD_UNLOCK, 50, 10, PASS, SERVER },
206 {2, CMD_UNLOCK, 1, 5, PASS, SERVER },
207 {2, CMD_UNLOCK, 70, 5, PASS, SERVER },
209 /* Add a lock to the middle of a list - no overlap */
210 {3, CMD_WRLOCK, 10, 10, PASS, SERVER },
211 {3, CMD_WRLOCK, 30, 10, PASS, SERVER },
212 {3, CMD_WRLOCK, 50, 10, PASS, SERVER },
213 {3, CMD_WRLOCK, 42, 5, PASS, SERVER },
215 {3, CMD_UNLOCK, 10, 10, PASS, SERVER },
216 {3, CMD_UNLOCK, 30, 10, PASS, SERVER },
217 {3, CMD_UNLOCK, 50, 10, PASS, SERVER },
218 {3, CMD_UNLOCK, 42, 5, PASS, SERVER },
220 /* Add different lock types to middle of the list - overlap exact match - 3 */
221 {4, CMD_WRLOCK, 10, 10, PASS, SERVER },
222 {4, CMD_WRLOCK, 30, 10, PASS, SERVER },
223 {4, CMD_WRLOCK, 50, 10, PASS, SERVER },
224 /* Exact match - same lock type */
225 {4, CMD_WRLOCK, 30, 10, PASS, SERVER },
226 /* Exact match - different lock type */
227 {4, CMD_RDLOCK, 30, 10, PASS, SERVER },
228 /* Exact match - unlock */
229 {4, CMD_UNLOCK, 30, 10, PASS, SERVER },
230 /* New lock - as above, inserting in the list again */
231 {4, CMD_WRLOCK, 30, 10, PASS, SERVER },
233 {4, CMD_UNLOCK, 10, 10, PASS, SERVER },
234 {4, CMD_UNLOCK, 30, 10, PASS, SERVER },
235 {4, CMD_UNLOCK, 50, 10, PASS, SERVER },
237 /* Add new lock which completely overlaps any old lock in the list - 4,5,6 */
238 {5, CMD_WRLOCK, 10, 10, PASS, SERVER },
239 {5, CMD_WRLOCK, 30, 10, PASS, SERVER },
240 {5, CMD_WRLOCK, 50, 10, PASS, SERVER },
241 /* The start is the same, end overlaps */
242 {5, CMD_WRLOCK, 30, 15, PASS, SERVER },
243 /* The start is before, end is the same */
244 {5, CMD_WRLOCK, 25, 20, PASS, SERVER },
245 /* Both start and end overlap */
246 {5, CMD_WRLOCK, 22, 26, PASS, SERVER },
248 {5, CMD_UNLOCK, 10, 10, PASS, SERVER },
249 {5, CMD_UNLOCK, 22, 26, PASS, SERVER },
250 {5, CMD_UNLOCK, 50, 10, PASS, SERVER },
252 /* Add new lock which itself is completely overlaped by any old lock in the list - 7,8,10 */
253 {6, CMD_WRLOCK, 10, 10, PASS, SERVER },
254 {6, CMD_WRLOCK, 30, 10, PASS, SERVER },
255 {6, CMD_WRLOCK, 50, 10, PASS, SERVER },
256 /* The start is the same, end is in the middle of old lock - NOP */
257 {6, CMD_WRLOCK, 30, 5, PASS, SERVER },
258 /* The start and end are in the middle of old lock - NOP */
259 {6, CMD_WRLOCK, 32, 6, PASS, SERVER },
260 /* Start in the middle and end is the same - NOP */
261 {6, CMD_WRLOCK, 32, 8, PASS, SERVER },
263 {6, CMD_UNLOCK, 10, 10, PASS, SERVER },
264 {6, CMD_UNLOCK, 30, 10, PASS, SERVER },
265 {6, CMD_UNLOCK, 32, 8, PASS, SERVER },
266 {6, CMD_UNLOCK, 50, 10, PASS, SERVER },
268 /* Add new lock which starts before any old lock in the list - 2,9 */
269 {7, CMD_WRLOCK, 10, 10, PASS, SERVER },
270 {7, CMD_WRLOCK, 30, 10, PASS, SERVER },
271 {7, CMD_WRLOCK, 50, 10, PASS, SERVER },
272 /* Here is the new lock */
273 {7, CMD_WRLOCK, 27, 10, PASS, SERVER },
274 /* Go again with the end of the new lock matching the start of old lock */
275 {7, CMD_WRLOCK, 25, 2, PASS, SERVER },
277 {7, CMD_UNLOCK, 10, 10, PASS, SERVER },
278 {7, CMD_UNLOCK, 25, 15, PASS, SERVER },
279 {7, CMD_UNLOCK, 50, 10, PASS, SERVER },
281 /* Add new lock which starts in the middle of any old lock in the list and ends after - 11,12 */
282 {8, CMD_WRLOCK, 10, 10, PASS, SERVER },
283 {8, CMD_WRLOCK, 30, 10, PASS, SERVER },
284 {8, CMD_WRLOCK, 50, 10, PASS, SERVER },
285 /* Here is the new lock */
286 {8, CMD_WRLOCK, 35, 10, PASS, SERVER },
287 /* Go again with the end of the new lock matching the start of old lock */
288 {8, CMD_WRLOCK, 45, 2, PASS, SERVER },
290 {8, CMD_UNLOCK, 10, 10, PASS, SERVER },
291 {8, CMD_UNLOCK, 30, 17, PASS, SERVER },
292 {8, CMD_UNLOCK, 50, 10, PASS, SERVER },
293 /* SECTION 2: Overlapping READ and WRITE and CMD_UNLOCK with the same process (SERVER) */
294 /* Add different new lock types which completely overlaps any old lock in the list - 4,5,6 */
295 {9, CMD_WRLOCK, 10, 10, PASS, SERVER },
296 {9, CMD_WRLOCK, 30, 10, PASS, SERVER },
297 {9, CMD_WRLOCK, 50, 10, PASS, SERVER },
298 /* The start is the same, end overlaps */
299 {9, CMD_RDLOCK, 30, 15, PASS, SERVER },
300 /* The start is before, end is the same */
301 {9, CMD_WRLOCK, 25, 20, PASS, SERVER },
302 /* Both start and end overlap */
303 {9, CMD_RDLOCK, 22, 26, PASS, SERVER },
305 {9, CMD_UNLOCK, 10, 10, PASS, SERVER },
306 {9, CMD_UNLOCK, 22, 26, PASS, SERVER },
307 {9, CMD_UNLOCK, 50, 10, PASS, SERVER },
309 /* Add different new locks which are completely overlaped by an old lock in the list - 7,8,10 */
310 {10, CMD_WRLOCK, 10, 10, PASS, SERVER },
311 {10, CMD_WRLOCK, 30, 10, PASS, SERVER },
312 {10, CMD_WRLOCK, 50, 10, PASS, SERVER },
313 /* The start is the same, end is in the middle of old lock */
314 {10, CMD_RDLOCK, 30, 5, PASS, SERVER },
315 /* The start and end are in the middle of a lock */
316 {10, CMD_WRLOCK, 32, 2, PASS, SERVER },
317 /* Start in the middle and end is the same */
318 {10, CMD_RDLOCK, 36, 5, PASS, SERVER },
320 {10, CMD_UNLOCK, 10, 10, PASS, SERVER },
321 {10, CMD_UNLOCK, 30, 11, PASS, SERVER },
322 {10, CMD_UNLOCK, 50, 10, PASS, SERVER },
324 /* Add different new lock types which start before the old lock in the list - 2,9 */
325 {11, CMD_WRLOCK, 10, 10, PASS, SERVER },
326 {11, CMD_WRLOCK, 30, 10, PASS, SERVER },
327 {11, CMD_WRLOCK, 50, 10, PASS, SERVER },
328 /* Here is the new lock */
329 {11, CMD_RDLOCK, 27, 10, PASS, SERVER },
330 /* Go again with the end of the new lock matching the start of lock */
331 {11, CMD_WRLOCK, 25, 3, PASS, SERVER },
333 {11, CMD_UNLOCK, 10, 10, PASS, SERVER },
334 {11, CMD_UNLOCK, 25, 15, PASS, SERVER },
335 {11, CMD_UNLOCK, 50, 10, PASS, SERVER },
337 /* Add different new lock types which start in the middle of an old lock in the list and end after - 11,12 */
338 {12, CMD_WRLOCK, 10, 10, PASS, SERVER },
339 {12, CMD_WRLOCK, 30, 10, PASS, SERVER },
340 {12, CMD_WRLOCK, 50, 10, PASS, SERVER },
341 /* Here is the new lock */
342 {12, CMD_RDLOCK, 35, 10, PASS, SERVER },
343 /* Go again with the end of the new lock matching the start of old lock */
344 {12, CMD_WRLOCK, 44, 3, PASS, SERVER },
346 {12, CMD_UNLOCK, 10, 10, PASS, SERVER },
347 {12, CMD_UNLOCK, 30, 18, PASS, SERVER },
348 {12, CMD_UNLOCK, 50, 10, PASS, SERVER },
350 /* SECTION 3: Overlapping READ and WRITE and CMD_UNLOCK with the different processes (CLIENT/SERVER) */
351 /* Add new lock, differing types and processes, to middle of the list - exact overlap match - 3 */
352 {13, CMD_WRLOCK, 10, 10, PASS, SERVER },
353 {13, CMD_WRLOCK, 30, 10, PASS, SERVER },
354 {13, CMD_RDLOCK, 50, 10, PASS, SERVER },
355 /* Same lock type, different process */
356 {13, CMD_WRLOCK, 30, 10, FAIL, CLIENT },
357 {13, CMD_RDLOCK, 50, 10, PASS, CLIENT },
358 /* Exact match - different lock type, different process */
359 {13, CMD_RDLOCK, 30, 10, FAIL, CLIENT },
360 /* Exact match - unlock */
361 {13, CMD_UNLOCK, 30, 10, PASS, CLIENT },
362 /* New lock - as above, inserting in the list again */
363 {13, CMD_UNLOCK, 30, 10, PASS, SERVER },
364 /* Exact match - same lock type, different process */
365 {13, CMD_WRLOCK, 30, 10, PASS, CLIENT },
367 {13, CMD_UNLOCK, 10, 10, PASS, SERVER },
368 {13, CMD_UNLOCK, 30, 10, PASS, CLIENT },
369 {13, CMD_UNLOCK, 50, 10, PASS, SERVER },
371 /* Add new lock, differing types and processes, which completely overlap any of the locks in the list - 4,5,6 */
372 {14, CMD_WRLOCK, 10, 10, PASS, SERVER },
373 {14, CMD_WRLOCK, 30, 10, PASS, SERVER },
374 {14, CMD_RDLOCK, 50, 10, PASS, SERVER },
375 /* The start is the same, end overlaps */
376 {14, CMD_RDLOCK, 30, 15, FAIL, CLIENT },
377 {14, CMD_WRLOCK, 30, 15, FAIL, CLIENT },
378 /* The start is before, end is the same */
379 {14, CMD_RDLOCK, 25, 20, FAIL, CLIENT },
380 {14, CMD_WRLOCK, 25, 20, FAIL, CLIENT },
381 /* Both start and end overlap */
382 {14, CMD_RDLOCK, 22, 26, FAIL, CLIENT },
383 {14, CMD_WRLOCK, 22, 26, FAIL, CLIENT },
385 /* The start is the same, end overlaps */
386 {14, CMD_RDLOCK, 50, 15, PASS, CLIENT },
387 {14, CMD_WRLOCK, 50, 17, FAIL, CLIENT },
388 /* The start is before, end is the same */
389 {14, CMD_RDLOCK, 45, 20, PASS, CLIENT },
390 {14, CMD_WRLOCK, 43, 22, FAIL, CLIENT },
391 /* Both start and end overlap */
392 {14, CMD_RDLOCK, 42, 26, PASS, CLIENT },
393 {14, CMD_WRLOCK, 41, 28, FAIL, CLIENT },
395 {14, CMD_UNLOCK, 10, 10, PASS, SERVER },
396 {14, CMD_UNLOCK, 22, 26, PASS, SERVER },
397 {14, CMD_UNLOCK, 42, 26, PASS, CLIENT },
399 /* Add new lock, differing types and processes, which are completely overlaped by an old lock in the list - 7,8,10 */
400 {15, CMD_WRLOCK, 10, 10, PASS, SERVER },
401 {15, CMD_RDLOCK, 30, 10, PASS, SERVER },
402 {15, CMD_WRLOCK, 50, 10, PASS, SERVER },
403 /* The start is the same, end is in the middle of old lock */
404 {15, CMD_RDLOCK, 50, 5, FAIL, CLIENT },
405 {15, CMD_WRLOCK, 50, 5, FAIL, CLIENT },
406 /* The start and end are in the middle of old lock */
407 {15, CMD_RDLOCK, 52, 6, FAIL, CLIENT },
408 {15, CMD_WRLOCK, 52, 6, FAIL, CLIENT },
409 /* Start in the middle and end is the same */
410 {15, CMD_RDLOCK, 52, 8, FAIL, CLIENT },
411 {15, CMD_WRLOCK, 52, 8, FAIL, CLIENT },
412 /* The start is the same, end is in the middle of old lock */
413 {15, CMD_RDLOCK, 30, 5, PASS, CLIENT },
414 {15, CMD_WRLOCK, 30, 5, FAIL, CLIENT },
415 /* The start and end are in the middle of old lock */
416 {15, CMD_RDLOCK, 32, 6, PASS, CLIENT },
417 {15, CMD_WRLOCK, 32, 6, FAIL, CLIENT },
418 /* Start in the middle and end is the same */
419 {15, CMD_RDLOCK, 32, 8, PASS, CLIENT },
420 {15, CMD_WRLOCK, 32, 8, FAIL, CLIENT },
422 {15, CMD_UNLOCK, 10, 10, PASS, SERVER },
423 {15, CMD_UNLOCK, 30, 10, PASS, SERVER },
424 {15, CMD_UNLOCK, 50, 10, PASS, SERVER },
425 /* Add new lock, differing types and processes, which start before a lock in the list - 2,9 */
426 {16, CMD_RDLOCK, 10, 10, PASS, SERVER },
427 {16, CMD_WRLOCK, 50, 10, PASS, SERVER },
428 /* Start is before, end is the start of the old lock in list */
429 {16, CMD_RDLOCK, 5, 6, PASS, CLIENT },
430 {16, CMD_WRLOCK, 5, 6, FAIL, CLIENT },
431 /* Start is before, end is in the middle of the old lock */
432 {16, CMD_RDLOCK, 5, 10, PASS, CLIENT },
433 {16, CMD_WRLOCK, 5, 10, FAIL, CLIENT },
434 /* Start is before, end is the start of the old lock in list */
435 {16, CMD_RDLOCK, 45, 6, FAIL, CLIENT },
436 {16, CMD_WRLOCK, 45, 6, FAIL, CLIENT },
437 /* Start is before, end is in the middle of the old lock */
438 {16, CMD_RDLOCK, 45, 10, FAIL, CLIENT },
439 {16, CMD_WRLOCK, 45, 10, FAIL, CLIENT },
441 {16, CMD_UNLOCK, 5, 15, PASS, CLIENT },
442 {16, CMD_UNLOCK, 30, 10, PASS, SERVER },
443 {16, CMD_UNLOCK, 50, 10, PASS, SERVER },
445 /* Add new lock, differing types and processes, which starts in the middle of a lock, and ends after - 11,12 */
446 {17, CMD_WRLOCK, 10, 10, PASS, SERVER },
447 {17, CMD_RDLOCK, 30, 10, PASS, SERVER },
448 {17, CMD_WRLOCK, 50, 10, PASS, SERVER },
449 /* Start in the middle, end after lock in list */
450 {17, CMD_WRLOCK, 35, 10, FAIL, CLIENT },
451 /* Start matches end of lock in list */
452 {17, CMD_RDLOCK, 35, 10, PASS, CLIENT },
453 {17, CMD_RDLOCK, 44, 2, PASS, CLIENT },
454 /* Start in the middle, end after lock in list */
455 {17, CMD_RDLOCK, 55, 10, FAIL, CLIENT },
456 {17, CMD_WRLOCK, 55, 10, FAIL, CLIENT },
457 /* Start matches end of lock in list */
458 {17, CMD_RDLOCK, 59, 5, FAIL, CLIENT },
459 {17, CMD_WRLOCK, 59, 5, FAIL, CLIENT },
461 {17, CMD_UNLOCK, 10, 10, PASS, SERVER },
462 {17, CMD_UNLOCK, 30, 16, PASS, CLIENT },
463 {17, CMD_UNLOCK, 50, 10, PASS, SERVER },
465 /* SECTION 4: overlapping and EOF tests */
466 /* Acquire overlapping ranges */
467 {18, CMD_WRLOCK, 11, 7, PASS, SERVER },
468 {18, CMD_WRLOCK, 13, 8, FAIL, CLIENT },
469 {18, CMD_UNLOCK, 11, 7, PASS, SERVER },
470 /* Acquire different ranges beyond EOF */
471 {19, CMD_WRLOCK, 10, FILE_SIZE, PASS, SERVER },
472 {19, CMD_WRLOCK, FILE_SIZE + 10, 10, PASS, CLIENT },
473 {19, CMD_UNLOCK, 10, FILE_SIZE, PASS, SERVER },
474 {19, CMD_UNLOCK, FILE_SIZE + 10, 10, PASS, CLIENT },
475 /* Acquire same range beyong EOF */
476 {20, CMD_WRLOCK, 10, FILE_SIZE, PASS, SERVER, },
477 {20, CMD_WRLOCK, 10, FILE_SIZE, FAIL, CLIENT, },
478 {20, CMD_UNLOCK, 10, FILE_SIZE, PASS, SERVER, },
479 /* Acquire whole file lock */
480 {21, CMD_WRLOCK, 0, 0, PASS, SERVER, },
481 {21, CMD_WRLOCK, 0, 0, FAIL, CLIENT, },
482 {21, CMD_UNLOCK, 0, 0, PASS, SERVER, },
483 /* Acquire whole file lock, then range */
484 {22, CMD_WRLOCK, 0, 0, PASS, SERVER, },
485 {22, CMD_WRLOCK, 1, 5, FAIL, CLIENT, },
486 {22, CMD_UNLOCK, 0, 0, PASS, SERVER, },
487 /* Acquire non-overlapping read locks */
488 {23, CMD_RDLOCK, 1, 5, PASS, SERVER, },
489 {23, CMD_RDLOCK, 7, 6, PASS, CLIENT, },
490 {23, CMD_UNLOCK, 1, 5, PASS, SERVER, },
491 {23, CMD_UNLOCK, 7, 6, PASS, CLIENT, },
492 /* Acquire overlapping read locks */
493 {24, CMD_RDLOCK, 1, 5, PASS, SERVER, },
494 {24, CMD_RDLOCK, 2, 6, PASS, CLIENT, },
495 {24, CMD_UNLOCK, 1, 5, PASS, SERVER, },
496 {24, CMD_UNLOCK, 1, 7, PASS, CLIENT, },
497 /* Acquire non-overlapping read and write locks */
498 {25, CMD_RDLOCK, 1, 5, PASS, SERVER, },
499 {25, CMD_WRLOCK, 7, 6, PASS, CLIENT, },
500 {25, CMD_UNLOCK, 1, 5, PASS, SERVER, },
501 {25, CMD_UNLOCK, 7, 6, PASS, CLIENT, },
502 /* Acquire overlapping read and write locks */
503 {26, CMD_RDLOCK, 1, 5, PASS, SERVER, },
504 {26, CMD_WRLOCK, 2, 6, FAIL, CLIENT, },
505 {26, CMD_UNLOCK, 1, 5, PASS, SERVER, },
506 /* Acquire whole file lock, then close (without unlocking) */
507 {27, CMD_WRLOCK, 0, 0, PASS, SERVER, },
508 {27, CMD_WRLOCK, 1, 5, FAIL, CLIENT, },
509 {27, CMD_CLOSE,0, 0, PASS, SERVER, },
510 {27, CMD_WRLOCK, 1, 5, PASS, CLIENT, },
511 {27, CMD_OPEN, O_RDWR, 0, PASS, SERVER, },
512 {27, CMD_UNLOCK, 1, 5, PASS, CLIENT, },
513 /* Acquire two read locks, close one file and then reopen to check that first lock still exists */
514 {28, CMD_RDLOCK, 1, 5, PASS, SERVER, },
515 {28, CMD_RDLOCK, 1, 5, PASS, CLIENT, },
516 {28, CMD_CLOSE,0, 0, PASS, SERVER, },
517 {28, CMD_OPEN, O_RDWR, 0, PASS, SERVER, },
518 {28, CMD_WRLOCK, 0, 0, FAIL, SERVER, },
519 {28, CMD_UNLOCK, 1, 5, PASS, SERVER, },
520 /* Verify that F_GETLK for F_WRLCK doesn't require that file be opened for write */
521 {29, CMD_CLOSE, 0, 0, PASS, SERVER, },
522 {29, CMD_OPEN, O_RDONLY, 0, PASS, SERVER, },
523 {29, CMD_WRTEST, 0, 0, PASS, SERVER, },
524 {29, CMD_CLOSE,0, 0, PASS, SERVER, },
525 {29, CMD_OPEN, O_RDWR, 0, PASS, SERVER, },
527 /* Close the opened file and open the file with SHLOCK, other client will try to open with SHLOCK too */
528 {30, CMD_CLOSE,0, 0, PASS, SERVER, },
529 {30, CMD_OPEN, O_RDWR|O_SHLOCK|O_NONBLOCK, 0, PASS, SERVER, },
530 {30, CMD_CLOSE,0, 0, PASS, CLIENT, },
531 {30, CMD_OPEN, O_RDWR|O_SHLOCK|O_NONBLOCK, 0, PASS, CLIENT, },
532 /* Close the opened file and open the file with SHLOCK, other client will try to open with EXLOCK */
533 {31, CMD_CLOSE,0, 0, PASS, SERVER, },
534 {31, CMD_CLOSE,0, 0, PASS, CLIENT, },
535 {31, CMD_OPEN, O_RDWR|O_SHLOCK|O_NONBLOCK, 0, PASS, SERVER, },
536 {31, CMD_OPEN, O_RDWR|O_EXLOCK|O_NONBLOCK, 0, FAIL, CLIENT, },
537 /* Close the opened file and open the file with EXLOCK, other client will try to open with EXLOCK too */
538 {32, CMD_CLOSE,0, 0, PASS, SERVER, },
539 {32, CMD_CLOSE,0, 0, FAIL, CLIENT, },
540 {32, CMD_OPEN, O_RDWR|O_EXLOCK|O_NONBLOCK, 0, PASS, SERVER, },
541 {32, CMD_OPEN, O_RDWR|O_EXLOCK|O_NONBLOCK, 0, FAIL, CLIENT, },
542 {32, CMD_CLOSE,0, 0, PASS, SERVER, },
543 {32, CMD_CLOSE,0, 0, FAIL, CLIENT, },
544 {32, CMD_OPEN, O_RDWR, 0, PASS, SERVER, },
545 {32, CMD_OPEN, O_RDWR, 0, PASS, CLIENT, },
547 /* indicate end of array */
560 int32_t padding; /* So mac and irix have the same size struct (bloody alignment) */
567 fprintf(stderr, "Usage: %s [options] sharedfile\n\
570 -p port TCP/IP port number for client-server communication\n\
571 -d enable debug tracing\n\
572 -n # test number to run\n\
573 -h host run as client and connect to server on remote host\n\
574 [default run as server]\n", prog);
578 #define INIT_BUFSZ 512
581 initialize(HANDLE fd)
587 int togo = FILE_SIZE;
589 ibuf = (char*)malloc(INIT_BUFSZ);
590 memset(ibuf, ':', INIT_BUFSZ);
595 j = togo > INIT_BUFSZ ? INIT_BUFSZ : togo;
597 if ((nwrite = WRITE(fd, ibuf, j)) != j) {
599 perror("initialize write:");
601 fprintf(stderr, "initialize: write() returns %d, not %d as expected\n",
611 int do_open(int flag)
613 int flags = flag|O_CREAT|O_BINARY;
616 fprintf(stderr, "do_open %s 0x%x\n", filename, flags);
618 if ((f_fd = open(filename, flags, 0666)) == INVALID_HANDLE) {
619 perror("shared file create");
626 static int do_lock(int cmd, int type, int start, int length)
633 fprintf(stderr, "do_lock: cmd=%d type=%d start=%d, length=%d\n", cmd, type, start, length);
641 fl.l_whence = SEEK_SET;
647 ret = fcntl(filedes, cmd, &fl);
651 fprintf(stderr, "do_lock: ret = %d, errno = %d (%s)\n", ret, errno, strerror(errno));
653 return(ret==0?PASS:FAIL);
659 fprintf(stderr, "do_close\n");
664 f_fd = INVALID_HANDLE;
669 fprintf(stderr, "%s errno = %d (%s)\n",
670 __FILE__, errno, strerror(errno));
676 static void init_ctl(int32_t index)
678 ctl.test= (int32_t)tests[index][TEST_NUM];
679 ctl.command = (int32_t)tests[index][COMMAND];
680 ctl.offset = tests[index][OFFSET];
681 ctl.length = tests[index][LENGTH];
683 ctl.result = (int32_t)tests[index][RESULT];
693 fprintf(stderr, "send_ctl: test=%d, command=%d offset=%"LL"d, length=%"LL"d, result=%d, error=%d\n",
694 ctl.test, ctl.command, (long long)ctl.offset, (long long)ctl.length,ctl.result, ctl.error);
697 ctl.test= bswap_uint32(ctl.test);
698 ctl.command = bswap_uint32(ctl.command);
699 ctl.offset = bswap_uint64(ctl.offset);
700 ctl.length = bswap_uint64(ctl.length);
701 ctl.result = bswap_uint32(ctl.result);
702 ctl.index= bswap_uint32(ctl.index);
703 ctl.error = bswap_uint32(ctl.error);
704 nwrite = SOCKET_WRITE(c_fd, (char*)&ctl, sizeof(ctl));
706 ctl.test= bswap_uint32(ctl.test);
707 ctl.command = bswap_uint32(ctl.command);
708 ctl.offset = bswap_uint64(ctl.offset);
709 ctl.length = bswap_uint64(ctl.length);
710 ctl.result = bswap_uint32(ctl.result);
711 ctl.index= bswap_uint32(ctl.index);
712 ctl.error= bswap_uint32(ctl.error);
713 if (nwrite != sizeof(ctl)) {
715 perror("send_ctl: write");
717 fprintf(stderr, "send_ctl[%d]: write() returns %d, not %zu as expected\n",
718 ctl.test, nwrite, sizeof(ctl));
728 if ((nread = SOCKET_READ(c_fd, (char*)&ctl, sizeof(ctl))) != sizeof(ctl)) {
730 perror("recv_ctl: read");
732 fprintf(stderr, "recv_ctl[%d]: read() returns %d, not %zu as expected\n",
733 ctl.test, nread, sizeof(ctl));
734 fprintf(stderr, "socket might has been closed by other locktest\n");
739 ctl.test= bswap_uint32(ctl.test);
740 ctl.command = bswap_uint32(ctl.command);
741 ctl.offset = bswap_uint64(ctl.offset);
742 ctl.length = bswap_uint64(ctl.length);
743 ctl.result = bswap_uint32(ctl.result);
744 ctl.index= bswap_uint32(ctl.index);
745 ctl.error= bswap_uint32(ctl.error);
748 fprintf(stderr, "recv_ctl: test=%d, command=%d offset=%"LL"d, length=%"LL"d, result=%d, error=%d\n",
749 ctl.test, ctl.command, (long long)ctl.offset, (long long)ctl.length, ctl.result, ctl.error);
769 main(int argc, char *argv[])
773 struct sockaddr_in myAddr;
774 struct linger noLinger = {1, 0};
787 /* trim command name of leading directory components */
789 for (p = prog; *p; p++) {
794 while ((c = getopt(argc, argv, "dn:h:p:?")) != EOF) {
797 case 'd': /* debug flag */
801 case 'h': /* (server) hostname */
807 testnumber = atoi(optarg);
810 case 'p': /* TCP/IP port */
811 port = (int)strtol(optarg, &endnum, 10);
812 if (*endnum != '\0') {
813 fprintf(stderr, "%s: -p argument must be a numeric\n",
827 if (errflag || optind != argc-1) {
832 filename=argv[optind];
834 fprintf(stderr, "Working on file : %s\n", filename);
835 if (do_open(O_RDWR) == FAIL)
838 setbuf(stderr, NULL);
843 s_fd = socket(AF_INET, SOCK_STREAM, 0);
844 if (s_fd == INVALID_SOCKET) {
849 if (setsockopt(s_fd, IPPROTO_TCP, TCP_NODELAY, (char*)&one, sizeof(one)) < 0) {
850 perror("setsockopt(nodelay)");
854 if (setsockopt(s_fd, SOL_SOCKET, SO_REUSEADDR, (char*)&one, sizeof(one))<0) {
855 perror("setsockopt(reuseaddr)");
860 if (setsockopt(s_fd, SOL_SOCKET, SO_REUSEPORT, (char*)&one, sizeof(one))<0) {
861 perror("setsockopt(reuseport)");
867 memset(&myAddr, 0, sizeof(myAddr));
868 myAddr.sin_family = AF_INET;
869 myAddr.sin_addr.s_addr = htonl(INADDR_ANY);
870 myAddr.sin_port = htons((short)port);
871 sts = bind(s_fd, (struct sockaddr*)&myAddr, sizeof(myAddr));
878 sts = listen(s_fd, 5); /* Max. of 5 pending connection requests */
886 socklen_t addr_len = sizeof(myAddr);
888 if (getsockname(s_fd, &myAddr, &addr_len)) {
889 perror("getsockname");
893 port = ntohs(myAddr.sin_port);
896 printf("server port: %d\n", port);
899 c_fd = accept(s_fd, NULL, NULL);
900 if (c_fd == INVALID_SOCKET) {
906 if (debug) fprintf(stderr, "Client accepted\n");
910 struct hostent *servInfo;
912 if ((servInfo = gethostbyname(host)) == NULL) {
913 fprintf(stderr, "Couldn't get hostbyname for %s", host);
914 if (h_errno == HOST_NOT_FOUND)
915 fprintf(stderr, ": host not found");
916 fprintf(stderr, "\n");
921 c_fd = socket(AF_INET, SOCK_STREAM, 0);
922 if (c_fd == INVALID_SOCKET) {
927 /* avoid 200 ms delay */
928 if (setsockopt(c_fd, IPPROTO_TCP, TCP_NODELAY, (char *)&i, sizeof(i)) < 0) {
929 perror("setsockopt(nodelay)");
933 /* Don't linger on close */
934 if (setsockopt(c_fd, SOL_SOCKET, SO_LINGER, (char *)&noLinger, sizeof(noLinger)) < 0) {
935 perror("setsockopt(nolinger)");
940 memset(&myAddr, 0, sizeof(myAddr)); /* Arrgh! &myAddr, not myAddr */
941 myAddr.sin_family = AF_INET;
942 memcpy(&myAddr.sin_addr, servInfo->h_addr, servInfo->h_length);
943 myAddr.sin_port = htons((short)port);
945 if (connect(c_fd, (struct sockaddr*)&myAddr, sizeof(myAddr)) < 0) {
946 perror("unable to connect");
947 fprintf(stderr, "Server might still initializing the shared file\n ");
952 if (debug) fprintf(stderr, "Connected to server\n");
957 /* only server need do shared file */
961 * TCP/IP connection to be established, safe to proceed.
963 * real work is in here ...
976 last_test = testnumber - 1;
977 while(tests[index][TEST_NUM] != testnumber && tests[index][TEST_NUM] != 0) {
981 /* If we have a server command, deal with it */
982 if(tests[index][WHO] == SERVER) {
984 fprintf(stderr, "Got a server command (%d)\n", index);
985 if(tests[index][TEST_NUM] == 0) {
989 memset(&ctl, 0, sizeof(ctl));
990 ctl.test = tests[index][TEST_NUM];
992 if(tests[index][TEST_NUM] != 0) {
993 switch(tests[index][COMMAND]) {
995 result = do_lock(F_SETLK, F_WRLCK, tests[index][OFFSET], tests[index][LENGTH]);
998 result = do_lock(F_SETLK, F_RDLCK, tests[index][OFFSET], tests[index][LENGTH]);
1001 result = do_lock(F_SETLK, F_UNLCK, tests[index][OFFSET], tests[index][LENGTH]);
1004 result = do_close();
1007 result = do_open(tests[index][FLAGS]);
1010 result = do_lock(F_GETLK, F_WRLCK, tests[index][OFFSET], tests[index][LENGTH]);
1013 result = do_lock(F_GETLK, F_RDLCK, tests[index][OFFSET], tests[index][LENGTH]);
1016 if( result != tests[index][RESULT]) {
1018 /* We have a failure */
1019 fprintf(stderr, " ***** Server failure *****\n");
1020 fprintf(stderr, " in test %d, while %sing using offset %lld, length %lld - err = %d:%s\n",
1021 ctl.test, get_cmd_str(tests[index][COMMAND]),
1022 (long long)tests[index][OFFSET],
1023 (long long)tests[index][LENGTH],
1024 saved_errno, strerror(saved_errno));
1025 fprintf(stderr, " %d:%s\n",
1026 ctl.test, descriptions[ctl.test - 1]);
1029 /* else send it off to the client */
1030 } else if (tests[index][WHO] == CLIENT) {
1031 if(tests[index][TEST_NUM] == 0) {
1035 /* get the client to do something */
1038 fprintf(stderr, "Sending command to client (%d) - %s - %lld:%lld\n",
1040 get_cmd_str(ctl.command),
1041 (long long)tests[index][OFFSET],
1042 (long long)tests[index][LENGTH]);
1043 /* get the client to do something */
1047 /* Get the clients response */
1049 /* this is the whether the test passed or failed,
1050 * not what the command returned */
1051 if( ctl.result == FAIL ) {
1053 fprintf(stderr, " ***** Client failure *****\n");
1054 fprintf(stderr, " in test %d, while %sing using offset %lld, length %lld - err = %d:%s\n",
1055 ctl.test, get_cmd_str(ctl.command),
1056 (long long)ctl.offset, (long long)ctl.length,
1057 ctl.error, strerror(ctl.error));
1058 fprintf(stderr, " %d:%s\n",
1059 ctl.test, descriptions[ctl.test - 1]);
1064 if(last_test != tests[index][TEST_NUM]) {
1069 last_test = tests[index][TEST_NUM];
1073 } else { /* CLIENT */
1075 fprintf(stderr,"client: waiting...\n");
1076 /* wait for the server to do something */
1079 /* check for a client command */
1081 if (tests[index][WHO] != CLIENT) {
1082 fprintf(stderr, "not a client command index (%d)\n", index);
1091 switch(ctl.command) {
1093 result = do_lock(F_SETLK, F_WRLCK, ctl.offset, ctl.length);
1096 result = do_lock(F_SETLK, F_RDLCK, ctl.offset, ctl.length);
1099 result = do_lock(F_SETLK, F_UNLCK, ctl.offset, ctl.length);
1102 result = do_close();
1105 result = do_open(tests[index][FLAGS]);
1108 result = do_lock(F_GETLK, F_WRLCK, ctl.offset, ctl.length);
1111 result = do_lock(F_GETLK, F_RDLCK, ctl.offset, ctl.length);
1114 if( result != ctl.result ) {
1115 fprintf(stderr,"Failure in %d:%s\n",
1116 ctl.test, descriptions[ctl.test - 1]);
1117 fprintf(stderr," Got %d, wanted %d\n",
1118 result, ctl.result);
1120 ctl.error = saved_errno;
1127 fprintf(stderr,"client: sending result to server (%d)\n", ctl.index);
1128 /* Send result to the server */
1130 if(last_test != tests[index][TEST_NUM]) {
1132 last_test = tests[index][TEST_NUM];
1136 fprintf(stderr, "%d tests run, %d failed\n", test_count, fail_count);