/* * Copyright (c) 2017-2019 Cisco and/or its affiliates. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include <limits.h> #include <src/config.h> #include <stdio.h> #include <src/core/connection.h> #include <src/core/messageHandler.h> #include <src/core/ticks.h> #include <src/core/wldr.h> #include <src/io/addressPair.h> #include <src/io/ioOperations.h> #include <parc/algol/parc_Memory.h> #include <parc/assert/parc_Assert.h> struct connection { const AddressPair *addressPair; IoOperations *ops; unsigned refCount; bool probing_active; unsigned probing_interval; unsigned counter; Ticks last_sent; Ticks delay; bool wldrAutoStart; // if true, wldr can be set automatically // by default this value is set to true. // if wldr is activated using a command (config // file/hicnLightControl) this value is set to false so // that a base station can not disable wldr at the client Wldr *wldr; }; Connection *connection_Create(IoOperations *ops) { parcAssertNotNull(ops, "Parameter ops must be non-null"); Connection *conn = parcMemory_AllocateAndClear(sizeof(Connection)); parcAssertNotNull(conn, "parcMemory_AllocateAndClear(%zu) returned NULL", sizeof(Connection)); conn->addressPair = ioOperations_GetAddressPair(ops); conn->ops = ops; conn->refCount = 1; conn->wldr = NULL; conn->probing_active = false; conn->wldrAutoStart = true; conn->probing_interval = 0; conn->counter = 0; conn->last_sent = 0; conn->delay = INT_MAX; return conn; } Connection *connection_Acquire(Connection *connection) { parcAssertNotNull(connection, "Parameter conn must be non-null"); connection->refCount++; return connection; } void connection_Release(Connection **connectionPtr) { parcAssertNotNull(connectionPtr, "Parameter must be non-null double pointer"); parcAssertNotNull(*connectionPtr, "Parameter must dereference to non-null pointer"); Connection *conn = *connectionPtr; parcAssertTrue( conn->refCount > 0, "Invalid state, connection reference count should be positive, got 0."); conn->refCount--; if (conn->refCount == 0) { // don't destroy addressPair, its part of ops. ioOperations_Release(&conn->ops); if (conn->wldr != NULL) { wldr_Destroy(&(conn->wldr)); } parcMemory_Deallocate((void **)&conn); } *connectionPtr = NULL; } bool connection_Send(const Connection *conn, Message *message) { parcAssertNotNull(conn, "Parameter conn must be non-null"); parcAssertNotNull(message, "Parameter message must be non-null"); if (ioOperations_IsUp(conn->ops)) { if (message_GetType(message) == MessagePacketType_ContentObject) { uint8_t connectionId = (uint8_t)connection_GetConnectionId(conn); message_UpdatePathLabel(message, connectionId); } if (conn->wldr != NULL) { wldr_SetLabel(conn->wldr, message); } else { message_ResetWldrLabel(message); } return ioOperations_Send(conn->ops, NULL, message); } return false; } bool connection_SendCommandResponse(const Connection *conn, struct iovec *msg){ parcAssertNotNull(conn, "Parameter conn must be non-null"); parcAssertNotNull(msg, "Parameter message must be non-null"); return ioOperations_SendCommandResponse(conn->ops, msg); } static void _sendProbe(Connection *conn, unsigned probeType, uint8_t *message) { parcAssertNotNull(conn, "Parameter conn must be non-null"); if (probeType == PACKET_TYPE_PROBE_REQUEST) { Ticks now = ioOperations_SendProbe(conn->ops, probeType, message); if (now != 0) { conn->last_sent = now; } } else { ioOperations_SendProbe(conn->ops, probeType, message); } } void connection_Probe(Connection *conn) { _sendProbe(conn, PACKET_TYPE_PROBE_REQUEST, NULL); } void connection_HandleProbe(Connection *conn, uint8_t *probe, Ticks actualTime) { parcAssertNotNull(conn, "Parameter conn must be non-null"); parcAssertNotNull(probe, "Parameter pkt must be non-null"); uint8_t probeType = messageHandler_GetProbePacketType(probe); if (probeType == PACKET_TYPE_PROBE_REQUEST) { _sendProbe(conn, PACKET_TYPE_PROBE_REPLY, probe); } else if (probeType == PACKET_TYPE_PROBE_REPLY) { Ticks delay = actualTime - conn->last_sent; if (delay == 0) { delay = 1; } if (delay < conn->delay) { conn->delay = delay; } } else { printf("receivde unkwon probe type\n"); } } uint64_t connection_GetDelay(Connection *conn) { return (uint64_t)conn->delay; } IoOperations *connection_GetIoOperations(const Connection *conn) { return conn->ops; } unsigned connection_GetConnectionId(const Connection *conn) { parcAssertNotNull(conn, "Parameter conn must be non-null"); return ioOperations_GetConnectionId(conn->ops); } const AddressPair *connection_GetAddressPair(const Connection *conn) { parcAssertNotNull(conn, "Parameter conn must be non-null"); return ioOperations_GetAddressPair(conn->ops); } bool connection_IsUp(const Connection *conn) { parcAssertNotNull(conn, "Parameter conn must be non-null"); if (!conn->ops) return false; return ioOperations_IsUp(conn->ops); } bool connection_IsLocal(const Connection *conn) { parcAssertNotNull(conn, "Parameter conn must be non-null"); return ioOperations_IsLocal(conn->ops); } const void *connection_Class(const Connection *conn) { parcAssertNotNull(conn, "Parameter conn must be non-null"); return ioOperations_Class(conn->ops); } bool connection_ReSend(const Connection *conn, Message *message, bool notification) { parcAssertNotNull(conn, "Parameter conn must be non-null"); parcAssertNotNull(message, "Parameter message must be non-null"); bool res = false; if (connection_IsUp(conn)) { // here the wldr header is alreay set: this message is a retransmission or a // notification // we need to recompiute the path lable since we always store a pointer to // the same message if this message will be sent again to someonelse, the // new path label must be computed starting from the orignal labelorignal // label. Notice that we heve the same problem in case of PIT aggregation. // That case is handled insied the MessageProcessor. This is specific to // WLDR retransmittions. This is done only for data packets if (message_GetType(message) == MessagePacketType_ContentObject) { uint8_t connectionId = (uint8_t)connection_GetConnectionId(conn); uint32_t old_path_label = message_GetPathLabel(message); message_UpdatePathLabel(message, connectionId); res = ioOperations_Send(conn->ops, NULL, message); message_SetPathLabel(message, old_path_label); } else { res = ioOperations_Send(conn->ops, NULL, message); } } if (notification) { // the notification is never destroyed message_Release(&message); } return res; } void connection_AllowWldrAutoStart(Connection *conn, bool allow) { conn->wldrAutoStart = allow; } void connection_EnableWldr(Connection *conn) { if (!connection_IsLocal(conn)) { if (conn->wldr == NULL) { printf("----------------- enable wldr\n"); conn->wldr = wldr_Init(); } } } void connection_DisableWldr(Connection *conn) { if (!connection_IsLocal(conn)) { if (conn->wldr != NULL) { printf("----------------- disable wldr\n"); wldr_Destroy(&(conn->wldr)); conn->wldr = NULL; } } } bool connection_HasWldr(const Connection *conn) { if (conn->wldr == NULL) { return false; } else { return true; } } bool connection_WldrAutoStartAllowed(const Connection *conn) { return conn->wldrAutoStart; } void connection_DetectLosses(Connection *conn, Message *message) { if (conn->wldr != NULL) wldr_DetectLosses(conn->wldr, conn, message); } void connection_HandleWldrNotification(Connection *conn, Message *message) { if (conn->wldr != NULL) wldr_HandleWldrNotification(conn->wldr, conn, message); }