/** * Send a packet out over one of the managed sockets, depending on the * address family type of the remote address * @param managed pointer to managed packet socket * @param remote pointer to remote socket * @param data pointer to data to send * @param length length of data * @return -1 if an error happened, 0 if packet was sent, 1 if this * type of address was switched off */ int oonf_packet_send_managed(struct oonf_packet_managed *managed, union netaddr_socket *remote, const void *data, size_t length) { #ifdef OONF_LOG_DEBUG_INFO struct netaddr_str buf; #endif if (netaddr_socket_get_addressfamily(remote) == AF_UNSPEC) { return 0; } if (list_is_node_added(&managed->socket_v4.scheduler_entry._node) && netaddr_socket_get_addressfamily(remote) == AF_INET) { return oonf_packet_send(&managed->socket_v4, remote, data, length); } if (list_is_node_added(&managed->socket_v6.scheduler_entry._node) && netaddr_socket_get_addressfamily(remote) == AF_INET6) { return oonf_packet_send(&managed->socket_v6, remote, data, length); } errno = 0; OONF_DEBUG(LOG_PACKET, "Managed socket did not sent packet to %s because socket was not active", netaddr_socket_to_string(&buf, remote)); return 0; }
/** * Send a data packet through a packet socket. The transmission might not * be happen synchronously if the socket would block. * @param pktsocket pointer to packet socket * @param remote ip/address to send packet to * @param data pointer to data to be sent * @param length length of data * @return -1 if an error happened, 0 otherwise */ int oonf_packet_send(struct oonf_packet_socket *pktsocket, union netaddr_socket *remote, const void *data, size_t length) { int result; struct netaddr_str buf; if (abuf_getlen(&pktsocket->out) == 0) { /* no backlog of outgoing packets, try to send directly */ result = os_fd_sendto(&pktsocket->scheduler_entry.fd, data, length, remote, pktsocket->config.dont_route); if (result > 0) { /* successful */ OONF_DEBUG(LOG_PACKET, "Sent %d bytes to %s %s", result, netaddr_socket_to_string(&buf, remote), pktsocket->os_if != NULL ? pktsocket->os_if->name : ""); return 0; } if (errno != EINTR && errno != EAGAIN && errno != EWOULDBLOCK) { OONF_WARN(LOG_PACKET, "Cannot send UDP packet to %s: %s (%d)", netaddr_socket_to_string(&buf, remote), strerror(errno), errno); return -1; } } /* append destination */ abuf_memcpy(&pktsocket->out, remote, sizeof(*remote)); /* append data length */ abuf_append_uint16(&pktsocket->out, length); /* append data */ abuf_memcpy(&pktsocket->out, data, length); /* activate outgoing socket scheduler */ oonf_socket_set_write(&pktsocket->scheduler_entry, true); return 0; }
/** * Callback to handle data from the olsr socket scheduler * @param fd filedescriptor to read data from * @param data custom data pointer * @param event_read true if read-event is incoming * @param event_write true if write-event is incoming */ static void _cb_packet_event(struct oonf_socket_entry *entry, bool multicast __attribute__((unused))) { struct oonf_packet_socket *pktsocket; union netaddr_socket sock; uint16_t length; char *pkt; ssize_t result; struct netaddr_str netbuf; #ifdef OONF_LOG_DEBUG_INFO const char *interf = ""; #endif pktsocket = container_of(entry, typeof(*pktsocket), scheduler_entry); #ifdef OONF_LOG_DEBUG_INFO if (pktsocket->os_if) { interf = pktsocket->os_if->name; } #endif if (oonf_socket_is_read(entry)) { uint8_t *buf; /* clear recvfrom memory */ memset(&sock, 0, sizeof(sock)); /* handle incoming data */ buf = pktsocket->config.input_buffer; result = os_fd_recvfrom(&entry->fd, buf, pktsocket->config.input_buffer_length-1, &sock, pktsocket->os_if); if (result > 0 && pktsocket->config.receive_data != NULL) { /* handle raw socket */ if (pktsocket->protocol) { buf = os_fd_skip_rawsocket_prefix(buf, &result, pktsocket->local_socket.std.sa_family); if (!buf) { OONF_WARN(LOG_PACKET, "Error while skipping IP header for socket %s:", netaddr_socket_to_string(&netbuf, &pktsocket->local_socket)); return; } } /* null terminate it */ buf[result] = 0; /* received valid packet */ OONF_DEBUG(LOG_PACKET, "Received %"PRINTF_SSIZE_T_SPECIFIER" bytes from %s %s (%s)", result, netaddr_socket_to_string(&netbuf, &sock), interf, multicast ? "multicast" : "unicast"); pktsocket->config.receive_data(pktsocket, &sock, buf, result); } else if (result < 0 && (errno != EINTR && errno != EAGAIN && errno != EWOULDBLOCK)) { OONF_WARN(LOG_PACKET, "Cannot read packet from socket %s: %s (%d)", netaddr_socket_to_string(&netbuf, &pktsocket->local_socket), strerror(errno), errno); } } if (oonf_socket_is_write(entry) && abuf_getlen(&pktsocket->out) > 0) { /* handle outgoing data */ pkt = abuf_getptr(&pktsocket->out); /* copy remote socket */ memcpy(&sock, pkt, sizeof(sock)); pkt += sizeof(sock); /* copy length */ memcpy(&length, pkt, 2); pkt += 2; /* try to send packet */ result = os_fd_sendto(&entry->fd, pkt, length, &sock, pktsocket->config.dont_route); if (result < 0 && (errno == EINTR || errno == EAGAIN || errno == EWOULDBLOCK)) { /* try again later */ OONF_DEBUG(LOG_PACKET, "Sending to %s %s could block, try again later", netaddr_socket_to_string(&netbuf, &sock), interf); return; } if (result < 0) { /* display error message */ OONF_WARN(LOG_PACKET, "Cannot send UDP packet to %s: %s (%d)", netaddr_socket_to_string(&netbuf, &sock), strerror(errno), errno); } else { OONF_DEBUG(LOG_PACKET, "Sent %"PRINTF_SSIZE_T_SPECIFIER" bytes to %s %s", result, netaddr_socket_to_string(&netbuf, &sock), interf); } /* remove data from outgoing buffer (both for success and for final error */ abuf_pull(&pktsocket->out, sizeof(sock) + 2 + length); } if (abuf_getlen(&pktsocket->out) == 0) { /* nothing left to send, disable outgoing events */ oonf_socket_set_write(&pktsocket->scheduler_entry, false); } }
/** * Callback to receive UDP data through oonf_packet_managed API * @param pkt packet socket * @param from network socket the packet was received from * @param ptr pointer to packet data * @param length length of packet data */ static void _cb_receive_udp(struct oonf_packet_socket *pkt, union netaddr_socket *from, void *ptr, size_t length) { struct dlep_if *interf; uint8_t *buffer; ssize_t processed; struct netaddr_str nbuf; interf = pkt->config.user; buffer = ptr; if (interf->session_tree.count > 0 && interf->single_session) { /* ignore UDP traffic as long as we have a connection */ return; } if (length < sizeof(_DLEP_PREFIX) - 1) { /* ignore unknown prefix */ return; } if (memcmp(buffer, _DLEP_PREFIX, sizeof(_DLEP_PREFIX)-1) != 0) { OONF_WARN(interf->session.log_source, "Incoming UDP packet with unknown signature"); return; } /* advance pointer and fix length */ buffer += (sizeof(_DLEP_PREFIX) - 1); length -= (sizeof(_DLEP_PREFIX) - 1); /* copy socket information */ memcpy(&interf->session.remote_socket, from, sizeof(interf->session.remote_socket)); processed = dlep_session_process_buffer(&interf->session, buffer, length); if (processed < 0) { return ; } if ((size_t)processed < length) { OONF_WARN(interf->session.log_source, "Received malformed or too short UDP packet from %s", netaddr_socket_to_string(&nbuf, from)); /* incomplete or bad packet, just ignore it */ return; } if (abuf_getlen(interf->session.writer.out) > sizeof(_DLEP_PREFIX) - 1) { /* send an unicast response */ oonf_packet_send_managed(&interf->udp, from, abuf_getptr(interf->session.writer.out), abuf_getlen(interf->session.writer.out)); abuf_clear(interf->session.writer.out); /* add dlep prefix to buffer */ abuf_memcpy(interf->session.writer.out, _DLEP_PREFIX, sizeof(_DLEP_PREFIX) - 1); } netaddr_socket_invalidate(&interf->session.remote_socket); }