]> git.tuebingen.mpg.de Git - paraslash.git/blobdiff - client_common.c
sched: Introduce sched_{read,write}_ok().
[paraslash.git] / client_common.c
index a7eee85d3cc0d5cf94073ca39c6223a7c4a639d4..7a353098c42ecfab3f36452b9e82d4a4a8637c32 100644 (file)
@@ -50,13 +50,12 @@ void client_close(struct client_task *ct)
 }
 
 /*
- * The preselect hook for server commands.
+ * This function asks the scheduler to monitor a file descriptor which
+ * corresponds to an active connection. The descriptor is monitored for either
+ * reading or writing, depending on the state of the connection.
  *
- * The task pointer must contain a pointer to the initialized client data
- * structure as it is returned by client_open().
- *
- * This function checks the state of the connection and adds the file descriptor
- * of the connection to the read or write fd set of s accordingly.
+ * The context pointer is assumed to refer to a client task structure that was
+ * initialized earlier by client_open().
  */
 static void client_pre_select(struct sched *s, void *context)
 {
@@ -86,7 +85,7 @@ static void client_pre_select(struct sched *s, void *context)
                        else if (ret > 0)
                                para_fd_set(ct->scc.fd, &s->wfds, &s->max_fileno);
                }
-               /* fallthrough */
+               __attribute__ ((fallthrough));
        case CL_EXECUTING:
                if (ct->btrn[0]) {
                        ret = btr_node_status(ct->btrn[0], 0, BTR_NT_ROOT);
@@ -126,8 +125,7 @@ static int send_sb(struct client_task *ct, int channel, void *buf, size_t numbyt
        return 0;
 }
 
-static int recv_sb(struct client_task *ct, fd_set *rfds,
-               struct sb_buffer *result)
+static int recv_sb(struct client_task *ct, struct sb_buffer *result)
 {
        int ret;
        size_t n;
@@ -135,8 +133,6 @@ static int recv_sb(struct client_task *ct, fd_set *rfds,
        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 {
@@ -147,7 +143,7 @@ static int recv_sb(struct client_task *ct, fd_set *rfds,
                ct->sbc[0] = sb_new_recv(0, trafo, trafo_context);
 again:
        sb_get_recv_buffer(ct->sbc[0], &iov);
-       ret = read_nonblock(ct->scc.fd, iov.iov_base, iov.iov_len, rfds, &n);
+       ret = read_nonblock(ct->scc.fd, iov.iov_base, iov.iov_len, &n);
        if (ret < 0) {
                sb_free(ct->sbc[0]);
                ct->sbc[0] = NULL;
@@ -259,13 +255,21 @@ static int send_sb_command(struct client_task *ct)
        return send_sb(ct, 0, command, len, SBD_COMMAND, false);
 }
 
+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.
+ * This function reads or writes to the socket file descriptor which
+ * corresponds to an established connection between the client and the server.
+ * It depends on the current state of the connection and on the readiness of
+ * the socket file descriptor which type of I/O is going to be performed.
+ * Besides the initial handshake and authentication, the function sends the
+ * server command and receives the output from the server, if any.
  *
- * Depending on the current state of the connection and the status of the read
- * and write fd sets of s, this function performs the necessary steps to
- * authenticate the connection, to send the command given by t->private_data
- * and to receive para_server's output, if any.
+ * The context pointer refers to a client task structure that was initialized
+ * earlier by client_open().
  */
 static int client_post_select(struct sched *s, void *context)
 {
@@ -281,23 +285,32 @@ static int client_post_select(struct sched *s, void *context)
                return 0;
        switch (ct->status) {
        case CL_CONNECTED: /* receive welcome message */
-               ret = read_nonblock(ct->scc.fd, buf, sizeof(buf), &s->rfds, &n);
+               ret = read_nonblock(ct->scc.fd, buf, sizeof(buf), &n);
                if (ret < 0 || n == 0)
                        goto out;
                ct->features = parse_features(buf);
                ct->status = CL_RECEIVED_WELCOME;
                return 0;
        case CL_RECEIVED_WELCOME: /* send auth command */
-               if (!FD_ISSET(ct->scc.fd, &s->wfds))
+               {
+               /*
+                * Use sha256 iff the server announced the feature. After 0.7.0
+                * we may request and use the feature unconditionally. After
+                * 0.8.0 we no longer need to request the feature.
+                */
+               bool has_sha256;
+               if (!sched_write_ok(ct->scc.fd, s))
                        return 0;
-               sprintf(buf, AUTH_REQUEST_MSG "%s sideband,aes_ctr128",
-                       ct->user);
+               has_sha256 = has_feature("sha256", ct);
+               sprintf(buf, AUTH_REQUEST_MSG "%s%s", ct->user, has_sha256?
+                       " sha256" : "");
                PARA_INFO_LOG("--> %s\n", buf);
                ret = write_buffer(ct->scc.fd, buf);
                if (ret < 0)
                        goto out;
                ct->status = CL_SENT_AUTH;
                return 0;
+               }
        case CL_SENT_AUTH:
                /*
                 * Receive challenge and session keys, decrypt the challenge and
@@ -308,7 +321,7 @@ static int client_post_select(struct sched *s, void *context)
                unsigned char crypt_buf[1024];
                struct sb_buffer sbb;
 
-               ret = recv_sb(ct, &s->rfds, &sbb);
+               ret = recv_sb(ct, &sbb);
                if (ret <= 0)
                        goto out;
                if (sbb.band != SBD_CHALLENGE) {
@@ -323,19 +336,29 @@ static int client_post_select(struct sched *s, void *context)
                free(sbb.iov.iov_base);
                if (ret < 0)
                        goto out;
-               ct->challenge_hash = para_malloc(HASH_SIZE);
-               hash_function((char *)crypt_buf, APC_CHALLENGE_SIZE, ct->challenge_hash);
+               ct->challenge_hash = para_malloc(HASH2_SIZE);
+
+               if (has_feature("sha256", ct)) {
+                       hash2_function((char *)crypt_buf, APC_CHALLENGE_SIZE, ct->challenge_hash);
+                       hash2_to_asc(ct->challenge_hash, buf);
+               } else {
+                       hash_function((char *)crypt_buf, APC_CHALLENGE_SIZE, ct->challenge_hash);
+                       hash_to_asc(ct->challenge_hash, buf);
+               }
                ct->scc.send = sc_new(crypt_buf + APC_CHALLENGE_SIZE, SESSION_KEY_LEN);
                ct->scc.recv = sc_new(crypt_buf + APC_CHALLENGE_SIZE + SESSION_KEY_LEN,
                        SESSION_KEY_LEN);
-               hash_to_asc(ct->challenge_hash, buf);
                PARA_INFO_LOG("--> %s\n", buf);
                ct->status = CL_RECEIVED_CHALLENGE;
                return 0;
                }
        case CL_RECEIVED_CHALLENGE:
-               ret = send_sb(ct, 0, ct->challenge_hash, HASH_SIZE,
-                       SBD_CHALLENGE_RESPONSE, false);
+               if (has_feature("sha256", ct))
+                       ret = send_sb(ct, 0, ct->challenge_hash, HASH2_SIZE,
+                               SBD_CHALLENGE_RESPONSE, false);
+               else
+                       ret = send_sb(ct, 0, ct->challenge_hash, HASH_SIZE,
+                               SBD_CHALLENGE_RESPONSE, false);
                if (ret != 0)
                        ct->challenge_hash = NULL;
                if (ret <= 0)
@@ -345,7 +368,7 @@ static int client_post_select(struct sched *s, void *context)
        case CL_SENT_CH_RESPONSE: /* read server response */
                {
                struct sb_buffer sbb;
-               ret = recv_sb(ct, &s->rfds, &sbb);
+               ret = recv_sb(ct, &sbb);
                if (ret <= 0)
                        goto out;
                free(sbb.iov.iov_base);
@@ -357,7 +380,7 @@ static int client_post_select(struct sched *s, void *context)
                }
        case CL_RECEIVED_PROCEED: /* concat args and send command */
                {
-               if (!FD_ISSET(ct->scc.fd, &s->wfds))
+               if (!sched_write_ok(ct->scc.fd, s))
                        return 0;
                ret = send_sb_command(ct);
                if (ret <= 0)
@@ -379,7 +402,7 @@ static int client_post_select(struct sched *s, void *context)
                        }
                        if (ret < 0)
                                goto close1;
-                       if (ret > 0 && FD_ISSET(ct->scc.fd, &s->wfds)) {
+                       if (ret > 0 && sched_write_ok(ct->scc.fd, s)) {
                                sz = btr_next_buffer(ct->btrn[1], &buf2);
                                assert(sz);
                                ret = send_sb(ct, 1, buf2, sz, SBD_BLOB_DATA, true);
@@ -389,15 +412,15 @@ static int client_post_select(struct sched *s, void *context)
                                        btr_consume(ct->btrn[1], sz);
                        }
                }
-               /* fall through */
+               __attribute__ ((fallthrough));
        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)) {
+                       if (ret > 0 && sched_read_ok(ct->scc.fd, s)) {
                                struct sb_buffer sbb;
-                               ret = recv_sb(ct, &s->rfds, &sbb);
+                               ret = recv_sb(ct, &sbb);
                                if (ret < 0)
                                        goto close0;
                                if (ret > 0) {
@@ -426,8 +449,7 @@ out:
                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));
+       PARA_NOTICE_LOG("closing connection (%s)\n", para_strerror(-ret));
        if (ct->scc.fd >= 0) {
                close(ct->scc.fd);
                ct->scc.fd = -1;