Add IPv6 support.
[srvx.git] / src / compat.c
1 #undef gettimeofday
2 #undef memcpy
3 #undef memset
4 #undef strerror
5
6 #include "common.h"
7
8 #ifdef HAVE_SYS_TIMEB_H
9 # include <sys/timeb.h>
10 #endif
11 #ifdef HAVE_MEMORY_H
12 # include <memory.h>
13 #endif
14
15 #if !defined(HAVE_GETTIMEOFDAY) && defined(HAVE_FTIME)
16 extern gettimeofday(struct timeval * tv, struct timezone * tz);
17 {
18     if (!tv)
19     {
20         errno = EFAULT;
21         return -1;
22     }
23
24     struct timeb tb;
25
26     ftime(&tb); /* FIXME: some versions are void return others int */
27
28     tv->tv_sec  = tb.time;
29     tv->tv_usec = ((long)tb.millitm)*1000;
30     if (tz)
31     {
32         tz->tz_minuteswest = 0;
33         tz->tz_dsttime     = 0;
34     }
35
36     return 0;
37 }
38 #endif
39
40 #ifndef HAVE_MEMCPY
41 extern void * memcpy(void * dest, void const * src, unsigned long n)
42 {
43 /* very slow, your fault for not having memcpy()*/
44     unsigned char * td=dest;
45     unsigned char * ts=src;
46     unsigned long   i;
47
48     if (!td || !ts)
49         return NULL;
50
51     for (i=0; i<n; i++)
52         td[i] = ts[i];
53     return dest;
54 }
55 #endif
56
57 #ifndef HAVE_MEMSET
58 /* very slow, deal with it */
59 extern void * memset(void * dest, int c, unsigned long n)
60 {
61     unsigned char * temp=dest;
62     unsigned long   i;
63
64     if (!temp)
65         return NULL;
66
67     for (i=0; i<n; i++)
68         temp[i] = (unsigned char)c;
69     return dest;
70 }
71 #endif
72
73 #ifndef HAVE_STRDUP
74 extern char * strdup(char const * str)
75 {
76     char * out;
77
78     if (!str)
79         return NULL;
80     if (!(out = malloc(strlen(str)+1)))
81         return NULL;
82     strcpy(out,str);
83     return out;
84 }
85 #endif
86
87 #ifndef HAVE_STRERROR
88 extern char const * strerror(int errornum)
89 {
90     if (errornum==0)
91         return "No error";
92 #ifdef EPERM
93     if (errornum==EPERM)
94         return "Operation not permitted";
95 #endif
96 #ifdef ENOENT
97     if (errornum==ENOENT)
98         return "No such file or directory";
99 #endif
100 #ifdef ESRCH
101     if (errornum==ESRCH)
102         return "No such process";
103 #endif
104 #ifdef EINTR
105     if (errornum==EINTR)
106         return "Interrupted system call";
107 #endif
108 #ifdef EIO
109     if (errornum==EIO)
110         return "I/O error";
111 #endif
112 #ifdef ENXIO
113     if (errornum==EIO)
114         return "No such device or address";
115 #endif
116 #ifdef EBADF
117     if (errornum==EBADF)
118         return "Bad file number";
119 #endif
120 #ifdef EAGAIN
121     if (errornum==EAGAIN)
122         return "Try again";
123 #endif
124 #ifdef ENOMEM
125     if (errornum==ENOMEM)
126         return "Out of memory";
127 #endif
128 #ifdef EACCES
129     if (errornum==EACCES)
130         return "Permission denied";
131 #endif
132 #ifdef EFAULT
133     if (errornum==EFAULT)
134         return "Bad address";
135 #endif
136 #ifdef EBUSY
137     if (errornum==EBUSY)
138         return "Device or resource busy";
139 #endif
140 #ifdef EEXIST
141     if (errornum==EEXIST)
142         return "File exists";
143 #endif
144 #ifdef EXDEV
145     if (errornum==EXDEV)
146         return "Cross-device link";
147 #endif
148 #ifdef EDEADLK
149     if (errornum==EXDEV)
150         return "Resource deadlock would occur";
151 #endif
152 #ifdef EDEADLOCK
153     if (errornum==EDEADLOCK)
154         return "Resource deadlock would occur";
155 #endif
156 #ifdef ENODEV
157     if (errornum==ENODEV)
158         return "No such device";
159 #endif
160 #ifdef ENOTDIR
161     if (errornum==ENOTDIR)
162         return "Not a directory";
163 #endif
164 #ifdef EISDIR
165     if (errornum==EISDIR)
166         return "Is a directory";
167 #endif
168 #ifdef EINVAL
169     if (errornum==EINVAL)
170         return "Invalid argument";
171 #endif
172 #ifdef ENFILE
173     if (errornum==ENFILE)
174         return "Too many open files in system";
175 #endif
176 #ifdef EMFILE
177     if (errornum==EMFILE)
178         return "Too many open files";
179 #endif
180 #ifdef ENOTTY
181     if (errornum==ENOTTY)
182         return "Not a typewriter";
183 #endif
184 #ifdef ETXTBSY
185     if (errornum==ETXTBSY)
186         return "Text file busy";
187 #endif
188 #ifdef EFBIG
189     if (errornum==EFBIG)
190         return "File too large";
191 #endif
192 #ifdef ENOSPC
193     if (errornum==ENOSPC)
194         return "No space left on device";
195 #endif
196 #ifdef ESPIPE
197     if (errornum==ESPIPE)
198         return "Illegal seek";
199 #endif
200 #ifdef EROFS
201     if (errornum==EROFS)
202         return "Read-only file system";
203 #endif
204 #ifdef EMLINK
205     if (errornum==EMLINK)
206         return "Too many links";
207 #endif
208 #ifdef EPIPE
209     if (errornum==EPIPE)
210         return "Broken pipe";
211 #endif
212 #ifdef EDOM
213     if (errornum==EDOM)
214         return "Math argument out of domain of func";
215 #endif
216 #ifdef ERANGE
217     if (errornum==ERANGE)
218         return "Math result not representable";
219 #endif
220 #ifdef ENAMETOOLONG
221     if (errornum==ENAMETOOLONG)
222         return "File name too long";
223 #endif
224 #ifdef ENOLCK
225     if (errornum==ENOLCK)
226         return "No record locks avaliable";
227 #endif
228 #ifdef ENOSYS
229     if (errornum==ENOSYS)
230         return "Function not implemented";
231 #endif
232 #ifdef ENOTEMPTY
233     if (errornum==ENOTEMPTY)
234         return "Directory not empty";
235 #endif
236 #ifdef ELOOP
237     if (errornum==ELOOP)
238         return "Too many symbolic links encountered";
239 #endif
240 #ifdef EHOSTDOWN
241     if (errornum==EHOSTDOWN)
242         return "Host is down";
243 #endif
244 #ifdef EHOSTUNREACH
245     if (errornum==EHOSTUNREACH)
246         return "No route to host";
247 #endif
248 #ifdef EALREADY
249     if (errornum==EALREADY)
250         return "Operation already in progress";
251 #endif
252 #ifdef EINPROGRESS
253     if (errornum==EINPROGRESS)
254         return "Operation now in progress";
255 #endif
256 #ifdef ESTALE
257     if (errornum==ESTALE)
258         return "Stale NFS filehandle";
259 #endif
260 #ifdef EDQUOT
261     if (errornum==EDQUOT)
262         return "Quota exceeded";
263 #endif
264 #ifdef EWOULDBLOCK
265     if (errornum==EWOULDBLOCK)
266         return "Operation would block";
267 #endif
268 #ifdef ECOMM
269     if (errornum==ECOMM)
270         return "Communication error on send";
271 #endif
272 #ifdef EPROTO
273     if (errornum==EPROTO)
274         return "Protocol error";
275 #endif
276 #ifdef EPROTONOSUPPORT
277     if (errornum==EPROTONOSUPPORT)
278         return "Protocol not supported";
279 #endif
280 #ifdef ESOCKTNOSUPPORT
281     if (errornum==ESOCKTNOSUPPORT)
282         return "Socket type not supported";
283 #endif
284 #ifdef ESOCKTNOSUPPORT
285     if (errornum==EOPNOTSUPP)
286         return "Operation not supported";
287 #endif
288 #ifdef EPFNOSUPPORT
289     if (errornum==EPFNOSUPPORT)
290         return "Protocol family not supported";
291 #endif
292 #ifdef EAFNOSUPPORT
293     if (errornum==EAFNOSUPPORT)
294         return "Address family not supported by protocol family";
295 #endif
296 #ifdef EADDRINUSE
297     if (errornum==EADDRINUSE)
298         return "Address already in use";
299 #endif
300 #ifdef EADDRNOTAVAIL
301     if (errornum==EADDRNOTAVAIL)
302         return "Cannot assign requested address";
303 #endif
304 #ifdef ENETDOWN
305     if (errornum==ENETDOWN)
306         return "Network is down";
307 #endif
308 #ifdef ENETUNREACH
309     if (errornum==ENETUNREACH)
310         return "Network is unreachable";
311 #endif
312 #ifdef ENETRESET
313     if (errornum==ENETRESET)
314         return "Network dropped connection on reset";
315 #endif
316 #ifdef ECONNABORTED
317     if (errornum==ECONNABORTED)
318         return "Software caused connection abort";
319 #endif
320 #ifdef ECONNRESET
321     if (errornum==ECONNRESET)
322         return " Connection reset by peer";
323 #endif
324 #ifdef ENOBUFS
325     if (errornum==ENOBUFS)
326         return "No buffer space available";
327 #endif
328 #ifdef EISCONN
329     if (errornum==EISCONN)
330         return "Socket is already connected";
331 #endif
332 #ifdef ENOTCONN
333     if (errornum==ENOTCONN)
334         return "Socket is not connected";
335 #endif
336 #ifdef ESHUTDOWN
337     if (errornum==ESHUTDOWN)
338         return " Cannot send after socket shutdown";
339 #endif
340 #ifdef ETIMEDOUT
341     if (errornum==ETIMEDOUT)
342         return "Connection timed out";
343 #endif
344 #ifdef ECONNREFUSED
345     if (errornum==ECONNREFUSED)
346         return "Connection refused";
347 #endif
348     return "Unknown error";
349 }
350 #endif
351
352 #ifndef HAVE_GETADDRINFO
353
354 int getaddrinfo(const char *node, const char *service, const struct addrinfo *hints, struct addrinfo **res)
355 {
356     /* Only support IPv4 if OS doesn't provide this function. */
357     struct sockaddr_in sin;
358
359     if (hints && hints->ai_family != AF_INET)
360         return 1;
361     memset(&sin, 0, sizeof(sin));
362     sin.sin_family = AF_INET;
363
364     if (node) {
365         if (hints && hints->ai_flags & AI_NUMERICHOST) {
366             if (!inet_aton(node, &sin.sin_addr))
367                 return 2;
368         } else {
369             struct hostent *he;
370             he = gethostbyname(node);
371             if (!he)
372                 return 3;
373             memcpy(&sin.sin_addr, he->h_addr, he->h_length);
374         }
375     } else if (hints && hints->ai_flags & AI_PASSIVE) {
376         /* leave it unspecifed */
377     } else {
378         inet_aton("127.0.0.1", &sin.sin_addr);
379     }
380
381     if (!service)
382         sin.sin_port = ntohs(0);
383     else if (!(sin.sin_port = ntohs(atoi(service))))
384         return 4;
385
386     *res = calloc(1, sizeof(**res) + sizeof(sin));
387     (*res)->ai_family = sin.sin_family;
388     (*res)->ai_socktype = hints && hints->ai_socktype ? hints->ai_socktype : SOCK_STREAM;
389     (*res)->ai_protocol = hints && hints->ai_socktype ? hints->ai_socktype : 0;
390     (*res)->ai_addrlen = sizeof(sin);
391     (*res)->ai_addr = (struct sockaddr*)(*res + 1);
392     memcpy((*res)->ai_addr, &sin, (*res)->ai_addrlen);
393     (*res)->ai_canonname = 0;
394     (*res)->ai_next = 0;
395     return 0;
396 }
397
398 /* TODO: implement fallback getnameinfo() */
399
400 void freeaddrinfo(struct addrinfo *res)
401 {
402     struct addrinfo *next;
403     for (; res; res = next) {
404         next = res->ai_next;
405         free(res);
406     }
407 }
408
409 #endif