+ if (ret == -ERRNO_TO_PARA_ERROR(EAGAIN))
+ return 0;
+ if (ret < 0)
+ return ret;
+ *n = ret;
+ return 0;
+}
+
+static int send_sb(struct client_task *ct, void *buf, size_t numbytes,
+ enum sb_designator band, bool dont_free)
+{
+ int ret, fd = ct->scc.fd;
+ struct iovec iov[2];
+
+ if (!ct->sbc) {
+ struct sb_buffer sbb;
+ sb_transformation trafo = ct->status < CL_RECEIVED_PROCEED?
+ NULL : sc_trafo;
+ sbb = (typeof(sbb))SBB_INIT(band, buf, numbytes);
+ ct->sbc = sb_new_send(&sbb, dont_free, trafo, ct->scc.send);
+ }
+ ret = sb_get_send_buffers(ct->sbc, iov);
+ ret = xwritev(fd, iov, ret);
+ if (ret < 0) {
+ sb_free(ct->sbc);
+ ct->sbc = NULL;
+ return ret;
+ }
+ if (sb_sent(ct->sbc, ret)) {
+ ct->sbc = NULL;
+ return 1;
+ }
+ return 0;
+}
+
+static int recv_sb(struct client_task *ct, fd_set *rfds,
+ struct sb_buffer *result)
+{
+ int ret;
+ size_t n;
+ sb_transformation trafo;
+ void *trafo_context;
+ struct iovec iov;
+
+ if (!FD_ISSET(ct->scc.fd, rfds))
+ return 0;
+ if (ct->status < CL_SENT_CH_RESPONSE)
+ trafo = trafo_context = NULL;
+ else {
+ trafo = sc_trafo;
+ trafo_context = ct->scc.recv;
+ }
+ if (!ct->sbc)
+ ct->sbc = sb_new_recv(0, trafo, trafo_context);
+again:
+ sb_get_recv_buffer(ct->sbc, &iov);
+ ret = read_nonblock(ct->scc.fd, iov.iov_base, iov.iov_len, rfds, &n);
+ if (ret < 0) {
+ sb_free(ct->sbc);
+ ct->sbc = NULL;
+ return ret;
+ }
+ if (n == 0)
+ return 0;
+ if (!sb_received(ct->sbc, n, result))
+ goto again;
+ ct->sbc = NULL;
+ return 1;
+}
+
+
+static char **parse_features(char *buf)
+{
+ int i;
+ const char id[] = "\nFeatures: ";
+ char *p, *q, **features;
+
+ p = strstr(buf, id);
+ if (!p)
+ return NULL;
+ p += strlen(id);
+ q = strchr(p, '\n');
+ if (!q)
+ return NULL;
+ *q = '\0';
+ create_argv(p, ",", &features);
+ for (i = 0; features[i]; i++)
+ PARA_INFO_LOG("server feature: %s\n", features[i]);
+ return features;
+}
+
+static int dispatch_sbb(struct client_task *ct, struct sb_buffer *sbb)
+{
+ int ret;
+ const char *designator[] = {SB_DESIGNATORS_ARRAY};
+
+ if (!sbb)
+ return 0;
+ if (sbb->band < NUM_SB_DESIGNATORS)
+ PARA_DEBUG_LOG("band: %s\n", designator[sbb->band]);
+
+ switch (sbb->band) {
+ case SBD_OUTPUT:
+ if (iov_valid(&sbb->iov))
+ btr_add_output(sbb->iov.iov_base, sbb->iov.iov_len,
+ ct->btrn);
+ ret = 1;
+ goto out;
+ case SBD_DEBUG_LOG:
+ case SBD_INFO_LOG:
+ case SBD_NOTICE_LOG:
+ case SBD_WARNING_LOG:
+ case SBD_ERROR_LOG:
+ case SBD_CRIT_LOG:
+ case SBD_EMERG_LOG:
+ if (iov_valid(&sbb->iov)) {
+ int ll = sbb->band - SBD_DEBUG_LOG;
+ para_log(ll, "remote: %s", (char *)sbb->iov.iov_base);
+ }
+ ret = 1;
+ goto deallocate;
+ case SBD_EXIT__SUCCESS:
+ ret = -E_SERVER_CMD_SUCCESS;
+ goto deallocate;
+ case SBD_EXIT__FAILURE:
+ ret = -E_SERVER_CMD_FAILURE;
+ goto deallocate;
+ default:
+ PARA_ERROR_LOG("invalid band %d\n", sbb->band);
+ ret = -E_BAD_BAND;
+ goto deallocate;
+ }
+deallocate:
+ free(sbb->iov.iov_base);
+out:
+ sbb->iov.iov_base = NULL;