Merge branch 't/remove_sb_compat'
authorAndre Noll <maan@systemlinux.org>
Sat, 17 Aug 2013 11:57:32 +0000 (13:57 +0200)
committerAndre Noll <maan@systemlinux.org>
Sat, 17 Aug 2013 12:06:35 +0000 (14:06 +0200)
This topic branch was cooking for over 4 months and should now be
ready for prime time. The patches break compatibility with earlier
versions, so we need to bump the version number real soon now.

72ffa7 client: Only start stdin task for addblob commands.
85a6ae Remove old stream cipher API.
d1407f Allow addblob commands to create output.
243e31 client: Remove client_recv_buffer().
277ed4 client: Remove sb-compatibility code.
36ba18 Reject non-sideband connections.
6ca50b blob: Avoid zero sized memcpy().
cf308c Fix typo in documentation of stdin_command().
fdb9d2 blob: Simplify fd2buf().

1  2 
NEWS
afs.c
aft.c
audiod.c
client.c
client_common.c
command.c
error.h
gcrypt.c
para.h

diff --cc NEWS
--- 1/NEWS
--- 2/NEWS
+++ b/NEWS
@@@ -1,30 -1,6 +1,36 @@@
 -------------------------------------------
 -0.?.? (to be announced) "spectral gravity"
 -------------------------------------------
 +---------------------------------------------
- 0.?.? (to be announced) "invertible validity"
++0.5.0 (to be announced) "invertible validity"
 +---------------------------------------------
 +
++      - The sideband compatibility code has been removed, hence
++        sideband connections (introduced in 0.4.11) are now mandatory.
++      - Addblob commands can produce output.
++      - The stat command no longer sends garbage when para_server was
++        compiled against libgcrypt.
++
 +--------------------------------------
 +0.4.13 (2013-07-29) "spectral gravity"
 +--------------------------------------
 +
 +One more 0.4.x release before the API-breaking changes for 0.5.0 go
 +in. The main features of this release are the ogg/opus audio format,
 +and UTF-8 support, but it includes also tons of other improvements
 +and fixes all over the place.
 +
 +      - New audio format: ogg/opus.
 +      - UTF8 support for para_gui and the mp3 audio format handler.
 +      - Scheduler improvements and fixes.
 +      - The obsolete gettimeofday() function has been replaced
 +        by clock_gettime() on systems which support it.
 +      - Speed and usability improvements for para_gui.
 +      - para_client now restores the fd flags of stdin and stdout
 +        on shutdown.
 +      - Improved manual pages.
 +      - Consistent version strings for all executables.
 +      - Reduced dependencies on generated files result in fewer
 +        recompilations on changes.
 +      - Performance improvements for the compress filter.
 +      - Improved downloads web page.
  
  -----------------------------------------
  0.4.12 (2012-12-20) "volatile relativity"
diff --cc afs.c
--- 1/afs.c
--- 2/afs.c
+++ b/afs.c
@@@ -546,31 -546,6 +546,28 @@@ static int activate_mood_or_playlist(ch
        return 1;
  }
  
