/*
* The olsr.org Optimized Link-State Routing daemon (olsrd)
*
* Copyright (c) 2004, Thomas Lopatic (thomas@olsr.org)
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* * Neither the name of olsr.org, olsrd nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* Visit http://www.olsr.org for more information.
*
* If you find this software useful feel free to make a donation
* to the project. For more information see the website or contact
* the copyright holders.
*
* $Id: os_unix.c,v 1.6 2007/04/19 23:01:32 bernd67 Exp $
*/
#if defined linux
#include "link.h"
#include "plugin.h"
#include "lib.h"
#include "os_unix.h"
#include "http.h"
#include "glua.h"
#include "glua_ext.h"
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <fcntl.h>
#include <stdlib.h>
#include <sys/select.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <time.h>
static int mainSocket;
void getRandomBytes(unsigned char *buff, int len)
{
int file;
int readLen;
memset(buff, 0, len);
file = open("/dev/random", O_RDONLY);
if (file < 0)
{
fprintf(stderr, "warning: cannot open /dev/random\n");
return;
}
while (len > 0)
{
readLen = read(file, buff, len);
if (readLen < 0)
{
fprintf(stderr, "warning: cannot read from /dev/random\n");
close(file);
return;
}
buff += readLen;
len -= readLen;
}
close(file);
}
int addrLen(int family)
{
return (family == AF_INET) ? sizeof (struct in_addr) :
sizeof (struct in6_addr);
}
void os_now(struct timeStamp *timeStamp)
{
timeStamp->time = time(NULL);
}
int timedOut(struct timeStamp *timeStamp, int sec)
{
time_t now;
time(&now);
if ((time_t)(timeStamp->time + sec) > now)
return -1;
return 0;
}
unsigned int getMicro(void)
{
struct timeval timeVal;
static struct timeval timeValPrev;
static int firstTime = 1;
gettimeofday(&timeVal, NULL);
if (firstTime == 0 &&
timeValPrev.tv_sec == timeVal.tv_sec &&
timeValPrev.tv_usec >= timeVal.tv_usec)
return timeValPrev.tv_sec * 1000000 + timeValPrev.tv_usec;
firstTime = 0;
timeValPrev.tv_sec = timeVal.tv_sec;
timeValPrev.tv_usec = timeVal.tv_usec;
return timeVal.tv_sec * 1000000 + timeVal.tv_usec;
}
void *allocMem(int len)
{
void *res;
res = malloc(len);
if (res == NULL)
{
fprintf(stderr, "cannot allocate %d bytes\n", len);
exit(0);
}
memset(res, 0, len);
return res;
}
void freeMem(void *mem)
{
free(mem);
}
int writeFileOs(const struct fileId *fileId, const unsigned char *data, int len)
{
int writeLen;
if (len == 0)
return 0;
do
writeLen = write(fileId->fileDesc, data, len);
while (writeLen < 0 && errno == EINTR);
if (writeLen < 0)
{
if (errno == EAGAIN)
return 0;
error("cannot write to file descriptor: %s\n", strerror(errno));
return -1;
}
return writeLen;
}
int readFileOs(const struct fileId *fileId, unsigned char *data, int len)
{
int readLen;
if (len == 0)
return 0;
do
readLen = read(fileId->fileDesc, data, len);
while (readLen < 0 && errno == EINTR);
if (readLen < 0)
{
if (errno == EAGAIN)
return 0;
error("cannot read from file descriptor: %s\n", strerror(errno));
return -1;
}
if (readLen == 0)
return -1;
return readLen;
}
int checkAbsPath(const char *path)
{
if (path[0] != '/')
return -1;
return 0;
}
char *fullPath(const char *dir, const char *path)
{
int dirLen = strlen(dir);
int pathLen = strlen(path);
char *buff = allocMem(dirLen + pathLen + 2);
memcpy(buff, dir, dirLen);
if (dirLen == 0 || buff[dirLen - 1] == '/')
dirLen--;
else
buff[dirLen] = '/';
memcpy(buff + dirLen + 1, path, pathLen + 1);
return buff;
}
void setExtension(char *res, const char *path, const char *ext)
{
int i;
int len = strlen(path);
for (i = len - 1; i >= 0 && path[i] != '.' && path[i] != '/'; i--);
if (path[i] == '.')
len = i;
memcpy(res, path, len);
memcpy(res + len, ext, strlen(ext) + 1);
}
int isDirectory(const char *rootDir, const char *path)
{
char *full = fullPath(rootDir, path);
struct stat statBuff;
int res;
res = stat(full, &statBuff);
freeMem(full);
if (res < 0)
return -1;
return S_ISDIR(statBuff.st_mode);
}
int openFile(struct fileId *fileId, const char *rootDir, const char *path)
{
int fileDesc;
char *full = fullPath(rootDir, path);
fileDesc = open(full, O_RDONLY | O_NONBLOCK);
if (fileDesc < 0)
{
error("cannot open file %s: %s\n", full, strerror(errno));
freeMem(full);
return -1;
}
fileId->fileDesc = fileDesc;
freeMem(full);
return 0;
}
void closeFile(const struct fileId *fileId)
{
close(fileId->fileDesc);
}
int fileIsNewer(const char *fileName1, const char *fileName2)
{
struct stat stat1, stat2;
if (stat(fileName1, &stat1) < 0)
{
error("cannot stat %s: %s\n", fileName1, strerror(errno));
return -1;
}
if (stat(fileName2, &stat2) < 0)
{
if (errno != ENOENT)
error("cannot stat %s: %s\n", fileName2, strerror(errno));
return -1;
}
return stat1.st_mtime > stat2.st_mtime;
}
int createAllDirs(char *path)
{
int i;
int fail;
for (i = 0; path[i] != 0; i++)
{
if (path[i] == '/' && i > 0)
{
path[i] = 0;
fail = (mkdir(path, 0755) < 0 && errno != EEXIST);
path[i] = '/';
if (fail)
return -1;
}
}
return 0;
}
int parseIpAddr(struct ipAddr *addr, const char *addrStr)
{
memset(addr, 0, sizeof (struct ipAddr));
if (inet_pton(AF_INET, addrStr, &addr->addr.v4) > 0)
{
addr->domain = PF_INET;
return 0;
}
if (inet_pton(AF_INET6, addrStr, &addr->addr.v6) > 0)
{
addr->domain = PF_INET6;
return 0;
}
fprintf(stderr, "cannot parse IP address\n");
return -1;
}
char *ipAddrToString(struct ipAddr *addr)
{
static char buff[8][40];
static int i = 0;
char *res;
res = buff[i];
if (addr->domain == PF_INET)
inet_ntop(AF_INET, &addr->addr.v4, res, 40);
else
inet_ntop(AF_INET6, &addr->addr.v6, res, 40);
i = (i + 1) & 7;
return res;
}
char *rawIpAddrToString(void *rawAddr, int len)
{
struct ipAddr addr;
if (len == 4)
{
memcpy(&addr.addr.v4, rawAddr, 4);
addr.domain = PF_INET;
}
else
{
memcpy(&addr.addr.v6, rawAddr, 16);
addr.domain = PF_INET6;
}
return ipAddrToString(&addr);
}
static int createSockAddr(struct sockaddr *sockAddr,
const struct ipAddr *addr, int port)
{
struct sockaddr_in *sockAddr4;
struct sockaddr_in6 *sockAddr6;
memset(sockAddr, 0, sizeof (struct sockaddr));
if (addr->domain == PF_INET)
{
sockAddr4 = (struct sockaddr_in *)sockAddr;
sockAddr4->sin_family = AF_INET;
sockAddr4->sin_port = htons((short)port);
sockAddr4->sin_addr.s_addr = addr->addr.v4.s_addr;
return 0;
}
if (addr->domain == PF_INET6)
{
sockAddr6 = (struct sockaddr_in6 *)sockAddr;
sockAddr6->sin6_family = AF_INET6;
sockAddr6->sin6_port = htons((short)port);
memcpy(&sockAddr6->sin6_addr, &addr->addr.v6, sizeof (struct in6_addr));
return 0;
}
fprintf(stderr, "invalid protocol family: %d\n", addr->domain);
return -1;
}
static int addrFromSockAddr(struct ipAddr *addr, const struct sockaddr *sockAddr)
{
struct sockaddr_in *sockAddr4 = (struct sockaddr_in *)sockAddr;
struct sockaddr_in6 *sockAddr6 = (struct sockaddr_in6 *)sockAddr;
memset(addr, 0, sizeof (struct ipAddr));
if (sockAddr4->sin_family == AF_INET)
{
addr->domain = PF_INET;
addr->addr.v4.s_addr = sockAddr4->sin_addr.s_addr;
return 0;
}
if (sockAddr6->sin6_family == AF_INET6)
{
addr->domain = PF_INET6;
memcpy(&addr->addr.v6, &sockAddr6->sin6_addr, sizeof (struct in6_addr));
return 0;
}
fprintf(stderr, "invalid address family: %d\n", sockAddr4->sin_family);
return -1;
}
int createMainSocket(const struct ipAddr *addr, int port)
{
struct sockaddr sockAddr;
static int truePara = 1;
int flags;
if (createSockAddr(&sockAddr, addr, port) < 0)
{
fprintf(stderr, "cannot create socket address\n");
return -1;
}
mainSocket = socket(addr->domain, SOCK_STREAM, IPPROTO_TCP);
if (mainSocket < 0)
{
error("cannot create main socket: %s\n", strerror(errno));
return -1;
}
if (setsockopt(mainSocket, SOL_SOCKET, SO_REUSEADDR, &truePara,
sizeof (truePara)) < 0)
{
error("cannot set SO_REUSEADDR socket option: %s\n", strerror(errno));
close(mainSocket);
return -1;
}
flags = fcntl(mainSocket, F_GETFL);
if (flags < 0)
{
error("cannot get flags : %s\n", strerror(errno));
close(mainSocket);
return -1;
}
if (fcntl(mainSocket, F_SETFL, flags | O_NONBLOCK) < 0)
{
error("cannot set flags: %s\n", strerror(errno));
close(mainSocket);
return -1;
}
if (bind(mainSocket, &sockAddr, sizeof (struct sockaddr)) < 0)
{
error("cannot bind main socket: %s\n", strerror(errno));
close(mainSocket);
return -1;
}
if (listen(mainSocket, 10) < 0)
{
error("cannot listen on main socket: %s\n", strerror(errno));
close(mainSocket);
return -1;
}
return 0;
}
int acceptConn(struct fileId **sockId, struct ipAddr **addr)
{
struct sockaddr sockAddr;
socklen_t len;
int sock;
int flags;
do
{
len = sizeof (struct sockaddr);
sock = accept(mainSocket, &sockAddr, &len);
}
while (sock < 0 && errno == EINTR);
if (sock < 0)
{
if (errno != EAGAIN)
error("accept failed: %s\n", strerror(errno));
return -1;
}
flags = fcntl(sock, F_GETFL);
if (flags < 0)
{
error("cannot get flags : %s\n", strerror(errno));
close(sock);
return -1;
}
if (fcntl(sock, F_SETFL, flags | O_NONBLOCK) < 0)
{
error("cannot set flags: %s\n", strerror(errno));
close(sock);
return -1;
}
*addr = allocMem(sizeof (struct ipAddr));
if (addrFromSockAddr(*addr, &sockAddr) < 0)
{
error("cannot convert socket address\n");
freeMem(addr);
close(sock);
return -1;
}
*sockId = allocMem(sizeof (struct fileId));
(*sockId)->fileDesc = sock;
return 0;
}
void closeMainSocket(void)
{
close(mainSocket);
}
int waitForSockets(struct fileId *sockIds[], int *flags[], int num)
{
fd_set readSet, writeSet;
int i;
int fileDesc;
int max;
int res;
FD_ZERO(&readSet);
FD_ZERO(&writeSet);
FD_SET(mainSocket, &readSet);
max = mainSocket;
for (i = 0; i < num; i++)
{
fileDesc = sockIds[i]->fileDesc;
if (fileDesc > max)
max = fileDesc;
if ((*flags[i] & FLAG_READ) != 0)
FD_SET(fileDesc, &readSet);
if ((*flags[i] & FLAG_WRITE) != 0)
FD_SET(fileDesc, &writeSet);
}
do
res = select(max + 1, &readSet, &writeSet, NULL, NULL);
while (res < 0 && errno == EINTR);
if (res < 0)
{
error("cannot select: %s\n", strerror(errno));
return -1;
}
for (i = 0; i < num; i++)
{
*flags[i] = 0;
fileDesc = sockIds[i]->fileDesc;
if (FD_ISSET(fileDesc, &readSet))
*flags[i] |= FLAG_READ;
if (FD_ISSET(fileDesc, &writeSet))
*flags[i] |= FLAG_WRITE;
}
return 0;
}
#endif
syntax highlighted by Code2HTML, v. 0.9.1