Annotation of libaitrpc/src/blob.c, revision 1.7.2.2

1.2       misho       1: /*************************************************************************
                      2: * (C) 2010 AITNET ltd - Sofia/Bulgaria - <misho@aitbg.com>
                      3: *  by Michael Pounov <misho@openbsd-bg.org>
                      4: *
                      5: * $Author: misho $
1.7.2.2 ! misho       6: * $Id: blob.c,v 1.7.2.1 2012/05/16 08:10:39 misho Exp $
1.2       misho       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: 
1.5       misho      15: Copyright 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012
1.2       misho      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: /*
1.7.2.1   misho      50:  * rpc_srv_blobCreate() - Create and map blob to memory region and return object
1.5       misho      51:  *
1.2       misho      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: 
1.3       misho      74:        memset(szFName, 0, sizeof szFName);
1.5       misho      75:        snprintf(szFName, sizeof szFName, BLOB_FILE, AIT_GET_STR(&srv->srv_blob.dir), rnd);
1.2       misho      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:        }
1.7.2.1   misho      84:        if (ftruncate(f, len) == -1) {
1.2       misho      85:                LOGERR;
                     86:                close(f);
                     87:                unlink(szFName);
                     88:                return NULL;
1.7.2.1   misho      89:        }
1.2       misho      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: /*
1.5       misho     115:  * rpc_srv_blobMap() - Map blob to memory region 
                    116:  *
1.2       misho     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) {
1.5       misho     128:                rpc_SetErr(EINVAL, "Invalid argument BLOB");
1.2       misho     129:                return -1;
                    130:        }
1.4       misho     131:        if (blob->blob_data) {
1.5       misho     132:                rpc_SetErr(EPERM, "Already mmapped object found!");
1.4       misho     133:                return -1;
                    134:        }
1.2       misho     135: 
1.3       misho     136:        memset(szFName, 0, sizeof szFName);
1.5       misho     137:        snprintf(szFName, sizeof szFName, BLOB_FILE, AIT_GET_STR(&srv->srv_blob.dir), blob->blob_var);
1.2       misho     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: /*
1.5       misho     160:  * rpc_srv_blobUnmap() - Unmap blob memory region 
                    161:  *
1.2       misho     162:  * @blob = Mapped BLOB element
                    163:  * return: none
                    164:  */
                    165: inline void
                    166: rpc_srv_blobUnmap(rpc_blob_t * __restrict blob)
                    167: {
1.7.2.1   misho     168:        if (blob && blob->blob_data)
1.2       misho     169:                munmap(blob->blob_data, blob->blob_len);
                    170:                blob->blob_data = NULL;
                    171:        }
                    172: }
                    173: 
                    174: /*
1.5       misho     175:  * rpc_srv_blobFree() - Free blob from disk & memory
                    176:  *
1.2       misho     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) {
1.5       misho     187:                rpc_SetErr(EINVAL, "Invalid argument BLOB");
1.2       misho     188:                return -1;
1.7.2.1   misho     189:        } else
1.2       misho     190:                rpc_srv_blobUnmap(blob);
                    191: 
1.3       misho     192:        memset(szFName, 0, sizeof szFName);
1.5       misho     193:        snprintf(szFName, sizeof szFName, BLOB_FILE, AIT_GET_STR(&srv->srv_blob.dir), blob->blob_var);
1.3       misho     194:        if (unlink(szFName) == -1) {
1.2       misho     195:                LOGERR;
                    196:                return -1;
                    197:        }
                    198: 
                    199:        return 0;
                    200: }
                    201: 
1.7.2.1   misho     202: /* ------------------------------------------------------------ */
1.2       misho     203: 
                    204: /*
1.5       misho     205:  * rpc_srv_sendBLOB() - Send mapped BLOB to client
                    206:  *
1.2       misho     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) {
1.5       misho     218:                rpc_SetErr(EINVAL, "Invalid arguments");
1.2       misho     219:                return -1;
                    220:        }
                    221: 
1.3       misho     222:        for (ret = blob->blob_len, pos = blob->blob_data; ret > 0; ret -= len, pos += len) {
1.7.2.2 ! misho     223:                len = send(cli->cli_sock, pos, ret, MSG_NOSIGNAL);
1.3       misho     224:                if (len == -1) {
1.2       misho     225:                        LOGERR;
                    226:                        return -1;
                    227:                }
1.3       misho     228:        }
1.2       misho     229: 
                    230:        return ret;
                    231: }
                    232: 
                    233: /*
1.5       misho     234:  * rpc_srv_recvBLOB() - Receive BLOB from client
                    235:  *
1.2       misho     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;
1.7       misho     245:        struct pollfd pfd;
1.2       misho     246: 
                    247:        if (!cli || !blob || !blob->blob_data) {
1.5       misho     248:                rpc_SetErr(EINVAL, "Invalid arguments");
1.2       misho     249:                return -1;
1.7       misho     250:        }
1.2       misho     251: 
1.7       misho     252:        pfd.fd = cli->cli_sock;
                    253:        pfd.events = POLLIN | POLLPRI;
1.2       misho     254:        for (ret = blob->blob_len, pos = blob->blob_data; ret > 0; ret -= len, pos += len) {
1.7.2.2 ! misho     255:                if ((len = poll(&pfd, 1, DEF_RPC_TIMEOUT * 1000)) < 1 || 
1.7       misho     256:                                pfd.revents & (POLLERR | POLLHUP | POLLNVAL)) {
1.2       misho     257:                        LOGERR;
                    258:                        return -1;
                    259:                }
                    260: 
1.3       misho     261:                len = recv(cli->cli_sock, pos, ret, 0);
                    262:                if (len == -1) {
1.2       misho     263:                        LOGERR;
                    264:                        return -1;
                    265:                }
                    266:        }
                    267: 
                    268:        return ret;
                    269: }
                    270: 
1.7.2.2 ! misho     271: /* ------------------------------------------------------------ */
1.2       misho     272: 
                    273: /*
1.5       misho     274:  * rpc_cli_sendBLOB() - Send BLOB to server
                    275:  *
1.2       misho     276:  * @cli = Client instance
                    277:  * @var = BLOB variable
                    278:  * @data = BLOB data
                    279:  * return: -1 error, 0 ok, 1 remote error
                    280:  */
                    281: int
