1 /*
2  *  Copyright (c) 2018, The OpenThread Authors.
3  *  All rights reserved.
4  *
5  *  Redistribution and use in source and binary forms, with or without
6  *  modification, are permitted provided that the following conditions are met:
7  *  1. Redistributions of source code must retain the above copyright
8  *     notice, this list of conditions and the following disclaimer.
9  *  2. Redistributions in binary form must reproduce the above copyright
10  *     notice, this list of conditions and the following disclaimer in the
11  *     documentation and/or other materials provided with the distribution.
12  *  3. Neither the name of the copyright holder nor the
13  *     names of its contributors may be used to endorse or promote products
14  *     derived from this software without specific prior written permission.
15  *
16  *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17  *  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18  *  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19  *  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
20  *  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21  *  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22  *  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23  *  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24  *  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25  *  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26  *  POSSIBILITY OF SUCH DAMAGE.
27  */
28 
29 /**
30  * @file
31  * @brief
32  *   This file implements the posix simulation.
33  */
34 
35 #include "openthread-posix-config.h"
36 #include "platform-posix.h"
37 
38 #include <arpa/inet.h>
39 #include <stddef.h>
40 #include <stdio.h>
41 #include <string.h>
42 #include <sys/select.h>
43 #include <unistd.h>
44 
45 #if OPENTHREAD_POSIX_VIRTUAL_TIME
46 
47 static const int kMaxNetworkSize = 33;      ///< Well-known ID used by a simulated radio supporting promiscuous mode.
48 static const int kBasePort       = 18000;   ///< This base port for posix app simulation.
49 static const int kUsPerSecond    = 1000000; ///< Number of microseconds per second.
50 
51 static uint64_t sNow        = 0;  ///< Time of simulation.
52 static int      sSockFd     = -1; ///< Socket used to communicating with simulator.
53 static uint16_t sPortOffset = 0;  ///< Port offset for simulation.
54 
virtualTimeInit(uint16_t aNodeId)55 void virtualTimeInit(uint16_t aNodeId)
56 {
57     struct sockaddr_in sockaddr;
58     char *             offset;
59 
60     memset(&sockaddr, 0, sizeof(sockaddr));
61     sockaddr.sin_family = AF_INET;
62 
63     offset = getenv("PORT_OFFSET");
64 
65     if (offset)
66     {
67         char *endptr;
68 
69         sPortOffset = (uint16_t)strtol(offset, &endptr, 0);
70 
71         if (*endptr != '\0')
72         {
73             const uint8_t kMsgSize = 40;
74             char          msg[kMsgSize];
75 
76             snprintf(msg, sizeof(msg), "Invalid PORT_OFFSET: %s", offset);
77             DieNowWithMessage(msg, OT_EXIT_INVALID_ARGUMENTS);
78         }
79 
80         sPortOffset *= (kMaxNetworkSize + 1);
81     }
82 
83     sockaddr.sin_port        = htons(kBasePort + sPortOffset + aNodeId);
84     sockaddr.sin_addr.s_addr = INADDR_ANY;
85 
86     sSockFd = SocketWithCloseExec(AF_INET, SOCK_DGRAM, IPPROTO_UDP, kSocketBlock);
87 
88     if (sSockFd == -1)
89     {
90         DieNowWithMessage("socket", OT_EXIT_ERROR_ERRNO);
91     }
92 
93     if (bind(sSockFd, (struct sockaddr *)&sockaddr, sizeof(sockaddr)) == -1)
94     {
95         DieNowWithMessage("bind", OT_EXIT_ERROR_ERRNO);
96     }
97 }
98 
virtualTimeDeinit(void)99 void virtualTimeDeinit(void)
100 {
101     if (sSockFd != -1)
102     {
103         close(sSockFd);
104         sSockFd = -1;
105     }
106 }
107 
virtualTimeSendEvent(struct VirtualTimeEvent * aEvent,size_t aLength)108 static void virtualTimeSendEvent(struct VirtualTimeEvent *aEvent, size_t aLength)
109 {
110     ssize_t            rval;
111     struct sockaddr_in sockaddr;
112 
113     memset(&sockaddr, 0, sizeof(sockaddr));
114     sockaddr.sin_family = AF_INET;
115     inet_pton(AF_INET, "127.0.0.1", &sockaddr.sin_addr);
116     sockaddr.sin_port = htons(9000 + sPortOffset);
117 
118     rval = sendto(sSockFd, aEvent, aLength, 0, (struct sockaddr *)&sockaddr, sizeof(sockaddr));
119 
120     if (rval < 0)
121     {
122         DieNowWithMessage("sendto", OT_EXIT_ERROR_ERRNO);
123     }
124 }
125 
virtualTimeReceiveEvent(struct VirtualTimeEvent * aEvent)126 void virtualTimeReceiveEvent(struct VirtualTimeEvent *aEvent)
127 {
128     ssize_t rval = recvfrom(sSockFd, aEvent, sizeof(*aEvent), 0, nullptr, nullptr);
129 
130     if (rval < 0 || (uint16_t)rval < offsetof(struct VirtualTimeEvent, mData))
131     {
132         DieNowWithMessage("recvfrom", (rval < 0) ? OT_EXIT_ERROR_ERRNO : OT_EXIT_FAILURE);
133     }
134 
135     sNow += aEvent->mDelay;
136 }
137 
virtualTimeSendSleepEvent(const struct timeval * aTimeout)138 void virtualTimeSendSleepEvent(const struct timeval *aTimeout)
139 {
140     struct VirtualTimeEvent event;
141 
142     event.mDelay      = (uint64_t)aTimeout->tv_sec * kUsPerSecond + (uint64_t)aTimeout->tv_usec;
143     event.mEvent      = OT_SIM_EVENT_ALARM_FIRED;
144     event.mDataLength = 0;
145 
146     virtualTimeSendEvent(&event, offsetof(struct VirtualTimeEvent, mData));
147 }
148 
virtualTimeSendRadioSpinelWriteEvent(const uint8_t * aData,uint16_t aLength)149 void virtualTimeSendRadioSpinelWriteEvent(const uint8_t *aData, uint16_t aLength)
150 {
151     struct VirtualTimeEvent event;
152 
153     event.mDelay      = 0;
154     event.mEvent      = OT_SIM_EVENT_RADIO_SPINEL_WRITE;
155     event.mDataLength = aLength;
156 
157     memcpy(event.mData, aData, aLength);
158 
159     virtualTimeSendEvent(&event, offsetof(struct VirtualTimeEvent, mData) + event.mDataLength);
160 }
161 
virtualTimeUpdateFdSet(fd_set * aReadFdSet,fd_set * aWriteFdSet,fd_set * aErrorFdSet,int * aMaxFd,struct timeval * aTimeout)162 void virtualTimeUpdateFdSet(fd_set *        aReadFdSet,
163                             fd_set *        aWriteFdSet,
164                             fd_set *        aErrorFdSet,
165                             int *           aMaxFd,
166                             struct timeval *aTimeout)
167 {
168     OT_UNUSED_VARIABLE(aWriteFdSet);
169     OT_UNUSED_VARIABLE(aErrorFdSet);
170     OT_UNUSED_VARIABLE(aTimeout);
171 
172     FD_SET(sSockFd, aReadFdSet);
173     if (*aMaxFd < sSockFd)
174     {
175         *aMaxFd = sSockFd;
176     }
177 }
178 
virtualTimeProcess(otInstance * aInstance,const fd_set * aReadFdSet,const fd_set * aWriteFdSet,const fd_set * aErrorFdSet)179 void virtualTimeProcess(otInstance *  aInstance,
180                         const fd_set *aReadFdSet,
181                         const fd_set *aWriteFdSet,
182                         const fd_set *aErrorFdSet)
183 {
184     struct VirtualTimeEvent event;
185 
186     memset(&event, 0, sizeof(event));
187 
188     OT_UNUSED_VARIABLE(aInstance);
189     OT_UNUSED_VARIABLE(aWriteFdSet);
190     OT_UNUSED_VARIABLE(aErrorFdSet);
191 
192     if (FD_ISSET(sSockFd, aReadFdSet))
193     {
194         virtualTimeReceiveEvent(&event);
195     }
196 
197     virtualTimeRadioSpinelProcess(aInstance, &event);
198 }
199 
otPlatTimeGet(void)200 uint64_t otPlatTimeGet(void)
201 {
202     return sNow;
203 }
204 
205 #endif // OPENTHREAD_POSIX_VIRTUAL_TIME
206