--- libaitio/src/aitio.c 2011/04/19 19:58:25 1.3.4.1 +++ libaitio/src/aitio.c 2012/08/02 00:47:47 1.12 @@ -1,19 +1,68 @@ /************************************************************************* -* (C) 2010 AITNET ltd - Sofia/Bulgaria - -* by Michael Pounov +* (C) 2010 AITNET ltd - Sofia/Bulgaria - +* by Michael Pounov * * $Author: misho $ -* $Id: aitio.c,v 1.3.4.1 2011/04/19 19:58:25 misho Exp $ +* $Id: aitio.c,v 1.12 2012/08/02 00:47:47 misho Exp $ * -*************************************************************************/ +************************************************************************** +The ELWIX and AITNET software is distributed under the following +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, 2012 + by Michael Pounov . All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. +2. 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. +3. All advertising materials mentioning features or use of this software + must display the following acknowledgement: +This product includes software developed by Michael Pounov +ELWIX - Embedded LightWeight unIX and its contributors. +4. Neither the name of AITNET 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 AITNET 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 REGENTS 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. +*/ #include "global.h" int io_Debug; +mpool_t *io_mpool; +/* Memory management */ + +void *(*io_malloc)(size_t) = malloc; +void *(*io_calloc)(size_t, size_t) = calloc; +void *(*io_realloc)(void*, size_t) = realloc; +char *(*io_strdup)(const char*) = strdup; +void (*io_free)(void*) = free; + + #pragma GCC visibility push(hidden) +int use_mm; + int io_Errno; char io_Error[STRSIZ]; @@ -21,19 +70,22 @@ char io_Error[STRSIZ]; // io_GetErrno() Get error code of last operation -inline int io_GetErrno() +inline int +io_GetErrno() { return io_Errno; } // io_GetError() Get error text of last operation -inline const char *io_GetError() +inline const char * +io_GetError() { return io_Error; } // io_SetErr() Set error to variables for internal use!!! -inline void io_SetErr(int eno, char *estr, ...) +inline void +io_SetErr(int eno, char *estr, ...) { va_list lst; @@ -44,16 +96,102 @@ inline void io_SetErr(int eno, char *estr, ...) va_end(lst); } +// io_mm_inuse() Check for memory management model +inline int +io_mm_inuse() +{ + return use_mm & IO_MPOOL; +} + +// init libaitio routine +void +_init() +{ + ioLibInit(IO_MPOOL, 0); +} + +// fini libaitio routine +void +_fini() +{ + ioLibFini(); +} + /* - * ioPromptRead() Read data from input h[0] with prompt to output h[1] + * ioLibInit() - Init libaitio library memory management + * + * @mm = memory management (IO_SYSM or IO_MPOOL) + * @maxmem = memory limit + * return: -1 error or !=-1 used memory management model + */ +inline int +ioLibInit(int mm, u_long maxmem) +{ + switch (mm) { + case IO_MPOOL: /* mpool */ + io_mpool = mpool_init(maxmem); + if (io_mpool) { + io_malloc = mpool_xmalloc; + io_calloc = mpool_xcalloc; + io_realloc = mpool_xrealloc; + io_strdup = mpool_xstrdup; + io_free = mpool_xfree; + use_mm = mm; + break; + } else { + #undef USE_MPOOL + } + case IO_SYSM: /* system */ + io_malloc = malloc; + io_calloc = calloc; + io_realloc = realloc; + io_strdup = strdup; + io_free = free; + use_mm = mm; + break; + default: /* not supported */ + io_SetErr(EINVAL, "Not supported memory management"); + return -1; + } + + return use_mm; +} + +/* + * ioLibFini() - Finish libaitio library memory management + * + * return: none + */ +inline void +ioLibFini() +{ + switch (use_mm) { + case IO_MPOOL: + mpool_destroy(&io_mpool); + + io_malloc = malloc; + io_calloc = calloc; + io_realloc = realloc; + io_strdup = strdup; + io_free = free; + use_mm = IO_SYSM; + break; + } +} + + +/* + * 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 * @dataLen = Length of data * return: 0 EOF; -1 error:: can`t read; >0 count of readed chars */ -int ioPromptRead(int *h, const char *csPrompt, char * __restrict psData, int dataLen) +int +ioPromptRead(int *h, const char *csPrompt, char * __restrict psData, int dataLen) { int ok = 0; FILE *inp, *out; @@ -98,7 +236,8 @@ int ioPromptRead(int *h, const char *csPrompt, char * } /* - * ioPromptPassword() Read password from input h[0] with prompt to output h[1] + * 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 @@ -106,7 +245,8 @@ int ioPromptRead(int *h, const char *csPrompt, char * * @confirm = Confirm password, 0 - get password, !=0 Ask for confirmation * return: 0 EOF; -1 error:: can`t read; >0 count of readed chars */ -int ioPromptPassword(int *h, const char *csPrompt, char * __restrict psPass, int passLen, int confirm) +int +ioPromptPassword(int *h, const char *csPrompt, char * __restrict psPass, int passLen, int confirm) { int ret, ok = 0; FILE *inp, *out; @@ -183,14 +323,16 @@ next: } /* - * ioRegexVerify() Function for verify data match in regex expression + * ioRegexVerify() - Function for verify data match in regex expression + * * @csRegex = Regulare expression pattern * @csData = Data for check and verify * @startPos = Return start positions * @endPos = Return end positions * return: NULL not match or error; !=NULL begin of matched data */ -const char *ioRegexVerify(const char *csRegex, const char *csData, int *startPos, int *endPos) +const char * +ioRegexVerify(const char *csRegex, const char *csData, int *startPos, int *endPos) { regex_t re; regmatch_t match; @@ -203,7 +345,7 @@ const char *ioRegexVerify(const char *csRegex, const c if ((ret = regcomp(&re, csRegex, REG_EXTENDED))) { regerror(ret, &re, szErr, STRSIZ); - io_SetErr(ret, "Error:: %s\n", szErr); + io_SetErr(ret, "%s", szErr); regfree(&re); return NULL; } @@ -221,7 +363,7 @@ const char *ioRegexVerify(const char *csRegex, const c if (ret) { regerror(ret, &re, szErr, STRSIZ); - io_SetErr(ret, "Error:: %s\n", szErr); + io_SetErr(ret, "%s", szErr); pos = NULL; } @@ -230,14 +372,16 @@ const char *ioRegexVerify(const char *csRegex, const c } /* - * ioRegexGet() Function for get data match in regex expression + * ioRegexGet() - Function for get data match in regex expression + * * @csRegex = Regulare expression pattern * @csData = Data from get * @psString = Returned string if match * @strLen = Length of string * return: 0 not match; >0 count of returned chars */ -int ioRegexGet(const char *csRegex, const char *csData, char * __restrict psString, int strLen) +int +ioRegexGet(const char *csRegex, const char *csData, char * __restrict psString, int strLen) { int sp, ep, len; const char *str; @@ -259,13 +403,15 @@ int ioRegexGet(const char *csRegex, const char *csData } /* - * ioRegexReplace() Function for replace data match in regex expression with newdata + * ioRegexReplace() - Function for replace data match in regex expression with newdata + * * @csRegex = Regulare expression pattern * @csData = Source data * @csNew = Data for replace - * return: NULL not match or error; !=NULL allocated new string, must be free after use! + * return: NULL not match or error; !=NULL allocated new string, must be io_free after use! */ -char *ioRegexReplace(const char *csRegex, const char *csData, const char *csNew) +char * +ioRegexReplace(const char *csRegex, const char *csData, const char *csNew) { int sp, ep, len; char *str = NULL; @@ -278,7 +424,7 @@ char *ioRegexReplace(const char *csRegex, const char * // ___ before match len = sp + 1; - str = malloc(len); + str = io_malloc(len); if (!str) { LOGERR; return NULL; @@ -287,7 +433,7 @@ char *ioRegexReplace(const char *csRegex, const char * // * replace match * if (csNew) { len += strlen(csNew); - str = realloc(str, len); + str = io_realloc(str, len); if (!str) { LOGERR; return NULL; @@ -296,7 +442,7 @@ char *ioRegexReplace(const char *csRegex, const char * } // after match ___ len += strlen(csData) - ep; - str = realloc(str, len); + str = io_realloc(str, len); if (!str) { LOGERR; return NULL; @@ -307,12 +453,13 @@ char *ioRegexReplace(const char *csRegex, const char * } /* - * 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() + * return: NULL error, !=NULL Allocated new string evaluated from input string, must be io_free() */ char * -ioVarAst(const char *csString) +ioStrAst(const char *csString) { char *ext, *str, *out = NULL; int e[2] = { 0 }; @@ -322,12 +469,12 @@ ioVarAst(const char *csString) if (!strchr(csString, '{') || !strrchr(csString, '}')) { memset(io_Error, 0, STRSIZ); - snprintf(io_Error, STRSIZ, "Error:: Invalid input string format ... " + snprintf(io_Error, STRSIZ, "Invalid input string format ... " "must be like {text[:[-]#[:#]]}"); io_Errno = EINVAL; return NULL; } else { - str = strdup(strchr(csString, '{') + 1); + str = io_strdup(strchr(csString, '{') + 1); *strrchr(str, '}') = 0; } @@ -349,15 +496,16 @@ ioVarAst(const char *csString) /* ok, clear show */ ext = str; - out = strdup(ext); - free(str); + out = io_strdup(ext); + io_free(str); return out; } /* - * ioMkDir() Function for racursive directory creation and validation + * 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 @@ -371,7 +519,7 @@ ioMkDir(const char *csDir, int mode) if (!csDir) return cx; - str = strdup(csDir); + str = io_strdup(csDir); if (!str) { LOGERR; return cx; @@ -399,12 +547,13 @@ ioMkDir(const char *csDir, int mode) } end: chdir(szOld); - free(str); + io_free(str); return cx; } /* - * ioWatchDirLoop() Function for watching changes in directory and fire callback + * 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 @@ -512,4 +661,169 @@ ioWatchDirLoop(const char *csDir, int (*callback)(cons close(d); close(kq); return n; +} + +/* + * ioCreatePIDFile() - Create PID file + * + * @csName = PID filename + * @ifExists = !=0 if filename exists return error + * return: -1 error or 0 ok + */ +inline int +ioCreatePIDFile(const char *csName, int ifExists) +{ + int fd; + char str[STRSIZ] = { 0 }; + + if (!csName) + return -1; + + fd = open(csName, O_WRONLY | O_CREAT | (ifExists ? O_EXCL : 0), 0644); + if (fd == -1) { + LOGERR; + return -1; + } + snprintf(str, sizeof str, "%d", getpid()); + 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 (ftruncate(fd, recvLen) == -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; }