Cope with lack of gnutls_certificate_set_key() in GnuTLS 2.12
[platform/upstream/openconnect.git] / compat.c
1 /*
2  * OpenConnect (SSL + DTLS) VPN client
3  *
4  * Copyright © 2008-2012 Intel Corporation.
5  *
6  * Authors: David Woodhouse <dwmw2@infradead.org>
7  *
8  * This program is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Lesser General Public License
10  * version 2.1, as published by the Free Software Foundation.
11  *
12  * This program is distributed in the hope that it will be useful, but
13  * WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this library; if not, write to:
19  *
20  *   Free Software Foundation, Inc.
21  *   51 Franklin Street, Fifth Floor,
22  *   Boston, MA 02110-1301 USA
23  */
24
25 #include "openconnect-internal.h"
26
27 #ifdef __sun__
28 #include <sys/time.h>
29
30 time_t openconnect__time(time_t *t)
31 {
32         time_t s = gethrtime() / 1000000000LL;
33         if (t)
34                 *t = s;
35
36         return s;
37 }
38 #endif
39
40 #ifndef HAVE_ASPRINTF
41 #include <stdarg.h>
42 #include <errno.h>
43
44 static int oc_vasprintf(char **strp, const char *fmt, va_list ap)
45 {
46         va_list ap2;
47         char *res = NULL;
48         int len = 160, len2;
49         int ret = 0;
50         int errno_save = -ENOMEM;
51
52         res = malloc(160);
53         if (!res)
54                 goto err;
55
56         /* Use a copy of 'ap', preserving it in case we need to retry into
57            a larger buffer. 160 characters should be sufficient for most
58            strings in openconnect. */
59 #ifdef HAVE_VA_COPY
60         va_copy(ap2, ap);
61 #elif defined (HAVE___VA_COPY)
62         __va_copy(ap2, ap);
63 #else
64 #error No va_copy()!
65         // You could try this.
66         ap2 = ap;
67         // Or this
68         *ap2 = *ap;
69 #endif
70         len = vsnprintf(res, 160, fmt, ap2);
71         va_end(ap2);
72
73         if (len < 0) {
74         printf_err:
75                 errno_save = errno;
76                 free(res);
77                 res = NULL;
78                 goto err;
79         }
80         if (len >=0 && len < 160)
81                 goto out;
82
83         free(res);
84         res = malloc(len+1);
85         if (!res)
86                 goto err;
87
88         len2 = vsnprintf(res, len+1, fmt, ap);
89         if (len2 < 0 || len2 > len)
90                 goto printf_err;
91
92         ret = 0;
93         goto out;
94
95  err:
96         errno = errno_save;
97         ret = -1;
98  out:
99         *strp = res;
100         return ret;
101 }
102
103 int openconnect__asprintf(char **strp, const char *fmt, ...)
104 {
105         va_list ap;
106         int ret;
107
108         va_start(ap, fmt);
109         ret = oc_vasprintf(strp, fmt, ap);
110         va_end(ap);
111         return ret;
112 }
113 #endif
114
115 #ifndef HAVE_GETLINE
116 ssize_t openconnect__getline(char **lineptr, size_t *n, FILE *stream)
117 {
118         int len = 0;
119
120         if (!*lineptr) {
121                 *n = 2;
122                 *lineptr = malloc(*n);
123                 if (!*lineptr)
124                         return -1;
125         }
126
127         while (fgets((*lineptr) + len, (*n) - len, stream)) {
128
129                 len += strlen((*lineptr) + len);
130                 if ((*lineptr)[len-1] == '\n')
131                         break;
132
133                 *n *= 2;
134                 *lineptr = realloc(*lineptr, *n);
135                 if (!*lineptr)
136                         return -1;
137         }
138         if (len)
139                 return len;
140         return -1;
141 }
142 #endif