The answer is implementation specific. You'll need to check tcp implementation header files on your OS. Here is a sample client for linux that returns the socket state.
ts = TCPSocket.new('localhost', 5777)
ssl = OpenSSL::SSL::SSLSocket.new(ts, OpenSSL::SSL::SSLContext.new)
ssl.sync = true
ssl.connect
# TCP_INFO is 11
# note that TCP_INFO isn't defined in the ruby source.
# i had to look up the integer value in /usr/include/netinet/tcp.h
optval = ts.getsockopt(Socket::SOL_TCP, 11)
state = optval.unpack "i"
puts "state: #{state}"
Here's the tcp_info struct for my up-to-date ubuntu linux
struct tcp_info
{
u_int8_t tcpi_state;
u_int8_t tcpi_ca_state;
u_int8_t tcpi_retransmits;
u_int8_t tcpi_probes;
u_int8_t tcpi_backoff;
u_int8_t tcpi_options;
u_int8_t tcpi_snd_wscale : 4, tcpi_rcv_wscale : 4;
u_int32_t tcpi_rto;
u_int32_t tcpi_ato;
u_int32_t tcpi_snd_mss;
u_int32_t tcpi_rcv_mss;
u_int32_t tcpi_unacked;
u_int32_t tcpi_sacked;
u_int32_t tcpi_lost;
u_int32_t tcpi_retrans;
u_int32_t tcpi_fackets;
/* Times. */
u_int32_t tcpi_last_data_sent;
u_int32_t tcpi_last_ack_sent; /* Not remembered, sorry. */
u_int32_t tcpi_last_data_recv;
u_int32_t tcpi_last_ack_recv;
/* Metrics. */
u_int32_t tcpi_pmtu;
u_int32_t tcpi_rcv_ssthresh;
u_int32_t tcpi_rtt;
u_int32_t tcpi_rttvar;
u_int32_t tcpi_snd_ssthresh;
u_int32_t tcpi_snd_cwnd;
u_int32_t tcpi_advmss;
u_int32_t tcpi_reordering;
u_int32_t tcpi_rcv_rtt;
u_int32_t tcpi_rcv_space;
u_int32_t tcpi_total_retrans;
};
You may note that my script only returns an integer. Here's the C enum that details the TCP states and their integer values. Again, this was found in /usr/include/netinet/tcp.h
enum
{
TCP_ESTABLISHED = 1,
TCP_SYN_SENT,
TCP_SYN_RECV,
TCP_FIN_WAIT1,
TCP_FIN_WAIT2,
TCP_TIME_WAIT,
TCP_CLOSE,
TCP_CLOSE_WAIT,
TCP_LAST_ACK,
TCP_LISTEN,
TCP_CLOSING /* now a valid state */
};
Also, this thread says that you can detect CLOSE_WAIT by reading EOF. But since you're concerned about whether data has been sent, you'll probably need to unpack up to tcpi_last_data_sent.
Finally, a caveat. I took on the challenge of answering your question 'cause it sounded fun and it was but my C legs are still wobbly so YMMV. :)