Imported Upstream version 1.15.1
[platform/upstream/krb5.git] / src / tests / threads / t_rcache.c
1 /* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2 /* tests/threads/t_rcache.c */
3 /*
4  * Copyright (C) 2006 by the Massachusetts Institute of Technology.
5  * All rights reserved.
6  *
7  * Export of this software from the United States of America may
8  *   require a specific license from the United States Government.
9  *   It is the responsibility of any person or organization contemplating
10  *   export to obtain such a license before exporting.
11  *
12  * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
13  * distribute this software and its documentation for any purpose and
14  * without fee is hereby granted, provided that the above copyright
15  * notice appear in all copies and that both that copyright notice and
16  * this permission notice appear in supporting documentation, and that
17  * the name of M.I.T. not be used in advertising or publicity pertaining
18  * to distribution of the software without specific, written prior
19  * permission.  Furthermore if you modify this software you must label
20  * your software as modified software and not distribute it in such a
21  * fashion that it might be confused with the original M.I.T. software.
22  * M.I.T. makes no representations about the suitability of
23  * this software for any purpose.  It is provided "as is" without express
24  * or implied warranty.
25  */
26
27 #include "k5-int.h"
28 #include <com_err.h>
29 #include <krb5.h>
30 #include <pthread.h>
31
32 krb5_context ctx;
33 krb5_rcache rcache;
34 krb5_data piece = { .data = "hello", .length = 5 };
35 time_t end_time;
36 const char *prog;
37
38 struct tinfo {
39     time_t now;
40     unsigned long my_ctime;
41     unsigned int my_cusec;
42     unsigned int total;
43     int idx;
44 };
45
46 #define DEFAULT_N_THREADS   2
47 #define DEFAULT_INTERVAL   20 /* 5 * 60 */
48
49 int init_once = 0;
50 int n_threads = DEFAULT_N_THREADS;
51 int interval = DEFAULT_INTERVAL;
52 int *ip;
53
54 static void wait_for_tick ()
55 {
56     time_t now, next;
57     now = time(0);
58     do {
59         next = time(0);
60     } while (now == next);
61 }
62
63 static void try_one (struct tinfo *t)
64 {
65     krb5_donot_replay r;
66     krb5_error_code err;
67     char buf[100], buf2[100];
68     krb5_rcache my_rcache;
69
70     snprintf(buf, sizeof(buf), "host/all-in-one.mit.edu/%p@ATHENA.MIT.EDU",
71              buf);
72     r.server = buf;
73     r.client = (t->my_cusec & 7) + "abcdefgh@ATHENA.MIT.EDU";
74     r.msghash = NULL;
75     if (t->now != t->my_ctime) {
76         if (t->my_ctime != 0) {
77             snprintf(buf2, sizeof(buf2), "%3d: %ld %5d\n", t->idx,
78                      t->my_ctime, t->my_cusec);
79             printf("%s", buf2);
80         }
81         t->my_ctime = t->now;
82         t->my_cusec = 1;
83     } else
84         t->my_cusec++;
85     r.ctime = t->my_ctime;
86     r.cusec = t->my_cusec;
87     if (!init_once) {
88         err = krb5_get_server_rcache(ctx, &piece, &my_rcache);
89         if (err) {
90             const char *msg = krb5_get_error_message(ctx, err);
91             fprintf(stderr, "%s: %s while initializing replay cache\n", prog, msg);
92             krb5_free_error_message(ctx, msg);
93             exit(1);
94         }
95     } else
96         my_rcache = rcache;
97     err = krb5_rc_store(ctx, my_rcache, &r);
98     if (err) {
99         com_err(prog, err, "storing in replay cache");
100         exit(1);
101     }
102     if (!init_once)
103         krb5_rc_close(ctx, my_rcache);
104 }
105
106 static void *run_a_loop (void *x)
107 {
108     struct tinfo t = { 0 };
109 /*    int chr = "ABCDEFGHIJKLMNOPQRSTUVWXYZ_"[(*(int*)x) % 27]; */
110
111     t.now = time(0);
112     t.idx = *(int *)x;
113     while (t.now != time(0))
114         ;
115     t.now = time(0);
116     while (t.now < end_time) {
117         t.now = time(0);
118         try_one(&t);
119         t.total++;
120 #if 0
121         printf("%c", chr);
122         fflush(stdout);
123 #endif
124     }
125 /*    printf("thread %u total %u\n", (unsigned) ((int *)x-ip), t.total);*/
126     *(int*)x = t.total;
127     return 0;
128 }
129
130 static void usage(void)
131 {
132     fprintf (stderr, "usage: %s [ options ]\n", prog);
133     fprintf (stderr, "options:\n");
134     fprintf (stderr, "\t-1\tcreate one rcache handle for process\n");
135     fprintf (stderr, "\t-t N\tnumber of threads to create (default: %d)\n",
136              DEFAULT_N_THREADS);
137     fprintf (stderr,
138              "\t-i N\tinterval to run test over, in seconds (default: %d)\n",
139              DEFAULT_INTERVAL);
140     exit(1);
141 }
142
143 static const char optstring[] = "1t:i:";
144
145 static void process_options (int argc, char *argv[])
146 {
147     int c;
148
149     prog = argv[0];
150     while ((c = getopt(argc, argv, optstring)) != -1) {
151         switch (c) {
152         case '?':
153         case ':':
154         default:
155             usage ();
156         case '1':
157             init_once = 1;
158             break;
159         case 't':
160             n_threads = atoi (optarg);
161             if (n_threads < 1 || n_threads > 10000)
162                 usage ();
163             break;
164         case 'i':
165             interval = atoi (optarg);
166             if (interval < 2 || n_threads > 100000)
167                 usage ();
168             break;
169         }
170     }
171 }
172
173 int main (int argc, char *argv[])
174 {
175     krb5_error_code err;
176     int i;
177     unsigned long sum;
178
179     process_options (argc, argv);
180     err = krb5_init_context(&ctx);
181     if (err) {
182         com_err(prog, err, "initializing context");
183         return 1;
184     }
185
186     /*
187      * For consistency, run the tests without an existing replay
188      * cache.  Since there isn't a way to ask the library for the
189      * pathname that would be used for the rcache, we create an rcache
190      * object and then destroy it.
191      */
192     err = krb5_get_server_rcache(ctx, &piece, &rcache);
193     if (err) {
194         const char *msg = krb5_get_error_message(ctx, err);
195         fprintf(stderr, "%s: %s while initializing replay cache\n", prog, msg);
196         krb5_free_error_message(ctx, msg);
197         return 1;
198     }
199     err = krb5_rc_destroy(ctx, rcache);
200     if (err) {
201         const char *msg = krb5_get_error_message(ctx, err);
202         fprintf(stderr, "%s: %s while destroying old replay cache\n",
203                 prog, msg);
204         krb5_free_error_message(ctx, msg);
205         return 1;
206     }
207     rcache = NULL;
208
209     if (init_once) {
210         err = krb5_get_server_rcache(ctx, &piece, &rcache);
211         if (err) {
212             const char *msg = krb5_get_error_message(ctx, err);
213             fprintf(stderr, "%s: %s while initializing new replay cache\n",
214                     prog, msg);
215             krb5_free_error_message(ctx, msg);
216             return 1;
217         }
218     }
219
220     ip = malloc(sizeof(int) * n_threads);
221     if (ip == 0 && n_threads > 0) {
222         perror("malloc");
223         exit(1);
224     }
225     for (i = 0; i < n_threads; i++)
226         ip[i] = i;
227
228     wait_for_tick ();
229     end_time = time(0) + interval;
230
231     for (i = 0; i < n_threads; i++) {
232         pthread_t new_thread;
233         int perr;
234         perr = pthread_create(&new_thread, 0, run_a_loop, &ip[i]);
235         if (perr) {
236             errno = perr;
237             perror("pthread_create");
238             exit(1);
239         }
240     }
241     while (time(0) < end_time + 1)
242         sleep(1);
243     sum = 0;
244     for (i = 0; i < n_threads; i++) {
245         sum += ip[i];
246         printf("thread %d total %5d, about %.1f per second\n", i, ip[i],
247                ((double) ip[i])/interval);
248     }
249     printf("total %lu in %d seconds, avg ~%.1f/sec, ~%.1f/sec/thread\n",
250            sum, interval,
251            ((double)sum)/interval, ((double)sum)/interval/n_threads);
252     free(ip);
253
254     if (init_once)
255         krb5_rc_close(ctx, rcache);
256     krb5_free_context(ctx);
257     return 0;
258 }