1.4       misho     282: rpc_cli_sendBLOB(rpc_cli_t * __restrict cli, ait_val_t * __restrict var, void * __restrict data)
1.2       misho     283: {
                    284:        int ret, len;
                    285:        uint8_t *pos;
                    286:        struct tagBLOBHdr hdr;
1.7       misho     287:        struct pollfd pfd;
1.2       misho     288: 
                    289:        if (!cli || !var || !data) {
1.5       misho     290:                rpc_SetErr(EINVAL, "Invalid arguments");
1.2       misho     291:                return -1;
1.7       misho     292:        }
1.2       misho     293: 
1.5       misho     294:        rpc_addPktSession(&hdr.hdr_session, cli->cli_parent);
1.2       misho     295:        hdr.hdr_cmd = set;
                    296:        hdr.hdr_var = 0;
                    297:        hdr.hdr_ret = 0;
1.5       misho     298:        hdr.hdr_len = htonl(AIT_LEN(var));
                    299:        /* calculate CRC */
                    300:        hdr.hdr_crc ^= hdr.hdr_crc;
1.6       misho     301:        hdr.hdr_crc = htons(crcFletcher16((u_short*) &hdr, sizeof hdr / 2));
1.5       misho     302: 
                    303:        /* send SET request */
1.2       misho     304:        if (send(cli->cli_sock, &hdr, sizeof hdr, 0) == -1) {
                    305:                LOGERR;
                    306:                return -1;
                    307:        }
                    308: 
1.4       misho     309:        /* send BLOB to server */
                    310:        for (ret = AIT_LEN(var), pos = data; ret > 0; ret -= len, pos += len)
1.3       misho     311:                if ((len = send(cli->cli_sock, pos, ret, 0)) == -1) {
1.2       misho     312:                        LOGERR;
                    313:                        return -1;
                    314:                }
                    315: 
1.5       misho     316:        /* wait for reply */
1.7       misho     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)
1.2       misho     322:                        LOGERR;
1.7       misho     323:                else
                    324:                        rpc_SetErr(ETIMEDOUT, "Timeout reached! Server not respond");
                    325:                return -1;
1.2       misho     326:        }
                    327:        if (recv(cli->cli_sock, &hdr, sizeof hdr, 0) == -1) {
                    328:                LOGERR;
1.5       misho     329:                return 1;
                    330:        }
                    331:        /* check CRC */
                    332:        ret = ntohs(hdr.hdr_crc);
                    333:        hdr.hdr_crc ^= hdr.hdr_crc;
1.6       misho     334:        if (ret != crcFletcher16((u_short*) &hdr, sizeof hdr / 2)) {
1.5       misho     335:                rpc_SetErr(ERPCMISMATCH, "Bad CRC BLOB packet");
                    336:                return 1;
1.2       misho     337:        }
1.5       misho     338: 
1.2       misho     339:        if (hdr.hdr_cmd != error) {
1.5       misho     340:                if (ntohl(hdr.hdr_len) != AIT_LEN(var)) {
                    341:                        rpc_SetErr(ECANCELED, "Bad return length packet");
                    342:                        return 1;
1.2       misho     343:                }
                    344: 
1.5       misho     345:                var->val.blob = ntohl(hdr.hdr_var);
1.2       misho     346:        }
                    347: 
                    348:        return hdr.hdr_cmd == error;
                    349: }
                    350: 
                    351: /*
1.5       misho     352:  * rpc_cli_recvBLOB() - Receive BLOB from server
                    353:  *
1.2       misho     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
1.4       misho     360: rpc_cli_recvBLOB(rpc_cli_t * __restrict cli, ait_val_t * __restrict var, void ** __restrict data)
1.2       misho     361: {
                    362:        int ret, len;
                    363:        uint8_t *pos;
1.7       misho     364:        struct pollfd pfd;
1.2       misho     365:        struct tagBLOBHdr hdr;
                    366: 
                    367:        if (!cli || !var || !data) {
1.5       misho     368:                rpc_SetErr(EINVAL, "Invalid arguments");
1.2       misho     369:                return -1;
1.7       misho     370:        }
1.2       misho     371: 
1.4       misho     372:        *data = malloc(AIT_LEN(var));
1.2       misho     373:        if (!*data) {
                    374:                LOGERR;
                    375:                return -1;
                    376:        } else
1.4       misho     377:                memset(*data, 0, AIT_LEN(var));
1.2       misho     378: 
1.5       misho     379:        rpc_addPktSession(&hdr.hdr_session, cli->cli_parent);
1.2       misho     380:        hdr.hdr_cmd = get;
1.5       misho     381:        hdr.hdr_var = htonl((uint32_t) AIT_GET_BLOB(var));
1.2       misho     382:        hdr.hdr_ret = 0;
                    383:        hdr.hdr_len = 0;
1.5       misho     384:        /* calculate CRC */
                    385:        hdr.hdr_crc ^= hdr.hdr_crc;
1.6       misho     386:        hdr.hdr_crc = htons(crcFletcher16((u_short*) &hdr, sizeof hdr / 2));
1.5       misho     387: 
                    388:        /* send GET request */
1.2       misho     389:        if (send(cli->cli_sock, &hdr, sizeof hdr, 0) == -1) {
                    390:                LOGERR;
                    391:                free(*data);
                    392:                *data = NULL;
                    393:                return -1;
                    394:        }
                    395: 
1.4       misho     396:        /* receive BLOB from server */
1.7       misho     397:        pfd.fd = cli->cli_sock;
                    398:        pfd.events = POLLIN | POLLPRI;
1.4       misho     399:        for (ret = AIT_LEN(var), pos = *data; ret > 0; ret -= len, pos += len) {
1.7       misho     400:                if ((len = poll(&pfd, 1, ((rpc_sess_t*) cli->cli_parent)->sess_timeout * 1000)) < 1 || 
                    401:                                pfd.revents & (POLLERR | POLLHUP | POLLNVAL)) {
1.2       misho     402:                        LOGERR;
                    403:                        free(*data);
                    404:                        *data = NULL;
                    405:                        return -1;
                    406:                }
                    407: 
1.3       misho     408:                if ((len = recv(cli->cli_sock, pos, ret, 0)) == -1) {
1.2       misho     409:                        LOGERR;
                    410:                        free(*data);
                    411:                        *data = NULL;
                    412:                        return -1;
                    413:                }
                    414:        }
                    415: 
1.5       misho     416:        /* wait for reply */
1.7       misho     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)
1.2       misho     420:                        LOGERR;
1.7       misho     421:                else
                    422:                        rpc_SetErr(ETIMEDOUT, "Timeout reached! Server not respond");
                    423:                free(*data);
                    424:                *data = NULL;
                    425:                return 1;
