📄 socket.c
字号:
struct sockaddr_in si; CLEAR (si); si.sin_addr.s_addr = htonl (addr); setenv_sockaddr (name_prefix, &si);}/* * Convert protocol names between index and ascii form. */struct proto_names { const char *short_form; const char *display_form;};/* Indexed by PROTO_x */static const struct proto_names proto_names[] = { {"udp", "UDPv4"}, {"tcp-server", "TCPv4_SERVER"}, {"tcp-client", "TCPv4_CLIENT"}};intascii2proto (const char* proto_name){ int i; ASSERT (PROTO_N == SIZE (proto_names)); for (i = 0; i < PROTO_N; ++i) if (!strcmp (proto_name, proto_names[i].short_form)) return i; return -1;}const char *proto2ascii (int proto, bool display_form){ ASSERT (PROTO_N == SIZE (proto_names)); if (proto < 0 || proto >= PROTO_N) return "[unknown protocol]"; else if (display_form) return proto_names[proto].display_form; else return proto_names[proto].short_form;}const char *proto2ascii_all (struct gc_arena *gc){ struct buffer out = alloc_buf_gc (256, gc); int i; ASSERT (PROTO_N == SIZE (proto_names)); for (i = 0; i < PROTO_N; ++i) { if (i) buf_printf(&out, " "); buf_printf(&out, "[%s]", proto2ascii(i, false)); } return BSTR (&out);}/* * Given a local proto, return local proto * if !remote, or compatible remote proto * if remote. * * This is used for options compatibility * checking. */intproto_remote (int proto, bool remote){ ASSERT (proto >= 0 && proto < PROTO_N); if (remote) { if (proto == PROTO_TCPv4_SERVER) return PROTO_TCPv4_CLIENT; if (proto == PROTO_TCPv4_CLIENT) return PROTO_TCPv4_SERVER; } return proto;}/* * Bad incoming address lengths that differ from what * we expect are considered to be fatal errors. */voidbad_address_length (int actual, int expected){ msg (M_FATAL, "ERROR: received strange incoming packet with an address length of %d -- we only accept address lengths of %d.", actual, expected);}/* * Socket Read Routines */intlink_socket_read_tcp (struct link_socket *sock, struct buffer *buf){ int len = 0; if (!sock->stream_buf.residual_fully_formed) {#ifdef WIN32 len = socket_finalize (sock->sd, &sock->reads, buf, NULL);#else struct buffer frag; stream_buf_get_next (&sock->stream_buf, &frag); len = recv (sock->sd, BPTR (&frag), BLEN (&frag), MSG_NOSIGNAL);#endif if (!len) sock->stream_reset = true; if (len <= 0) return buf->len = len; } if (sock->stream_buf.residual_fully_formed || stream_buf_added (&sock->stream_buf, len)) /* packet complete? */ { stream_buf_get_final (&sock->stream_buf, buf); stream_buf_reset (&sock->stream_buf); return buf->len; } else return buf->len = 0; /* no error, but packet is still incomplete */}#ifndef WIN32intlink_socket_read_udp_posix (struct link_socket *sock, struct buffer *buf, int maxsize, struct sockaddr_in *from){ socklen_t fromlen = sizeof (*from); CLEAR (*from); ASSERT (buf_safe (buf, maxsize)); buf->len = recvfrom (sock->sd, BPTR (buf), maxsize, 0, (struct sockaddr *) from, &fromlen); if (fromlen != sizeof (*from)) bad_address_length (fromlen, sizeof (*from)); return buf->len;}#endif/* * Socket Write Routines */intlink_socket_write_tcp (struct link_socket *sock, struct buffer *buf, struct sockaddr_in *to){ packet_size_type len = BLEN (buf); msg (D_STREAM_DEBUG, "STREAM: WRITE %d offset=%d", (int)len, buf->offset); ASSERT (len <= sock->stream_buf.maxlen); len = htonps (len); ASSERT (buf_write_prepend (buf, &len, sizeof (len)));#ifdef WIN32 return link_socket_write_win32 (sock, buf, to);#else return link_socket_write_tcp_posix (sock, buf, to); #endif}/* * Win32 overlapped socket I/O functions. */#ifdef WIN32intsocket_recv_queue (struct link_socket *sock, int maxsize){ if (sock->reads.iostate == IOSTATE_INITIAL) { WSABUF wsabuf[1]; int status; /* reset buf to its initial state */ if (sock->info.proto == PROTO_UDPv4) { sock->reads.buf = sock->reads.buf_init; } else if (sock->info.proto == PROTO_TCPv4_CLIENT || sock->info.proto == PROTO_TCPv4_SERVER) { stream_buf_get_next (&sock->stream_buf, &sock->reads.buf); } else { ASSERT (0); } /* Win32 docs say it's okay to allocate the wsabuf on the stack */ wsabuf[0].buf = BPTR (&sock->reads.buf); wsabuf[0].len = maxsize ? maxsize : BLEN (&sock->reads.buf); /* check for buffer overflow */ ASSERT (wsabuf[0].len <= BLEN (&sock->reads.buf)); /* the overlapped read will signal this event on I/O completion */ ASSERT (ResetEvent (sock->reads.overlapped.hEvent)); sock->reads.flags = 0; if (sock->info.proto == PROTO_UDPv4) { sock->reads.addr_defined = true; sock->reads.addrlen = sizeof (sock->reads.addr); status = WSARecvFrom( sock->sd, wsabuf, 1, &sock->reads.size, &sock->reads.flags, (struct sockaddr *) &sock->reads.addr, &sock->reads.addrlen, &sock->reads.overlapped, NULL); } else if (sock->info.proto == PROTO_TCPv4_CLIENT || sock->info.proto == PROTO_TCPv4_SERVER) { sock->reads.addr_defined = false; status = WSARecv( sock->sd, wsabuf, 1, &sock->reads.size, &sock->reads.flags, &sock->reads.overlapped, NULL); } else { status = 0; ASSERT (0); } if (!status) /* operation completed immediately? */ { if (sock->reads.addr_defined && sock->reads.addrlen != sizeof (sock->reads.addr)) bad_address_length (sock->reads.addrlen, sizeof (sock->reads.addr)); sock->reads.iostate = IOSTATE_IMMEDIATE_RETURN; /* since we got an immediate return, we must signal the event object ourselves */ ASSERT (SetEvent (sock->reads.overlapped.hEvent)); sock->reads.status = 0; msg (D_WIN32_IO, "WIN32 I/O: Socket Receive immediate return [%d,%d]", (int) wsabuf[0].len, (int) sock->reads.size); } else { status = WSAGetLastError (); if (status == WSA_IO_PENDING) /* operation queued? */ { sock->reads.iostate = IOSTATE_QUEUED; sock->reads.status = status; msg (D_WIN32_IO, "WIN32 I/O: Socket Receive queued [%d]", (int) wsabuf[0].len); } else /* error occurred */ { struct gc_arena gc = gc_new (); ASSERT (SetEvent (sock->reads.overlapped.hEvent)); sock->reads.iostate = IOSTATE_IMMEDIATE_RETURN; sock->reads.status = status; msg (D_WIN32_IO, "WIN32 I/O: Socket Receive error [%d]: %s", (int) wsabuf[0].len, strerror_win32 (status, &gc)); gc_free (&gc); } } } return sock->reads.iostate;}intsocket_send_queue (struct link_socket *sock, struct buffer *buf, const struct sockaddr_in *to){ if (sock->writes.iostate == IOSTATE_INITIAL) { WSABUF wsabuf[1]; int status; /* make a private copy of buf */ sock->writes.buf = sock->writes.buf_init; sock->writes.buf.len = 0; ASSERT (buf_copy (&sock->writes.buf, buf)); /* Win32 docs say it's okay to allocate the wsabuf on the stack */ wsabuf[0].buf = BPTR (&sock->writes.buf); wsabuf[0].len = BLEN (&sock->writes.buf); /* the overlapped write will signal this event on I/O completion */ ASSERT (ResetEvent (sock->writes.overlapped.hEvent)); sock->writes.flags = 0; if (sock->info.proto == PROTO_UDPv4) { /* set destination address for UDP writes */ sock->writes.addr_defined = true; sock->writes.addr = *to; sock->writes.addrlen = sizeof (sock->writes.addr); status = WSASendTo( sock->sd, wsabuf, 1, &sock->writes.size, sock->writes.flags, (struct sockaddr *) &sock->writes.addr, sock->writes.addrlen, &sock->writes.overlapped, NULL); } else if (sock->info.proto == PROTO_TCPv4_CLIENT || sock->info.proto == PROTO_TCPv4_SERVER) { /* destination address for TCP writes was established on connection initiation */ sock->writes.addr_defined = false; status = WSASend( sock->sd, wsabuf, 1, &sock->writes.size, sock->writes.flags, &sock->writes.overlapped, NULL); } else { status = 0; ASSERT (0); } if (!status) /* operation completed immediately? */ { sock->writes.iostate = IOSTATE_IMMEDIATE_RETURN; /* since we got an immediate return, we must signal the event object ourselves */ ASSERT (SetEvent (sock->writes.overlapped.hEvent)); sock->writes.status = 0; msg (D_WIN32_IO, "WIN32 I/O: Socket Send immediate return [%d,%d]", (int) wsabuf[0].len, (int) sock->writes.size); } else { status = WSAGetLastError (); if (status == WSA_IO_PENDING) /* operation queued? */ { sock->writes.iostate = IOSTATE_QUEUED; sock->writes.status = status; msg (D_WIN32_IO, "WIN32 I/O: Socket Send queued [%d]", (int) wsabuf[0].len); } else /* error occurred */ { struct gc_arena gc = gc_new (); ASSERT (SetEvent (sock->writes.overlapped.hEvent)); sock->writes.iostate = IOSTATE_IMMEDIATE_RETURN; sock->writes.status = status; msg (D_WIN32_IO, "WIN32 I/O: Socket Send error [%d]: %s", (int) wsabuf[0].len, strerror_win32 (status, &gc)); gc_free (&gc); } } } return sock->writes.iostate;}intsocket_finalize ( SOCKET s, struct overlapped_io *io, struct buffer *buf, struct sockaddr_in *from){ int ret = -1; BOOL status; switch (io->iostate) { case IOSTATE_QUEUED: status = WSAGetOverlappedResult( s, &io->overlapped, &io->size, FALSE, &io->flags ); if (status) { /* successful return for a queued operation */ if (buf) *buf = io->buf; ret = io->size; io->iostate = IOSTATE_INITIAL; ASSERT (ResetEvent (io->overlapped.hEvent)); msg (D_WIN32_IO, "WIN32 I/O: Socket Completion success [%d]", ret); } else { /* error during a queued operation */ ret = -1; if (WSAGetLastError() != WSA_IO_INCOMPLETE) { /* if no error (i.e. just not finished yet), then DON'T execute this code */ io->iostate = IOSTATE_INITIAL; ASSERT (ResetEvent (io->overlapped.hEvent)); msg (D_WIN32_IO | M_ERRNO_SOCK, "WIN32 I/O: Socket Completion error"); } } break; case IOSTATE_IMMEDIATE_RETURN: io->iostate = IOSTATE_INITIAL; ASSERT (ResetEvent (io->overlapped.hEvent)); if (io->status) { /* error return for a non-queued operation */ WSASetLastError (io->status); ret = -1; msg (D_WIN32_IO | M_ERRNO_SOCK, "WIN32 I/O: Socket Completion non-queued error"); } else { /* successful return for a non-queued operation */ if (buf) *buf = io->buf; ret = io->size; msg (D_WIN32_IO, "WIN32 I/O: Socket Completion non-queued success [%d]", ret); } break; case IOSTATE_INITIAL: /* were we called without proper queueing? */ WSASetLastError (WSAEINVAL); ret = -1; msg (D_WIN32_IO, "WIN32 I/O: Socket Completion BAD STATE"); break; default: ASSERT (0); } /* return from address if requested */ if (from) { if (ret >= 0 && io->addr_defined) { if (io->addrlen != sizeof (io->addr)) bad_address_length (io->addrlen, sizeof (io->addr)); *from = io->addr; } else CLEAR (*from); } if (buf) buf->len = ret; return ret;}#endif /* WIN32 */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -