be71866860e2480a15260e39c7ec68efdd6392d5
[xfstests-dev.git] / src / locktest.c
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * Copyright (c) 2000-2003 Silicon Graphics, Inc.
4  * Copyright (c) 2019 Intel Corp.
5  * All Rights Reserved.
6  */
7
8 /*
9  * Synchronized byte range lock and lease exerciser
10  */
11
12 #include <stdio.h>
13 #include <stdlib.h>
14 #include <malloc.h>
15 #include <fcntl.h>
16 #include <errno.h>
17 #include <string.h>
18 #include <sys/stat.h>
19 #include <sys/socket.h>
20 #include <netinet/in.h>
21 #include <netinet/tcp.h>
22
23 #include <unistd.h>
24 #include <sys/types.h>
25 #include <netdb.h>
26 #include <endian.h>
27 #include <byteswap.h>
28 #include <errno.h>
29 #include <string.h>
30 #include <signal.h>
31
32 #define     HEX_2_ASC(x)    ((x) > 9) ? (x)-10+'a' : (x)+'0'
33 #define         FILE_SIZE       1024
34 #define PLATFORM_INIT()     /*no-op*/
35 #define PLATFORM_CLEANUP()  /*no-op*/
36 #define LL                  "ll"
37
38 extern int h_errno;
39
40 #define inet_aton(STRING, INADDRP) \
41     (((INADDRP)->s_addr = inet_addr(STRING)) == -1 ? 0 : 1)
42
43 /* this assumes 32 bit pointers */
44 #define PTR_TO_U64(P) ((unsigned __int64)(unsigned int)(P))
45 #define U64_TO_PTR(T,U) ((T)(void *)(unsigned int)(U))
46
47 #if __BYTE_ORDER == __LITTLE_ENDIAN
48 #define bswap_uint16(x)         (uint16_t)bswap_16(x)
49 #define bswap_uint32(x)         (uint32_t)bswap_32(x)
50 #define bswap_uint64(x)         (uint64_t)bswap_64(x)
51 #else
52 #define bswap_uint16(x)         x
53 #define bswap_uint32(x)         x
54 #define bswap_uint64(x)         x
55 #endif
56
57 #define SOCKET              int
58 #define SOCKET_READ         read
59 #define SOCKET_WRITE        write
60 #define SOCKET_CLOSE(S)     (close(S))
61 #define INVALID_SOCKET      -1
62
63 #define O_BINARY            0
64        
65 #define HANDLE              int
66 #define INVALID_HANDLE      -1
67 #define SEEK(H, O)          (lseek(H, O, SEEK_SET))
68 #define READ(H, B, L)       (read(H, B, L))
69 #define WRITE(H, B, L)      (write(H, B, L))
70 #define CLOSE(H)            (close(H))
71
72 #define RAND()              (rand())
73 #define SRAND(s)            (srand(s))
74
75 #define MIN(A,B)            (((A)<(B))?(A):(B))
76 #define MAX(A,B)            (((A)>(B))?(A):(B))
77
78 #define ALLOC_ALIGNED(S)    (memalign(65536, S)) 
79 #define FREE_ALIGNED(P)     (free(P)) 
80
81 static char     *prog;
82 static char     *filename = 0;
83 static int      debug = 0;
84 static int      server = 1;
85 static int      port = 0;
86 static int      testnumber = -1;
87 static int      saved_errno = 0;
88 static int      got_sigio = 0;
89
90 static SOCKET   s_fd = -1;              /* listen socket    */
91 static SOCKET   c_fd = -1;              /* IPC socket       */
92 static HANDLE   f_fd = INVALID_HANDLE;  /* shared file      */
93
94 #define         CMD_WRLOCK      0
95 #define         CMD_RDLOCK      1
96 #define         CMD_UNLOCK      2
97 #define         CMD_CLOSE       3
98 #define         CMD_OPEN        4
99 #define         CMD_WRTEST      5
100 #define         CMD_RDTEST      6
101 #define         CMD_SETLEASE    7
102 #define         CMD_GETLEASE    8
103 #define         CMD_SIGIO       9
104 #define         CMD_WAIT_SIGIO  10
105
106 #define         PASS    1
107 #define         FAIL    0
108
109 #define         SERVER  0
110 #define         CLIENT  1
111
112 #define         TEST_NUM        0
113 #define         COMMAND         1
114 #define         OFFSET          2
115 #define         LENGTH          3
116 #define         RESULT          4
117 #define         WHO             5
118 #define         FLAGS           2 /* index 2 is also used for do_open() flag, see below */
119 #define         ARG             FLAGS /* Arguments for Lease operations */
120 #define         TIME            FLAGS /* Time for waiting on sigio */
121
122 static char *get_cmd_str(int cmd)
123 {
124         switch (cmd) {
125                 case CMD_WRLOCK: return "write lock"; break;
126                 case CMD_RDLOCK: return "read lock"; break;
127                 case CMD_UNLOCK: return "unlock"; break;
128                 case CMD_CLOSE:  return "close"; break;
129                 case CMD_OPEN:   return "open"; break;
130                 case CMD_WRTEST: return "Wait for SIGIO"; break;
131                 case CMD_RDTEST: return "Truncate"; break;
132                 case CMD_SETLEASE: return "Set Lease"; break;
133                 case CMD_GETLEASE: return "Get Lease"; break;
134                 case CMD_SIGIO:    return "Setup SIGIO"; break;
135                 case CMD_WAIT_SIGIO: return "Wait for SIGIO"; break;
136         }
137         return "unknown";
138 }
139 /* 
140  * flags for Mac OS X do_open() 
141  * O_RDONLY     0x0000
142  * O_WRONLY     0x0001  
143  * O_RDWR       0x0002
144  * O_NONBLOCK   0x0004  
145  * O_APPEND     0x0008
146  * O_SHLOCK     0x0010  
147  * O_EXLOCK     0x0020
148  * O_ASYNC      0x0040  
149  * O_FSYNC      0x0080
150  * O_NOFOLLOW   0x0100  
151  * O_CREAT      0x0200
152  * O_TRUNC      0x0400
153  * O_EXCL       0x0800
154  */
155
156 /*
157  * When adding tests be sure to add to both the descriptions AND tests array. 
158  * Also, be sure to undo whatever is set for each test (eg unlock any locks)
159  * There is no need to have a matching client command for each server command
160  * (or vice versa)
161  */
162
163 char *lock_descriptions[] = {
164     /* 1 */"Add a lock to an empty lock list",
165     /* 2 */"Add a lock to the start and end of a list - no overlaps",
166     /* 3 */"Add a lock to the middle of a list - no overlap",
167     /* 4 */"Add different lock types to middle of the list - overlap exact match", 
168     /* 5 */"Add new lock which completely overlaps any old lock in the list", 
169     /* 6 */"Add new lock which itself is completely overlaped by any old lock in the list",
170     /* 7 */"Add new lock which starts before any old lock in the list",
171     /* 8 */"Add new lock which starts in the middle of any old lock in the list and ends after",
172     /* 9 */"Add different new lock types which completely overlaps any old lock in the list",
173     /* 10 */"Add different new locks which are completely overlaped by an old lock in the list",
174     /* 11 */"Add different new lock types which start before the old lock in the list",
175     /* 12 */"Add different new lock types which start in the middle of an old lock in the list and end after",
176     /* 13 */"Add new lock, differing types and processes, to middle of the list - exact overlap match",
177     /* 14 */"Add new lock, differing types and processes, which completely overlap any of the locks in the list",
178     /* 15 */"Add new lock, differing types and processes, which are completely overlaped by locks in the list",
179     /* 16 */"Add new lock, differing types and processes, which start before a lock in the list",
180     /* 17 */"Add new lock, differing types and processes, which starts in the middle of a lock, and ends after",
181     /* 18 */"Acquire write locks with overlapping ranges",
182     /* 19 */"Acquire write locks with non-overlapping ranges extending beyond EOF",
183     /* 20 */"Acquire write locks with overlapping ranges extending beyond EOF",
184     /* 21 */"Acquire write locks on whole files",
185     /* 22 */"Acquire write lock on whole file and range write lock",
186     /* 23 */"Acquire read locks with non-overlapping ranges",
187     /* 24 */"Acquire read locks with overlapping ranges",
188     /* 25 */"Acquire read and write locks with no overlapping ranges",
189     /* 26 */"Acquire read and write locks with overlapping ranges",
190     /* 27 */"Acquire whole file write lock and then close without unlocking (and attempt a lock)",
191     /* 28 */"Acquire two read locks, close and reopen the file, and test if the inital lock is still there",
192     /* 29 */"Verify that F_GETLK for F_WRLCK doesn't require that file be opened for write",
193     #if defined(macosx)
194     /* 30 */"Close the opened file and open the file with SHLOCK, other client will try to open with SHLOCK too",
195     /* 31 */"Close the opened file and open the file with SHLOCK, other client will try to open with EXLOCK",
196     /* 32 */"Close the opened file and open the file with EXLOCK, other client will try to open with EXLOCK too"
197     #endif
198 };
199
200 static int64_t lock_tests[][6] =
201         /*      test #  Action  [offset|flags]  length          expected        server/client */
202         {       
203         /* Various simple tests exercising the list */
204
205 /* SECTION 1: WRITE and CMD_UNLOCK with the same process (SERVER) */
206         /* Add a lock to an empty list */
207                 {1,     CMD_WRLOCK,     1,              10,             PASS,           SERVER  },
208                 {1,     CMD_UNLOCK,     1,              10,             PASS,           SERVER  },
209                 
210         /* Add a lock to the start and end of a list - 1, 13 - no overlap */
211                 {2,     CMD_WRLOCK,     10,             10,             PASS,           SERVER  },
212                 {2,     CMD_WRLOCK,     30,             10,             PASS,           SERVER  },
213                 {2,     CMD_WRLOCK,     50,             10,             PASS,           SERVER  },
214                 {2,     CMD_WRLOCK,     1,              5,              PASS,           SERVER  },
215                 {2,     CMD_WRLOCK,     70,             5,              PASS,           SERVER  },
216                 
217                 {2,     CMD_UNLOCK,     10,             10,             PASS,           SERVER  },
218                 {2,     CMD_UNLOCK,     30,             10,             PASS,           SERVER  },
219                 {2,     CMD_UNLOCK,     50,             10,             PASS,           SERVER  },
220                 {2,     CMD_UNLOCK,     1,              5,              PASS,           SERVER  },
221                 {2,     CMD_UNLOCK,     70,             5,              PASS,           SERVER  },
222                 
223         /* Add a lock to the middle of a list - no overlap */
224                 {3,     CMD_WRLOCK,     10,             10,             PASS,           SERVER  },
225                 {3,     CMD_WRLOCK,     30,             10,             PASS,           SERVER  },
226                 {3,     CMD_WRLOCK,     50,             10,             PASS,           SERVER  },
227                 {3,     CMD_WRLOCK,     42,             5,              PASS,           SERVER  },
228                 
229                 {3,     CMD_UNLOCK,     10,             10,             PASS,           SERVER  },
230                 {3,     CMD_UNLOCK,     30,             10,             PASS,           SERVER  },
231                 {3,     CMD_UNLOCK,     50,             10,             PASS,           SERVER  },
232                 {3,     CMD_UNLOCK,     42,             5,              PASS,           SERVER  },
233                 
234         /* Add different lock types to middle of the list - overlap exact match - 3 */
235                 {4,     CMD_WRLOCK,     10,             10,             PASS,           SERVER  },
236                 {4,     CMD_WRLOCK,     30,             10,             PASS,           SERVER  },
237                 {4,     CMD_WRLOCK,     50,             10,             PASS,           SERVER  },
238                 /* Exact match - same lock type */
239                 {4,     CMD_WRLOCK,     30,             10,             PASS,           SERVER  },
240                 /* Exact match - different lock type */
241                 {4,     CMD_RDLOCK,     30,             10,             PASS,           SERVER  },
242                 /* Exact match - unlock */
243                 {4,     CMD_UNLOCK,     30,             10,             PASS,           SERVER  },
244                 /* New lock - as above, inserting in the list again */
245                 {4,     CMD_WRLOCK,     30,             10,             PASS,           SERVER  },
246                 
247                 {4,     CMD_UNLOCK,     10,             10,             PASS,           SERVER  },
248                 {4,     CMD_UNLOCK,     30,             10,             PASS,           SERVER  },
249                 {4,     CMD_UNLOCK,     50,             10,             PASS,           SERVER  },
250                 
251         /* Add new lock which completely overlaps any old lock in the list - 4,5,6 */
252                 {5,     CMD_WRLOCK,     10,             10,             PASS,           SERVER  },
253                 {5,     CMD_WRLOCK,     30,             10,             PASS,           SERVER  },
254                 {5,     CMD_WRLOCK,     50,             10,             PASS,           SERVER  },
255                 /* The start is the same, end overlaps */
256                 {5,     CMD_WRLOCK,     30,             15,             PASS,           SERVER  },
257                 /* The start is before, end is the same */
258                 {5,     CMD_WRLOCK,     25,             20,             PASS,           SERVER  },
259                 /* Both start and end overlap */
260                 {5,     CMD_WRLOCK,     22,             26,             PASS,           SERVER  },
261                 
262                 {5,     CMD_UNLOCK,     10,             10,             PASS,           SERVER  },
263                 {5,     CMD_UNLOCK,     22,             26,             PASS,           SERVER  },
264                 {5,     CMD_UNLOCK,     50,             10,             PASS,           SERVER  },
265                 
266         /* Add new lock which itself is completely overlaped by any old lock in the list - 7,8,10 */
267                 {6,     CMD_WRLOCK,     10,             10,             PASS,           SERVER  },
268                 {6,     CMD_WRLOCK,     30,             10,             PASS,           SERVER  },
269                 {6,     CMD_WRLOCK,     50,             10,             PASS,           SERVER  },
270                 /* The start is the same, end is in the middle of old lock - NOP */
271                 {6,     CMD_WRLOCK,     30,             5,              PASS,           SERVER  },
272                 /* The start and end are in the middle of old lock - NOP */
273                 {6,     CMD_WRLOCK,     32,             6,              PASS,           SERVER  },
274                 /* Start in the middle and end is the same - NOP */
275                 {6,     CMD_WRLOCK,     32,             8,              PASS,           SERVER  },
276                 
277                 {6,     CMD_UNLOCK,     10,             10,             PASS,           SERVER  },
278                 {6,     CMD_UNLOCK,     30,             10,             PASS,           SERVER  },
279                 {6,     CMD_UNLOCK,     32,             8,              PASS,           SERVER  },
280                 {6,     CMD_UNLOCK,     50,             10,             PASS,           SERVER  },
281                 
282         /* Add new lock which starts before any old lock in the list - 2,9 */
283                 {7,     CMD_WRLOCK,     10,             10,             PASS,           SERVER  },
284                 {7,     CMD_WRLOCK,     30,             10,             PASS,           SERVER  },
285                 {7,     CMD_WRLOCK,     50,             10,             PASS,           SERVER  },
286                 /* Here is the new lock */
287                 {7,     CMD_WRLOCK,     27,             10,             PASS,           SERVER  },
288                 /* Go again with the end of the new lock matching the start of old lock */
289                 {7,     CMD_WRLOCK,     25,             2,              PASS,           SERVER  },
290                 
291                 {7,     CMD_UNLOCK,     10,             10,             PASS,           SERVER  },
292                 {7,     CMD_UNLOCK,     25,             15,             PASS,           SERVER  },
293                 {7,     CMD_UNLOCK,     50,             10,             PASS,           SERVER  },
294         
295         /* Add new lock which starts in the middle of any old lock in the list and ends after - 11,12 */
296                 {8,     CMD_WRLOCK,     10,             10,             PASS,           SERVER  },
297                 {8,     CMD_WRLOCK,     30,             10,             PASS,           SERVER  },
298                 {8,     CMD_WRLOCK,     50,             10,             PASS,           SERVER  },
299                 /* Here is the new lock */
300                 {8,     CMD_WRLOCK,     35,             10,             PASS,           SERVER  },
301                 /* Go again with the end of the new lock matching the start of old lock */
302                 {8,     CMD_WRLOCK,     45,             2,              PASS,           SERVER  },
303                 
304                 {8,     CMD_UNLOCK,     10,             10,             PASS,           SERVER  },
305                 {8,     CMD_UNLOCK,     30,             17,             PASS,           SERVER  },
306                 {8,     CMD_UNLOCK,     50,             10,             PASS,           SERVER  },
307 /* SECTION 2: Overlapping READ and WRITE and CMD_UNLOCK with the same process (SERVER) */
308         /* Add different new lock types which completely overlaps any old lock in the list - 4,5,6 */
309                 {9,     CMD_WRLOCK,     10,             10,             PASS,           SERVER  },
310                 {9,     CMD_WRLOCK,     30,             10,             PASS,           SERVER  },
311                 {9,     CMD_WRLOCK,     50,             10,             PASS,           SERVER  },
312                 /* The start is the same, end overlaps */
313                 {9,     CMD_RDLOCK,     30,             15,             PASS,           SERVER  },
314                 /* The start is before, end is the same */
315                 {9,     CMD_WRLOCK,     25,             20,             PASS,           SERVER  },
316                 /* Both start and end overlap */
317                 {9,     CMD_RDLOCK,     22,             26,             PASS,           SERVER  },
318                 
319                 {9,     CMD_UNLOCK,     10,             10,             PASS,           SERVER  },
320                 {9,     CMD_UNLOCK,     22,             26,             PASS,           SERVER  },
321                 {9,     CMD_UNLOCK,     50,             10,             PASS,           SERVER  },
322                 
323         /* Add different new locks which are completely overlaped by an old lock in the list - 7,8,10 */
324                 {10,    CMD_WRLOCK,     10,             10,             PASS,           SERVER  },
325                 {10,    CMD_WRLOCK,     30,             10,             PASS,           SERVER  },
326                 {10,    CMD_WRLOCK,     50,             10,             PASS,           SERVER  },
327                 /* The start is the same, end is in the middle of old lock */
328                 {10,    CMD_RDLOCK,     30,             5,              PASS,           SERVER  },
329                 /* The start and end are in the middle of a lock */
330                 {10,    CMD_WRLOCK,     32,             2,              PASS,           SERVER  },
331                 /* Start in the middle and end is the same */
332                 {10,    CMD_RDLOCK,     36,             5,              PASS,           SERVER  },
333                 
334                 {10,    CMD_UNLOCK,     10,             10,             PASS,           SERVER  },
335                 {10,    CMD_UNLOCK,     30,             11,             PASS,           SERVER  },
336                 {10,    CMD_UNLOCK,     50,             10,             PASS,           SERVER  },
337                 
338         /* Add different new lock types which start before the old lock in the list - 2,9 */
339                 {11,    CMD_WRLOCK,     10,             10,             PASS,           SERVER  },
340                 {11,    CMD_WRLOCK,     30,             10,             PASS,           SERVER  },
341                 {11,    CMD_WRLOCK,     50,             10,             PASS,           SERVER  },
342                 /* Here is the new lock */
343                 {11,    CMD_RDLOCK,     27,             10,             PASS,           SERVER  },
344                 /* Go again with the end of the new lock matching the start of lock */
345                 {11,    CMD_WRLOCK,     25,             3,              PASS,           SERVER  },
346                 
347                 {11,    CMD_UNLOCK,     10,             10,             PASS,           SERVER  },
348                 {11,    CMD_UNLOCK,     25,             15,             PASS,           SERVER  },
349                 {11,    CMD_UNLOCK,     50,             10,             PASS,           SERVER  },
350         
351         /* Add different new lock types which start in the middle of an old lock in the list and end after - 11,12 */
352                 {12,    CMD_WRLOCK,     10,             10,             PASS,           SERVER  },
353                 {12,    CMD_WRLOCK,     30,             10,             PASS,           SERVER  },
354                 {12,    CMD_WRLOCK,     50,             10,             PASS,           SERVER  },
355                 /* Here is the new lock */
356                 {12,    CMD_RDLOCK,     35,             10,             PASS,           SERVER  },
357                 /* Go again with the end of the new lock matching the start of old lock */
358                 {12,    CMD_WRLOCK,     44,             3,              PASS,           SERVER  },
359                 
360                 {12,    CMD_UNLOCK,     10,             10,             PASS,           SERVER  },
361                 {12,    CMD_UNLOCK,     30,             18,             PASS,           SERVER  },
362                 {12,    CMD_UNLOCK,     50,             10,             PASS,           SERVER  },
363
364 /* SECTION 3: Overlapping READ and WRITE and CMD_UNLOCK with the different processes (CLIENT/SERVER) */
365         /* Add new lock, differing types and processes, to middle of the list - exact overlap match - 3 */
366                 {13,    CMD_WRLOCK,     10,             10,             PASS,           SERVER  },
367                 {13,    CMD_WRLOCK,     30,             10,             PASS,           SERVER  },
368                 {13,    CMD_RDLOCK,     50,             10,             PASS,           SERVER  },
369                 /* Same lock type, different process */
370                 {13,    CMD_WRLOCK,     30,             10,             FAIL,           CLIENT  },
371                 {13,    CMD_RDLOCK,     50,             10,             PASS,           CLIENT  },
372                 /* Exact match - different lock type, different process */
373                 {13,    CMD_RDLOCK,     30,             10,             FAIL,           CLIENT  },
374                 /* Exact match - unlock */
375                 {13,    CMD_UNLOCK,     30,             10,             PASS,           CLIENT  },
376                 /* New lock - as above, inserting in the list again */
377                 {13,    CMD_UNLOCK,     30,             10,             PASS,           SERVER  },
378                 /* Exact match - same lock type, different process */
379                 {13,    CMD_WRLOCK,     30,             10,             PASS,           CLIENT  },
380                 
381                 {13,    CMD_UNLOCK,     10,             10,             PASS,           SERVER  },
382                 {13,    CMD_UNLOCK,     30,             10,             PASS,           CLIENT  },
383                 {13,    CMD_UNLOCK,     50,             10,             PASS,           SERVER  },
384                 
385         /* Add new lock, differing types and processes, which completely overlap any of the locks in the list - 4,5,6 */
386                 {14,    CMD_WRLOCK,     10,             10,             PASS,           SERVER  },
387                 {14,    CMD_WRLOCK,     30,             10,             PASS,           SERVER  },
388                 {14,    CMD_RDLOCK,     50,             10,             PASS,           SERVER  },
389                 /* The start is the same, end overlaps */
390                 {14,    CMD_RDLOCK,     30,             15,             FAIL,           CLIENT  },
391                 {14,    CMD_WRLOCK,     30,             15,             FAIL,           CLIENT  },
392                 /* The start is before, end is the same */
393                 {14,    CMD_RDLOCK,     25,             20,             FAIL,           CLIENT  },
394                 {14,    CMD_WRLOCK,     25,             20,             FAIL,           CLIENT  },
395                 /* Both start and end overlap */
396                 {14,    CMD_RDLOCK,     22,             26,             FAIL,           CLIENT  },
397                 {14,    CMD_WRLOCK,     22,             26,             FAIL,           CLIENT  },
398                 
399                 /* The start is the same, end overlaps */
400                 {14,    CMD_RDLOCK,     50,             15,             PASS,           CLIENT  },
401                 {14,    CMD_WRLOCK,     50,             17,             FAIL,           CLIENT  },
402                 /* The start is before, end is the same */
403                 {14,    CMD_RDLOCK,     45,             20,             PASS,           CLIENT  },
404                 {14,    CMD_WRLOCK,     43,             22,             FAIL,           CLIENT  },
405                 /* Both start and end overlap */
406                 {14,    CMD_RDLOCK,     42,             26,             PASS,           CLIENT  },
407                 {14,    CMD_WRLOCK,     41,             28,             FAIL,           CLIENT  },
408                 
409                 {14,    CMD_UNLOCK,     10,             10,             PASS,           SERVER  },
410                 {14,    CMD_UNLOCK,     22,             26,             PASS,           SERVER  },
411                 {14,    CMD_UNLOCK,     42,             26,             PASS,           CLIENT  },
412
413         /* Add new lock, differing types and processes, which are completely overlaped by an old lock in the list - 7,8,10 */
414                 {15,    CMD_WRLOCK,     10,             10,             PASS,           SERVER  },
415                 {15,    CMD_RDLOCK,     30,             10,             PASS,           SERVER  },
416                 {15,    CMD_WRLOCK,     50,             10,             PASS,           SERVER  },
417                 /* The start is the same, end is in the middle of old lock */
418                 {15,    CMD_RDLOCK,     50,             5,              FAIL,           CLIENT  },
419                 {15,    CMD_WRLOCK,     50,             5,              FAIL,           CLIENT  },
420                 /* The start and end are in the middle of old lock */
421                 {15,    CMD_RDLOCK,     52,             6,              FAIL,           CLIENT  },
422                 {15,    CMD_WRLOCK,     52,             6,              FAIL,           CLIENT  },
423                 /* Start in the middle and end is the same */
424                 {15,    CMD_RDLOCK,     52,             8,              FAIL,           CLIENT  },
425                 {15,    CMD_WRLOCK,     52,             8,              FAIL,           CLIENT  },
426                 /* The start is the same, end is in the middle of old lock */
427                 {15,    CMD_RDLOCK,     30,             5,              PASS,           CLIENT  },
428                 {15,    CMD_WRLOCK,     30,             5,              FAIL,           CLIENT  },
429                 /* The start and end are in the middle of old lock */
430                 {15,    CMD_RDLOCK,     32,             6,              PASS,           CLIENT  },
431                 {15,    CMD_WRLOCK,     32,             6,              FAIL,           CLIENT  },
432                 /* Start in the middle and end is the same */
433                 {15,    CMD_RDLOCK,     32,             8,              PASS,           CLIENT  },
434                 {15,    CMD_WRLOCK,     32,             8,              FAIL,           CLIENT  },
435                 
436                 {15,    CMD_UNLOCK,     10,             10,             PASS,           SERVER  },
437                 {15,    CMD_UNLOCK,     30,             10,             PASS,           SERVER  },
438                 {15,    CMD_UNLOCK,     50,             10,             PASS,           SERVER  },
439         /* Add new lock, differing types and processes, which start before a lock in the list - 2,9 */
440                 {16,    CMD_RDLOCK,     10,             10,             PASS,           SERVER  },
441                 {16,    CMD_WRLOCK,     50,             10,             PASS,           SERVER  },
442                 /* Start is before, end is the start of the old lock in list */
443                 {16,    CMD_RDLOCK,     5,              6,              PASS,           CLIENT  },
444                 {16,    CMD_WRLOCK,     5,              6,              FAIL,           CLIENT  },
445                 /* Start is before, end is in the middle of the old lock */
446                 {16,    CMD_RDLOCK,     5,              10,             PASS,           CLIENT  },
447                 {16,    CMD_WRLOCK,     5,              10,             FAIL,           CLIENT  },
448                 /* Start is before, end is the start of the old lock in list */
449                 {16,    CMD_RDLOCK,     45,             6,              FAIL,           CLIENT  },
450                 {16,    CMD_WRLOCK,     45,             6,              FAIL,           CLIENT  },
451                 /* Start is before, end is in the middle of the old lock */
452                 {16,    CMD_RDLOCK,     45,             10,             FAIL,           CLIENT  },
453                 {16,    CMD_WRLOCK,     45,             10,             FAIL,           CLIENT  },
454                 
455                 {16,    CMD_UNLOCK,     5,              15,             PASS,           CLIENT  },
456                 {16,    CMD_UNLOCK,     30,             10,             PASS,           SERVER  },
457                 {16,    CMD_UNLOCK,     50,             10,             PASS,           SERVER  },
458
459         /* Add new lock, differing types and processes, which starts in the middle of a lock, and ends after - 11,12 */
460                 {17,    CMD_WRLOCK,     10,             10,             PASS,           SERVER  },
461                 {17,    CMD_RDLOCK,     30,             10,             PASS,           SERVER  },
462                 {17,    CMD_WRLOCK,     50,             10,             PASS,           SERVER  },
463                 /* Start in the middle, end after lock in list */
464                 {17,    CMD_WRLOCK,     35,             10,             FAIL,           CLIENT  },
465                 /* Start matches end of lock in list  */
466                 {17,    CMD_RDLOCK,     35,             10,             PASS,           CLIENT  },
467                 {17,    CMD_RDLOCK,     44,             2,              PASS,           CLIENT  },
468                 /* Start in the middle, end after lock in list */
469                 {17,    CMD_RDLOCK,     55,             10,             FAIL,           CLIENT  },
470                 {17,    CMD_WRLOCK,     55,             10,             FAIL,           CLIENT  },
471                 /* Start matches end of lock in list  */
472                 {17,    CMD_RDLOCK,     59,             5,              FAIL,           CLIENT  },
473                 {17,    CMD_WRLOCK,     59,             5,              FAIL,           CLIENT  },
474                 
475                 {17,    CMD_UNLOCK,     10,             10,             PASS,           SERVER  },
476                 {17,    CMD_UNLOCK,     30,             16,             PASS,           CLIENT  },
477                 {17,    CMD_UNLOCK,     50,             10,             PASS,           SERVER  },
478
479 /* SECTION 4: overlapping and EOF tests */
480         /* Acquire overlapping ranges */
481                 {18,    CMD_WRLOCK,     11,             7,              PASS,           SERVER  },
482                 {18,    CMD_WRLOCK,     13,             8,              FAIL,           CLIENT  },
483                 {18,    CMD_UNLOCK,     11,             7,              PASS,           SERVER  },
484         /* Acquire different ranges beyond EOF */
485                 {19,    CMD_WRLOCK,     10,             FILE_SIZE,      PASS,           SERVER  },
486                 {19,    CMD_WRLOCK,     FILE_SIZE + 10, 10,             PASS,           CLIENT  },
487                 {19,    CMD_UNLOCK,     10,             FILE_SIZE,      PASS,           SERVER  },
488                 {19,    CMD_UNLOCK,     FILE_SIZE + 10, 10,             PASS,           CLIENT  },
489         /* Acquire same range beyong EOF */
490                 {20,    CMD_WRLOCK,     10,             FILE_SIZE,      PASS,           SERVER, },
491                 {20,    CMD_WRLOCK,     10,             FILE_SIZE,      FAIL,           CLIENT, },
492                 {20,    CMD_UNLOCK,     10,             FILE_SIZE,      PASS,           SERVER, },
493         /* Acquire whole file lock */
494                 {21,    CMD_WRLOCK,     0,              0,              PASS,           SERVER, },
495                 {21,    CMD_WRLOCK,     0,              0,              FAIL,           CLIENT, },
496                 {21,    CMD_UNLOCK,     0,              0,              PASS,           SERVER, },
497         /* Acquire whole file lock, then range */
498                 {22,    CMD_WRLOCK,     0,              0,              PASS,           SERVER, },
499                 {22,    CMD_WRLOCK,     1,              5,              FAIL,           CLIENT, },
500                 {22,    CMD_UNLOCK,     0,              0,              PASS,           SERVER, },
501         /* Acquire non-overlapping read locks */
502                 {23,    CMD_RDLOCK, 1,          5,              PASS,           SERVER, },
503                 {23,    CMD_RDLOCK, 7,          6,              PASS,           CLIENT, },
504                 {23,    CMD_UNLOCK, 1,          5,              PASS,           SERVER, },
505                 {23,    CMD_UNLOCK, 7,          6,              PASS,           CLIENT, },
506         /* Acquire overlapping read locks */
507                 {24,    CMD_RDLOCK, 1,          5,              PASS,           SERVER, },
508                 {24,    CMD_RDLOCK, 2,          6,              PASS,           CLIENT, },
509                 {24,    CMD_UNLOCK, 1,          5,              PASS,           SERVER, },
510                 {24,    CMD_UNLOCK, 1,          7,              PASS,           CLIENT, },
511         /* Acquire non-overlapping read and write locks */
512                 {25,    CMD_RDLOCK, 1,          5,              PASS,           SERVER, },
513                 {25,    CMD_WRLOCK, 7,          6,              PASS,           CLIENT, },
514                 {25,    CMD_UNLOCK, 1,          5,              PASS,           SERVER, },
515                 {25,    CMD_UNLOCK, 7,          6,              PASS,           CLIENT, },
516         /* Acquire overlapping read and write locks */
517                 {26,    CMD_RDLOCK, 1,          5,              PASS,           SERVER, },
518                 {26,    CMD_WRLOCK, 2,          6,              FAIL,           CLIENT, },
519                 {26,    CMD_UNLOCK, 1,          5,              PASS,           SERVER, },
520         /* Acquire whole file lock, then close (without unlocking) */
521                 {27,    CMD_WRLOCK,     0,              0,              PASS,           SERVER, },
522                 {27,    CMD_WRLOCK,     1,              5,              FAIL,           CLIENT, },
523                 {27,    CMD_CLOSE,0,            0,              PASS,           SERVER, },
524                 {27,    CMD_WRLOCK,     1,              5,              PASS,           CLIENT, },
525                 {27,    CMD_OPEN,       O_RDWR,         0,              PASS,           SERVER, },
526                 {27,    CMD_UNLOCK,     1,              5,              PASS,           CLIENT, },
527         /* Acquire two read locks, close one file and then reopen to check that first lock still exists */
528                 {28,    CMD_RDLOCK,     1,              5,              PASS,           SERVER, },
529                 {28,    CMD_RDLOCK,     1,              5,              PASS,           CLIENT, },
530                 {28,    CMD_CLOSE,0,            0,              PASS,           SERVER, },
531                 {28,    CMD_OPEN,       O_RDWR,         0,              PASS,           SERVER, },
532                 {28,    CMD_WRLOCK,     0,              0,              FAIL,           SERVER, },
533                 {28,    CMD_UNLOCK,     1,              5,              PASS,           SERVER, },
534         /* Verify that F_GETLK for F_WRLCK doesn't require that file be opened for write */
535                 {29,    CMD_CLOSE, 0,           0,              PASS,           SERVER, },
536                 {29,    CMD_OPEN, O_RDONLY,     0,              PASS,           SERVER, },
537                 {29,    CMD_WRTEST, 0,          0,              PASS,           SERVER, },
538                 {29,    CMD_CLOSE,0,            0,              PASS,           SERVER, },
539                 {29,    CMD_OPEN,       O_RDWR,         0,              PASS,           SERVER, },
540 #ifdef macosx
541         /* Close the opened file and open the file with SHLOCK, other client will try to open with SHLOCK too */
542                 {30,    CMD_CLOSE,0,            0,              PASS,           SERVER, },
543                 {30,    CMD_OPEN,       O_RDWR|O_SHLOCK|O_NONBLOCK,     0,      PASS,           SERVER, },
544                 {30,    CMD_CLOSE,0,            0,              PASS,           CLIENT, },
545                 {30,    CMD_OPEN,       O_RDWR|O_SHLOCK|O_NONBLOCK,     0,      PASS,           CLIENT, },
546         /* Close the opened file and open the file with SHLOCK, other client will try to open with EXLOCK */
547                 {31,    CMD_CLOSE,0,            0,              PASS,           SERVER, },
548                 {31,    CMD_CLOSE,0,            0,              PASS,           CLIENT, },
549                 {31,    CMD_OPEN,       O_RDWR|O_SHLOCK|O_NONBLOCK,     0,      PASS,           SERVER, },
550                 {31,    CMD_OPEN,       O_RDWR|O_EXLOCK|O_NONBLOCK,     0,      FAIL,           CLIENT, },
551         /* Close the opened file and open the file with EXLOCK, other client will try to open with EXLOCK too */
552                 {32,    CMD_CLOSE,0,            0,              PASS,           SERVER, },
553                 {32,    CMD_CLOSE,0,            0,              FAIL,           CLIENT, },
554                 {32,    CMD_OPEN,       O_RDWR|O_EXLOCK|O_NONBLOCK,     0,      PASS,           SERVER, },
555                 {32,    CMD_OPEN,       O_RDWR|O_EXLOCK|O_NONBLOCK,     0,      FAIL,           CLIENT, },
556                 {32,    CMD_CLOSE,0,            0,              PASS,           SERVER, },
557                 {32,    CMD_CLOSE,0,            0,              FAIL,           CLIENT, },
558                 {32,    CMD_OPEN,       O_RDWR,         0,              PASS,           SERVER, },
559                 {32,    CMD_OPEN,       O_RDWR,         0,              PASS,           CLIENT, },
560 #endif /* macosx */
561
562         /* indicate end of array */
563                 {0,0,0,0,0,SERVER},
564                 {0,0,0,0,0,CLIENT}
565         };
566
567
568 char *lease_descriptions[] = {
569     /*  1 */"Take Read Lease",
570     /*  2 */"Take Write Lease",
571     /*  3 */"Fail Write Lease if file is open somewhere else",
572     /*  4 */"Fail Read Lease if opened with write permissions",
573     /*  5 */"Read lease gets SIGIO on write open",
574     /*  6 */"Write lease gets SIGIO on read open",
575     /*  7 */"Read lease does _not_ get SIGIO on read open",
576     /*  8 */"Read lease gets SIGIO on write open",
577 };
578
579 static int64_t lease_tests[][6] =
580         /*      test #  Action  [offset|flags|arg]      length          expected        server/client */
581         /*                      [sigio_wait_time]                                               */
582         {
583         /* Various tests to exercise leases */
584
585 /* SECTION 1: Simple verification of being able to take leases */
586         /* Take Read Lease */
587                 {1,     CMD_CLOSE,      0,              0,      PASS,           CLIENT  },
588                 {1,     CMD_OPEN,       O_RDONLY,       0,      PASS,           CLIENT  },
589                 {1,     CMD_CLOSE,      0,              0,      PASS,           SERVER  },
590                 {1,     CMD_OPEN,       O_RDONLY,       0,      PASS,           SERVER  },
591                 {1,     CMD_SETLEASE,   F_RDLCK,        0,      PASS,           SERVER  },
592                 {1,     CMD_GETLEASE,   F_RDLCK,        0,      PASS,           SERVER  },
593                 {1,     CMD_SETLEASE,   F_UNLCK,        0,      PASS,           SERVER  },
594                 {1,     CMD_CLOSE,      0,              0,      PASS,           SERVER  },
595                 {1,     CMD_CLOSE,      0,              0,      PASS,           CLIENT  },
596
597         /* Take Write Lease */
598                 {2,     CMD_OPEN,       O_RDWR,         0,      PASS,           SERVER  },
599                 {2,     CMD_SETLEASE,   F_WRLCK,        0,      PASS,           SERVER  },
600                 {2,     CMD_GETLEASE,   F_WRLCK,        0,      PASS,           SERVER  },
601                 {2,     CMD_SETLEASE,   F_UNLCK,        0,      PASS,           SERVER  },
602                 {2,     CMD_CLOSE,      0,              0,      PASS,           SERVER  },
603         /* Fail Write Lease with other users */
604                 {3,     CMD_OPEN,       O_RDONLY,       0,      PASS,           CLIENT  },
605                 {3,     CMD_OPEN,       O_RDWR,         0,      PASS,           SERVER  },
606                 {3,     CMD_SETLEASE,   F_WRLCK,        0,      FAIL,           SERVER  },
607                 {3,     CMD_GETLEASE,   F_WRLCK,        0,      FAIL,           SERVER  },
608                 {3,     CMD_CLOSE,      0,              0,      PASS,           SERVER  },
609                 {3,     CMD_CLOSE,      0,              0,      PASS,           CLIENT  },
610         /* Fail Read Lease if opened for write */
611                 {4,     CMD_OPEN,       O_RDWR,         0,      PASS,           SERVER  },
612                 {4,     CMD_SETLEASE,   F_RDLCK,        0,      FAIL,           SERVER  },
613                 {4,     CMD_GETLEASE,   F_RDLCK,        0,      FAIL,           SERVER  },
614                 {4,     CMD_CLOSE,      0,              0,      PASS,           SERVER  },
615
616 /* SECTION 2: Proper SIGIO notifications */
617         /* Get SIGIO when read lease is broken by write */
618                 {5,     CMD_OPEN,       O_RDONLY,       0,      PASS,           CLIENT  },
619                 {5,     CMD_SETLEASE,   F_RDLCK,        0,      PASS,           CLIENT  },
620                 {5,     CMD_GETLEASE,   F_RDLCK,        0,      PASS,           CLIENT  },
621                 {5,     CMD_SIGIO,      0,              0,      PASS,           CLIENT  },
622                 {5,     CMD_OPEN,       O_RDWR,         0,      PASS,           SERVER  },
623                 {5,     CMD_WAIT_SIGIO, 5,              0,      PASS,           CLIENT  },
624                 {5,     CMD_CLOSE,      0,              0,      PASS,           SERVER  },
625                 {5,     CMD_CLOSE,      0,              0,      PASS,           CLIENT  },
626
627         /* Get SIGIO when write lease is broken by read */
628                 {6,     CMD_OPEN,       O_RDWR,         0,      PASS,           CLIENT  },
629                 {6,     CMD_SETLEASE,   F_WRLCK,        0,      PASS,           CLIENT  },
630                 {6,     CMD_GETLEASE,   F_WRLCK,        0,      PASS,           CLIENT  },
631                 {6,     CMD_SIGIO,      0,              0,      PASS,           CLIENT  },
632                 {6,     CMD_OPEN,       O_RDONLY,       0,      PASS,           SERVER  },
633                 {6,     CMD_WAIT_SIGIO, 5,              0,      PASS,           CLIENT  },
634                 {6,     CMD_CLOSE,      0,              0,      PASS,           SERVER  },
635                 {6,     CMD_CLOSE,      0,              0,      PASS,           CLIENT  },
636
637         /* Don't get SIGIO when read lease is taken by read */
638                 {7,     CMD_OPEN,       O_RDONLY,       0,      PASS,           CLIENT  },
639                 {7,     CMD_SETLEASE,   F_RDLCK,        0,      PASS,           CLIENT  },
640                 {7,     CMD_GETLEASE,   F_RDLCK,        0,      PASS,           CLIENT  },
641                 {7,     CMD_SIGIO,      0,              0,      PASS,           CLIENT  },
642                 {7,     CMD_OPEN,       O_RDONLY,       0,      PASS,           SERVER  },
643                 {7,     CMD_WAIT_SIGIO, 5,              0,      FAIL,           CLIENT  },
644                 {7,     CMD_CLOSE,      0,              0,      PASS,           SERVER  },
645                 {7,     CMD_CLOSE,      0,              0,      PASS,           CLIENT  },
646
647         /* Get SIGIO when Read lease is broken by Write */
648                 {8,     CMD_OPEN,       O_RDONLY,       0,      PASS,           CLIENT  },
649                 {8,     CMD_SETLEASE,   F_RDLCK,        0,      PASS,           CLIENT  },
650                 {8,     CMD_GETLEASE,   F_RDLCK,        0,      PASS,           CLIENT  },
651                 {8,     CMD_SIGIO,      0,              0,      PASS,           CLIENT  },
652                 {8,     CMD_OPEN,       O_RDWR,         0,      PASS,           SERVER  },
653                 {8,     CMD_WAIT_SIGIO, 5,              0,      PASS,           CLIENT  },
654                 {8,     CMD_CLOSE,      0,              0,      PASS,           SERVER  },
655                 {8,     CMD_CLOSE,      0,              0,      PASS,           CLIENT  },
656
657         /* indicate end of array */
658                 {0,0,0,0,0,SERVER},
659                 {0,0,0,0,0,CLIENT}
660         };
661
662 static struct {
663     int32_t             test;
664     int32_t             command;
665     int64_t             offset;
666     int64_t             length;
667     int32_t             result;
668     int32_t             index;
669     int32_t             error;
670     int32_t             padding; /* So mac and irix have the same size struct (bloody alignment) */
671 } ctl;
672
673
674 void
675 usage(void)
676 {
677     fprintf(stderr, "Usage: %s [options] sharedfile\n\
678 \n\
679 options:\n\
680   -p port       TCP/IP port number for client-server communication\n\
681   -d            enable debug tracing\n\
682   -n #          test number to run\n\
683   -h host       run as client and connect to server on remote host\n\
684                 [default run as server]\n", prog);
685     exit(1);
686 }
687
688 #define INIT_BUFSZ 512 
689
690 void
691 initialize(HANDLE fd)
692 {
693     char*       ibuf;
694     int         j=0;
695     int         nwrite;
696     int         offset = 0;
697     int         togo = FILE_SIZE;
698
699     ibuf = (char*)malloc(INIT_BUFSZ);
700     memset(ibuf, ':', INIT_BUFSZ);
701
702     SEEK(fd, 0L);
703     while (togo) {
704         offset+=j;
705         j = togo > INIT_BUFSZ ? INIT_BUFSZ : togo;
706
707         if ((nwrite = WRITE(fd, ibuf, j)) != j) {
708             if (nwrite < 0)
709                 perror("initialize write:");
710             else
711                 fprintf(stderr, "initialize: write() returns %d, not %d as expected\n", 
712                         nwrite, j);
713             exit(1);
714             /*NOTREACHED*/
715         }
716         togo -= j;
717     }
718 }
719
720 void release_lease(int fd)
721 {
722         int rc;
723
724         rc = fcntl(fd, F_SETLEASE, F_UNLCK);
725         if (rc != 0)
726                 fprintf(stderr, "%s Failed to remove lease %d : %d %s\n",
727                         __FILE__, rc, errno, strerror(errno));
728 }
729
730 void lease_break(int sig, siginfo_t *info, void *p)
731 {
732     if (debug)
733         fprintf(stderr, "lease break %d %p fd %d\n",
734                 sig, info, info->si_fd);
735     got_sigio = 1;
736     release_lease(f_fd);
737 }
738
739 struct sigaction lease_break_action = {
740         .sa_sigaction = lease_break,
741         .sa_flags = SA_SIGINFO,
742 };
743
744 int do_setup_sigio(int fd)
745 {
746         int rc;
747
748         got_sigio = 0;
749
750         rc = sigaction(SIGIO, &lease_break_action, NULL);
751         if (rc != 0) {
752                 fprintf(stderr, "%s Set '%s' sigaction failed %d\n",
753                         __FILE__, strsignal(SIGIO), rc);
754                 return FAIL;
755         }
756
757         if (debug)
758                 fprintf(stderr, "Set '%s' sigaction on %d\n",
759                         strsignal(SIGIO), fd);
760
761         rc = fcntl(fd, F_SETSIG, SIGIO);
762         if (rc)
763                 fprintf(stderr, "%s Set '%s' sigaction failed %d\n",
764                         __FILE__, strsignal(SIGIO), rc);
765
766         return (rc == 0 ? PASS : FAIL);
767 }
768
769 int do_wait_sigio(int32_t time)
770 {
771     if (time <= 0)
772         return FAIL;
773
774     while (!got_sigio && time--) {
775         sleep(1);
776     }
777
778     if (debug > 1 && !got_sigio)
779         fprintf(stderr, "%s failed to get sigio\n",
780                 __FILE__);
781
782     return (got_sigio ? PASS: FAIL);
783 }
784
785 int do_open(int flag)
786 {
787     int flags = flag|O_CREAT|O_BINARY;
788
789     if(debug > 1)
790         fprintf(stderr, "do_open %s 0x%x\n", filename, flags);
791
792     if ((f_fd = open(filename, flags, 0666)) == INVALID_HANDLE) {
793         perror("shared file create");
794         return FAIL;
795         /*NOTREACHED*/
796     }
797     return PASS;
798 }
799
800 static int do_lock(int cmd, int type, int start, int length)
801 {
802     int ret;
803     int filedes = f_fd;
804     struct flock fl;
805
806     if(debug > 1) {
807         fprintf(stderr, "do_lock: cmd=%d type=%d start=%d, length=%d\n", cmd, type, start, length);
808     }
809
810     if (f_fd < 0)
811         return f_fd;
812     
813     fl.l_start = start;
814     fl.l_len = length;
815     fl.l_whence = SEEK_SET;
816     fl.l_pid = getpid();
817     fl.l_type = type;
818
819     errno = 0;
820
821     ret = fcntl(filedes, cmd, &fl);
822     saved_errno = errno;            
823
824     if(ret)
825         fprintf(stderr, "do_lock: ret = %d, errno = %d (%s)\n", ret, errno, strerror(errno));
826
827     return(ret==0?PASS:FAIL);
828 }
829
830 static int do_lease(int cmd, int arg, int expected)
831 {
832     int ret;
833
834     if(debug > 1)
835         fprintf(stderr, "do_lease: cmd=%d arg=%d exp=%X\n",
836                 cmd, arg, expected);
837
838     if (f_fd < 0)
839         return f_fd;
840
841     errno = 0;
842
843     ret = fcntl(f_fd, cmd, arg);
844     saved_errno = errno;
845
846     if (expected && (expected == ret))
847         ret = 0;
848
849     if(ret)
850         fprintf(stderr, "%s do_lease: ret = %d, errno = %d (%s)\n",
851                 __FILE__, ret, errno, strerror(errno));
852
853     return(ret==0?PASS:FAIL);
854 }
855
856 int do_close(void)
857 {       
858     if(debug > 1) {
859         fprintf(stderr, "do_close\n");
860     }
861
862     errno =0;
863     CLOSE(f_fd);
864     f_fd = INVALID_HANDLE;
865
866     saved_errno = errno;            
867         
868     if (errno) {
869         fprintf(stderr, "%s errno = %d (%s)\n",
870                 __FILE__, errno, strerror(errno));
871         return FAIL;
872     }
873     return PASS;
874 }
875
876 static void init_ctl(int64_t tests[][6], int32_t index)
877 {
878     ctl.test= (int32_t)tests[index][TEST_NUM];
879     ctl.command = (int32_t)tests[index][COMMAND];
880     ctl.offset = tests[index][OFFSET];
881     ctl.length = tests[index][LENGTH];
882     ctl.index = index;
883     ctl.result = (int32_t)tests[index][RESULT];
884     ctl.error = 0;
885 }
886
887 void
888 send_ctl(void)
889 {
890     int         nwrite;
891
892     if (debug) {
893         fprintf(stderr, "send_ctl: test=%d, command=%d offset=%"LL"d, length=%"LL"d, result=%d, error=%d\n", 
894                 ctl.test, ctl.command, (long long)ctl.offset, (long long)ctl.length,ctl.result, ctl.error);
895     }
896
897     ctl.test= bswap_uint32(ctl.test);
898     ctl.command = bswap_uint32(ctl.command);
899     ctl.offset = bswap_uint64(ctl.offset);
900     ctl.length = bswap_uint64(ctl.length);
901     ctl.result = bswap_uint32(ctl.result);
902     ctl.index= bswap_uint32(ctl.index);
903     ctl.error = bswap_uint32(ctl.error);
904     nwrite = SOCKET_WRITE(c_fd, (char*)&ctl, sizeof(ctl));
905
906     ctl.test= bswap_uint32(ctl.test);
907     ctl.command = bswap_uint32(ctl.command);
908     ctl.offset = bswap_uint64(ctl.offset);
909     ctl.length = bswap_uint64(ctl.length);
910     ctl.result = bswap_uint32(ctl.result);
911     ctl.index= bswap_uint32(ctl.index);
912     ctl.error= bswap_uint32(ctl.error);
913     if (nwrite != sizeof(ctl)) {
914         if (nwrite < 0)
915             perror("send_ctl: write");
916         else
917             fprintf(stderr, "send_ctl[%d]: write() returns %d, not %zu as expected\n", 
918                     ctl.test, nwrite, sizeof(ctl));
919         exit(1);
920         /*NOTREACHED*/
921     }
922 }
923
924 void recv_ctl(void)
925 {
926     int         nread;
927
928 again:
929     if ((nread = SOCKET_READ(c_fd, (char*)&ctl, sizeof(ctl))) != sizeof(ctl)) {
930         if (nread < 0) {
931             if (errno == EINTR)
932                 goto again;
933             perror("recv_ctl: read");
934         } else {
935             fprintf(stderr, "recv_ctl[%d]: read() returns %d, not %zu as expected\n", 
936                     ctl.test, nread, sizeof(ctl));
937             fprintf(stderr, "socket might has been closed by other locktest\n");
938         } 
939         exit(1);
940         /*NOTREACHED*/
941     }
942     ctl.test= bswap_uint32(ctl.test);
943     ctl.command = bswap_uint32(ctl.command);
944     ctl.offset = bswap_uint64(ctl.offset);
945     ctl.length = bswap_uint64(ctl.length);
946     ctl.result = bswap_uint32(ctl.result);
947     ctl.index= bswap_uint32(ctl.index);
948     ctl.error= bswap_uint32(ctl.error);
949
950     if (debug) {
951         fprintf(stderr, "recv_ctl: test=%d, command=%d offset=%"LL"d, length=%"LL"d, result=%d, error=%d\n", 
952                 ctl.test, ctl.command, (long long)ctl.offset, (long long)ctl.length, ctl.result, ctl.error);
953     }
954 }
955
956 void
957 cleanup(void)
958 {
959     if (f_fd>=0)
960         CLOSE(f_fd);
961     
962     if (c_fd>=0)
963         SOCKET_CLOSE(c_fd);
964     
965     if (s_fd>=0)
966         SOCKET_CLOSE(s_fd);
967     
968     PLATFORM_CLEANUP();
969 }
970
971 int
972 run(int64_t tests[][6], char *descriptions[]);
973
974 int
975 main(int argc, char *argv[])
976 {
977     int         i, sts;
978     int         c;
979     struct sockaddr_in  myAddr;
980     struct linger       noLinger = {1, 0};
981     char        *host = NULL;
982     char        *endnum;
983     int         errflag = 0;
984     char        *p;
985     extern char *optarg;
986     extern int  optind;
987     int fail_count = 0;
988     int run_leases = 0;
989     
990     atexit(cleanup);
991     
992     PLATFORM_INIT();
993
994     /* trim command name of leading directory components */
995     prog = argv[0];
996     for (p = prog; *p; p++) {
997         if (*p == '/')
998             prog = p+1;
999     }
1000
1001     while ((c = getopt(argc, argv, "dLn:h:p:?")) != EOF) {
1002         switch (c) {
1003
1004         case 'd':       /* debug flag */
1005             debug++;
1006             break;
1007
1008         case 'L':       /* Lease testing */
1009             run_leases = 1;
1010             break;
1011
1012         case 'h':       /* (server) hostname */
1013             server = 0;
1014             host = optarg;
1015             break;
1016
1017         case 'n':
1018             testnumber = atoi(optarg);
1019             break;
1020
1021         case 'p':       /* TCP/IP port */
1022             port = (int)strtol(optarg, &endnum, 10);
1023             if (*endnum != '\0') {
1024                 fprintf(stderr, "%s: -p argument must be a numeric\n", 
1025                         prog);
1026                 exit(1);
1027                 /*NOTREACHED*/
1028             }
1029             break;
1030
1031         case '?':
1032         default:
1033             errflag++;
1034             break;
1035         }
1036     }
1037
1038     if (errflag || optind != argc-1) {
1039         usage();
1040         /*NOTREACHED*/
1041     }
1042
1043     filename=argv[optind];
1044     if (debug)
1045         fprintf(stderr, "Working on file : %s\n", filename);
1046     if (do_open(O_RDWR) == FAIL)
1047         exit(1);
1048
1049     setbuf(stderr, NULL);
1050
1051     if (server) {
1052         int one = 1;
1053         
1054         s_fd = socket(AF_INET, SOCK_STREAM, 0);
1055         if (s_fd == INVALID_SOCKET) {
1056             perror("socket");
1057             exit(1);
1058             /*NOTREACHED*/
1059         }
1060         if (setsockopt(s_fd, IPPROTO_TCP, TCP_NODELAY, (char*)&one, sizeof(one)) < 0) {
1061             perror("setsockopt(nodelay)");
1062             exit(1);
1063             /*NOTREACHED*/
1064         }
1065         if (setsockopt(s_fd, SOL_SOCKET, SO_REUSEADDR, (char*)&one, sizeof(one))<0) {
1066             perror("setsockopt(reuseaddr)");
1067             exit(1);
1068             /*NOTREACHED*/
1069         }
1070 #ifdef SO_REUSEPORT
1071         if (setsockopt(s_fd, SOL_SOCKET, SO_REUSEPORT, (char*)&one, sizeof(one))<0) {
1072             perror("setsockopt(reuseport)");
1073             exit(1);
1074             /*NOTREACHED*/
1075         }
1076 #endif
1077
1078         memset(&myAddr, 0, sizeof(myAddr));
1079         myAddr.sin_family = AF_INET;
1080         myAddr.sin_addr.s_addr = htonl(INADDR_ANY);
1081         myAddr.sin_port = htons((short)port);
1082         sts = bind(s_fd, (struct sockaddr*)&myAddr, sizeof(myAddr));
1083         if (sts < 0) {
1084             perror("bind");
1085             exit(1);
1086             /*NOTREACHED*/
1087         }
1088
1089         sts = listen(s_fd, 5);  /* Max. of 5 pending connection requests */
1090         if (sts == -1) {
1091             perror("listen");
1092             exit(1);
1093             /*NOTREACHED*/
1094         }
1095
1096         if (port == 0) {
1097                 socklen_t addr_len = sizeof(myAddr);
1098
1099                 if (getsockname(s_fd, &myAddr, &addr_len)) {
1100                     perror("getsockname");
1101                     exit(1);
1102                 }
1103
1104                 port = ntohs(myAddr.sin_port);
1105         }
1106
1107         printf("server port: %d\n", port);
1108         fflush(stdout);
1109
1110         c_fd = accept(s_fd, NULL, NULL);
1111         if (c_fd == INVALID_SOCKET) {
1112             perror("accept");
1113             exit(1);
1114             /*NOTREACHED*/
1115         }
1116
1117         if (debug) fprintf(stderr, "Client accepted\n");
1118         SRAND(12345L);
1119     }
1120     else {
1121         struct hostent  *servInfo;
1122
1123         if ((servInfo = gethostbyname(host)) == NULL) {
1124             fprintf(stderr, "Couldn't get hostbyname for %s", host);
1125             if (h_errno == HOST_NOT_FOUND)
1126                 fprintf(stderr, ": host not found");
1127             fprintf(stderr, "\n");
1128             exit(1);
1129             /*NOTREACHED*/
1130         }
1131
1132         c_fd = socket(AF_INET, SOCK_STREAM, 0);
1133         if (c_fd == INVALID_SOCKET) {
1134             perror("socket");
1135             exit(1);
1136             /*NOTREACHED*/
1137         }
1138         /* avoid 200 ms delay */
1139         if (setsockopt(c_fd, IPPROTO_TCP, TCP_NODELAY, (char *)&i, sizeof(i)) < 0) {
1140             perror("setsockopt(nodelay)");
1141             exit(1);
1142             /*NOTREACHED*/
1143         }
1144         /* Don't linger on close */
1145         if (setsockopt(c_fd, SOL_SOCKET, SO_LINGER, (char *)&noLinger, sizeof(noLinger)) < 0) {
1146             perror("setsockopt(nolinger)");
1147             exit(1);
1148             /*NOTREACHED*/
1149         }
1150
1151         memset(&myAddr, 0, sizeof(myAddr));     /* Arrgh! &myAddr, not myAddr */
1152         myAddr.sin_family = AF_INET;
1153         memcpy(&myAddr.sin_addr, servInfo->h_addr, servInfo->h_length);
1154         myAddr.sin_port = htons((short)port);
1155
1156         if (connect(c_fd, (struct sockaddr*)&myAddr, sizeof(myAddr)) < 0) {
1157             perror("unable to connect");
1158             fprintf(stderr, "Server might still initializing the shared file\n ");
1159             exit(1);
1160             /*NOTREACHED*/
1161         }
1162
1163         if (debug) fprintf(stderr, "Connected to server\n");
1164         SRAND(6789L);
1165     }
1166
1167     if (server)
1168         /* only server need do shared file */
1169         initialize(f_fd);
1170
1171     /*
1172      * TCP/IP connection to be established, safe to proceed.
1173      *
1174      * real work is in here ...
1175      */
1176     if (run_leases)
1177         fail_count = run(lease_tests, lease_descriptions);
1178     else
1179         fail_count = run(lock_tests, lock_descriptions);
1180
1181     exit(fail_count);
1182     /*NOTREACHED*/
1183 }
1184
1185 int run(int64_t tests[][6], char *descriptions[])
1186 {
1187     int index = 0;
1188     int end = 0;
1189     int result = 0;
1190     int last_test = 0;
1191     int test_count = -1;
1192     int fail_flag = 0;
1193     int fail_count = 0;
1194     while(!end) {
1195         if (server) {
1196             if(testnumber > 0) {
1197                 last_test = testnumber - 1;
1198                 while(tests[index][TEST_NUM] != testnumber && tests[index][TEST_NUM] != 0) {
1199                     index++;
1200                 }
1201             }
1202             /* If we have a server command, deal with it */
1203             if(tests[index][WHO] == SERVER) {
1204                 if(debug)
1205                     fprintf(stderr, "Got a server command (%d)\n", index);
1206                 if(tests[index][TEST_NUM] == 0) {
1207                     index++;
1208                     continue;
1209                 } 
1210                 memset(&ctl, 0, sizeof(ctl));
1211                 ctl.test = tests[index][TEST_NUM];
1212
1213                 if(tests[index][TEST_NUM] != 0) {
1214                     switch(tests[index][COMMAND]) {
1215                         case CMD_WRLOCK:
1216                             result = do_lock(F_SETLK, F_WRLCK, tests[index][OFFSET], tests[index][LENGTH]);
1217                             break;
1218                         case CMD_RDLOCK:
1219                             result = do_lock(F_SETLK, F_RDLCK, tests[index][OFFSET], tests[index][LENGTH]);
1220                             break;
1221                         case CMD_UNLOCK:
1222                             result = do_lock(F_SETLK, F_UNLCK, tests[index][OFFSET], tests[index][LENGTH]);
1223                             break;
1224                         case CMD_CLOSE:
1225                             result = do_close();
1226                             break;
1227                         case CMD_OPEN:
1228                             result = do_open(tests[index][FLAGS]);
1229                             break;
1230                         case CMD_WRTEST:
1231                             result = do_lock(F_GETLK, F_WRLCK, tests[index][OFFSET], tests[index][LENGTH]);
1232                             break;
1233                         case CMD_RDTEST:
1234                             result = do_lock(F_GETLK, F_RDLCK, tests[index][OFFSET], tests[index][LENGTH]);
1235                             break;
1236                         case CMD_SETLEASE:
1237                             result = do_lease(F_SETLEASE, tests[index][ARG], 0);
1238                             break;
1239                         case CMD_GETLEASE:
1240                             result = do_lease(F_GETLEASE, tests[index][ARG], tests[index][ARG]);
1241                             break;
1242                         case CMD_SIGIO:
1243                             result = do_setup_sigio(f_fd);
1244                             break;
1245                         case CMD_WAIT_SIGIO:
1246                             result = do_wait_sigio(tests[index][TIME]);
1247                             break;
1248                     }
1249                     if( result != tests[index][RESULT]) {
1250                         fail_flag++;
1251                         /* We have a failure */
1252                         fprintf(stderr, "     ***** Server failure *****\n");
1253                         fprintf(stderr, "     in test %d, while %sing using offset %lld, length %lld - err = %d:%s\n",
1254                                 ctl.test, get_cmd_str(tests[index][COMMAND]),
1255                                 (long long)tests[index][OFFSET],
1256                                 (long long)tests[index][LENGTH],
1257                                 saved_errno, strerror(saved_errno));
1258                         fprintf(stderr, "     %d:%s\n",
1259                                         ctl.test, descriptions[ctl.test - 1]);
1260                     }
1261                 }
1262             /* else send it off to the client */
1263             } else if (tests[index][WHO] == CLIENT) {
1264                 if(tests[index][TEST_NUM] == 0) {
1265                     ctl.test = 0;
1266                     end=1;
1267                 } 
1268                 /* get the client to do something */
1269                 init_ctl(tests, index);
1270                 if(debug)
1271                     fprintf(stderr, "Sending command to client (%d) - %s - %lld:%lld\n", 
1272                                         index,
1273                                         get_cmd_str(ctl.command),
1274                                         (long long)tests[index][OFFSET],
1275                                         (long long)tests[index][LENGTH]);
1276                 /* get the client to do something */
1277                 ctl.index = index;
1278                 send_ctl();
1279                 if(ctl.test != 0) {
1280                     /* Get the clients response */
1281                     recv_ctl();
1282                     /* this is the whether the test passed or failed,
1283                      * not what the command returned */
1284                     if( ctl.result == FAIL ) {
1285                         fail_flag++;
1286                         fprintf(stderr, "     ***** Client failure *****\n");
1287                         fprintf(stderr, "     in test %d, while %sing using offset %lld, length %lld - err = %d:%s\n",
1288                                         ctl.test, get_cmd_str(ctl.command),
1289                                         (long long)ctl.offset, (long long)ctl.length,
1290                                         ctl.error, strerror(ctl.error));
1291                         fprintf(stderr, "     %d:%s\n",
1292                                         ctl.test, descriptions[ctl.test - 1]);
1293                     }
1294                 }
1295             }
1296
1297             if(last_test != tests[index][TEST_NUM]) {
1298                 test_count++;
1299                 if(fail_flag)
1300                     fail_count++;
1301                 fail_flag = 0;
1302                 last_test = tests[index][TEST_NUM];
1303             }
1304                 
1305             index++;
1306         } else { /* CLIENT */
1307             if(debug)
1308                 fprintf(stderr,"client: waiting...\n");
1309             /* wait for the server to do something */
1310             recv_ctl();
1311
1312             /* check for a client command */
1313             index = ctl.index;
1314             if (tests[index][WHO] != CLIENT) { 
1315                 fprintf(stderr, "not a client command index (%d)\n", index);
1316                 exit(1);
1317             }
1318                 
1319             if(ctl.test == 0) {
1320                 end = 1;
1321                 break;
1322             }
1323
1324             switch(ctl.command) {
1325                 case CMD_WRLOCK:
1326                     result = do_lock(F_SETLK, F_WRLCK, ctl.offset, ctl.length);
1327                     break;
1328                 case CMD_RDLOCK:
1329                     result = do_lock(F_SETLK, F_RDLCK, ctl.offset, ctl.length);
1330                     break;
1331                 case CMD_UNLOCK:
1332                     result = do_lock(F_SETLK, F_UNLCK, ctl.offset, ctl.length);
1333                     break;
1334                 case CMD_CLOSE:
1335                     result = do_close();
1336                     break;
1337                 case CMD_OPEN:
1338                     result = do_open(tests[index][FLAGS]);
1339                     break;
1340                 case CMD_WRTEST:
1341                     result = do_lock(F_GETLK, F_WRLCK, ctl.offset, ctl.length);
1342                     break;
1343                 case CMD_RDTEST:
1344                     result = do_lock(F_GETLK, F_RDLCK, ctl.offset, ctl.length);
1345                     break;
1346                 /* NOTE offset carries the argument values */
1347                 case CMD_SETLEASE:
1348                     result = do_lease(F_SETLEASE, ctl.offset, 0);
1349                     break;
1350                 case CMD_GETLEASE:
1351                     result = do_lease(F_GETLEASE, ctl.offset, ctl.offset);
1352                     break;
1353                 case CMD_SIGIO:
1354                     result = do_setup_sigio(f_fd);
1355                     break;
1356                 case CMD_WAIT_SIGIO:
1357                     result = do_wait_sigio(ctl.offset);
1358                     break;
1359             }
1360             if( result != ctl.result ) {
1361                 fprintf(stderr,"Failure in %d:%s\n",
1362                         ctl.test, descriptions[ctl.test - 1]);
1363                 fprintf(stderr,"     Got %d, wanted %d\n",
1364                         result, ctl.result);
1365                 ctl.result = FAIL;
1366                 ctl.error = saved_errno;
1367                 fail_count++;
1368             } else {
1369                 ctl.result = PASS;
1370                 ctl.error = 0;
1371             }
1372             if(debug)
1373                 fprintf(stderr,"client: sending result to server (%d)\n", ctl.index);
1374             /* Send result to the server */
1375             send_ctl();
1376             if(last_test != tests[index][TEST_NUM]) {
1377                 test_count++;
1378                 last_test = tests[index][TEST_NUM];
1379             }
1380         }
1381     }
1382     fprintf(stderr, "%d tests run, %d failed\n", test_count, fail_count);
1383
1384     return fail_count;
1385 }