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