upload http
[bottlenecks.git] / rubbos / app / httpd-2.0.64 / srclib / apr / misc / unix / rand.c
1 /* Licensed to the Apache Software Foundation (ASF) under one or more
2  * contributor license agreements.  See the NOTICE file distributed with
3  * this work for additional information regarding copyright ownership.
4  * The ASF licenses this file to You under the Apache License, Version 2.0
5  * (the "License"); you may not use this file except in compliance with
6  * the License.  You may obtain a copy of the License at
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 #define APR_WANT_MEMFUNC
18 #include "apr_want.h"
19 #include "apr_general.h"
20
21 #include "apr_arch_misc.h"
22 #include <sys/stat.h>
23 #if APR_HAVE_SYS_TYPES_H
24 #include <sys/types.h>
25 #endif
26 #if APR_HAVE_SYS_SOCKET_H
27 #include <sys/socket.h>
28 #endif
29 #if APR_HAVE_FCNTL_H
30 #include <fcntl.h>
31 #endif
32 #if APR_HAVE_UNISTD_H
33 #include <unistd.h>
34 #endif
35 #if APR_HAVE_SYS_UN_H
36 #include <sys/un.h>
37 #endif
38
39 #ifndef SHUT_RDWR
40 #define SHUT_RDWR 2
41 #endif
42
43 #if APR_HAS_RANDOM
44
45 APR_DECLARE(apr_status_t) apr_generate_random_bytes(unsigned char *buf, 
46 #ifdef APR_ENABLE_FOR_1_0
47                                                     apr_size_t length)
48 #else
49                                                     int length)
50 #endif
51 {
52 #ifdef DEV_RANDOM
53
54     int fd = -1;
55
56     /* On BSD/OS 4.1, /dev/random gives out 8 bytes at a time, then
57      * gives EOF, so reading 'length' bytes may require opening the
58      * device several times. */
59     do {
60         apr_ssize_t rc;
61
62         if (fd == -1)
63             if ((fd = open(DEV_RANDOM, O_RDONLY)) == -1)
64                 return errno;
65         
66         rc = read(fd, buf, length);
67         if (rc < 0) {
68             int errnum = errno;
69             close(fd);
70             return errnum;
71         }
72         else if (rc == 0) {
73             close(fd);
74             fd = -1; /* force open() again */
75         }
76         else {
77             buf += rc;
78             length -= rc;
79         }
80     } while (length > 0);
81     
82     close(fd);
83 #elif defined(OS2)
84     static UCHAR randbyte();
85     unsigned int idx;
86
87     for (idx=0; idx<length; idx++)
88         buf[idx] = randbyte();
89
90 #elif defined(HAVE_EGD)
91     /* use EGD-compatible socket daemon (such as EGD or PRNGd).
92      * message format:
93      * 0x00 (get entropy level)
94      *   0xMM (msb) 0xmm 0xll 0xLL (lsb)
95      * 0x01 (read entropy nonblocking) 0xNN (bytes requested)
96      *   0xMM (bytes granted) MM bytes
97      * 0x02 (read entropy blocking) 0xNN (bytes desired)
98      *   [block] NN bytes
99      * 0x03 (write entropy) 0xMM 0xLL (bits of entropy) 0xNN (bytes of data) 
100      *      NN bytes
101      * (no response - write only) 
102      * 0x04 (report PID)
103      *   0xMM (length of PID string, not null-terminated) MM chars
104      */
105     static const char *egd_sockets[] = { EGD_DEFAULT_SOCKET, NULL };
106     const char **egdsockname = NULL;
107
108     int egd_socket, egd_path_len, rv, bad_errno;
109     struct sockaddr_un addr;
110     apr_socklen_t egd_addr_len;
111     apr_size_t resp_expected;
112     unsigned char req[2], resp[255];
113     unsigned char *curbuf = buf;
114
115     for (egdsockname = egd_sockets; *egdsockname && length > 0; egdsockname++) {
116         egd_path_len = strlen(*egdsockname);
117         
118         if (egd_path_len > sizeof(addr.sun_path)) {
119             return APR_EINVAL;
120         }
121
122         memset(&addr, 0, sizeof(struct sockaddr_un));
123         addr.sun_family = AF_UNIX;
124         memcpy(addr.sun_path, *egdsockname, egd_path_len);
125         egd_addr_len = APR_OFFSETOF(struct sockaddr_un, sun_path) + 
126           egd_path_len; 
127
128         egd_socket = socket(PF_UNIX, SOCK_STREAM, 0);
129
130         if (egd_socket == -1) {
131             return errno;
132         }
133
134         rv = connect(egd_socket, (struct sockaddr*)&addr, egd_addr_len);
135
136         if (rv == -1) {
137             bad_errno = errno;
138             continue;
139         }
140
141         /* EGD can only return 255 bytes of data at a time.  Silly.  */ 
142         while (length > 0) {
143             apr_ssize_t srv;
144             req[0] = 2; /* We'll block for now. */
145             req[1] = length > 255 ? 255: length;
146
147             srv = write(egd_socket, req, 2);
148             if (srv == -1) {
149                 bad_errno = errno;
150                 shutdown(egd_socket, SHUT_RDWR);
151                 close(egd_socket);
152                 break;
153             }
154
155             if (srv != 2) {
156                 shutdown(egd_socket, SHUT_RDWR);
157                 close(egd_socket);
158                 return APR_EGENERAL;
159             }
160             
161             resp_expected = req[1];
162             srv = read(egd_socket, resp, resp_expected);
163             if (srv == -1) {
164                 bad_errno = errno;
165                 shutdown(egd_socket, SHUT_RDWR);
166                 close(egd_socket);
167                 return bad_errno;
168             }
169             
170             memcpy(curbuf, resp, srv);
171             curbuf += srv;
172             length -= srv;
173         }
174         
175         shutdown(egd_socket, SHUT_RDWR);
176         close(egd_socket);
177     }
178
179     if (length > 0) {
180         /* We must have iterated through the list of sockets,
181          * and no go. Return the errno.
182          */
183         return bad_errno;
184     }
185
186 #elif defined(HAVE_TRUERAND) /* use truerand */
187
188     extern int randbyte(void);  /* from the truerand library */
189     unsigned int idx;
190
191     /* this will increase the startup time of the server, unfortunately...
192      * (generating 20 bytes takes about 8 seconds)
193      */
194     for (idx=0; idx<length; idx++)
195         buf[idx] = (unsigned char) randbyte();
196
197 #endif  /* DEV_RANDOM */
198
199     return APR_SUCCESS;
200 }
201
202 #undef  STR
203 #undef  XSTR
204
205 #ifdef OS2
206 #include "../os2/randbyte.c"
207 #endif
208
209 #endif /* APR_HAS_RANDOM */