📄 icmp-socket.c
字号:
#endif /* ENABLE_DEBUG */ return ICMP_ERROR;}/* * Default reader for ICMP sockets. The sender is stored within * @code{sock->remote_addr} and @code{sock->remote_port} afterwards. */intsvz_icmp_read_socket (svz_socket_t *sock){ int num_read; socklen_t len; struct sockaddr_in sender; int trunc; len = sizeof (struct sockaddr_in); /* Receive data. */ if (!(sock->flags & SOCK_FLAG_CONNECTED)) { num_read = recvfrom (sock->sock_desc, svz_icmp_buffer, sizeof (svz_icmp_buffer), 0, (struct sockaddr *) &sender, &len); } else { num_read = recv (sock->sock_desc, svz_icmp_buffer, sizeof (svz_icmp_buffer), 0); } /* Valid packet data arrived. */ if (num_read > 0) {#if 0 svz_hexdump (stdout, "icmp packet received", sock->sock_desc, svz_icmp_buffer, num_read, 0);#endif sock->last_recv = time (NULL); if (!(sock->flags & SOCK_FLAG_FIXED)) { sock->remote_addr = sender.sin_addr.s_addr; }#if ENABLE_DEBUG svz_log (LOG_DEBUG, "icmp: recv%s: %s (%u bytes)\n", sock->flags & SOCK_FLAG_CONNECTED ? "" : "from", svz_inet_ntoa (sock->remote_addr), num_read);#endif /* ENABLE_DEBUG */ /* * Check the ICMP packet and put the packet load only into the * receive buffer of the socket structure. */ trunc = svz_icmp_check_packet (sock, (svz_uint8_t *) svz_icmp_buffer, num_read); if (trunc >= 0) { num_read -= trunc; if (num_read > sock->recv_buffer_size - sock->recv_buffer_fill) { svz_log (LOG_ERROR, "receive buffer overflow on icmp socket %d\n", sock->sock_desc); return -1; } memcpy (sock->recv_buffer + sock->recv_buffer_fill, svz_icmp_buffer + trunc, num_read); sock->recv_buffer_fill += num_read; /* Check access lists. */ if (svz_sock_check_access (sock, sock) < 0) return 0; if (sock->check_request) sock->check_request (sock); } else if (trunc == ICMP_DISCONNECT) { return -1; } } /* Some error occurred. */ else { svz_log (LOG_ERROR, "icmp: recv%s: %s\n", sock->flags & SOCK_FLAG_CONNECTED ? "" : "from", NET_ERROR); if (svz_errno != SOCK_UNAVAILABLE) return -1; } return 0;}/* * The default ICMP write callback is called whenever the socket * descriptor has been @code{select()}'ed or @code{poll()}'ed to be ready for * sending. */intsvz_icmp_write_socket (svz_socket_t *sock){ int num_written; unsigned do_write; char *p; socklen_t len; struct sockaddr_in receiver; /* Return here if there is nothing to do. */ if (sock->send_buffer_fill <= 0) return 0; len = sizeof (struct sockaddr_in); receiver.sin_family = AF_INET; /* Get destination address and data length from send buffer. */ p = sock->send_buffer; memcpy (&do_write, p, sizeof (do_write)); p += sizeof (do_write); memcpy (&receiver.sin_addr.s_addr, p, sizeof (sock->remote_addr)); p += sizeof (sock->remote_addr); memcpy (&receiver.sin_port, p, sizeof (sock->remote_port)); p += sizeof (sock->remote_port); assert ((int) do_write <= sock->send_buffer_fill); /* If socket is `connect ()'ed use `send ()' instead of `sendto ()'. */ if (!(sock->flags & SOCK_FLAG_CONNECTED)) { num_written = sendto (sock->sock_desc, p, do_write - (p - sock->send_buffer), 0, (struct sockaddr *) &receiver, len); } else { num_written = send (sock->sock_desc, p, do_write - (p - sock->send_buffer), 0); } /* Some error occurred while sending. */ if (num_written < 0) { svz_log (LOG_ERROR, "icmp: send%s: %s\n", sock->flags & SOCK_FLAG_CONNECTED ? "" : "to", NET_ERROR); if (svz_errno == SOCK_UNAVAILABLE) num_written = 0; } /* Packet data could be transmitted. */ else { sock->last_send = time (NULL); if ((unsigned) sock->send_buffer_fill > do_write) { memmove (sock->send_buffer, sock->send_buffer + do_write, sock->send_buffer_fill - do_write); } sock->send_buffer_fill -= do_write; }#if ENABLE_DEBUG svz_log (LOG_DEBUG, "icmp: send%s: %s (%u bytes)\n", sock->flags & SOCK_FLAG_CONNECTED ? "" : "to", svz_inet_ntoa (receiver.sin_addr.s_addr), do_write - (p - sock->send_buffer));#endif /* ENABLE_DEBUG */ return num_written < 0 ? -1 : 0;}/* * If you are calling this function we will send an empty ICMP packet * signaling that this connection is going down soon. */intsvz_icmp_send_control (svz_socket_t *sock, svz_uint8_t type){ static char *buffer = svz_icmp_buffer; svz_icmp_header_t hdr; unsigned len; int ret = 0; len = sizeof (len); memcpy (&buffer[len], &sock->remote_addr, sizeof (sock->remote_addr)); len += sizeof (sock->remote_addr); memcpy (&buffer[len], &sock->remote_port, sizeof (sock->remote_port)); len += sizeof (sock->remote_port); hdr.type = sock->itype; hdr.code = type; hdr.checksum = svz_raw_ip_checksum (NULL, 0); hdr.ident = (unsigned short) (getpid () + sock->id); hdr.sequence = sock->send_seq; hdr.port = sock->remote_port; memcpy (&buffer[len], svz_icmp_put_header (&hdr), ICMP_HEADER_SIZE); len += ICMP_HEADER_SIZE; memcpy (buffer, &len, sizeof (len)); if ((ret = svz_sock_write (sock, buffer, len)) == -1) { sock->flags |= SOCK_FLAG_KILLED; } return ret;}/* * Send a given buffer @var{buf} with length @var{length} via this ICMP * socket. If the length argument supersedes the maximum ICMP message * size the buffer is split into smaller packets. */intsvz_icmp_write (svz_socket_t *sock, char *buf, int length){ static char *buffer = svz_icmp_buffer; svz_icmp_header_t hdr; unsigned len, size; int ret = 0; /* Return if the socket has already been killed. */ if (sock->flags & SOCK_FLAG_KILLED) return 0; while (length) { /* * Put the data length and destination address in front * of each packet. */ len = sizeof (len); memcpy (&buffer[len], &sock->remote_addr, sizeof (sock->remote_addr)); len += sizeof (sock->remote_addr); memcpy (&buffer[len], &sock->remote_port, sizeof (sock->remote_port)); len += sizeof (sock->remote_port); if ((size = length) > ICMP_MSG_SIZE) size = ICMP_MSG_SIZE; /* Create ICMP header and put it in front of packet load. */ hdr.type = sock->itype; hdr.code = ICMP_SERVEEZ_DATA; hdr.checksum = svz_raw_ip_checksum ((svz_uint8_t *) buf, size); hdr.ident = (unsigned short) (getpid () + sock->id); hdr.sequence = sock->send_seq++; hdr.port = sock->remote_port; memcpy (&buffer[len], svz_icmp_put_header (&hdr), ICMP_HEADER_SIZE); len += ICMP_HEADER_SIZE; /* Copy the given buffer. */ memcpy (&buffer[len], buf, size); len += size; /* Put chunk length to buffer. */ memcpy (buffer, &len, sizeof (len)); buf += size; length -= size; /* Actually send the data or put it into the send buffer queue. */ if ((ret = svz_sock_write (sock, buffer, len)) == -1) { sock->flags |= SOCK_FLAG_KILLED; break; } } return ret;}/* * Put a formatted string to the icmp socket @var{sock}. Packet length and * destination address are additionally saved to the send buffer. The * destination is taken from @code{sock->remote_addr}. Furthermore a valid * icmp header is stored in front of the actual packet data. */intsvz_icmp_printf (svz_socket_t *sock, const char *fmt, ...){ va_list args; static char buffer[VSNPRINTF_BUF_SIZE]; unsigned len; /* return if there is nothing to do */ if (sock->flags & SOCK_FLAG_KILLED) return 0; /* save actual packet load */ va_start (args, fmt); len = svz_vsnprintf (buffer, VSNPRINTF_BUF_SIZE, fmt, args); va_end (args); return svz_icmp_write (sock, buffer, len);}/* * Default @code{check_request()} callback for ICMP sockets. */intsvz_icmp_check_request (svz_socket_t *sock){ int n; svz_server_t *server; if (sock->data == NULL && sock->handle_request == NULL) return -1; /* * If there is a valid `handle_request' callback (dedicated icmp * connection) call it. This kind of behaviour is due to a socket * creation via 'icmp_connect' (s.b.) and setting up a static * `handle_request' callback. */ if (sock->handle_request) { if (sock->handle_request (sock, sock->recv_buffer, sock->recv_buffer_fill)) return -1; sock->recv_buffer_fill = 0; return 0; } /* Go through all icmp servers on this server socket. */ svz_array_foreach (sock->data, server, n) { sock->cfg = server->cfg; if (server->handle_request) { if (!server->handle_request (sock, sock->recv_buffer, sock->recv_buffer_fill)) { sock->recv_buffer_fill = 0; break; } } } /* Check if any server processed this packet. */ if (sock->recv_buffer_fill) {#if ENABLE_DEBUG svz_log (LOG_DEBUG, "rejecting icmp packet on socket %d\n", sock->sock_desc);#endif sock->recv_buffer_fill = 0; } sock->cfg = NULL; return 0;}/* * This function creates an ICMP socket for receiving and sending. * Return @code{NULL} on errors, otherwise an enqueued socket structure. */svz_socket_t *svz_icmp_connect (unsigned long host, unsigned short port, unsigned char type){ SOCKET sockfd; svz_socket_t *sock; /* Create a client socket. */ if ((sockfd = svz_socket_create (PROTO_ICMP)) == (SOCKET) -1) return NULL; /* Try to connect to the server. Does it make sense for ICMP ? */ if (svz_socket_connect (sockfd, host, port) == -1) return NULL; /* Create socket structure and enqueue it. */ if ((sock = svz_sock_alloc ()) == NULL) { closesocket (sockfd); return NULL; } svz_sock_resize_buffers (sock, ICMP_BUF_SIZE, ICMP_BUF_SIZE); svz_sock_unique_id (sock); sock->sock_desc = sockfd; sock->flags |= (SOCK_FLAG_SOCK | SOCK_FLAG_CONNECTED | SOCK_FLAG_FIXED); sock->itype = type; svz_sock_enqueue (sock); svz_sock_intern_connection_info (sock); /* Put foreign address here. */ sock->remote_addr = host; sock->remote_port = (unsigned short) sock->id; sock->read_socket = svz_icmp_read_socket; sock->write_socket = svz_icmp_write_socket; sock->check_request = svz_icmp_check_request; /* Finally send a connection message. */ svz_icmp_send_control (sock, ICMP_SERVEEZ_CONNECT); svz_sock_connections++; return sock;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -