tFortify error-checks and FSM - ratox - FIFO based tox client
 (DIR) Log
 (DIR) Files
 (DIR) Refs
 (DIR) README
 (DIR) LICENSE
       ---
 (DIR) commit 91cf7e937b43cd56e45699e2f1c73f109c16e0b6
 (DIR) parent 2fe183edfe6273cdf1a1f0c3c1cf8a638b823caf
 (HTM) Author: FRIGN <dev@frign.de>
       Date:   Mon, 13 Oct 2014 19:09:35 +0200
       
       Fortify error-checks and FSM
       
       Basically the direct calls to cancelcall() should be minimized
       and only set off in a callback.
       Additionally, tweak other error-cases and don't always quit fatally
       but instead provide ways to get out of an error-condition.
       
       Diffstat:
         M ratox.c                             |      95 +++++++++++++++++++------------
       
       1 file changed, 60 insertions(+), 35 deletions(-)
       ---
 (DIR) diff --git a/ratox.c b/ratox.c
       t@@ -367,6 +367,9 @@ cbcallinvite(void *av, int32_t cnum, void *udata)
                fnum = toxav_get_peer_id(toxav, cnum, 0);
                if (fnum < 0) {
                        weprintf("Failed to determine peer-id from call-id\n");
       +                r = toxav_reject(toxav, cnum, NULL);
       +                if (r < 0)
       +                        weprintf("Failed to reject call\n");
                        return;
                }
                TAILQ_FOREACH(f, &friendhead, entry)
       t@@ -379,6 +382,9 @@ cbcallinvite(void *av, int32_t cnum, void *udata)
                r = toxav_get_peer_csettings(toxav, cnum, 0, &avconfig);
                if (r < 0) {
                        weprintf("Failed to determine peer call type\n");
       +                r = toxav_reject(toxav, f->av.num, NULL);
       +                if (r < 0)
       +                        weprintf("Failed to reject call\n");
                        return;
                }
        
       t@@ -413,10 +419,12 @@ cbcallstart(void *av, int32_t cnum, void *type)
        
                if(!strncmp(type, "Tx", 2))
                        preparetxcall(f);
       -        r = toxav_prepare_transmission(toxav, cnum, av_jbufdc, av_VADd, 0);
       +        r = toxav_prepare_transmission(toxav, f->av.num, av_jbufdc, av_VADd, 0);
                if (r < 0) {
                        weprintf("Failed to prepare %s AV transmission\n", type);
       -                cancelcall(f, "Failed");
       +                r = toxav_hangup(toxav, f->av.num);
       +                if (r < 0)
       +                        weprintf("Failed to hang up\n");
                        return;
                }
                logmsg(": %s : %s AV > Started\n", f->name, type);
       t@@ -490,13 +498,15 @@ cancelcall(struct friend *f, char *action)
                logmsg(": %s : Rx/Tx AV > %s\n", f->name, action);
        
                if (f->av.num != -1) {
       -                r = toxav_kill_transmission(toxav, f->av.num);
       -                if (r < 0)
       -                        weprintf("Failed to kill transmission\n");
       +                if (toxav_get_call_state(toxav, f->av.num) != av_CallInviting) {
       +                        r = toxav_kill_transmission(toxav, f->av.num);
       +                        if (r < 0)
       +                                weprintf("Failed to kill transmission\n");
       +                }
                }
                f->av.num = -1;
        
       -        /* Cancel Tx side of the call */
       +        /* Cancel Rx side of the call */
                if (f->fd[FCALL_OUT] != -1) {
                        close(f->fd[FCALL_OUT]);
                        f->fd[FCALL_OUT] = -1;
       t@@ -505,7 +515,7 @@ cancelcall(struct friend *f, char *action)
                lseek(f->fd[FCALL_PENDING], 0, SEEK_SET);
                dprintf(f->fd[FCALL_PENDING], "0\n");
        
       -        /* Cancel Rx side of the call */
       +        /* Cancel Tx side of the call */
                free(f->av.frame);
                f->av.frame = NULL;
                fiforeset(f->dirfd, &f->fd[FCALL_IN], ffiles[FCALL_IN]);
       t@@ -542,8 +552,10 @@ sendfriendcalldata(struct friend *f)
                payloadsize = toxav_prepare_audio_frame(toxav, f->av.num,
                                                        f->av.payload, sizeof(f->av.payload),
                                                        (int16_t *)f->av.frame, framesize);
       -        if (payloadsize < 0)
       -                eprintf("Failed to encode payload\n");
       +        if (payloadsize < 0) {
       +                weprintf("Failed to encode payload\n");
       +                return;
       +        }
        
                clock_gettime(CLOCK_MONOTONIC, &now);
                diff = timediff(f->av.lastsent, now);
       t@@ -554,7 +566,7 @@ sendfriendcalldata(struct friend *f)
                clock_gettime(CLOCK_MONOTONIC, &f->av.lastsent);
                r = toxav_send_audio(toxav, f->av.num, f->av.payload, payloadsize);
                if (r < 0)
       -                eprintf("Failed to send audio frame\n");
       +                weprintf("Failed to send audio frame\n");
        }
        
        static void
       t@@ -566,9 +578,10 @@ cbconnstatus(Tox *m, int32_t frnum, uint8_t status, void *udata)
                int r;
        
                r = tox_get_name(tox, frnum, (uint8_t *)name);
       -        if (r < 0)
       -                eprintf("Failed to get name for friend number %ld\n",
       -                        (long)frnum);
       +        if (r < 0) {
       +                weprintf("Failed to get name for friend number %ld\n", (long)frnum);
       +                return;
       +        }
        
                if (r == 0)
                        snprintf(name, sizeof(name), "Anonymous");
       t@@ -965,8 +978,10 @@ readpass(const char *prompt)
                char pass[BUFSIZ], *p;
        
                p = readpassphrase(prompt, pass, sizeof(pass), RPP_ECHO_OFF);
       -        if (!p)
       -                eprintf("readpassphrase:");
       +        if (!p) {
       +                weprintf("readpassphrase:");
       +                return -1;
       +        }
                if (p[0] == '\0')
                        return -1;
                passphrase = realloc(passphrase, strlen(p)); /* not null-terminated */
       t@@ -994,8 +1009,10 @@ dataload(void)
                sz = lseek(fd, 0, SEEK_END);
                lseek(fd, 0, SEEK_SET);
        
       -        if (sz == 0)
       -                eprintf("Data : %s > Empty\n", DATAFILE);
       +        if (sz == 0) {
       +                weprintf("Data : %s > Empty\n", DATAFILE);
       +                return;
       +        }
        
                data = malloc(sz);
                if (!data)
       t@@ -1095,29 +1112,31 @@ localinit(void)
        
                /* Dump current name */
                r = tox_get_self_name(tox, name);
       -        if (r == 0)
       +        if (r == 0) {
                        weprintf("Failed to get current name\n");
       -        if (r > sizeof(name) - 1)
       +        } else if (r > sizeof(name) - 1) {
                        r = sizeof(name) - 1;
       +        }
                name[r] = '\0';
                ftruncate(gslots[NAME].fd[OUT], 0);
                dprintf(gslots[NAME].fd[OUT], "%s\n", name);
        
                /* Dump status */
                r = tox_get_self_status_message(tox, status, sizeof(status) - 1);
       -        if (r == 0)
       +        if (r == 0) {
                        weprintf("Failed to get current status\n");
       -        if (r > sizeof(status) - 1)
       +        } else if (r > sizeof(status) - 1) {
                        r = sizeof(status) - 1;
       +        }
                status[r] = '\0';
                ftruncate(gslots[STATUS].fd[OUT], 0);
                dprintf(gslots[STATUS].fd[OUT], "%s\n", status);
        
                /* Dump user state */
                r = tox_get_self_user_status(tox);
       -        if (r < 0)
       +        if (r < 0) {
                        weprintf("Failed to get current state\n");
       -        if (r >= LEN(ustate)) {
       +        } else if (r >= LEN(ustate)) {
                        ftruncate(gslots[STATE].fd[ERR], 0);
                        dprintf(gslots[STATE].fd[ERR], "invalid\n");
                        weprintf("Invalid user state: %d\n", r);
       t@@ -1259,9 +1278,10 @@ friendcreate(int32_t frnum)
                        eprintf("calloc:");
        
                r = tox_get_name(tox, frnum, (uint8_t *)f->name);
       -        if (r < 0)
       -                eprintf("Failed to get name for friend number %ld\n",
       -                        (long)frnum);
       +        if (r < 0) {
       +                weprintf("Failed to get name for friend number %ld\n", (long)frnum);
       +                return NULL;
       +        }
                if (r == 0)
                        snprintf(f->name, sizeof(f->name), "Anonymous");
                else
       t@@ -1307,19 +1327,21 @@ friendcreate(int32_t frnum)
        
                /* Dump status */
                r = tox_get_status_message(tox, frnum, status, sizeof(status) - 1);
       -        if (r < 0 )
       +        if (r < 0) {
                        weprintf("Failed to get user status\n");
       -        if (r > sizeof(status) - 1)
       +                r = 0;
       +        } else if (r > sizeof(status) - 1) {
                        r = sizeof(status) - 1;
       +        }
                status[r] = '\0';
                ftruncate(f->fd[FSTATUS], 0);
                dprintf(f->fd[FSTATUS], "%s\n", status);
        
                /* Dump user state */
                r = tox_get_user_status(tox, frnum);
       -        if (r < 0)
       +        if (r < 0) {
                        weprintf("Failed to get user state\n");
       -        if (r >= LEN(ustate)) {
       +        } else if (r >= LEN(ustate)) {
                        weprintf("Invalid user state: %d\n", r);
                } else {
                        ftruncate(f->fd[FSTATE], 0);
       t@@ -1348,7 +1370,7 @@ frienddestroy(struct friend *f)
                canceltxtransfer(f);
                cancelrxtransfer(f);
                if (f->av.num != -1 && toxav_get_call_state(toxav, f->av.num) != av_CallNonExistant)
       -                cancelcall(f, "Destroying");
       +                cancelcall(f, "Destroying"); /* todo: check state */
                for (i = 0; i < LEN(ffiles); i++) {
                        if (f->dirfd != -1) {
                                unlinkat(f->dirfd, ffiles[i].name, 0);
       t@@ -1733,7 +1755,9 @@ loop(void)
                                                r = toxav_answer(toxav, f->av.num, &toxavconfig);
                                                if (r < 0) {
                                                        weprintf("Failed to answer call\n");
       -                                                cancelcall(f, "Failed");
       +                                                r = toxav_reject(toxav, f->av.num, NULL);
       +                                                if (r < 0)
       +                                                        weprintf("Failed to reject call\n");
                                                }
                                                break;
                                        case av_CallActive:
       t@@ -1777,7 +1801,8 @@ loop(void)
                                r = tox_add_friend_norequest(tox, req->id);
                                if (r < 0) {
                                        weprintf("Failed to add friend %s\n", req->idstr);
       -                                goto cleanup;
       +                                fiforeset(gslots[REQUEST].fd[OUT], &req->fd, reqfifo);
       +                                continue;
                                }
                                if (c == '1') {
                                        friendcreate(r);
       t@@ -1787,7 +1812,6 @@ loop(void)
                                        tox_del_friend(tox, r);
                                        logmsg("Request : %s > Rejected\n", req->idstr);
                                }
       -cleanup:
                                unlinkat(gslots[REQUEST].fd[OUT], req->idstr, 0);
                                close(req->fd);
                                TAILQ_REMOVE(&reqhead, req, entry);
       t@@ -1825,7 +1849,8 @@ cleanup:
                                                r = toxav_call(toxav, &f->av.num, f->num, &toxavconfig, RINGINGDELAY);
                                                if (r < 0) {
                                                        weprintf("Failed to call\n");
       -                                                cancelcall(f, "Failed");
       +                                                fiforeset(f->dirfd, &f->fd[FCALL_IN], ffiles[FCALL_IN]);
       +                                                break;
                                                }
                                                logmsg(": %s : Tx AV > Inviting\n", f->name);
                                                break;