--- libaitio/src/aitio.c 2011/10/31 13:53:51 1.7 +++ libaitio/src/aitio.c 2012/03/27 21:37:56 1.8.6.1 @@ -3,7 +3,7 @@ * by Michael Pounov * * $Author: misho $ -* $Id: aitio.c,v 1.7 2011/10/31 13:53:51 misho Exp $ +* $Id: aitio.c,v 1.8.6.1 2012/03/27 21:37:56 misho Exp $ * ************************************************************************** The ELWIX and AITNET software is distributed under the following @@ -12,7 +12,7 @@ terms: All of the documentation and software included in the ELWIX and AITNET Releases is copyrighted by ELWIX - Sofia/Bulgaria -Copyright 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 +Copyright 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012 by Michael Pounov . All rights reserved. Redistribution and use in source and binary forms, with or without @@ -87,6 +87,7 @@ io_SetErr(int eno, char *estr, ...) /* * ioPromptRead() Read data from input h[0] with prompt to output h[1] + * * @h = file handles h[0] = input, h[1] = output, if NULL use stdin, stdout * @csPrompt = Prompt before input, may be NULL * @psData = Readed data @@ -140,6 +141,7 @@ ioPromptRead(int *h, const char *csPrompt, char * __re /* * ioPromptPassword() Read password from input h[0] with prompt to output h[1] + * * @h = file handles h[0] = input, h[1] = output, if NULL use stdin, stdout * @csPrompt = Prompt before input, may be NULL * @psPass = Readed password @@ -226,6 +228,7 @@ next: /* * ioRegexVerify() Function for verify data match in regex expression + * * @csRegex = Regulare expression pattern * @csData = Data for check and verify * @startPos = Return start positions @@ -274,6 +277,7 @@ ioRegexVerify(const char *csRegex, const char *csData, /* * ioRegexGet() Function for get data match in regex expression + * * @csRegex = Regulare expression pattern * @csData = Data from get * @psString = Returned string if match @@ -304,6 +308,7 @@ ioRegexGet(const char *csRegex, const char *csData, ch /* * ioRegexReplace() Function for replace data match in regex expression with newdata + * * @csRegex = Regulare expression pattern * @csData = Source data * @csNew = Data for replace @@ -352,12 +357,13 @@ ioRegexReplace(const char *csRegex, const char *csData } /* - * ioVarAst() Function for evaluate string like asterisk variable "{text[:[-]#[:#]]}" + * ioStrAst() Function for evaluate string like asterisk variable "{text[:[-]#[:#]]}" + * * @csString = Input string * return: NULL error, !=NULL Allocated new string evaluated from input string, must be free() */ char * -ioVarAst(const char *csString) +ioStrAst(const char *csString) { char *ext, *str, *out = NULL; int e[2] = { 0 }; @@ -403,6 +409,7 @@ ioVarAst(const char *csString) /* * ioMkDir() Function for racursive directory creation and validation + * * @csDir = Full directory path * @mode = Mode for directory creation if missing dir * return: -1 error, 0 directory path exist, >0 created missing dirs @@ -450,6 +457,7 @@ end: /* * ioWatchDirLoop() Function for watching changes in directory and fire callback + * * @csDir = Full directory path * @callback = Callback if raise event! nOp -1 delete, 0 change/move, 1 create * return: -1 error, !=-1 ok, number of total signaled events @@ -561,6 +569,7 @@ ioWatchDirLoop(const char *csDir, int (*callback)(cons /* * ioCreatePIDFile() Create PID file + * * @csName = PID filename * @ifExists = !=0 if filename exists return error * return: -1 error or 0 ok @@ -583,4 +592,148 @@ ioCreatePIDFile(const char *csName, int ifExists) write(fd, str, strlen(str)); close(fd); return 0; +} + + +/* + * ioSendFile() AITNET sendfile() userland implementation, not dependant from OS + * + * @s = socket + * @csFile = file for send + * @sendLen = bytes to send, if 0 send all data + * @offset = start file offset + * @sndbuf = SO_SNDBUF value, if 0 use default + * return: 0 error, >0 ok, sended bytes + */ +size_t +ioSendFile(int s, const char *csFile, size_t sendLen, off_t offset, int sndbuf) +{ + void *addr; + int fd; + size_t len = 0; + register size_t off = 0; + + if (!csFile) + return 0; + + if (sndbuf) + if (setsockopt(s, SOL_SOCKET, SO_SNDBUF, &sndbuf, sizeof sndbuf) == -1) { + LOGERR; + return 0; + } + + fd = open(csFile, O_RDONLY); + if (fd == -1) { + LOGERR; + return 0; + } + if (!sendLen) { + sendLen = lseek(fd, 0, SEEK_END); + if (sendLen == -1) { + LOGERR; + close(fd); + return 0; + } + } + addr = mmap(NULL, sendLen, PROT_READ, MAP_SHARED, fd, offset); + if (addr == MAP_FAILED) { + LOGERR; + close(fd); + return 0; + } else + close(fd); + + while (off < sendLen && (len = write(s, addr + off, sendLen - off)) != -1) + off += len; + if (len == -1) { + LOGERR; + munmap(addr, sendLen); + return 0; + } else + len = off; + + if (len != sendLen) { + io_SetErr(ECANCELED, "Different sizes - request %u bytes, actually sended %u bytes\n", + sendLen, len); + len ^= len; + } + + munmap(addr, sendLen); + return len; +} + +/* + * ioRecvFile() Receive file from socket, fastest (zero-copy) way + * + * @s = socket + * @csFile = file for receive + * @recvLen = receive bytes + * @over = overwrite file if exists with mode like 0644 + * @rcvbuf = SO_RCVBUF value, if 0 use default + * return: 0 error, >0 ok, received bytes + */ +size_t +ioRecvFile(int s, const char *csFile, size_t recvLen, int over, int rcvbuf) +{ + void *addr; + int fd; + size_t len = 0; + register size_t off = 0; + struct pollfd pfd = { s, POLLIN | POLLPRI, 0 }; + + if (!csFile || !recvLen) + return 0; + if (!over && !access(csFile, F_OK)) + return 0; + + if (rcvbuf) + if (setsockopt(s, SOL_SOCKET, SO_RCVBUF, &rcvbuf, sizeof rcvbuf) == -1) { + LOGERR; + return 0; + } + + fd = open(csFile, O_WRONLY | O_CREAT | O_TRUNC, over); + if (fd == -1) { + LOGERR; + unlink(csFile); + return 0; + } + if (lseek(fd, recvLen - 1, SEEK_SET) == -1) { + LOGERR; + close(fd); + unlink(csFile); + return 0; + } + if (write(fd, "", 1) == -1) { + LOGERR; + close(fd); + unlink(csFile); + return 0; + } + addr = mmap(NULL, recvLen, PROT_WRITE, MAP_SHARED, fd, 0); + if (addr == MAP_FAILED) { + LOGERR; + close(fd); + unlink(csFile); + return 0; + } else + close(fd); + + while (off < recvLen && poll(&pfd, 1, RECV_TIMEOUT) != -1) + while (off < recvLen && (len = read(s, addr + off, recvLen - off)) != -1) + off += len; + if (len == -1) { + LOGERR; + munmap(addr, recvLen); + unlink(csFile); + return 0; + } else + len = off; + + if (len != recvLen) + io_SetErr(EAGAIN, "Different sizes - request %u bytes, actually received %u bytes\n", + recvLen, len); + + munmap(addr, recvLen); + return len; }