1 /*
2 * util.c -- common utility routines for thrulay.
3 *
4 * Written by Stanislav Shalunov, http://www.internet2.edu/~shalunov/
5 * Bernhard Lutzmann, belu@users.sf.net
6 * Federico Montesino Pouzols, fedemp@altern.org
7 *
8 * Copyright 2003, 2006, Internet2.
9 * Legal conditions are in file LICENSE
10 * (MD5 = ecfa50d1b0bfbb81b658c810d0476a52).
11 */
12
13 #ifdef HAVE_CONFIG_H
14 #include <config.h>
15 #endif
16
17 #include <stdio.h>
18 #include <string.h>
19 #include <stdlib.h>
20 #include <sys/types.h>
21 #ifndef WIN32
22 #include <sys/socket.h>
23 #include <netinet/in.h>
24 #endif
25 #include "util.h"
26 #include "rcs.h"
27
28 #ifndef SOL_IP
29 #ifdef IPPROTO_IP
30 #define SOL_IP IPPROTO_IP
31 #endif
32 #endif
33
34 #ifndef SOL_IPV6
35 #ifdef IPPROTO_IPV6
36 #define SOL_IPV6 IPPROTO_IPV6
37 #endif
38 #endif
39
40 RCS_ID("@(#) $Id: util.c,v 1.1.1.1.2.6 2006/08/20 18:06:19 fedemp Exp $")
41
42 #ifndef HAVE_GETRUSAGE
43 #ifdef WIN32
44 /* Implementation of getrusage based on Windows native calls. Note
45 this is a minimal implementation that only fills in the fields used
46 by the thrulay server (ru_utime and ru_stime) with the times for
47 the current thread. */
getrusage(int process,struct rusage * rusage)48 int getrusage(int process, struct rusage* rusage)
49 {
50 FILETIME f_kernel, f_user;
51 HANDLE thread = OpenThread(THREAD_QUERY_INFORMATION, FALSE,
52 GetCurrentThreadId());
53
54 if (GetThreadTimes(thread, NULL, NULL, &f_kernel, &f_user) ) {
55 LONGLONG t_user = *(LONGLONG*)&f_user;
56 LONGLONG t_kernel = *(LONGLONG*)&f_kernel;
57 if (rusage) {
58 rusage->ru_utime.tv_usec = (DWORD)(t_user/10);
59 rusage->ru_stime.tv_usec = (DWORD)(t_kernel / 10);
60 }
61 } else {
62 if (rusage)
63 memset(rusage, 0, sizeof(rusage));
64 }
65
66 return 0;
67 }
68 #endif
69 #endif
70
71 #ifdef WIN32
72
73 int
gettimeofday(struct timeval * tv,void * tz)74 gettimeofday(struct timeval *tv, void *tz)
75 {
76 DWORD ms = GetTickCount();
77 tv->tv_sec = ms / 1000;
78 tv->tv_usec = ms * 1000;
79 return 0;
80 }
81
82 #ifdef HAVE_W32_GETADDRINFO
inet_ntop(int af,const void * src,char * dst,socklen_t cnt)83 const char *inet_ntop(int af, const void *src, char *dst, socklen_t cnt)
84 {
85 socklen_t len;
86
87 switch (af) {
88 case AF_INET:
89 len = sizeof(struct sockaddr_in);
90 break;
91 case AF_INET6:
92 len = sizeof(struct sockaddr_in6);
93 break;
94 default:
95 return NULL;
96 }
97
98 if ( 0 != getnameinfo((struct sockaddr *)src, len, dst, cnt,
99 NULL, 0, NI_NUMERICHOST) )
100 return NULL;
101
102 return dst;
103 }
104
gai_strerror(int errcode)105 const char *gai_strerror(int errcode)
106 {
107 static char result[256];
108
109 /* Obviously, this is not the best solution. A list of error
110 descriptions should be added at some time. */
111 snprintf(result,sizeof(result),
112 "error code: %d; no description available on Windows",
113 errcode);
114
115 return result;
116 }
117
118 #endif
119
120 #endif /* ifdef WIN32 */
121
122 void
error(int errcode,const char * msg)123 error(int errcode, const char *msg)
124 {
125 const char *prefix;
126 int fatal = 1;
127
128 if (errcode == ERR_FATAL) {
129 prefix = "fatal";
130 } else if (errcode == ERR_WARNING) {
131 prefix = "warning";
132 fatal = 0;
133 } else {
134 prefix = "UNKNOWN ERROR TYPE";
135 }
136 fprintf(stderr, "%s: %s\n", prefix, msg);
137 if (fatal)
138 exit(1);
139 }
140
141 ssize_t
recv_exactly(int d,void * buf,size_t nbytes)142 recv_exactly(int d, void *buf, size_t nbytes)
143 {
144 ssize_t rc = 0;
145 size_t bytes_read = 0;
146 while (bytes_read < nbytes &&
147 /* In Win32, read/write don't work with sockets! */
148 #ifndef WIN32
149 (rc = read(d, (char *)buf+bytes_read,
150 nbytes-bytes_read)) > 0)
151 #else
152 (rc = recv(d, (char *)buf+bytes_read,
153 nbytes-bytes_read, 0)) > 0)
154 #endif
155 bytes_read += rc;
156 return rc == -1? rc: (ssize_t) bytes_read;
157 }
158
159 ssize_t
write_exactly(int d,const void * buf,size_t nbytes)160 write_exactly(int d, const void *buf, size_t nbytes)
161 {
162 ssize_t rc = 0;
163 size_t bytes_written = 0;
164 while (bytes_written < nbytes &&
165 (rc = write(d, (const char *)buf+bytes_written,
166 nbytes-bytes_written)) > 0)
167 bytes_written += rc;
168 return rc == -1? rc: (ssize_t) bytes_written;
169 }
170
171 ssize_t
send_exactly(int d,const void * buf,size_t nbytes)172 send_exactly(int d, const void *buf, size_t nbytes)
173 {
174 ssize_t rc = 0;
175 size_t bytes_written = 0;
176 /* In Win32, read/write don't work with sockets! */
177 #ifndef WIN32
178 while (bytes_written < nbytes &&
179 (rc = write(d, (const char *)buf+bytes_written,
180 nbytes-bytes_written)) > 0)
181 #else
182 while (bytes_written < nbytes &&
183 (rc = send(d, (const char *)buf+bytes_written,
184 nbytes-bytes_written, 0)) > 0)
185 #endif
186 bytes_written += rc;
187 return rc == -1? rc: (ssize_t) bytes_written;
188 }
189
190 double
time_diff(const struct timeval * tv1,const struct timeval * tv2)191 time_diff(const struct timeval *tv1, const struct timeval *tv2)
192 {
193 return (double) (tv2->tv_sec - tv1->tv_sec)
194 + (double) (tv2->tv_usec - tv1->tv_usec)/1000000.0;
195 }
196
197 /* Set window size for file descriptor FD (which must point to a
198 socket) to WINDOW for given direction DIRECTION (typically
199 SO_SNDBUF or SO_RCVBUF). Try hard. Return actual window size. */
200 int
set_window_size_directed(int fd,int window,int direction)201 set_window_size_directed(int fd, int window, int direction)
202 {
203 int rc, try, w;
204 unsigned int optlen = sizeof w;
205
206 rc = getsockopt(fd, SOL_SOCKET, direction, (char *)&w, &optlen);
207 if (rc == -1)
208 return -1;
209 if (window <= 0)
210 return w;
211
212 try = window;
213 do {
214 rc = setsockopt(fd, SOL_SOCKET, direction,
215 (char *)&try, optlen);
216 try *= 7;
217 try /= 8;
218 } while (try > w && rc == -1);
219
220 rc = getsockopt(fd, SOL_SOCKET, direction, (char *)&w, &optlen);
221 if (rc == -1)
222 return -1;
223 else
224 return w;
225 }
226
227 /* Set window size for file descriptor FD (which must point to a
228 socket) to WINDOW. Try hard. Return actual window size. */
229 int
set_window_size(int fd,int window)230 set_window_size(int fd, int window)
231 {
232 int send, receive;
233
234 send = set_window_size_directed(fd, window, SO_SNDBUF);
235 receive = set_window_size_directed(fd, window, SO_RCVBUF);
236 return send < receive? send: receive;
237 }
238
239 /* Set RFC 2474 style DSCP value for TOS byte. Returns 0 on success, -1 on
240 * failure. */
241 int
set_dscp(int sock,uint8_t dscp)242 set_dscp(int sock, uint8_t dscp)
243 {
244 int optname = IP_TOS;
245 int optlevel = SOL_IP;
246 int sopt;
247
248 if ((dscp & ~0x3F)) {
249 fprintf(stderr, "Error: set_dscp(): bad DSCP value.\n");
250 return -1;
251 }
252
253 /* Shift to set CU to zero
254 *
255 * 0 1 2 3 4 5 6 7
256 * +---+---+---+---+---+---+---+---+
257 * | DSCP | CU |
258 * +---+---+---+---+---+---+---+---+
259 */
260 sopt = dscp << 2;
261
262 {
263 struct sockaddr_storage addr;
264 socklen_t len = sizeof(addr);
265
266 if (getsockname(sock, (struct sockaddr *)&addr,
267 &len) == -1) {
268 perror("getsockname");
269 return -1;
270 }
271
272 switch (((struct sockaddr *)&addr)->sa_family) {
273 case AF_INET:
274 optlevel = SOL_IP;
275 optname = IP_TOS;
276 break;
277 case AF_INET6:
278 #ifdef IPV6_TCLASS
279 optlevel = SOL_IPV6;
280 optname = IPV6_TCLASS;
281 break;
282 #else
283 error(ERR_WARNING, "system does not support setting "
284 "DSCP value in IPv6 traffic class.");
285 return 0; /* return 0 so we don't get two
286 error messages. */
287 #endif
288 default:
289 error(ERR_WARNING, "set_dscp(): Unknown address "
290 "family");
291 return -1;
292 }
293 }
294
295 if (setsockopt(sock, optlevel, optname, (char *)&sopt,
296 sizeof(sopt)) == -1) {
297 perror("setsockopt");
298 return -1;
299 }
300
301 return 0;
302 }
303
304 #define NTP_EPOCH_OFFSET 2208988800ULL
305
306 /*
307 * Convert `timeval' structure value into NTP format (RFC 1305) timestamp.
308 * The ntp pointer must resolve to already allocated memory (8 bytes) that
309 * will contain the result of the conversion.
310 * NTP format is 4 octets of unsigned integer number of whole seconds since
311 * NTP epoch, followed by 4 octets of unsigned integer number of
312 * fractional seconds (both numbers are in network byte order).
313 */
314 void
tv2ntp(const struct timeval * tv,char * ntp)315 tv2ntp(const struct timeval *tv, char *ntp)
316 {
317 uint32_t msb, lsb;
318
319 msb = tv->tv_sec + NTP_EPOCH_OFFSET;
320 lsb = (uint32_t)((double)tv->tv_usec * 4294967296.0 / 1000000.0);
321
322 msb = htonl(msb);
323 lsb = htonl(lsb);
324
325 memcpy(ntp, &msb, sizeof(msb));
326 memcpy(ntp + sizeof(msb), &lsb, sizeof(lsb));
327 }
328
329 /*
330 * Convert 8-byte NTP format timestamp into `timeval' structure value.
331 * The counterpart to tv2ntp().
332 */
333 void
ntp2tv(struct timeval * tv,const char * ntp)334 ntp2tv(struct timeval *tv, const char *ntp)
335 {
336 uint32_t msb, lsb;
337
338 memcpy(&msb, ntp, sizeof(msb));
339 memcpy(&lsb, ntp + sizeof(msb), sizeof(lsb));
340
341 msb = ntohl(msb);
342 lsb = ntohl(lsb);
343
344 tv->tv_sec = msb - NTP_EPOCH_OFFSET;
345 tv->tv_usec = (uint32_t)((double)lsb * 1000000.0 / 4294967296.0);
346 }
347
348 /* Make sure 0 <= tv.tv_usec < 1000000. Return 0 if it was normal,
349 * positive number otherwise. */
350 int
normalize_tv(struct timeval * tv)351 normalize_tv(struct timeval *tv)
352 {
353 int result = 0;
354
355 while (tv->tv_usec >= 1000000) {
356 tv->tv_usec -= 1000000;
357 tv->tv_sec++;
358 result++;
359 }
360 while (tv->tv_usec < 0) {
361 tv->tv_usec += 1000000;
362 tv->tv_sec--;
363 result++;
364 }
365 return result;
366 }
367
368 #ifndef HAVE_SYSLOG_H
369
370 /* Definition of logging functions when missing. Logs are written to a
371 '.log' file. */
372
373 FILE *syslog_file;
374 int syslog_pid;
375 char *syslog_filename_suffix = "-syslog.log";
376 char *syslog_ident;
377
378 void
openlog(const char * ident,int option,int facility)379 openlog(const char *ident, int option, int facility)
380 {
381 const size_t buf_max_size = 256;
382 char buf[buf_max_size];
383
384 syslog_ident = strdup(ident);
385 /* Concatenate ident + syslog_filename_suffix */
386 memccpy(buf, ident, '\0',
387 buf_max_size - strlen(syslog_filename_suffix) - 1);
388 strncpy(buf + strlen(ident), syslog_filename_suffix,
389 strlen(syslog_filename_suffix) + 1);
390
391 if (syslog_file)
392 fclose(syslog_file);
393
394 syslog_file = fopen(buf, "a");
395 }
396
397 void
syslog(int priority,const char * format,...)398 syslog(int priority, const char *format, ...)
399 {
400 const char *priority_string[] = { "", "alert", "",
401 "error", "warning", "notice" };
402 const size_t line_max_size = 512;
403 char line[line_max_size];
404 int rc;
405 time_t now;
406 struct tm *dt;
407 va_list ap;
408
409 time(&now);
410 dt = localtime(&now);
411
412 rc = snprintf(line, line_max_size,
413 "%04d-%02d-%02d %02d:%02d:%02d %s(%s): ",
414 dt->tm_year + 1900, dt->tm_mon + 1, dt->tm_mday,
415 dt->tm_hour, dt->tm_min, dt->tm_sec,
416 syslog_ident, priority_string[priority]);
417
418 va_start(ap, format);
419 vsnprintf(line + rc, line_max_size - rc, format, ap);
420 va_end(ap);
421
422 if (syslog_file) {
423 fputs(line, syslog_file);
424 fputs("\n", syslog_file);
425 }
426 }
427
428 void
closelog(void)429 closelog(void)
430 {
431 if (syslog_file)
432 fclose(syslog_file);
433 free(syslog_ident);
434 }
435
436 #endif /* HAVE_SYSLOG_H */
437