#include "crypt.h"
#include "net.h"
#include "fd.h"
+#include "sideband.h"
#include "string.h"
#include "client.cmdline.h"
#include "client.h"
return;
if (ct->scc.fd >= 0)
close(ct->scc.fd);
+ free_argv(ct->features);
sc_free(ct->scc.recv);
ct->scc.recv = NULL;
sc_free(ct->scc.send);
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 bool has_feature(const char *feature, struct client_task *ct)
+{
+ return find_arg(feature, ct->features) >= 0? true : false;
+}
+
/**
* The post select hook for client commands.
*
ret = client_recv_buffer(ct, &s->rfds, buf, sizeof(buf), &n);
if (ret < 0 || n == 0)
goto out;
+ ct->features = parse_features(buf);
ct->status = CL_RECEIVED_WELCOME;
return;
case CL_RECEIVED_WELCOME: /* send auth command */
- sprintf(buf, AUTH_REQUEST_MSG "%s", ct->user);
- PARA_INFO_LOG("--> %s\n", buf);
if (!FD_ISSET(ct->scc.fd, &s->wfds))
return;
- ret = send_buffer(ct->scc.fd, buf);
+ 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);
+ PARA_INFO_LOG("--> %s\n", buf);
+ ret = write_buffer(ct->scc.fd, buf);
if (ret < 0)
goto out;
ct->status = CL_SENT_AUTH;