Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Concatenate header and first upstream payload #73

Merged
merged 3 commits into from Jul 28, 2020
Merged

Concatenate header and first upstream payload #73

merged 3 commits into from Jul 28, 2020

Conversation

@bemasc
Copy link

@bemasc bemasc commented Jul 21, 2020

When possible, this change concatenates the Shadowsocks header and the
first upstream payload into a single TCP segment.

This change imposes additional memory (extra buffer) and time (lock
acquisition) costs, but only during the first read.

When possible, this change concatenates the Shadowsocks header and the
first upstream payload into a single TCP segment.

This change imposes additional memory (extra buffer) and time (lock
acquisition) costs, but only during the first read.
@bemasc bemasc requested review from fortuna and alalamav Jul 21, 2020
// We therefore use a short delay, longer than any reasonable IPC but similar to
// typical network latency. (In an Android emulator, the 90th percentile delay
// was ~1 ms.) If no client payload is received by this time, we connect without it.
const helloWait = 20 * time.Millisecond
Copy link

@fortuna fortuna Jul 27, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How did you decide no 20 ms?
This will only delay connections where the client doesn't immediately send data, but I have no idea what those are, so maybe reduce the wait time?

Loading

Copy link
Author

@bemasc bemasc Jul 27, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK, reduced to 10ms

Loading

t.Fatalf("ShadowsocksClient.DialTCP failed: %v", err)
}

// Wait for more than 20 milliseconds to ensure that the target
Copy link

@fortuna fortuna Jul 27, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we check that no data was sent in the first 20ms?

Loading

Copy link
Author

@bemasc bemasc Jul 27, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK, I added a test for this.

Loading

LazyWrite(p []byte) (int, error)
// Flush sends the pending data, if any. This method is
// thread-safe, but must not be the first method called.
Flush() error
Copy link

@fortuna fortuna Jul 27, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't get the "MUST". Why can't it be called first? Wouldn't it just return and do nothing? I don't see what would break.

Loading

Copy link
Author

@bemasc bemasc Jul 27, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Flush() relies on init() having run, but it can't run init() because init() isn't thread-safe.

Loading

Copy link

@fortuna fortuna Jul 27, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When there was no write, you only depend on needFlush and the mutex, both of which are initialized before init(). A sequence Flush, LazyWrite, Write seems safe.

Loading

Copy link
Author

@bemasc bemasc Jul 28, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You're right. Done.

Loading

// modified on the flush thread.
// Any size is acceptable here, but this is the largest value
// for which a single call to enqueue() is sufficient.
readBuf := make([]byte, len(payloadBuf)-pending)
Copy link

@fortuna fortuna Jul 27, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You don't need this allocation.
You can use sw.buf[saltSize + 2 + sw.aead,Overhead() + sw.pending + sw.aead.Overhead():]

The enqueue call later will shift things to the right position.

Loading

Copy link
Author

@bemasc bemasc Jul 27, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Beautiful. Done.

Loading

sw.mu.Lock()

sw.enqueue(readBuf[:plaintextSize])
readBuf = nil // Release memory before blocking I/O.
Copy link

@fortuna fortuna Jul 27, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This can be deleted if you remove the make call

Loading

Copy link
Author

@bemasc bemasc Jul 27, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

Loading

LazyWrite(p []byte) (int, error)
// Flush sends the pending data, if any. This method is
// thread-safe, but must not be the first method called.
Flush() error
Copy link

@fortuna fortuna Jul 27, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When there was no write, you only depend on needFlush and the mutex, both of which are initialized before init(). A sequence Flush, LazyWrite, Write seems safe.

Loading

if err != nil {
t.Errorf("Write failed: %v", err)
}
if buf.Len() == len1 {
Copy link

@fortuna fortuna Jul 27, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also add a check that buf.Len() == 8 to show the first write got flushed

Loading

Copy link

@fortuna fortuna Jul 27, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I also suggest you make the second write be 3 or 5 bytes, so it's not confused with the first write.

Loading

Copy link
Author

@bemasc bemasc Jul 28, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK, done

Loading

@fortuna
Copy link

@fortuna fortuna commented Jul 27, 2020

Thanks for this change. I'm hopeful it will help disguise server access. Hopefully we'll see a decrease in probes.

Loading

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Linked issues

Successfully merging this pull request may close these issues.

None yet

2 participants