Question: I'm trying to understand how the events in a BSD socket interface translate to the state of a TCP Connection. In particular, I'm trying to understand at what stage in the connection process `accept()` returns on the server side

1. client sends SYN
2. server sends SYN+ACK
3. client sends ACK

In which one of these steps does `accept()` return?

Answer: 
`accept` returns when the connection is complete. The connection is complete **after the client sends his ACK**.

`accept` gives you a socket on which you can communicate. Of course you know, you can't communicate until the connection is established. And the connection can't be established before the handshake.

It wouldn't make sense to return before the client sens his ACK. It is entirely possible he won't say anything after the initial SYN.
The TCP/IP stack code in the kernel normally[1] completes the three-way handshake entirely without intervention from any user space code. The three steps you list all happen *before* `accept()` returns. Indeed, they may happen before `accept()` is even called!

When you tell the stack to `listen()` for connections on a particular TCP port, you pass a `backlog` parameter, which tells the kernel how many connections it can silently accept on behalf of your program at once. It is this queue that is being used when the kernel automatically accepts new connection requests, and there that they are held until your program gets around to `accept()`ing them. When there is one or more connections in the listen backlog queue when you call `accept()`, all that happens is that the oldest is removed from the queue and bound to a new socket.[2]

In other words, if your program calls `listen(sd, 5)`, then goes into an infinite do-nothing loop so that it never calls `accept()`, five concurrent client connection requests will succeed, from the clients' point of view. A sixth connection request will get stalled on the first SYN packet until either the program owning the TCP port calls `accept()` or one of the other clients drops its connection.

---

[1] Firewall and other stack modifications can change this behavior, of course. I am speaking here only of default BSD sockets stack behavior.

[2] If there are no connections waiting in the backlog when you call `accept()`, it blocks by default, unless the listener socket was set to non-blocking, in which case it returns -1 and `errno` is `EWOULDBLOCK`.