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.
bool receive_meta(meshlink_handle_t *mesh, connection_t *c) {
int inlen;
char inbuf[MAXBUFSIZE];
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) {
if(inlen <= 0) {
if(!inlen || !errno) {
}
if(c->allow_request == ID) {
}
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;
+ 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);