Imported Upstream version 1.10.2
[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 <stdio.h>
28 #include <com_err.h>
29
30 #include "k5-int.h"
31 #include <krb5.h>
32 #include <pthread.h>
33
34 krb5_context ctx;
35 krb5_rcache rcache;
36 krb5_data piece = { .data = "hello", .length = 5 };
37 time_t end_time;
38 const char *prog;
39
40 struct tinfo {
41     time_t now;
42     unsigned long my_ctime;
43     unsigned int my_cusec;
44     unsigned int total;
45     int idx;
46 };
47
48 #define DEFAULT_N_THREADS   2
49 #define DEFAULT_INTERVAL   20 /* 5 * 60 */
50
51 int init_once = 0;
52 int n_threads = DEFAULT_N_THREADS;
53 int interval = DEFAULT_INTERVAL;
54 int *ip;
55
56 static void wait_for_tick ()
57 {
58     time_t now, next;
59     now = time(0);
60     do {
61         next = time(0);
62     } while (now == next);
63 }
64
65 static void try_one (struct tinfo *t)
66 {
67     krb5_donot_replay r;
68     krb5_error_code err;
69     char buf[100], buf2[100];
70     krb5_rcache my_rcache;
71
72     snprintf(buf, sizeof(buf), "host/all-in-one.mit.edu/%p@ATHENA.MIT.EDU",
73              buf);
74     r.server = buf;
75     r.client = (t->my_cusec & 7) + "abcdefgh@ATHENA.MIT.EDU";
76     r.msghash = NULL;
77     if (t->now != t->my_ctime) {
78         if (t->my_ctime != 0) {
79             snprintf(buf2, sizeof(buf2), "%3d: %ld %5d\n", t->idx,
80                      t->my_ctime, t->my_cusec);
81             printf("%s", buf2);
82         }
83         t->my_ctime = t->now;
84         t->my_cusec = 1;
85     } else
86         t->my_cusec++;
87     r.ctime = t->my_ctime;
88     r.cusec = t->my_cusec;
89     if (!init_once) {
90         err = krb5_get_server_rcache(ctx, &piece, &my_rcache);
91         if (err) {
92             const char *msg = krb5_get_error_message(ctx, err);
93             fprintf(stderr, "%s: %s while initializing replay cache\n", prog, msg);
94             krb5_free_error_message(ctx, msg);
95             exit(1);
96         }
97     } else
98         my_rcache = rcache;
99     err = krb5_rc_store(ctx, my_rcache, &r);
100     if (err) {
101         com_err(prog, err, "storing in replay cache");
102         exit(1);
103     }
104     if (!init_once)
105         krb5_rc_close(ctx, my_rcache);
106 }
107
108 static void *run_a_loop (void *x)
109 {
110     struct tinfo t = { 0 };
111 /*    int chr = "ABCDEFGHIJKLMNOPQRSTUVWXYZ_"[(*(int*)x) % 27]; */
112
113     t.now = time(0);
114     t.idx = *(int *)x;
115     while (t.now != time(0))
116         ;
117     t.now = time(0);
118     while (t.now < end_time) {
119         t.now = time(0);
120         try_one(&t);
121         t.total++;
122 #if 0
123         printf("%c", chr);
124         fflush(stdout);
125 #endif
126     }
127 /*    printf("thread %u total %u\n", (unsigned) ((int *)x-ip), t.total);*/
128     *(int*)x = t.total;
129     return 0;
130 }
131
132 static void usage(void)
133 {
134     fprintf (stderr, "usage: %s [ options ]\n", prog);
135     fprintf (stderr, "options:\n");
136     fprintf (stderr, "\t-1\tcreate one rcache handle for process\n");
137     fprintf (stderr, "\t-t N\tnumber of threads to create (default: %d)\n",
138              DEFAULT_N_THREADS);
139     fprintf (stderr,
140              "\t-i N\tinterval to run test over, in seconds (default: %d)\n",
141              DEFAULT_INTERVAL);
142     exit(1);
143 }
144
145 static const char optstring[] = "1t:i:";
146
147 static void process_options (int argc, char *argv[])
148 {
149     int c;
150
151     prog = argv[0];
152     while ((c = getopt(argc, argv, optstring)) != -1) {
153         switch (c) {
154         case '?':
155         case ':':
156         default:
157             usage ();
158         case '1':
159             init_once = 1;
160             break;
161         case 't':
162             n_threads = atoi (optarg);
163             if (n_threads < 1 || n_threads > 10000)
164                 usage ();
165             break;
166         case 'i':
167             interval = atoi (optarg);
168             if (interval < 2 || n_threads > 100000)
169                 usage ();
170             break;
171         }
172     }
173 }
174
175 int main (int argc, char *argv[])
176 {
177     krb5_error_code err;
178     int i;
179     unsigned long sum;
180
181     process_options (argc, argv);
182     err = krb5_init_context(&ctx);
183     if (err) {
184         com_err(prog, err, "initializing context");
185         return 1;
186     }
187
188     /*
189      * For consistency, run the tests without an existing replay
190      * cache.  Since there isn't a way to ask the library for the
191      * pathname that would be used for the rcache, we create an rcache
192      * object and then destroy it.
193      */
194     err = krb5_get_server_rcache(ctx, &piece, &rcache);
195     if (err) {
196         const char *msg = krb5_get_error_message(ctx, err);
197         fprintf(stderr, "%s: %s while initializing replay cache\n", prog, msg);
198         krb5_free_error_message(ctx, msg);
199         return 1;
200     }
201     err = krb5_rc_destroy(ctx, rcache);
202     if (err) {
203         const char *msg = krb5_get_error_message(ctx, err);
204         fprintf(stderr, "%s: %s while destroying old replay cache\n",
205                 prog, msg);
206         krb5_free_error_message(ctx, msg);
207         return 1;
208     }
209     rcache = NULL;
210
211     if (init_once) {
212         err = krb5_get_server_rcache(ctx, &piece, &rcache);
213         if (err) {
214             const char *msg = krb5_get_error_message(ctx, err);
215             fprintf(stderr, "%s: %s while initializing new replay cache\n",
216                     prog, msg);
217             krb5_free_error_message(ctx, msg);
218             return 1;
219         }
220     }
221
222     ip = malloc(sizeof(int) * n_threads);
223     if (ip == 0 && n_threads > 0) {
224         perror("malloc");
225         exit(1);
226     }
227     for (i = 0; i < n_threads; i++)
228         ip[i] = i;
229
230     wait_for_tick ();
231     end_time = time(0) + interval;
232
233     for (i = 0; i < n_threads; i++) {
234         pthread_t new_thread;
235         int perr;
236         perr = pthread_create(&new_thread, 0, run_a_loop, &ip[i]);
237         if (perr) {
238             errno = perr;
239             perror("pthread_create");
240             exit(1);
241         }
242     }
243     while (time(0) < end_time + 1)
244         sleep(1);
245     sum = 0;
246     for (i = 0; i < n_threads; i++) {
247         sum += ip[i];
248         printf("thread %d total %5d, about %.1f per second\n", i, ip[i],
249                ((double) ip[i])/interval);
250     }
251     printf("total %lu in %d seconds, avg ~%.1f/sec, ~%.1f/sec/thread\n",
252            sum, interval,
253            ((double)sum)/interval, ((double)sum)/interval/n_threads);
254     free(ip);
255
256     if (init_once)
257         krb5_rc_close(ctx, rcache);
258     krb5_free_context(ctx);
259     return 0;
260 }