]> git.meshlink.io Git - meshlink/commitdiff
Fix processing of mixed ID and SPTPS data.
authorGuus Sliepen <guus@meshlink.io>
Sun, 25 Jun 2017 14:32:15 +0000 (16:32 +0200)
committerGuus Sliepen <guus@meshlink.io>
Sun, 25 Jun 2017 14:32:15 +0000 (16:32 +0200)
When making a connection with another peer, the ID message and the first
SPTPS data is sent using separate send() calls, but they can be merged
along the way to the other side. When receiving the ID message, we
accidentily discarded the rest of the received packet. Handle this
properly.

The problem was found to trigger much more often on Linux kernel 4.4 in
KVM.

src/meta.c

index 97cbed2a316959e6b3e697320be3ebcea62a37ad..a51df8dd182f40ce44f261063fe7393ca13e50ce 100644 (file)
@@ -110,25 +110,8 @@ bool receive_meta_sptps(void *handle, uint8_t type, const void *data, uint16_t l
 bool receive_meta(meshlink_handle_t *mesh, connection_t *c) {
        int inlen;
        char inbuf[MAXBUFSIZE];
-       char *bufp = inbuf, *endp;
 
-       /* Strategy:
-          - Read as much as possible from the TCP socket in one go.
-          - Decrypt it.
-          - Check if a full request is in the input buffer.
-          - If yes, process request and remove it from the buffer,
-          then check again.
-          - If not, keep stuff in buffer and exit.
-        */
-
-       buffer_compact(&c->inbuf, MAXBUFSIZE);
-
-       if(sizeof inbuf <= c->inbuf.len) {
-               logger(mesh, MESHLINK_ERROR, "Input buffer full for %s (%s)", c->name, c->hostname);
-               return false;
-       }
-
-       inlen = recv(c->socket, inbuf, sizeof inbuf - c->inbuf.len, 0);
+       inlen = recv(c->socket, inbuf, sizeof inbuf, 0);
 
        if(inlen <= 0) {
                if(!inlen || !errno) {
@@ -143,31 +126,29 @@ bool receive_meta(meshlink_handle_t *mesh, connection_t *c) {
        }
 
        if(c->allow_request == ID) {
-               endp = memchr(bufp, '\n', inlen);
-               if(endp)
-                       endp++;
-               else
-                       endp = bufp + inlen;
-
-               buffer_add(&c->inbuf, bufp, endp - bufp);
-
-               inlen -= endp - bufp;
-               bufp = endp;
-
-               while(c->inbuf.len) {
-                       char *request = buffer_readline(&c->inbuf);
-                       if(request) {
-                               bool result = receive_request(mesh, c, request);
-                               if(!result)
-                                       return false;
-                               continue;
-                       } else {
-                               break;
-                       }
+               buffer_add(&c->inbuf, inbuf, inlen);
+
+               char *request = buffer_readline(&c->inbuf);
+
+               if(request) {
+                       if(!receive_request(mesh, c, request) || c->allow_request == ID)
+                               return false;
+
+                       int left = c->inbuf.len - c->inbuf.offset;
+                       if(left > 0) {
+                               fprintf(stderr, "GOT A LITTLE MORE\n");
+                               return sptps_receive_data(&c->sptps, buffer_read(&c->inbuf, left), left);
+                       } else
+                               return true;
                }
 
-               return true;
+               if(c->inbuf.len >= sizeof inbuf) {
+                       logger(mesh, MESHLINK_ERROR, "Input buffer full for %s (%s)", c->name, c->hostname);
+                       return false;
+               } else {
+                       return true;
+               }
        }
 
-       return sptps_receive_data(&c->sptps, bufp, inlen);
+       return sptps_receive_data(&c->sptps, inbuf, inlen);
 }