File:  [ELWIX - Embedded LightWeight unIX -] / libaitrpc / src / blob.c
Revision 1.7.2.2: download - view: text, annotated - select for diffs - revision graph
Wed May 16 08:18:00 2012 UTC (12 years, 1 month ago) by misho
Branches: rpc3_3
Diff to: branchpoint 1.7: preferred, unified
finish server side blob

    1: /*************************************************************************
    2: * (C) 2010 AITNET ltd - Sofia/Bulgaria - <misho@aitbg.com>
    3: *  by Michael Pounov <misho@openbsd-bg.org>
    4: *
    5: * $Author: misho $
    6: * $Id: blob.c,v 1.7.2.2 2012/05/16 08:18:00 misho Exp $
    7: *
    8: **************************************************************************
    9: The ELWIX and AITNET software is distributed under the following
   10: terms:
   11: 
   12: All of the documentation and software included in the ELWIX and AITNET
   13: Releases is copyrighted by ELWIX - Sofia/Bulgaria <info@elwix.org>
   14: 
   15: Copyright 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012
   16: 	by Michael Pounov <misho@elwix.org>.  All rights reserved.
   17: 
   18: Redistribution and use in source and binary forms, with or without
   19: modification, are permitted provided that the following conditions
   20: are met:
   21: 1. Redistributions of source code must retain the above copyright
   22:    notice, this list of conditions and the following disclaimer.
   23: 2. Redistributions in binary form must reproduce the above copyright
   24:    notice, this list of conditions and the following disclaimer in the
   25:    documentation and/or other materials provided with the distribution.
   26: 3. All advertising materials mentioning features or use of this software
   27:    must display the following acknowledgement:
   28: This product includes software developed by Michael Pounov <misho@elwix.org>
   29: ELWIX - Embedded LightWeight unIX and its contributors.
   30: 4. Neither the name of AITNET nor the names of its contributors
   31:    may be used to endorse or promote products derived from this software
   32:    without specific prior written permission.
   33: 
   34: THIS SOFTWARE IS PROVIDED BY AITNET AND CONTRIBUTORS ``AS IS'' AND
   35: ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   36: IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   37: ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
   38: FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   39: DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   40: OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   41: HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   42: LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   43: OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   44: SUCH DAMAGE.
   45: */
   46: #include "global.h"
   47: 
   48: 
   49: /*
   50:  * rpc_srv_blobCreate() - Create and map blob to memory region and return object
   51:  *
   52:  * @srv = RPC Server instance
   53:  * @len = BLOB length object
   54:  * return: NULL error or !=NULL allocated BLOB object
   55:  */
   56: inline rpc_blob_t *
   57: rpc_srv_blobCreate(rpc_srv_t * __restrict srv, int len)
   58: {
   59: 	rpc_blob_t *blob = NULL;
   60: 	char szFName[MAXPATHLEN];
   61: 	int f;
   62: 	u_int rnd;
   63: 
   64: #ifdef HAVE_SRANDOMDEV
   65: 	srandomdev();
   66: #else
   67: 	time_t tim;
   68: 
   69: 	srandom((time(&tim) ^ getpid()));
   70: #endif
   71: again:
   72: 	rnd = random() % UINT_MAX;
   73: 
   74: 	memset(szFName, 0, sizeof szFName);
   75: 	snprintf(szFName, sizeof szFName, BLOB_FILE, AIT_GET_STR(&srv->srv_blob.dir), rnd);
   76: 	f = open(szFName, O_CREAT | O_EXCL | O_RDWR, 0600);
   77: 	if (f == -1) {
   78: 		if (errno == EEXIST)
   79: 			goto again;
   80: 
   81: 		LOGERR;
   82: 		return NULL;
   83: 	}
   84: 	if (ftruncate(f, len) == -1) {
   85: 		LOGERR;
   86: 		close(f);
   87: 		unlink(szFName);
   88: 		return NULL;
   89: 	}
   90: 
   91: 	blob = malloc(sizeof(rpc_blob_t));
   92: 	if (!blob) {
   93: 		LOGERR;
   94: 		close(f);
   95: 		unlink(szFName);
   96: 		return NULL;
   97: 	}
   98: 
   99: 	blob->blob_data = mmap(NULL, len, PROT_READ | PROT_WRITE, MAP_SHARED, f, 0);
  100: 	if (blob->blob_data == MAP_FAILED) {
  101: 		LOGERR;
  102: 		free(blob);
  103: 		close(f);
  104: 		unlink(szFName);
  105: 		return NULL;
  106: 	} else
  107: 		close(f);
  108: 
  109: 	blob->blob_len = len;
  110: 	blob->blob_var = rnd;
  111: 	return blob;
  112: }
  113: 
  114: /*
  115:  * rpc_srv_blobMap() - Map blob to memory region 
  116:  *
  117:  * @srv = RPC Server instance
  118:  * @blob = Map to this BLOB element
  119:  * return: -1 error or 0 ok
  120:  */
  121: inline int
  122: rpc_srv_blobMap(rpc_srv_t * __restrict srv, rpc_blob_t * __restrict blob)
  123: {
  124: 	int f;
  125: 	char szFName[MAXPATHLEN];
  126: 
  127: 	if (!blob) {
  128: 		rpc_SetErr(EINVAL, "Invalid argument BLOB");
  129: 		return -1;
  130: 	}
  131: 	if (blob->blob_data) {
  132: 		rpc_SetErr(EPERM, "Already mmapped object found!");
  133: 		return -1;
  134: 	}
  135: 
  136: 	memset(szFName, 0, sizeof szFName);
  137: 	snprintf(szFName, sizeof szFName, BLOB_FILE, AIT_GET_STR(&srv->srv_blob.dir), blob->blob_var);
  138: 	f = open(szFName, O_RDWR);
  139: 	if (f == -1) {
  140: 		LOGERR;
  141: 		return -1;
  142: 	}
  143: 
  144: 	blob->blob_data = mmap(NULL, blob->blob_len, PROT_READ | PROT_WRITE, MAP_SHARED, f, 0);
  145: 	if (blob->blob_data == MAP_FAILED) {
  146: 		LOGERR;
  147: 		close(f);
  148: 		blob->blob_data = NULL;
  149: 		return -1;
  150: 	} else {
  151: 		close(f);
  152: 
  153: 		madvise(blob->blob_data, blob->blob_len, MADV_SEQUENTIAL);
  154: 	}
  155: 
  156: 	return 0;
  157: }
  158: 
  159: /*
  160:  * rpc_srv_blobUnmap() - Unmap blob memory region 
  161:  *
  162:  * @blob = Mapped BLOB element
  163:  * return: none
  164:  */
  165: inline void
  166: rpc_srv_blobUnmap(rpc_blob_t * __restrict blob)
  167: {
  168: 	if (blob && blob->blob_data)
  169: 		munmap(blob->blob_data, blob->blob_len);
  170: 		blob->blob_data = NULL;
  171: 	}
  172: }
  173: 
  174: /*
  175:  * rpc_srv_blobFree() - Free blob from disk & memory
  176:  *
  177:  * @srv = RPC Server instance
  178:  * @blob = Mapped BLOB element
  179:  * return: -1 error or 0 ok
  180:  */
  181: inline int
  182: rpc_srv_blobFree(rpc_srv_t * __restrict srv, rpc_blob_t * __restrict blob)
  183: {
  184: 	char szFName[MAXPATHLEN];
  185: 
  186: 	if (!blob) {
  187: 		rpc_SetErr(EINVAL, "Invalid argument BLOB");
  188: 		return -1;
  189: 	} else
  190: 		rpc_srv_blobUnmap(blob);
  191: 
  192: 	memset(szFName, 0, sizeof szFName);
  193: 	snprintf(szFName, sizeof szFName, BLOB_FILE, AIT_GET_STR(&srv->srv_blob.dir), blob->blob_var);
  194: 	if (unlink(szFName) == -1) {
  195: 		LOGERR;
  196: 		return -1;
  197: 	}
  198: 
  199: 	return 0;
  200: }
  201: 
  202: /* ------------------------------------------------------------ */
  203: 
  204: /*
  205:  * rpc_srv_sendBLOB() - Send mapped BLOB to client
  206:  *
  207:  * @cli = Client instance
  208:  * @blob = Mapped BLOB element
  209:  * return: -1 error, 0 ok
  210:  */
  211: int
  212: rpc_srv_sendBLOB(rpc_cli_t * __restrict cli, rpc_blob_t * __restrict blob)
  213: {
  214: 	int ret, len;
  215: 	uint8_t *pos;
  216: 
  217: 	if (!cli || !blob || !blob->blob_data) {
  218: 		rpc_SetErr(EINVAL, "Invalid arguments");
  219: 		return -1;
  220: 	}
  221: 
  222: 	for (ret = blob->blob_len, pos = blob->blob_data; ret > 0; ret -= len, pos += len) {
  223: 		len = send(cli->cli_sock, pos, ret, MSG_NOSIGNAL);
  224: 		if (len == -1) {
  225: 			LOGERR;
  226: 			return -1;
  227: 		}
  228: 	}
  229: 
  230: 	return ret;
  231: }
  232: 
  233: /*
  234:  * rpc_srv_recvBLOB() - Receive BLOB from client
  235:  *
  236:  * @cli = Client instance
  237:  * @blob = Mapped BLOB element
  238:  * return: -1 error, 0 ok, >0 unreceived data from client, may be error?
  239:  */
  240: int
  241: rpc_srv_recvBLOB(rpc_cli_t * __restrict cli, rpc_blob_t * __restrict blob)
  242: {
  243: 	int ret, len;
  244: 	uint8_t *pos;
  245: 	struct pollfd pfd;
  246: 
  247: 	if (!cli || !blob || !blob->blob_data) {
  248: 		rpc_SetErr(EINVAL, "Invalid arguments");
  249: 		return -1;
  250: 	}
  251: 
  252: 	pfd.fd = cli->cli_sock;
  253: 	pfd.events = POLLIN | POLLPRI;
  254: 	for (ret = blob->blob_len, pos = blob->blob_data; ret > 0; ret -= len, pos += len) {
  255: 		if ((len = poll(&pfd, 1, DEF_RPC_TIMEOUT * 1000)) < 1 || 
  256: 				pfd.revents & (POLLERR | POLLHUP | POLLNVAL)) {
  257: 			LOGERR;
  258: 			return -1;
  259: 		}
  260: 
  261: 		len = recv(cli->cli_sock, pos, ret, 0);
  262: 		if (len == -1) {
  263: 			LOGERR;
  264: 			return -1;
  265: 		}
  266: 	}
  267: 
  268: 	return ret;
  269: }
  270: 
  271: /* ------------------------------------------------------------ */
  272: 
  273: /*
  274:  * rpc_cli_sendBLOB() - Send BLOB to server
  275:  *
  276:  * @cli = Client instance
  277:  * @var = BLOB variable
  278:  * @data = BLOB data
  279:  * return: -1 error, 0 ok, 1 remote error
  280:  */
  281: int
  282: rpc_cli_sendBLOB(rpc_cli_t * __restrict cli, ait_val_t * __restrict var, void * __restrict data)
  283: {
  284: 	int ret, len;
  285: 	uint8_t *pos;
  286: 	struct tagBLOBHdr hdr;
  287: 	struct pollfd pfd;
  288: 
  289: 	if (!cli || !var || !data) {
  290: 		rpc_SetErr(EINVAL, "Invalid arguments");
  291: 		return -1;
  292: 	}
  293: 
  294: 	rpc_addPktSession(&hdr.hdr_session, cli->cli_parent);
  295: 	hdr.hdr_cmd = set;
  296: 	hdr.hdr_var = 0;
  297: 	hdr.hdr_ret = 0;
  298: 	hdr.hdr_len = htonl(AIT_LEN(var));
  299: 	/* calculate CRC */
  300: 	hdr.hdr_crc ^= hdr.hdr_crc;
  301: 	hdr.hdr_crc = htons(crcFletcher16((u_short*) &hdr, sizeof hdr / 2));
  302: 
  303: 	/* send SET request */
  304: 	if (send(cli->cli_sock, &hdr, sizeof hdr, 0) == -1) {
  305: 		LOGERR;
  306: 		return -1;
  307: 	}
  308: 
  309: 	/* send BLOB to server */
  310: 	for (ret = AIT_LEN(var), pos = data; ret > 0; ret -= len, pos += len)
  311: 		if ((len = send(cli->cli_sock, pos, ret, 0)) == -1) {
  312: 			LOGERR;
  313: 			return -1;
  314: 		}
  315: 
  316: 	/* wait for reply */
  317: 	pfd.fd = cli->cli_sock;
  318: 	pfd.events = POLLIN | POLLPRI;
  319: 	if ((ret = poll(&pfd, 1, ((rpc_sess_t*) cli->cli_parent)->sess_timeout * 1000)) < 1 || 
  320: 			pfd.revents & (POLLERR | POLLHUP | POLLNVAL)) {
  321: 		if (ret)
  322: 			LOGERR;
  323: 		else
  324: 			rpc_SetErr(ETIMEDOUT, "Timeout reached! Server not respond");
  325: 		return -1;
  326: 	}
  327: 	if (recv(cli->cli_sock, &hdr, sizeof hdr, 0) == -1) {
  328: 		LOGERR;
  329: 		return 1;
  330: 	}
  331: 	/* check CRC */
  332: 	ret = ntohs(hdr.hdr_crc);
  333: 	hdr.hdr_crc ^= hdr.hdr_crc;
  334: 	if (ret != crcFletcher16((u_short*) &hdr, sizeof hdr / 2)) {
  335: 		rpc_SetErr(ERPCMISMATCH, "Bad CRC BLOB packet");
  336: 		return 1;
  337: 	}
  338: 
  339: 	if (hdr.hdr_cmd != error) {
  340: 		if (ntohl(hdr.hdr_len) != AIT_LEN(var)) {
  341: 			rpc_SetErr(ECANCELED, "Bad return length packet");
  342: 			return 1;
  343: 		}
  344: 
  345: 		var->val.blob = ntohl(hdr.hdr_var);
  346: 	}
  347: 
  348: 	return hdr.hdr_cmd == error;
  349: }
  350: 
  351: /*
  352:  * rpc_cli_recvBLOB() - Receive BLOB from server
  353:  *
  354:  * @cli = Client instance
  355:  * @var = BLOB variable
  356:  * @data = BLOB data, must be free after use!
  357:  * return: -1 error, 0 ok, 1 remote error
  358:  */
  359: int
  360: rpc_cli_recvBLOB(rpc_cli_t * __restrict cli, ait_val_t * __restrict var, void ** __restrict data)
  361: {
  362: 	int ret, len;
  363: 	uint8_t *pos;
  364: 	struct pollfd pfd;
  365: 	struct tagBLOBHdr hdr;
  366: 
  367: 	if (!cli || !var || !data) {
  368: 		rpc_SetErr(EINVAL, "Invalid arguments");
  369: 		return -1;
  370: 	}
  371: 
  372: 	*data = malloc(AIT_LEN(var));
  373: 	if (!*data) {
  374: 		LOGERR;
  375: 		return -1;
  376: 	} else
  377: 		memset(*data, 0, AIT_LEN(var));
  378: 
  379: 	rpc_addPktSession(&hdr.hdr_session, cli->cli_parent);
  380: 	hdr.hdr_cmd = get;
  381: 	hdr.hdr_var = htonl((uint32_t) AIT_GET_BLOB(var));
  382: 	hdr.hdr_ret = 0;
  383: 	hdr.hdr_len = 0;
  384: 	/* calculate CRC */
  385: 	hdr.hdr_crc ^= hdr.hdr_crc;
  386: 	hdr.hdr_crc = htons(crcFletcher16((u_short*) &hdr, sizeof hdr / 2));
  387: 
  388: 	/* send GET request */
  389: 	if (send(cli->cli_sock, &hdr, sizeof hdr, 0) == -1) {
  390: 		LOGERR;
  391: 		free(*data);
  392: 		*data = NULL;
  393: 		return -1;
  394: 	}
  395: 
  396: 	/* receive BLOB from server */
  397: 	pfd.fd = cli->cli_sock;
  398: 	pfd.events = POLLIN | POLLPRI;
  399: 	for (ret = AIT_LEN(var), pos = *data; ret > 0; ret -= len, pos += len) {
  400: 		if ((len = poll(&pfd, 1, ((rpc_sess_t*) cli->cli_parent)->sess_timeout * 1000)) < 1 || 
  401: 				pfd.revents & (POLLERR | POLLHUP | POLLNVAL)) {
  402: 			LOGERR;
  403: 			free(*data);
  404: 			*data = NULL;
  405: 			return -1;
  406: 		}
  407: 
  408: 		if ((len = recv(cli->cli_sock, pos, ret, 0)) == -1) {
  409: 			LOGERR;
  410: 			free(*data);
  411: 			*data = NULL;
  412: 			return -1;
  413: 		}
  414: 	}
  415: 
  416: 	/* wait for reply */
  417: 	if ((len = poll(&pfd, 1, ((rpc_sess_t*) cli->cli_parent)->sess_timeout * 1000)) < 1 || 
  418: 			pfd.revents & (POLLERR | POLLHUP | POLLNVAL)) {
  419: 		if (len)
  420: 			LOGERR;
  421: 		else
  422: 			rpc_SetErr(ETIMEDOUT, "Timeout reached! Server not respond");
  423: 		free(*data);
  424: 		*data = NULL;
  425: 		return 1;
  426: 	}
  427: 	if (recv(cli->cli_sock, &hdr, sizeof hdr, 0) == -1) {
  428: 		LOGERR;
  429: 		free(*data);
  430: 		*data = NULL;
  431: 		return 1;
  432: 	}
  433: 	/* check CRC */
  434: 	ret = ntohs(hdr.hdr_crc);
  435: 	hdr.hdr_crc ^= hdr.hdr_crc;
  436: 	if (ret != crcFletcher16((u_short*) &hdr, sizeof hdr / 2)) {
  437: 		rpc_SetErr(ERPCMISMATCH, "Bad CRC BLOB packet");
  438: 		free(*data);
  439: 		*data = NULL;
  440: 		return 1;
  441: 	}
  442: 	if (hdr.hdr_cmd != error) {
  443: 		if (ntohl(hdr.hdr_len) != AIT_LEN(var)) {
  444: 			rpc_SetErr(ECANCELED, "Bad return length packet");
  445: 			free(*data);
  446: 			*data = NULL;
  447: 			return 1;
  448: 		}
  449: 	}
  450: 
  451: 	return hdr.hdr_cmd == error;
  452: }
  453: 
  454: /*
  455:  * rpc_cli_delBLOB() - Delete BLOB from server
  456:  *
  457:  * @cli = Client instance
  458:  * @var = BLOB variable
  459:  * return: -1 error, 0 ok, 1 remote error
  460:  */
  461: int
  462: rpc_cli_delBLOB(rpc_cli_t * __restrict cli, ait_val_t * __restrict var)
  463: {
  464: 	struct tagBLOBHdr hdr;
  465: 	struct pollfd pfd;
  466: 	int ret;
  467: 
  468: 	if (!cli || !var) {
  469: 		rpc_SetErr(EINVAL, "Invalid arguments");
  470: 		return -1;
  471: 	}
  472: 
  473: 	rpc_addPktSession(&hdr.hdr_session, cli->cli_parent);
  474: 	hdr.hdr_cmd = unset;
  475: 	hdr.hdr_var = htonl((uint32_t) AIT_GET_BLOB(var));
  476: 	hdr.hdr_ret = 0;
  477: 	hdr.hdr_len = 0;
  478: 	/* calculate CRC */
  479: 	hdr.hdr_crc ^= hdr.hdr_crc;
  480: 	hdr.hdr_crc = htons(crcFletcher16((u_short*) &hdr, sizeof hdr / 2));
  481: 
  482: 	/* send UNSET request */
  483: 	if (send(cli->cli_sock, &hdr, sizeof hdr, 0) == -1) {
  484: 		LOGERR;
  485: 		return -1;
  486: 	}
  487: 
  488: 	/* wait for reply */
  489: 	pfd.fd = cli->cli_sock;
  490: 	pfd.events = POLLIN | POLLPRI;
  491: 	if ((ret = poll(&pfd, 1, ((rpc_sess_t*) cli->cli_parent)->sess_timeout * 1000)) < 1 || 
  492: 			pfd.revents & (POLLERR | POLLHUP | POLLNVAL)) {
  493: 		if (ret)
  494: 			LOGERR;
  495: 		else
  496: 			rpc_SetErr(ETIMEDOUT, "Timeout reached! Server not respond");
  497: 		return 1;
  498: 	}
  499: 	if (recv(cli->cli_sock, &hdr, sizeof hdr, 0) == -1) {
  500: 		LOGERR;
  501: 		return 1;
  502: 	}
  503: 	/* check CRC */
  504: 	ret = ntohs(hdr.hdr_crc);
  505: 	hdr.hdr_crc ^= hdr.hdr_crc;
  506: 	if (ret != crcFletcher16((u_short*) &hdr, sizeof hdr / 2)) {
  507: 		rpc_SetErr(ERPCMISMATCH, "Bad CRC BLOB packet");
  508: 		return 1;
  509: 	}
  510: 
  511: 	return hdr.hdr_cmd == error;
  512: }
  513: 
  514: /*
  515:  * rpc_cli_getBLOB() - Receive BLOB from server and Delete after that
  516:  *
  517:  * @cli = Client instance
  518:  * @var = BLOB variable
  519:  * @data = BLOB data, must be free after use!
  520:  * return: -1 error, 0 ok, 1 remote error
  521:  */
  522: inline int
  523: rpc_cli_getBLOB(rpc_cli_t * __restrict cli, ait_val_t * __restrict var, void ** __restrict data)
  524: {
  525: 	int ret;
  526: 
  527: 	ret = rpc_cli_recvBLOB(cli, var, data);
  528: 	ret |= rpc_cli_delBLOB(cli, var) > 0 ? 2 : 0;
  529: 
  530: 	return ret;
  531: }

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>