ef3dfc2a76b73951c5c230f801fb334f5d7527f1
[olsrd.git] / lib / tas / src / os_unix.c
1
2 /*
3  * The olsr.org Optimized Link-State Routing daemon (olsrd)
4  *
5  * Copyright (c) 2004, Thomas Lopatic (thomas@olsr.org)
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  *
12  * * Redistributions of source code must retain the above copyright
13  *   notice, this list of conditions and the following disclaimer.
14  * * Redistributions in binary form must reproduce the above copyright
15  *   notice, this list of conditions and the following disclaimer in
16  *   the documentation and/or other materials provided with the
17  *   distribution.
18  * * Neither the name of olsr.org, olsrd nor the names of its
19  *   contributors may be used to endorse or promote products derived
20  *   from this software without specific prior written permission.
21  *
22  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
23  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
24  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
25  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
26  * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
27  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
28  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
29  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
30  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
32  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
33  * POSSIBILITY OF SUCH DAMAGE.
34  *
35  * Visit http://www.olsr.org for more information.
36  *
37  * If you find this software useful feel free to make a donation
38  * to the project. For more information see the website or contact
39  * the copyright holders.
40  *
41  */
42
43 #if defined linux
44
45 #include "link.h"
46 #include "plugin.h"
47 #include "lib.h"
48 #include "os_unix.h"
49 #include "http.h"
50 #include "glua.h"
51 #include "glua_ext.h"
52 #include "defs.h" /* ARM_NOWARN_ALIGN */
53
54 #include <sys/types.h>
55 #include <sys/socket.h>
56 #include <arpa/inet.h>
57 #include <unistd.h>
58 #include <stdio.h>
59 #include <errno.h>
60 #include <string.h>
61 #include <fcntl.h>
62 #include <stdlib.h>
63 #include <sys/select.h>
64 #include <sys/stat.h>
65 #include <sys/time.h>
66 #include <time.h>
67
68 static int mainSocket;
69
70 void
71 getRandomBytes(unsigned char *buff, int len)
72 {
73   int file;
74   int readLen;
75
76   memset(buff, 0, len);
77
78   file = open("/dev/random", O_RDONLY);
79
80   if (file < 0) {
81     fprintf(stderr, "warning: cannot open /dev/random\n");
82     return;
83   }
84
85   while (len > 0) {
86     readLen = read(file, buff, len);
87
88     if (readLen < 0) {
89       fprintf(stderr, "warning: cannot read from /dev/random\n");
90       close(file);
91       return;
92     }
93
94     buff += readLen;
95     len -= readLen;
96   }
97
98   close(file);
99 }
100
101 int
102 addrLen(int family)
103 {
104   return (family == AF_INET) ? sizeof(struct in_addr) : sizeof(struct in6_addr);
105 }
106
107 void
108 os_now(struct timeStamp *timeStamp)
109 {
110   timeStamp->time = time(NULL);
111 }
112
113 int
114 timedOut(struct timeStamp *timeStamp, int sec)
115 {
116   time_t now;
117
118   time(&now);
119
120   if ((time_t) (timeStamp->time + sec) > now)
121     return -1;
122
123   return 0;
124 }
125
126 unsigned int
127 getMicro(void)
128 {
129   struct timeval timeVal;
130   static struct timeval timeValPrev;
131   static int firstTime = 1;
132
133   gettimeofday(&timeVal, NULL);
134
135   if (firstTime == 0 && timeValPrev.tv_sec == timeVal.tv_sec && timeValPrev.tv_usec >= timeVal.tv_usec)
136     return timeValPrev.tv_sec * 1000000 + timeValPrev.tv_usec;
137
138   firstTime = 0;
139
140   timeValPrev.tv_sec = timeVal.tv_sec;
141   timeValPrev.tv_usec = timeVal.tv_usec;
142
143   return timeVal.tv_sec * 1000000 + timeVal.tv_usec;
144 }
145
146 void *
147 allocMem(int len)
148 {
149   void *res;
150
151   res = malloc(len);
152
153   if (res == NULL) {
154     fprintf(stderr, "cannot allocate %d bytes\n", len);
155     exit(0);
156   }
157
158   memset(res, 0, len);
159
160   return res;
161 }
162
163 void
164 freeMem(void *mem)
165 {
166   free(mem);
167 }
168
169 int
170 writeFileOs(const struct fileId *fileId, const unsigned char *data, int len)
171 {
172   int writeLen;
173
174   if (len == 0)
175     return 0;
176
177   do
178     writeLen = write(fileId->fileDesc, data, len);
179   while (writeLen < 0 && errno == EINTR);
180
181   if (writeLen < 0) {
182     if (errno == EAGAIN)
183       return 0;
184
185     error("cannot write to file descriptor: %s\n", strerror(errno));
186     return -1;
187   }
188
189   return writeLen;
190 }
191
192 int
193 readFileOs(const struct fileId *fileId, unsigned char *data, int len)
194 {
195   int readLen;
196
197   if (len == 0)
198     return 0;
199
200   do
201     readLen = read(fileId->fileDesc, data, len);
202   while (readLen < 0 && errno == EINTR);
203
204   if (readLen < 0) {
205     if (errno == EAGAIN)
206       return 0;
207
208     error("cannot read from file descriptor: %s\n", strerror(errno));
209     return -1;
210   }
211
212   if (readLen == 0)
213     return -1;
214
215   return readLen;
216 }
217
218 int
219 checkAbsPath(const char *path)
220 {
221   if (path[0] != '/')
222     return -1;
223
224   return 0;
225 }
226
227 char *
228 fullPath(const char *dir, const char *path)
229 {
230   int dirLen = strlen(dir);
231   int pathLen = strlen(path);
232   char *buff = allocMem(dirLen + pathLen + 2);
233
234   memcpy(buff, dir, dirLen);
235
236   if (dirLen == 0 || buff[dirLen - 1] == '/')
237     dirLen--;
238
239   else
240     buff[dirLen] = '/';
241
242   memcpy(buff + dirLen + 1, path, pathLen + 1);
243
244   return buff;
245 }
246
247 void
248 setExtension(char *res, const char *path, const char *ext)
249 {
250   int i;
251   int len = strlen(path);
252
253   for (i = len - 1; i >= 0 && path[i] != '.' && path[i] != '/'; i--);
254
255   if (path[i] == '.')
256     len = i;
257
258   memcpy(res, path, len);
259   memcpy(res + len, ext, strlen(ext) + 1);
260 }
261
262 int
263 isDirectory(const char *rootDir, const char *path)
264 {
265   char *full = fullPath(rootDir, path);
266   struct stat statBuff;
267   int res;
268
269   res = stat(full, &statBuff);
270
271   freeMem(full);
272
273   if (res < 0)
274     return -1;
275
276   return S_ISDIR(statBuff.st_mode);
277 }
278
279 int
280 openFile(struct fileId *fileId, const char *rootDir, const char *path)
281 {
282   int fileDesc;
283   char *full = fullPath(rootDir, path);
284
285   fileDesc = open(full, O_RDONLY | O_NONBLOCK);
286
287   if (fileDesc < 0) {
288     error("cannot open file %s: %s\n", full, strerror(errno));
289     freeMem(full);
290     return -1;
291   }
292
293   fileId->fileDesc = fileDesc;
294
295   freeMem(full);
296   return 0;
297 }
298
299 void
300 closeFile(const struct fileId *fileId)
301 {
302   close(fileId->fileDesc);
303 }
304
305 int
306 fileIsNewer(const char *fileName1, const char *fileName2)
307 {
308   struct stat stat1, stat2;
309
310   if (stat(fileName1, &stat1) < 0) {
311     error("cannot stat %s: %s\n", fileName1, strerror(errno));
312     return -1;
313   }
314
315   if (stat(fileName2, &stat2) < 0) {
316     if (errno != ENOENT)
317       error("cannot stat %s: %s\n", fileName2, strerror(errno));
318
319     return -1;
320   }
321
322   return stat1.st_mtime > stat2.st_mtime;
323 }
324
325 int
326 createAllDirs(char *path)
327 {
328   int i;
329   int fail;
330
331   for (i = 0; path[i] != 0; i++) {
332     if (path[i] == '/' && i > 0) {
333       path[i] = 0;
334
335       fail = (mkdir(path, 0755) < 0 && errno != EEXIST);
336
337       path[i] = '/';
338
339       if (fail)
340         return -1;
341     }
342   }
343
344   return 0;
345 }
346
347 int
348 parseIpAddr(struct ipAddr *addr, const char *addrStr)
349 {
350   memset(addr, 0, sizeof(struct ipAddr));
351
352   if (inet_pton(AF_INET, addrStr, &addr->addr.v4) > 0) {
353     addr->domain = PF_INET;
354     return 0;
355   }
356
357   if (inet_pton(AF_INET6, addrStr, &addr->addr.v6) > 0) {
358     addr->domain = PF_INET6;
359     return 0;
360   }
361
362   fprintf(stderr, "cannot parse IP address\n");
363   return -1;
364 }
365
366 char *
367 ipAddrToString(struct ipAddr *addr)
368 {
369   static char buff[8][40];
370   static int i = 0;
371   char *res;
372
373   res = buff[i];
374
375   if (addr->domain == PF_INET)
376     inet_ntop(AF_INET, &addr->addr.v4, res, 40);
377
378   else
379     inet_ntop(AF_INET6, &addr->addr.v6, res, 40);
380
381   i = (i + 1) & 7;
382
383   return res;
384 }
385
386 char *
387 rawIpAddrToString(void *rawAddr, int len)
388 {
389   struct ipAddr addr;
390
391   if (len == 4) {
392     memcpy(&addr.addr.v4, rawAddr, 4);
393     addr.domain = PF_INET;
394   }
395
396   else {
397     memcpy(&addr.addr.v6, rawAddr, 16);
398     addr.domain = PF_INET6;
399   }
400
401   return ipAddrToString(&addr);
402 }
403
404 static int
405 createSockAddr(struct sockaddr *sockAddr, const struct ipAddr *addr, int port)
406 {
407   struct sockaddr_in *sockAddr4;
408   struct sockaddr_in6 *sockAddr6;
409
410   memset(sockAddr, 0, sizeof(struct sockaddr));
411
412   if (addr->domain == PF_INET) {
413     sockAddr4 = (struct sockaddr_in *)(ARM_NOWARN_ALIGN)sockAddr;
414
415     sockAddr4->sin_family = AF_INET;
416     sockAddr4->sin_port = htons((short)port);
417     sockAddr4->sin_addr.s_addr = addr->addr.v4.s_addr;
418
419     return 0;
420   }
421
422   if (addr->domain == PF_INET6) {
423     sockAddr6 = (struct sockaddr_in6 *)(ARM_NOWARN_ALIGN)sockAddr;
424
425     sockAddr6->sin6_family = AF_INET6;
426     sockAddr6->sin6_port = htons((short)port);
427     memcpy(&sockAddr6->sin6_addr, &addr->addr.v6, sizeof(struct in6_addr));
428
429     return 0;
430   }
431
432   fprintf(stderr, "invalid protocol family: %d\n", addr->domain);
433   return -1;
434 }
435
436 static int
437 addrFromSockAddr(struct ipAddr *addr, const struct sockaddr *sockAddr)
438 {
439   const struct sockaddr_in *sockAddr4 = (const struct sockaddr_in *)(const ARM_NOWARN_ALIGN)sockAddr;
440   const struct sockaddr_in6 *sockAddr6 = (const struct sockaddr_in6 *)(const ARM_NOWARN_ALIGN)sockAddr;
441
442   memset(addr, 0, sizeof(struct ipAddr));
443
444   if (sockAddr4->sin_family == AF_INET) {
445     addr->domain = PF_INET;
446     addr->addr.v4.s_addr = sockAddr4->sin_addr.s_addr;
447     return 0;
448   }
449
450   if (sockAddr6->sin6_family == AF_INET6) {
451     addr->domain = PF_INET6;
452     memcpy(&addr->addr.v6, &sockAddr6->sin6_addr, sizeof(struct in6_addr));
453     return 0;
454   }
455
456   fprintf(stderr, "invalid address family: %d\n", sockAddr4->sin_family);
457   return -1;
458 }
459
460 int
461 createMainSocket(const struct ipAddr *addr, int port)
462 {
463   struct sockaddr sockAddr;
464   static int truePara = 1;
465   int flags;
466
467   if (createSockAddr(&sockAddr, addr, port) < 0) {
468     fprintf(stderr, "cannot create socket address\n");
469     return -1;
470   }
471
472   mainSocket = socket(addr->domain, SOCK_STREAM, IPPROTO_TCP);
473
474   if (mainSocket < 0) {
475     error("cannot create main socket: %s\n", strerror(errno));
476     return -1;
477   }
478
479   if (setsockopt(mainSocket, SOL_SOCKET, SO_REUSEADDR, &truePara, sizeof(truePara)) < 0) {
480     error("cannot set SO_REUSEADDR socket option: %s\n", strerror(errno));
481     close(mainSocket);
482     return -1;
483   }
484
485   flags = fcntl(mainSocket, F_GETFL);
486
487   if (flags < 0) {
488     error("cannot get flags : %s\n", strerror(errno));
489     close(mainSocket);
490     return -1;
491   }
492
493   if (fcntl(mainSocket, F_SETFL, flags | O_NONBLOCK) < 0) {
494     error("cannot set flags: %s\n", strerror(errno));
495     close(mainSocket);
496     return -1;
497   }
498
499   if (bind(mainSocket, &sockAddr, sizeof(struct sockaddr)) < 0) {
500     error("cannot bind main socket: %s\n", strerror(errno));
501     close(mainSocket);
502     return -1;
503   }
504
505   if (listen(mainSocket, 10) < 0) {
506     error("cannot listen on main socket: %s\n", strerror(errno));
507     close(mainSocket);
508     return -1;
509   }
510
511   return 0;
512 }
513
514 int
515 acceptConn(struct fileId **sockId, struct ipAddr **addr)
516 {
517   struct sockaddr sockAddr;
518   socklen_t len;
519   int sock;
520   int flags;
521
522   do {
523     len = sizeof(struct sockaddr);
524
525     sock = accept(mainSocket, &sockAddr, &len);
526   }
527   while (sock < 0 && errno == EINTR);
528
529   if (sock < 0) {
530     if (errno != EAGAIN)
531       error("accept failed: %s\n", strerror(errno));
532
533     return -1;
534   }
535
536   flags = fcntl(sock, F_GETFL);
537
538   if (flags < 0) {
539     error("cannot get flags : %s\n", strerror(errno));
540     close(sock);
541     return -1;
542   }
543
544   if (fcntl(sock, F_SETFL, flags | O_NONBLOCK) < 0) {
545     error("cannot set flags: %s\n", strerror(errno));
546     close(sock);
547     return -1;
548   }
549
550   *addr = allocMem(sizeof(struct ipAddr));
551
552   if (addrFromSockAddr(*addr, &sockAddr) < 0) {
553     error("cannot convert socket address\n");
554     freeMem(addr);
555     close(sock);
556     return -1;
557   }
558
559   *sockId = allocMem(sizeof(struct fileId));
560
561   (*sockId)->fileDesc = sock;
562
563   return 0;
564 }
565
566 void
567 closeMainSocket(void)
568 {
569   close(mainSocket);
570 }
571
572 int
573 waitForSockets(struct fileId *sockIds[], int *flags[], int num)
574 {
575   fd_set readSet, writeSet;
576   int i;
577   int fileDesc;
578   int max;
579   int res;
580
581   FD_ZERO(&readSet);
582   FD_ZERO(&writeSet);
583
584   FD_SET(mainSocket, &readSet);
585
586   max = mainSocket;
587
588   for (i = 0; i < num; i++) {
589     fileDesc = sockIds[i]->fileDesc;
590
591     if (fileDesc > max)
592       max = fileDesc;
593
594     if ((*flags[i] & FLAG_READ) != 0)
595       FD_SET(fileDesc, &readSet);
596
597     if ((*flags[i] & FLAG_WRITE) != 0)
598       FD_SET(fileDesc, &writeSet);
599   }
600
601   do
602     res = select(max + 1, &readSet, &writeSet, NULL, NULL);
603   while (res < 0 && errno == EINTR);
604
605   if (res < 0) {
606     error("cannot select: %s\n", strerror(errno));
607     return -1;
608   }
609
610   for (i = 0; i < num; i++) {
611     *flags[i] = 0;
612
613     fileDesc = sockIds[i]->fileDesc;
614
615     if (FD_ISSET(fileDesc, &readSet))
616       *flags[i] |= FLAG_READ;
617
618     if (FD_ISSET(fileDesc, &writeSet))
619       *flags[i] |= FLAG_WRITE;
620   }
621
622   return 0;
623 }
624
625 #endif
626
627 /*
628  * Local Variables:
629  * c-basic-offset: 2
630  * indent-tabs-mode: nil
631  * End:
632  */