2 * Copyright (c) 2000-2003 Silicon Graphics, Inc.
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License as
7 * published by the Free Software Foundation.
9 * This program is distributed in the hope that it would be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write the Free Software Foundation,
16 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
20 * Synchronized byte range lock exerciser
30 #include <sys/socket.h>
31 #include <netinet/in.h>
32 #include <netinet/tcp.h>
35 #include <sys/types.h>
41 #define HEX_2_ASC(x) ((x) > 9) ? (x)-10+'a' : (x)+'0'
42 #define FILE_SIZE 1024
43 #define PLATFORM_INIT() /*no-op*/
44 #define PLATFORM_CLEANUP() /*no-op*/
49 #define inet_aton(STRING, INADDRP) \
50 (((INADDRP)->s_addr = inet_addr(STRING)) == -1 ? 0 : 1)
52 /* this assumes 32 bit pointers */
53 #define PTR_TO_U64(P) ((unsigned __int64)(unsigned int)(P))
54 #define U64_TO_PTR(T,U) ((T)(void *)(unsigned int)(U))
56 #if __BYTE_ORDER == __LITTLE_ENDIAN
57 #define bswap_uint16(x) (uint16_t)bswap_16(x)
58 #define bswap_uint32(x) (uint32_t)bswap_32(x)
59 #define bswap_uint64(x) (uint64_t)bswap_64(x)
61 #define bswap_uint16(x) x
62 #define bswap_uint32(x) x
63 #define bswap_uint64(x) x
67 #define SOCKET_READ read
68 #define SOCKET_WRITE write
69 #define SOCKET_CLOSE(S) (close(S))
70 #define INVALID_SOCKET -1
75 #define INVALID_HANDLE -1
76 #define OPEN(N,F) (open(N, F|O_CREAT|O_RDWR|O_BINARY| \
77 (D_flag ? O_DIRECT : 0), 0644))
78 #define SEEK(H, O) (lseek(H, O, SEEK_SET))
79 #define READ(H, B, L) (read(H, B, L))
80 #define WRITE(H, B, L) (write(H, B, L))
81 #define CLOSE(H) (close(H))
83 #define RAND() (rand())
84 #define SRAND(s) (srand(s))
85 #define SLEEP(s) (sleep(s))
87 #define MIN(A,B) (((A)<(B))?(A):(B))
88 #define MAX(A,B) (((A)>(B))?(A):(B))
90 #define ALLOC_ALIGNED(S) (memalign(65536, S))
91 #define FREE_ALIGNED(P) (free(P))
94 static char *filename = 0;
96 static int server = 1;
97 static int maxio = 8192;
98 static int port = 7890;
101 static int testnumber = -1;
102 static int saved_errno = 0;
104 static SOCKET s_fd = -1; /* listen socket */
105 static SOCKET c_fd = -1; /* IPC socket */
106 static HANDLE f_fd = INVALID_HANDLE; /* shared file */
107 static char *buf; /* I/O buffer */
108 static int D_flag = 0;
128 #define FLAGS 2 /* index 2 is also used for do_open() flag, see below */
131 * flags for Mac OS X do_open()
148 * When adding tests be sure to add to both the descriptions AND tests array.
149 * Also, be sure to undo whatever is set for each test (eg unlock any locks)
150 * There is no need to have a matching client command for each server command
154 char *descriptions[] = {
155 /* 1 */"Add a lock to an empty lock list",
156 /* 2 */"Add a lock to the start and end of a list - no overlaps",
157 /* 3 */"Add a lock to the middle of a list - no overlap",
158 /* 4 */"Add different lock types to middle of the list - overlap exact match",
159 /* 5 */"Add new lock which completely overlaps any old lock in the list",
160 /* 6 */"Add new lock which itself is completely overlaped by any old lock in the list",
161 /* 7 */"Add new lock which starts before any old lock in the list",
162 /* 8 */"Add new lock which starts in the middle of any old lock in the list and ends after",
163 /* 9 */"Add different new lock types which completely overlaps any old lock in the list",
164 /* 10 */"Add different new locks which are completely overlaped by an old lock in the list",
165 /* 11 */"Add different new lock types which start before the old lock in the list",
166 /* 12 */"Add different new lock types which start in the middle of an old lock in the list and end after",
167 /* 13 */"Add new lock, differing types and processes, to middle of the list - exact overlap match",
168 /* 14 */"Add new lock, differing types and processes, which completely overlap any of the locks in the list",
169 /* 15 */"Add new lock, differing types and processes, which are completely overlaped by locks in the list",
170 /* 16 */"Add new lock, differing types and processes, which start before a lock in the list",
171 /* 17 */"Add new lock, differing types and processes, which starts in the middle of a lock, and ends after",
172 /* 18 */"Acquire write locks with overlapping ranges",
173 /* 19 */"Acquire write locks with non-overlapping ranges extending beyond EOF",
174 /* 20 */"Acquire write locks with overlapping ranges extending beyond EOF",
175 /* 21 */"Acquire write locks on whole files",
176 /* 22 */"Acquire write lock on whole file and range write lock",
177 /* 23 */"Acquire read locks with non-overlapping ranges",
178 /* 24 */"Acquire read locks with overlapping ranges",
179 /* 25 */"Acquire read and write locks with no overlapping ranges",
180 /* 26 */"Acquire read and write locks with overlapping ranges",
181 /* 27 */"Acquire whole file write lock and then close without unlocking (and attempt a lock)",
182 /* 28 */"Acquire two read locks, close and reopen the file, and test if the inital lock is still there",
184 /* 29 */"Close the opened file and open the file with SHLOCK, other client will try to open with SHLOCK too",
185 /* 30 */"Close the opened file and open the file with SHLOCK, other client will try to open with EXLOCK",
186 /* 31 */"Close the opened file and open the file with EXLOCK, other client will try to open with EXLOCK too"
190 static int64_t tests[][6] =
191 /* test # Action offset length expected server/client */
193 /* Various simple tests exercising the list */
195 /* SECTION 1: WRITE and UNLOCK with the same process (SERVER) */
196 /* Add a lock to an empty list */
197 {1, WRLOCK, 1, 10, PASS, SERVER },
198 {1, UNLOCK, 1, 10, PASS, SERVER },
200 /* Add a lock to the start and end of a list - 1, 13 - no overlap */
201 {2, WRLOCK, 10, 10, PASS, SERVER },
202 {2, WRLOCK, 30, 10, PASS, SERVER },
203 {2, WRLOCK, 50, 10, PASS, SERVER },
204 {2, WRLOCK, 1, 5, PASS, SERVER },
205 {2, WRLOCK, 70, 5, PASS, SERVER },
207 {2, UNLOCK, 10, 10, PASS, SERVER },
208 {2, UNLOCK, 30, 10, PASS, SERVER },
209 {2, UNLOCK, 50, 10, PASS, SERVER },
210 {2, UNLOCK, 1, 5, PASS, SERVER },
211 {2, UNLOCK, 70, 5, PASS, SERVER },
213 /* Add a lock to the middle of a list - no overlap */
214 {3, WRLOCK, 10, 10, PASS, SERVER },
215 {3, WRLOCK, 30, 10, PASS, SERVER },
216 {3, WRLOCK, 50, 10, PASS, SERVER },
217 {3, WRLOCK, 42, 5, PASS, SERVER },
219 {3, UNLOCK, 10, 10, PASS, SERVER },
220 {3, UNLOCK, 30, 10, PASS, SERVER },
221 {3, UNLOCK, 50, 10, PASS, SERVER },
222 {3, UNLOCK, 42, 5, PASS, SERVER },
224 /* Add different lock types to middle of the list - overlap exact match - 3 */
225 {4, WRLOCK, 10, 10, PASS, SERVER },
226 {4, WRLOCK, 30, 10, PASS, SERVER },
227 {4, WRLOCK, 50, 10, PASS, SERVER },
228 /* Exact match - same lock type */
229 {4, WRLOCK, 30, 10, PASS, SERVER },
230 /* Exact match - different lock type */
231 {4, RDLOCK, 30, 10, PASS, SERVER },
232 /* Exact match - unlock */
233 {4, UNLOCK, 30, 10, PASS, SERVER },
234 /* New lock - as above, inserting in the list again */
235 {4, WRLOCK, 30, 10, PASS, SERVER },
237 {4, UNLOCK, 10, 10, PASS, SERVER },
238 {4, UNLOCK, 30, 10, PASS, SERVER },
239 {4, UNLOCK, 50, 10, PASS, SERVER },
241 /* Add new lock which completely overlaps any old lock in the list - 4,5,6 */
242 {5, WRLOCK, 10, 10, PASS, SERVER },
243 {5, WRLOCK, 30, 10, PASS, SERVER },
244 {5, WRLOCK, 50, 10, PASS, SERVER },
245 /* The start is the same, end overlaps */
246 {5, WRLOCK, 30, 15, PASS, SERVER },
247 /* The start is before, end is the same */
248 {5, WRLOCK, 25, 20, PASS, SERVER },
249 /* Both start and end overlap */
250 {5, WRLOCK, 22, 26, PASS, SERVER },
252 {5, UNLOCK, 10, 10, PASS, SERVER },
253 {5, UNLOCK, 22, 26, PASS, SERVER },
254 {5, UNLOCK, 50, 10, PASS, SERVER },
256 /* Add new lock which itself is completely overlaped by any old lock in the list - 7,8,10 */
257 {6, WRLOCK, 10, 10, PASS, SERVER },
258 {6, WRLOCK, 30, 10, PASS, SERVER },
259 {6, WRLOCK, 50, 10, PASS, SERVER },
260 /* The start is the same, end is in the middle of old lock - NOP */
261 {6, WRLOCK, 30, 5, PASS, SERVER },
262 /* The start and end are in the middle of old lock - NOP */
263 {6, WRLOCK, 32, 6, PASS, SERVER },
264 /* Start in the middle and end is the same - NOP */
265 {6, WRLOCK, 32, 8, PASS, SERVER },
267 {6, UNLOCK, 10, 10, PASS, SERVER },
268 {6, UNLOCK, 30, 10, PASS, SERVER },
269 {6, UNLOCK, 32, 8, PASS, SERVER },
270 {6, UNLOCK, 50, 10, PASS, SERVER },
272 /* Add new lock which starts before any old lock in the list - 2,9 */
273 {7, WRLOCK, 10, 10, PASS, SERVER },
274 {7, WRLOCK, 30, 10, PASS, SERVER },
275 {7, WRLOCK, 50, 10, PASS, SERVER },
276 /* Here is the new lock */
277 {7, WRLOCK, 27, 10, PASS, SERVER },
278 /* Go again with the end of the new lock matching the start of old lock */
279 {7, WRLOCK, 25, 2, PASS, SERVER },
281 {7, UNLOCK, 10, 10, PASS, SERVER },
282 {7, UNLOCK, 25, 15, PASS, SERVER },
283 {7, UNLOCK, 50, 10, PASS, SERVER },
285 /* Add new lock which starts in the middle of any old lock in the list and ends after - 11,12 */
286 {8, WRLOCK, 10, 10, PASS, SERVER },
287 {8, WRLOCK, 30, 10, PASS, SERVER },
288 {8, WRLOCK, 50, 10, PASS, SERVER },
289 /* Here is the new lock */
290 {8, WRLOCK, 35, 10, PASS, SERVER },
291 /* Go again with the end of the new lock matching the start of old lock */
292 {8, WRLOCK, 45, 2, PASS, SERVER },
294 {8, UNLOCK, 10, 10, PASS, SERVER },
295 {8, UNLOCK, 30, 17, PASS, SERVER },
296 {8, UNLOCK, 50, 10, PASS, SERVER },
297 /* SECTION 2: Overlapping READ and WRITE and UNLOCK with the same process (SERVER) */
298 /* Add different new lock types which completely overlaps any old lock in the list - 4,5,6 */
299 {9, WRLOCK, 10, 10, PASS, SERVER },
300 {9, WRLOCK, 30, 10, PASS, SERVER },
301 {9, WRLOCK, 50, 10, PASS, SERVER },
302 /* The start is the same, end overlaps */
303 {9, RDLOCK, 30, 15, PASS, SERVER },
304 /* The start is before, end is the same */
305 {9, WRLOCK, 25, 20, PASS, SERVER },
306 /* Both start and end overlap */
307 {9, RDLOCK, 22, 26, PASS, SERVER },
309 {9, UNLOCK, 10, 10, PASS, SERVER },
310 {9, UNLOCK, 22, 26, PASS, SERVER },
311 {9, UNLOCK, 50, 10, PASS, SERVER },
313 /* Add different new locks which are completely overlaped by an old lock in the list - 7,8,10 */
314 {10, WRLOCK, 10, 10, PASS, SERVER },
315 {10, WRLOCK, 30, 10, PASS, SERVER },
316 {10, WRLOCK, 50, 10, PASS, SERVER },
317 /* The start is the same, end is in the middle of old lock */
318 {10, RDLOCK, 30, 5, PASS, SERVER },
319 /* The start and end are in the middle of a lock */
320 {10, WRLOCK, 32, 2, PASS, SERVER },
321 /* Start in the middle and end is the same */
322 {10, RDLOCK, 36, 5, PASS, SERVER },
324 {10, UNLOCK, 10, 10, PASS, SERVER },
325 {10, UNLOCK, 30, 11, PASS, SERVER },
326 {10, UNLOCK, 50, 10, PASS, SERVER },
328 /* Add different new lock types which start before the old lock in the list - 2,9 */
329 {11, WRLOCK, 10, 10, PASS, SERVER },
330 {11, WRLOCK, 30, 10, PASS, SERVER },
331 {11, WRLOCK, 50, 10, PASS, SERVER },
332 /* Here is the new lock */
333 {11, RDLOCK, 27, 10, PASS, SERVER },
334 /* Go again with the end of the new lock matching the start of lock */
335 {11, WRLOCK, 25, 3, PASS, SERVER },
337 {11, UNLOCK, 10, 10, PASS, SERVER },
338 {11, UNLOCK, 25, 15, PASS, SERVER },
339 {11, UNLOCK, 50, 10, PASS, SERVER },
341 /* Add different new lock types which start in the middle of an old lock in the list and end after - 11,12 */
342 {12, WRLOCK, 10, 10, PASS, SERVER },
343 {12, WRLOCK, 30, 10, PASS, SERVER },
344 {12, WRLOCK, 50, 10, PASS, SERVER },
345 /* Here is the new lock */
346 {12, RDLOCK, 35, 10, PASS, SERVER },
347 /* Go again with the end of the new lock matching the start of old lock */
348 {12, WRLOCK, 44, 3, PASS, SERVER },
350 {12, UNLOCK, 10, 10, PASS, SERVER },
351 {12, UNLOCK, 30, 18, PASS, SERVER },
352 {12, UNLOCK, 50, 10, PASS, SERVER },
354 /* SECTION 3: Overlapping READ and WRITE and UNLOCK with the different processes (CLIENT/SERVER) */
355 /* Add new lock, differing types and processes, to middle of the list - exact overlap match - 3 */
356 {13, WRLOCK, 10, 10, PASS, SERVER },
357 {13, WRLOCK, 30, 10, PASS, SERVER },
358 {13, RDLOCK, 50, 10, PASS, SERVER },
359 /* Same lock type, different process */
360 {13, WRLOCK, 30, 10, FAIL, CLIENT },
361 {13, RDLOCK, 50, 10, PASS, CLIENT },
362 /* Exact match - different lock type, different process */
363 {13, RDLOCK, 30, 10, FAIL, CLIENT },
364 /* Exact match - unlock */
365 {13, UNLOCK, 30, 10, PASS, CLIENT },
366 /* New lock - as above, inserting in the list again */
367 {13, UNLOCK, 30, 10, PASS, SERVER },
368 /* Exact match - same lock type, different process */
369 {13, WRLOCK, 30, 10, PASS, CLIENT },
371 {13, UNLOCK, 10, 10, PASS, SERVER },
372 {13, UNLOCK, 30, 10, PASS, CLIENT },
373 {13, UNLOCK, 50, 10, PASS, SERVER },
375 /* Add new lock, differing types and processes, which completely overlap any of the locks in the list - 4,5,6 */
376 {14, WRLOCK, 10, 10, PASS, SERVER },
377 {14, WRLOCK, 30, 10, PASS, SERVER },
378 {14, RDLOCK, 50, 10, PASS, SERVER },
379 /* The start is the same, end overlaps */
380 {14, RDLOCK, 30, 15, FAIL, CLIENT },
381 {14, WRLOCK, 30, 15, FAIL, CLIENT },
382 /* The start is before, end is the same */
383 {14, RDLOCK, 25, 20, FAIL, CLIENT },
384 {14, WRLOCK, 25, 20, FAIL, CLIENT },
385 /* Both start and end overlap */
386 {14, RDLOCK, 22, 26, FAIL, CLIENT },
387 {14, WRLOCK, 22, 26, FAIL, CLIENT },
389 /* The start is the same, end overlaps */
390 {14, RDLOCK, 50, 15, PASS, CLIENT },
391 {14, WRLOCK, 50, 17, FAIL, CLIENT },
392 /* The start is before, end is the same */
393 {14, RDLOCK, 45, 20, PASS, CLIENT },
394 {14, WRLOCK, 43, 22, FAIL, CLIENT },
395 /* Both start and end overlap */
396 {14, RDLOCK, 42, 26, PASS, CLIENT },
397 {14, WRLOCK, 41, 28, FAIL, CLIENT },
399 {14, UNLOCK, 10, 10, PASS, SERVER },
400 {14, UNLOCK, 22, 26, PASS, SERVER },
401 {14, UNLOCK, 42, 26, PASS, CLIENT },
403 /* Add new lock, differing types and processes, which are completely overlaped by an old lock in the list - 7,8,10 */
404 {15, WRLOCK, 10, 10, PASS, SERVER },
405 {15, RDLOCK, 30, 10, PASS, SERVER },
406 {15, WRLOCK, 50, 10, PASS, SERVER },
407 /* The start is the same, end is in the middle of old lock */
408 {15, RDLOCK, 50, 5, FAIL, CLIENT },
409 {15, WRLOCK, 50, 5, FAIL, CLIENT },
410 /* The start and end are in the middle of old lock */
411 {15, RDLOCK, 52, 6, FAIL, CLIENT },
412 {15, WRLOCK, 52, 6, FAIL, CLIENT },
413 /* Start in the middle and end is the same */
414 {15, RDLOCK, 52, 8, FAIL, CLIENT },
415 {15, WRLOCK, 52, 8, FAIL, CLIENT },
416 /* The start is the same, end is in the middle of old lock */
417 {15, RDLOCK, 30, 5, PASS, CLIENT },
418 {15, WRLOCK, 30, 5, FAIL, CLIENT },
419 /* The start and end are in the middle of old lock */
420 {15, RDLOCK, 32, 6, PASS, CLIENT },
421 {15, WRLOCK, 32, 6, FAIL, CLIENT },
422 /* Start in the middle and end is the same */
423 {15, RDLOCK, 32, 8, PASS, CLIENT },
424 {15, WRLOCK, 32, 8, FAIL, CLIENT },
426 {15, UNLOCK, 10, 10, PASS, SERVER },
427 {15, UNLOCK, 30, 10, PASS, SERVER },
428 {15, UNLOCK, 50, 10, PASS, SERVER },
429 /* Add new lock, differing types and processes, which start before a lock in the list - 2,9 */
430 {16, RDLOCK, 10, 10, PASS, SERVER },
431 {16, WRLOCK, 50, 10, PASS, SERVER },
432 /* Start is before, end is the start of the old lock in list */
433 {16, RDLOCK, 5, 6, PASS, CLIENT },
434 {16, WRLOCK, 5, 6, FAIL, CLIENT },
435 /* Start is before, end is in the middle of the old lock */
436 {16, RDLOCK, 5, 10, PASS, CLIENT },
437 {16, WRLOCK, 5, 10, FAIL, CLIENT },
438 /* Start is before, end is the start of the old lock in list */
439 {16, RDLOCK, 45, 6, FAIL, CLIENT },
440 {16, WRLOCK, 45, 6, FAIL, CLIENT },
441 /* Start is before, end is in the middle of the old lock */
442 {16, RDLOCK, 45, 10, FAIL, CLIENT },
443 {16, WRLOCK, 45, 10, FAIL, CLIENT },
445 {16, UNLOCK, 5, 15, PASS, CLIENT },
446 {16, UNLOCK, 30, 10, PASS, SERVER },
447 {16, UNLOCK, 50, 10, PASS, SERVER },
449 /* Add new lock, differing types and processes, which starts in the middle of a lock, and ends after - 11,12 */
450 {17, WRLOCK, 10, 10, PASS, SERVER },
451 {17, RDLOCK, 30, 10, PASS, SERVER },
452 {17, WRLOCK, 50, 10, PASS, SERVER },
453 /* Start in the middle, end after lock in list */
454 {17, WRLOCK, 35, 10, FAIL, CLIENT },
455 /* Start matches end of lock in list */
456 {17, RDLOCK, 35, 10, PASS, CLIENT },
457 {17, RDLOCK, 44, 2, PASS, CLIENT },
458 /* Start in the middle, end after lock in list */
459 {17, RDLOCK, 55, 10, FAIL, CLIENT },
460 {17, WRLOCK, 55, 10, FAIL, CLIENT },
461 /* Start matches end of lock in list */
462 {17, RDLOCK, 59, 5, FAIL, CLIENT },
463 {17, WRLOCK, 59, 5, FAIL, CLIENT },
465 {17, UNLOCK, 10, 10, PASS, SERVER },
466 {17, UNLOCK, 30, 16, PASS, CLIENT },
467 {17, UNLOCK, 50, 10, PASS, SERVER },
469 /* SECTION 4: overlapping and EOF tests */
470 /* Acquire overlapping ranges */
471 {18, WRLOCK, 11, 7, PASS, SERVER },
472 {18, WRLOCK, 13, 8, FAIL, CLIENT },
473 {18, UNLOCK, 11, 7, PASS, SERVER },
474 /* Acquire different ranges beyond EOF */
475 {19, WRLOCK, 10, FILE_SIZE, PASS, SERVER },
476 {19, WRLOCK, FILE_SIZE + 10, 10, PASS, CLIENT },
477 {19, UNLOCK, 10, FILE_SIZE, PASS, SERVER },
478 {19, UNLOCK, FILE_SIZE + 10, 10, PASS, CLIENT },
479 /* Acquire same range beyong EOF */
480 {20, WRLOCK, 10, FILE_SIZE, PASS, SERVER, },
481 {20, WRLOCK, 10, FILE_SIZE, FAIL, CLIENT, },
482 {20, UNLOCK, 10, FILE_SIZE, PASS, SERVER, },
483 /* Acquire whole file lock */
484 {21, WRLOCK, 0, 0, PASS, SERVER, },
485 {21, WRLOCK, 0, 0, FAIL, CLIENT, },
486 {21, UNLOCK, 0, 0, PASS, SERVER, },
487 /* Acquire whole file lock, then range */
488 {22, WRLOCK, 0, 0, PASS, SERVER, },
489 {22, WRLOCK, 1, 5, FAIL, CLIENT, },
490 {22, UNLOCK, 0, 0, PASS, SERVER, },
491 /* Acquire non-overlapping read locks */
492 {23, RDLOCK, 1, 5, PASS, SERVER, },
493 {23, RDLOCK, 7, 6, PASS, CLIENT, },
494 {23, UNLOCK, 1, 5, PASS, SERVER, },
495 {23, UNLOCK, 7, 6, PASS, CLIENT, },
496 /* Acquire overlapping read locks */
497 {24, RDLOCK, 1, 5, PASS, SERVER, },
498 {24, RDLOCK, 2, 6, PASS, CLIENT, },
499 {24, UNLOCK, 1, 5, PASS, SERVER, },
500 {24, UNLOCK, 1, 7, PASS, CLIENT, },
501 /* Acquire non-overlapping read and write locks */
502 {25, RDLOCK, 1, 5, PASS, SERVER, },
503 {25, WRLOCK, 7, 6, PASS, CLIENT, },
504 {25, UNLOCK, 1, 5, PASS, SERVER, },
505 {25, UNLOCK, 7, 6, PASS, CLIENT, },
506 /* Acquire overlapping read and write locks */
507 {26, RDLOCK, 1, 5, PASS, SERVER, },
508 {26, WRLOCK, 2, 6, FAIL, CLIENT, },
509 {26, UNLOCK, 1, 5, PASS, SERVER, },
510 /* Acquire whole file lock, then close (without unlocking) */
511 {27, WRLOCK, 0, 0, PASS, SERVER, },
512 {27, WRLOCK, 1, 5, FAIL, CLIENT, },
513 {27, F_CLOSE,0, 0, PASS, SERVER, },
514 {27, WRLOCK, 1, 5, PASS, CLIENT, },
515 {27, F_OPEN, 0, 0, PASS, SERVER, },
516 {27, UNLOCK, 1, 5, PASS, CLIENT, },
517 /* Acquire two read locks, close one file and then reopen to check that first lock still exists */
518 {28, RDLOCK, 1, 5, PASS, SERVER, },
519 {28, RDLOCK, 1, 5, PASS, CLIENT, },
520 {28, F_CLOSE,0, 0, PASS, SERVER, },
521 {28, F_OPEN, 0, 0, PASS, SERVER, },
522 {28, WRLOCK, 0, 0, FAIL, SERVER, },
523 {28, UNLOCK, 1, 5, PASS, SERVER, },
525 /* Close the opened file and open the file with SHLOCK, other client will try to open with SHLOCK too */
526 {29, F_CLOSE,0, 0, PASS, SERVER, },
527 {29, F_OPEN, O_SHLOCK|O_NONBLOCK, 0, PASS, SERVER, },
528 {29, F_CLOSE,0, 0, PASS, CLIENT, },
529 {29, F_OPEN, O_SHLOCK|O_NONBLOCK, 0, PASS, CLIENT, },
530 /* Close the opened file and open the file with SHLOCK, other client will try to open with EXLOCK */
531 {30, F_CLOSE,0, 0, PASS, SERVER, },
532 {30, F_CLOSE,0, 0, PASS, CLIENT, },
533 {30, F_OPEN, O_SHLOCK|O_NONBLOCK, 0, PASS, SERVER, },
534 {30, F_OPEN, O_EXLOCK|O_NONBLOCK, 0, FAIL, CLIENT, },
535 /* Close the opened file and open the file with EXLOCK, other client will try to open with EXLOCK too */
536 {31, F_CLOSE,0, 0, PASS, SERVER, },
537 {31, F_CLOSE,0, 0, FAIL, CLIENT, },
538 {31, F_OPEN, O_EXLOCK|O_NONBLOCK, 0, PASS, SERVER, },
539 {31, F_OPEN, O_EXLOCK|O_NONBLOCK, 0, FAIL, CLIENT, },
540 {31, F_CLOSE,0, 0, PASS, SERVER, },
541 {31, F_CLOSE,0, 0, FAIL, CLIENT, },
542 {31, F_OPEN, 0, 0, PASS, SERVER, },
543 {31, F_OPEN, 0, 0, PASS, CLIENT, },
545 /* indicate end of array */
558 int32_t padding; /* So mac and irix have the same size struct (bloody alignment) */
565 fprintf(stderr, "Usage: %s [options] sharedfile\n\
568 -p port TCP/IP port number for client-server communication\n\
569 -d enable debug tracing\n\
570 -n # test number to run\n\
571 -h host run as client and connect to server on remote host\n\
572 [default run as server]\n", prog);
576 #define INIT_BUFSZ 512
579 initialize(HANDLE fd)
585 int togo = FILE_SIZE;
588 ibuf = (char *)ALLOC_ALIGNED(INIT_BUFSZ);
591 ibuf = (char*)malloc(INIT_BUFSZ);
593 memset(ibuf, ':', INIT_BUFSZ);
598 j = togo > INIT_BUFSZ ? INIT_BUFSZ : togo;
600 if ((nwrite = WRITE(fd, ibuf, j)) != j) {
602 perror("initialize write:");
604 fprintf(stderr, "initialize: write() returns %d, not %d as expected\n",
614 int do_open(int flag)
616 if ((f_fd = OPEN(filename, flag)) == INVALID_HANDLE) {
617 perror("shared file create");
618 if (!flag) /* Only exit if the first open fails */
629 directio(f_fd, DIRECTIO_ON);
631 #elif defined(__APPLE__)
633 fcntl(f_fd, F_NOCACHE, 1);
639 int do_lock(int type, int start, int length)
646 fprintf(stderr, "do_lock: start=%d, length=%d\n", start, length);
654 fl.l_whence = SEEK_SET;
660 ret = fcntl(filedes, F_SETLK, &fl);
664 fprintf(stderr, "do_lock: ret = %d, errno = %d (%s)\n", ret, errno, strerror(errno));
666 return(ret==0?PASS:FAIL);
669 int do_unlock(int start, int length)
676 fprintf(stderr, "do_unlock: start=%d, length=%d\n", start, length);
684 fl.l_whence = SEEK_SET;
690 ret = fcntl(filedes, F_SETLK, &fl);
693 fprintf(stderr, "do_lock: ret = %d, errno = %d (%s)\n", ret, errno, strerror(errno));
695 return(ret==0?PASS:FAIL);
701 fprintf(stderr, "do_close\n");
720 fprintf(stderr, "send_ctl: test=%d, command=%d offset=%"LL"d, length=%"LL"d, result=%d, error=%d\n",
721 ctl.test, ctl.command, (long long)ctl.offset, (long long)ctl.length,ctl.result, ctl.error);
724 ctl.test= bswap_uint32(ctl.test);
725 ctl.command = bswap_uint32(ctl.command);
726 ctl.offset = bswap_uint64(ctl.offset);
727 ctl.length = bswap_uint64(ctl.length);
728 ctl.result = bswap_uint32(ctl.result);
729 ctl.index= bswap_uint32(ctl.index);
730 ctl.error = bswap_uint32(ctl.error);
731 nwrite = SOCKET_WRITE(c_fd, (char*)&ctl, sizeof(ctl));
733 ctl.test= bswap_uint32(ctl.test);
734 ctl.command = bswap_uint32(ctl.command);
735 ctl.offset = bswap_uint64(ctl.offset);
736 ctl.length = bswap_uint64(ctl.length);
737 ctl.result = bswap_uint32(ctl.result);
738 ctl.index= bswap_uint32(ctl.index);
739 ctl.error= bswap_uint32(ctl.error);
740 if (nwrite != sizeof(ctl)) {
742 perror("send_ctl: write");
744 fprintf(stderr, "send_ctl[%d]: write() returns %d, not %zu as expected\n",
745 ctl.test, nwrite, sizeof(ctl));
755 if ((nread = SOCKET_READ(c_fd, (char*)&ctl, sizeof(ctl))) != sizeof(ctl)) {
757 perror("recv_ctl: read");
759 fprintf(stderr, "recv_ctl[%d]: read() returns %d, not %zu as expected\n",
760 ctl.test, nread, sizeof(ctl));
761 fprintf(stderr, "socket might has been closed by other locktest\n");
766 ctl.test= bswap_uint32(ctl.test);
767 ctl.command = bswap_uint32(ctl.command);
768 ctl.offset = bswap_uint64(ctl.offset);
769 ctl.length = bswap_uint64(ctl.length);
770 ctl.result = bswap_uint32(ctl.result);
771 ctl.index= bswap_uint32(ctl.index);
772 ctl.error= bswap_uint32(ctl.error);
775 fprintf(stderr, "recv_ctl: test=%d, command=%d offset=%"LL"d, length=%"LL"d, result=%d, error=%d\n",
776 ctl.test, ctl.command, (long long)ctl.offset, (long long)ctl.length, ctl.result, ctl.error);
783 if (f_fd>=0 && !reopen && !closed)
796 main(int argc, char *argv[])
800 struct sockaddr_in myAddr;
801 struct linger noLinger = {1, 0};
815 /* trim command name of leading directory components */
817 for (p = prog; *p; p++) {
822 while ((c = getopt(argc, argv, "dn:h:p:?")) != EOF) {
825 case 'd': /* debug flag */
829 case 'h': /* (server) hostname */
835 testnumber = atoi(optarg);
838 case 'p': /* TCP/IP port */
839 port = (int)strtol(optarg, &endnum, 10);
840 if (*endnum != '\0') {
841 fprintf(stderr, "%s: -p argument must be a numeric\n",
855 if (errflag || optind != argc-1) {
860 filename=argv[optind];
864 * +10 is slop for the iteration number if do_write() ... never
865 * needed unless maxio is very small
868 if ((buf = (char *)ALLOC_ALIGNED(maxio + 10)) == NULL) {
869 perror("aligned alloc buf");
874 if ((buf = (char *)malloc(maxio + 10)) == NULL) {
875 perror("malloc buf");
881 setbuf(stderr, NULL);
886 s_fd = socket(AF_INET, SOCK_STREAM, 0);
887 if (s_fd == INVALID_SOCKET) {
892 if (setsockopt(s_fd, IPPROTO_TCP, TCP_NODELAY, (char*)&one, sizeof(one)) < 0) {
893 perror("setsockopt(nodelay)");
897 if (setsockopt(s_fd, SOL_SOCKET, SO_REUSEADDR, (char*)&one, sizeof(one))<0) {
898 perror("setsockopt(reuseaddr)");
903 if (setsockopt(s_fd, SOL_SOCKET, SO_REUSEPORT, (char*)&one, sizeof(one))<0) {
904 perror("setsockopt(reuseport)");
910 memset(&myAddr, 0, sizeof(myAddr));
911 myAddr.sin_family = AF_INET;
912 myAddr.sin_addr.s_addr = htonl(INADDR_ANY);
913 myAddr.sin_port = htons((short)port);
914 sts = bind(s_fd, (struct sockaddr*)&myAddr, sizeof(myAddr));
921 sts = listen(s_fd, 5); /* Max. of 5 pending connection requests */
928 c_fd = accept(s_fd, NULL, NULL);
929 if (c_fd == INVALID_SOCKET) {
935 if (debug) fprintf(stderr, "Client accepted\n");
939 struct hostent *servInfo;
941 if ((servInfo = gethostbyname(host)) == NULL) {
942 printf("Couldn't get hostbyname for %s", host);
943 if (h_errno == HOST_NOT_FOUND)
944 printf(": host not found");
950 c_fd = socket(AF_INET, SOCK_STREAM, 0);
951 if (c_fd == INVALID_SOCKET) {
956 /* avoid 200 ms delay */
957 if (setsockopt(c_fd, IPPROTO_TCP, TCP_NODELAY, (char *)&i, sizeof(i)) < 0) {
958 perror("setsockopt(nodelay)");
962 /* Don't linger on close */
963 if (setsockopt(c_fd, SOL_SOCKET, SO_LINGER, (char *)&noLinger, sizeof(noLinger)) < 0) {
964 perror("setsockopt(nolinger)");
969 memset(&myAddr, 0, sizeof(myAddr)); /* Arrgh! &myAddr, not myAddr */
970 myAddr.sin_family = AF_INET;
971 memcpy(&myAddr.sin_addr, servInfo->h_addr, servInfo->h_length);
972 myAddr.sin_port = htons((short)port);
974 if (connect(c_fd, (struct sockaddr*)&myAddr, sizeof(myAddr)) < 0) {
975 perror("unable to connect");
976 fprintf(stderr, "Server might still initializing the shared file\n ");
981 if (debug) fprintf(stderr, "Connected to server\n");
986 /* only server need do shared file */
990 * TCP/IP connection to be established, safe to proceed.
992 * real work is in here ...
1004 if(testnumber > 0) {
1005 last_test = testnumber - 1;
1006 while(tests[index][TEST_NUM] != testnumber && tests[index][TEST_NUM] != 0) {
1010 /* If we have a server command, deal with it */
1011 if(tests[index][WHO] == SERVER) {
1013 fprintf(stderr, "Got a server command (%d)\n", index);
1014 if(tests[index][TEST_NUM] == 0) {
1018 memset(&ctl, 0, sizeof(ctl));
1019 ctl.test = tests[index][TEST_NUM];
1021 if(tests[index][TEST_NUM] != 0) {
1022 switch(tests[index][COMMAND]) {
1024 result = do_lock(F_WRLCK, tests[index][OFFSET], tests[index][LENGTH]);
1027 result = do_lock(F_RDLCK, tests[index][OFFSET], tests[index][LENGTH]);
1030 result = do_unlock(tests[index][OFFSET], tests[index][LENGTH]);
1033 result = do_close();
1036 result = do_open(tests[index][FLAGS]);
1039 if( result != tests[index][RESULT]) {
1041 /* We have a failure */
1043 fprintf(stderr, "Server failure in test %d, while %sing using offset %lld, length %lld - err = %d:%s\n",
1044 ctl.test, tests[index][COMMAND]==WRLOCK?"write lock":
1045 tests[index][COMMAND]==RDLOCK?"read lock":
1046 tests[index][COMMAND]==UNLOCK?"unlock":
1047 tests[index][COMMAND]==F_OPEN?"open":"clos",
1048 (long long)tests[index][OFFSET],
1049 (long long)tests[index][LENGTH],
1050 saved_errno, strerror(saved_errno));
1051 fprintf(stderr, "Server failure in %lld:%s\n",
1052 (long long)tests[index][TEST_NUM],
1053 descriptions[tests[index][TEST_NUM] - 1]);
1056 /* else send it off to the client */
1057 } else if (tests[index][WHO] == CLIENT) {
1058 if(tests[index][TEST_NUM] == 0) {
1063 fprintf(stderr, "Sending command to client (%d) - %s - %lld:%lld\n",
1064 index, tests[index][COMMAND]==WRLOCK?"write lock":
1065 tests[index][COMMAND]==RDLOCK?"read lock":
1066 tests[index][COMMAND]==UNLOCK?"unlock":
1067 tests[index][COMMAND]==F_OPEN?"open":"clos",
1068 (long long)tests[index][OFFSET],
1069 (long long)tests[index][LENGTH]);
1070 /* get the client to do something */
1074 /* Get the clients response */
1076 /* this is the whether the test passed or failed,
1077 * not what the command returned */
1078 if( ctl.result == FAIL ) {
1081 fprintf(stderr, "Client failure in test %d, while %sing using offset %lld, length %lld - err = %d:%s\n",
1082 ctl.test, ctl.command==WRLOCK?"write lock":
1083 ctl.command==RDLOCK?"read lock":
1084 ctl.command==UNLOCK?"unlock":
1085 ctl.command==F_OPEN?"open":"clos",
1086 (long long)ctl.offset, (long long)ctl.length,
1087 ctl.error, strerror(ctl.error));
1088 fprintf(stderr, "Client failure in %lld:%s\n",
1089 (long long)tests[index][TEST_NUM],
1090 descriptions[tests[index][TEST_NUM] - 1]);
1095 fprintf(stderr, "server sleeping ...\n");
1098 if(tests[index][TEST_NUM] != 0) {
1099 if(last_test != tests[index][TEST_NUM]) {
1106 last_test = tests[index][TEST_NUM];
1110 } else { /* CLIENT */
1112 fprintf(stderr,"client: waiting...\n");
1113 /* wait for the server to do something */
1116 /* check for a client command */
1118 if (tests[index][WHO] != CLIENT) {
1119 fprintf(stderr, "not a client command index (%d)\n", index);
1129 ctl.command = tests[index][COMMAND];
1130 ctl.offset = tests[index][OFFSET];
1131 ctl.length = tests[index][LENGTH];
1132 switch(tests[index][COMMAND]) {
1134 result = do_lock(F_WRLCK, tests[index][OFFSET], tests[index][LENGTH]);
1137 result = do_lock(F_RDLCK, tests[index][OFFSET], tests[index][LENGTH]);
1140 result = do_unlock(tests[index][OFFSET], tests[index][LENGTH]);
1143 result = do_close();
1146 result = do_open(tests[index][FLAGS]);
1149 if( result != tests[index][RESULT] ) {
1151 fprintf(stderr,"Got %d, wanted %lld\n", result,
1152 (long long)tests[index][RESULT]);
1154 ctl.error = saved_errno;
1160 fprintf(stderr,"client: sending result to server (%d)\n", ctl.index);
1161 /* Send result to the server */
1163 if(tests[index][TEST_NUM] != 0) {
1164 if(last_test != tests[index][TEST_NUM])
1166 last_test = tests[index][TEST_NUM];
1171 printf("%d tests run, %d failed\n", test_count, fail_count);