1.2       misho     426:        }
                    427:        if (recv(cli->cli_sock, &hdr, sizeof hdr, 0) == -1) {
                    428:                LOGERR;
                    429:                free(*data);
                    430:                *data = NULL;
1.5       misho     431:                return 1;
                    432:        }
                    433:        /* check CRC */
                    434:        ret = ntohs(hdr.hdr_crc);
                    435:        hdr.hdr_crc ^= hdr.hdr_crc;
1.6       misho     436:        if (ret != crcFletcher16((u_short*) &hdr, sizeof hdr / 2)) {
1.5       misho     437:                rpc_SetErr(ERPCMISMATCH, "Bad CRC BLOB packet");
                    438:                free(*data);
                    439:                *data = NULL;
                    440:                return 1;
1.2       misho     441:        }
                    442:        if (hdr.hdr_cmd != error) {
1.5       misho     443:                if (ntohl(hdr.hdr_len) != AIT_LEN(var)) {
                    444:                        rpc_SetErr(ECANCELED, "Bad return length packet");
1.2       misho     445:                        free(*data);
                    446:                        *data = NULL;
1.5       misho     447:                        return 1;
1.2       misho     448:                }
                    449:        }
                    450: 
                    451:        return hdr.hdr_cmd == error;
                    452: }
                    453: 
                    454: /*
1.5       misho     455:  * rpc_cli_delBLOB() - Delete BLOB from server
                    456:  *
1.2       misho     457:  * @cli = Client instance
                    458:  * @var = BLOB variable
                    459:  * return: -1 error, 0 ok, 1 remote error
                    460:  */
                    461: int
1.4       misho     462: rpc_cli_delBLOB(rpc_cli_t * __restrict cli, ait_val_t * __restrict var)
1.2       misho     463: {
                    464:        struct tagBLOBHdr hdr;
1.7       misho     465:        struct pollfd pfd;
1.5       misho     466:        int ret;
1.2       misho     467: 
                    468:        if (!cli || !var) {
1.5       misho     469:                rpc_SetErr(EINVAL, "Invalid arguments");
1.2       misho     470:                return -1;
1.7       misho     471:        }
1.2       misho     472: 
1.5       misho     473:        rpc_addPktSession(&hdr.hdr_session, cli->cli_parent);
1.2       misho     474:        hdr.hdr_cmd = unset;
1.5       misho     475:        hdr.hdr_var = htonl((uint32_t) AIT_GET_BLOB(var));
1.2       misho     476:        hdr.hdr_ret = 0;
                    477:        hdr.hdr_len = 0;
1.5       misho     478:        /* calculate CRC */
                    479:        hdr.hdr_crc ^= hdr.hdr_crc;
1.6       misho     480:        hdr.hdr_crc = htons(crcFletcher16((u_short*) &hdr, sizeof hdr / 2));
1.5       misho     481: 
                    482:        /* send UNSET request */
1.2       misho     483:        if (send(cli->cli_sock, &hdr, sizeof hdr, 0) == -1) {
                    484:                LOGERR;
                    485:                return -1;
                    486:        }
                    487: 
1.5       misho     488:        /* wait for reply */
1.7       misho     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)
1.2       misho     494:                        LOGERR;
1.7       misho     495:                else
                    496:                        rpc_SetErr(ETIMEDOUT, "Timeout reached! Server not respond");
                    497:                return 1;
1.2       misho     498:        }
                    499:        if (recv(cli->cli_sock, &hdr, sizeof hdr, 0) == -1) {
                    500:                LOGERR;
1.5       misho     501:                return 1;
                    502:        }
                    503:        /* check CRC */
                    504:        ret = ntohs(hdr.hdr_crc);
                    505:        hdr.hdr_crc ^= hdr.hdr_crc;
1.6       misho     506:        if (ret != crcFletcher16((u_short*) &hdr, sizeof hdr / 2)) {
1.5       misho     507:                rpc_SetErr(ERPCMISMATCH, "Bad CRC BLOB packet");
                    508:                return 1;
1.2       misho     509:        }
                    510: 
                    511:        return hdr.hdr_cmd == error;
                    512: }
                    513: 
                    514: /*
1.5       misho     515:  * rpc_cli_getBLOB() - Receive BLOB from server and Delete after that
                    516:  *
1.2       misho     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
1.4       misho     523: rpc_cli_getBLOB(rpc_cli_t * __restrict cli, ait_val_t * __restrict var, void ** __restrict data)
1.2       misho     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>