-       if (cc->use_sideband)
-               return send_sb(&cc->scc, result->data, result->size, band,
-                       true);
-       return sc_send_bin_buffer(&cc->scc, result->data, result->size);
 +/**
 + * Result handler for sending data to the para_client process.
 + *
 + * \param result The data to be sent.
 + * \param band The band designator.
 + * \param private Pointer to the command context.
 + *
 + * \return The return value of the underlying call to \ref command.c::send_sb.
 + *
 + * \sa \ref callback_result_handler, \ref command.c::send_sb.
 + */
 +int afs_cb_result_handler(struct osl_object *result, uint8_t band,
 +              void *private)
 +{
 +      struct command_context *cc = private;
 +
 +      assert(cc);
 +      if (!result->size)
 +              return 1;
++      return send_sb(&cc->scc, result->data, result->size, band, true);
 +}
 +
  static void com_select_callback(int fd, const struct osl_object *query)
  {
        struct para_buffer pb = {
diff --cc aft.c
Simple merge
diff --cc audiod.c
Simple merge
diff --cc client.c
+++ b/client.c
@@@ -528,26 -531,39 +528,37 @@@ __noreturn static void print_completion
  
  #endif /* HAVE_READLINE */
  
- static int supervisor_post_select(struct sched *s, __a_unused struct task *t)
+ struct supervisor_task {
+       bool stdout_task_started;
+       struct task task;
+ };
 -static void supervisor_post_select(struct sched *s, struct task *t)
++static int supervisor_post_select(struct sched *s, struct task *t)
  {
 -      if (ct->task.error < 0) {
 -              t->error = ct->task.error;
 -              return;
 -      }
+       struct supervisor_task *svt = container_of(t, struct supervisor_task,
+               task);
 -              return;
 +      if (ct->task.error < 0)
 +              return ct->task.error;
+       if (!svt->stdout_task_started && ct->status == CL_EXECUTING) {
+               stdout_set_defaults(&sot);
+               register_task(s, &sot.task);
+               svt->stdout_task_started = true;
++              return 1;
+       }
        if (ct->status == CL_SENDING) {
                stdin_set_defaults(&sit);
                register_task(s, &sit.task);
 -              t->error = -E_TASK_STARTED;
 -              return;
 +              return -E_TASK_STARTED;
        }
-       if (ct->status == CL_RECEIVING) {
-               stdout_set_defaults(&sot);
-               register_task(s, &sot.task);
-               return -E_TASK_STARTED;
-       }
 +      return 0;
  }
  
- static struct task svt = {
-       .post_select = supervisor_post_select,
-       .status = "supervisor task"
+ static struct supervisor_task supervisor_task = {
+       .task = {
+               .post_select = supervisor_post_select,
+               .status = "supervisor task"
+       }
  };
  
  /**
diff --cc client_common.c
@@@ -326,10 -303,9 +303,9 @@@ static int send_sb_command(struct clien
   *
   * \sa struct sched, struct task.
   */
 -static void client_post_select(struct sched *s, struct task *t)
 +static int client_post_select(struct sched *s, struct task *t)
  {
        struct client_task *ct = container_of(t, struct client_task, task);
-       struct btr_node *btrn = ct->btrn;
        int ret = 0;
        size_t n;
        char buf[CLIENT_BUFSIZE];
        if (ret < 0)
                goto out;
        if (ct->scc.fd < 0)
 -              return;
 +              return 0;
        switch (ct->status) {
        case CL_CONNECTED: /* receive welcome message */
-               ret = client_recv_buffer(ct, &s->rfds, buf, sizeof(buf), &n);
+               ret = read_nonblock(ct->scc.fd, buf, sizeof(buf), &s->rfds, &n);
                if (ret < 0 || n == 0)
                        goto out;
                ct->features = parse_features(buf);
+               if (!has_feature("sideband", ct)) {
+                       PARA_ERROR_LOG("server has no sideband support\n");
+                       ret = -E_INCOMPAT_FEAT;
+                       goto out;
+               }
                ct->status = CL_RECEIVED_WELCOME;
 -              return;
 +              return 0;
        case CL_RECEIVED_WELCOME: /* send auth command */
                if (!FD_ISSET(ct->scc.fd, &s->wfds))
 -                      return;
 +                      return 0;
-               if (has_feature("sideband", ct)) {
-                       ct->use_sideband = true;
-                       sprintf(buf, AUTH_REQUEST_MSG "%s sideband", ct->user);
-               } else
-                       sprintf(buf, AUTH_REQUEST_MSG "%s", ct->user);
+               sprintf(buf, AUTH_REQUEST_MSG "%s sideband", ct->user);
                PARA_INFO_LOG("--> %s\n", buf);
                ret = write_buffer(ct->scc.fd, buf);
                if (ret < 0)
                hash_to_asc(ct->challenge_hash, buf);
                PARA_INFO_LOG("--> %s\n", buf);
                ct->status = CL_RECEIVED_CHALLENGE;
 -              return;
 +              return 0;
                }
        case CL_RECEIVED_CHALLENGE:
-               if (ct->use_sideband) {
-                       ret = send_sb(ct, ct->challenge_hash, HASH_SIZE,
-                               SBD_CHALLENGE_RESPONSE, false);
-                       if (ret != 0)
-                               ct->challenge_hash = NULL;
-                       if (ret <= 0)
-                               goto out;
-               } else {
-                       ret = write_all(ct->scc.fd, (char *)ct->challenge_hash, HASH_SIZE);
-                       if (ret < 0)
-                               goto out;
-               }
+               ret = send_sb(ct, 0, ct->challenge_hash, HASH_SIZE,
+                       SBD_CHALLENGE_RESPONSE, false);
+               if (ret != 0)
+                       ct->challenge_hash = NULL;
+               if (ret <= 0)
+                       goto out;
                ct->status = CL_SENT_CH_RESPONSE;
                goto out;
        case CL_SENT_CH_RESPONSE: /* read server response */
                }
        case CL_RECEIVED_PROCEED: /* concat args and send command */
                {
-               int i;
-               char *command = NULL;
                if (!FD_ISSET(ct->scc.fd, &s->wfds))
 -                      return;
 +                      return 0;
-               if (ct->use_sideband) {
-                       ret = send_sb_command(ct);
-                       if (ret <= 0)
-                               goto out;
-                       ct->status = CL_SENT_COMMAND;
-                       return 0;
-               }
-               for (i = 0; i < ct->conf.inputs_num; i++) {
-                       char *tmp = command;
-                       command = make_message("%s\n%s", command?
-                               command : "", ct->conf.inputs[i]);
-                       free(tmp);
-               }
-               command = para_strcat(command, EOC_MSG "\n");
-               PARA_DEBUG_LOG("--> %s\n", command);
-               ret = sc_send_buffer(&ct->scc, command);
-               free(command);
-               if (ret < 0)
+               ret = send_sb_command(ct);
+               if (ret <= 0)
                        goto out;
-               ct->status = CL_SENT_COMMAND;
+               ct->status = CL_EXECUTING;
 -              return;
 +              return 0;
                }
-       case CL_SENT_COMMAND:
-               {
-               char *buf2;
-               if (ct->use_sideband) {
-                       struct sb_buffer sbb;
-                       ret = recv_sb(ct, &s->rfds, &sbb);
-                       if (ret <= 0)
-                               goto out;
-                       if (sbb.band == SBD_AWAITING_DATA) {
-                               ct->status = CL_SENDING;
-                               free(sbb.iov.iov_base);
-                               goto out;
+       case CL_SENDING:
+               if (ct->btrn[1]) {
+                       char *buf2;
+                       size_t sz;
+                       ret = btr_node_status(ct->btrn[1], 0, BTR_NT_LEAF);
+                       if (ret == -E_BTR_EOF) {
+                               /* empty blob data packet indicates EOF */
+                               PARA_INFO_LOG("blob sent\n");
+                               ret = send_sb(ct, 1, NULL, 0, SBD_BLOB_DATA, true);
+                               if (ret >= 0)
+                                       ret = -E_BTR_EOF;
                        }
-                       ct->status = CL_RECEIVING;
-                       ret = dispatch_sbb(ct, &sbb);
-                       goto out;
-               }
-               /* can not use "buf" here because we need a malloced buffer */
-               buf2 = para_malloc(CLIENT_BUFSIZE);
-               ret = client_recv_buffer(ct, &s->rfds, buf2, CLIENT_BUFSIZE, &n);
-               if (n > 0) {
-                       if (strstr(buf2, AWAITING_DATA_MSG)) {
-                               free(buf2);
-                               ct->status = CL_SENDING;
-                               return 0;
+                       if (ret < 0)
+                               goto close1;
+                       if (ret > 0 && FD_ISSET(ct->scc.fd, &s->wfds)) {
+                               sz = btr_next_buffer(ct->btrn[1], &buf2);
+                               assert(sz);
+                               ret = send_sb(ct, 1, buf2, sz, SBD_BLOB_DATA, true);
+                               if (ret < 0)
+                                       goto close1;
+                               if (ret > 0)
+                                       btr_consume(ct->btrn[1], sz);
                        }
-                       ct->status = CL_RECEIVING;
-                       btr_add_output(buf2, n, btrn);
-               } else
-                       free(buf2);
-               goto out;
                }
-       case CL_SENDING:
-               {
-               char *buf2;
-               size_t sz;
-               ret = btr_node_status(btrn, 0, BTR_NT_LEAF);
-               if (ret < 0)
-                       goto out;
-               if (ret == 0)
-                       return 0;
-               if (!FD_ISSET(ct->scc.fd, &s->wfds))
-                       return 0;
-               sz = btr_next_buffer(btrn, &buf2);
-               ret = sc_send_bin_buffer(&ct->scc, buf2, sz);
-               if (ret < 0)
-                       goto out;
-               btr_consume(btrn, sz);
-               return 0;
-               }
-       case CL_RECEIVING:
-               {
-               char *buf2;
-               ret = btr_node_status(btrn, 0, BTR_NT_ROOT);
-               if (ret < 0)
-                       goto out;
-               if (ret == 0)
-                       return 0;
-               /*
-                * The FD_ISSET() is not strictly necessary, but is allows us
-                * to skip the malloc below if there is nothing to read anyway.
-                */
-               if (!FD_ISSET(ct->scc.fd, &s->rfds))
-                       return 0;
-               if (ct->use_sideband) {
-                       struct sb_buffer sbb;
-                       ret = recv_sb(ct, &s->rfds, &sbb);
-                       if (ret > 0)
-                               ret = dispatch_sbb(ct, &sbb);
-                       goto out;
+               /* fall though */
+       case CL_EXECUTING:
+               if (ct->btrn[0]) {
+                       ret = btr_node_status(ct->btrn[0], 0, BTR_NT_ROOT);
+                       if (ret < 0)
+                               goto close0;
+                       if (ret > 0 && FD_ISSET(ct->scc.fd, &s->rfds)) {
+                               struct sb_buffer sbb;
+                               ret = recv_sb(ct, &s->rfds, &sbb);
+                               if (ret < 0)
+                                       goto close0;
+                               if (ret > 0) {
+                                       ret = dispatch_sbb(ct, &sbb);
+                                       if (ret < 0)
+                                               goto close0;
+                               }
+                       }
                }
-               buf2 = para_malloc(CLIENT_BUFSIZE);
-               ret = client_recv_buffer(ct, &s->rfds, buf2, CLIENT_BUFSIZE, &n);
-               if (n > 0) {
-                       buf2 = para_realloc(buf2, n);
-                       btr_add_output(buf2, n, btrn);
-               } else
-                       free(buf2);
+               ret = 0;
                goto out;
-               }
        }
 -              return;
+ close1:
+       PARA_INFO_LOG("channel 1: %s\n", para_strerror(-ret));
+       btr_remove_node(&ct->btrn[1]);
+       if (ct->btrn[0])
 -              return;
++              return 0;
+       goto out;
+ close0:
+       PARA_INFO_LOG("channel 0: %s\n", para_strerror(-ret));
+       btr_remove_node(&ct->btrn[0]);
+       if (ct->btrn[1] && ct->status == CL_SENDING)
++              return 0;
  out:
-       if (ret < 0) {
-               if (!ct->use_sideband && ret != -E_SERVER_EOF &&
-                               ret != -E_BTR_EOF && ret != -E_EOF)
-                       PARA_ERROR_LOG("%s\n", para_strerror(-ret));
-               btr_remove_node(&ct->btrn);
-       }
+       if (ret >= 0)
 -              return;
++              return 0;
+       btr_remove_node(&ct->btrn[0]);
+       btr_remove_node(&ct->btrn[1]);
+       if (ret != -E_SERVER_CMD_SUCCESS && ret != -E_SERVER_CMD_FAILURE)
+               PARA_ERROR_LOG("%s\n", para_strerror(-ret));
 -      t->error = ret;
 +      return ret;
  }
  
  /**
diff --cc command.c
+++ b/command.c
@@@ -433,10 -416,10 +417,8 @@@ static int com_version(struct command_c
  
        if (cc->argc != 1)
                return -E_COMMAND_SYNTAX;
 -      msg = VERSION_TEXT("server") "built: " BUILD_DATE "\n" UNAME_RS
 -              ", " CC_VERSION "\n";
 -      len = strlen(msg);
 -      return send_sb(&cc->scc, msg, len, SBD_OUTPUT, true);
 +      len = xasprintf(&msg, "%s", version_text("server"));
-       if (cc->use_sideband)
-               return send_sb(&cc->scc, msg, len, SBD_OUTPUT, false);
-       return sc_send_bin_buffer(&cc->scc, msg, len);
++      return send_sb(&cc->scc, msg, len, SBD_OUTPUT, false);
  }
  
  #define EMPTY_STATUS_ITEMS \
@@@ -545,15 -527,8 +522,9 @@@ static int com_stat(struct command_cont
                if (ret < 0)
                        goto out;
                if (nmmd->vss_status_flags & VSS_NEXT) {
 +                      char *esi;
                        ret = empty_status_items(parser_friendly, &esi);
-                       if (cc->use_sideband)
-                               ret = send_sb(&cc->scc, esi, ret, SBD_OUTPUT,
-                                       false);
-                       else {
-                               ret = sc_send_bin_buffer(&cc->scc, esi, ret);
-                               free(esi);
-                       }
 -                      ret = send_sb(&cc->scc, esi, ret, SBD_OUTPUT, true);
++                      ret = send_sb(&cc->scc, esi, ret, SBD_OUTPUT, false);
                        if (ret < 0)
                                goto out;
                } else
diff --cc error.h
+++ b/error.h
@@@ -301,8 -289,14 +301,9 @@@ extern const char **para_errlist[]
        PARA_ERROR(SERVER_EOF, "connection closed by para_server"), \
        PARA_ERROR(SERVER_CMD_SUCCESS, "command terminated successfully"), \
        PARA_ERROR(SERVER_CMD_FAILURE, "command failed"), \
+       PARA_ERROR(INCOMPAT_FEAT, "client/server incompatibility"), \
  
  
 -#define SCHED_ERRORS \
 -      PARA_ERROR(NOT_INITIALIZED, "scheduler not yet initialized"), \
 -      PARA_ERROR(SCHED_SHUTDOWN, "scheduler was shut down"), \
 -
 -
  #define NET_ERRORS \
        PARA_ERROR(NAME_TOO_LONG, "name too long for struct sockaddr_un"), \
        PARA_ERROR(ADDRESS_LOOKUP, "can not resolve requested address"),\
diff --cc gcrypt.c
Simple merge
diff --cc para.h
Simple merge