Restructure O1 module to run as a thread in O-DU High binary [Issue-Id: ODUHIGH-297]
[o-du/l2.git] / src / o1 / UnixSocketServer.cpp
1 /*******************************************************************************
2 ################################################################################
3 #   Copyright (c) [2020-2021] [HCL Technologies Ltd.]                          #
4 #                                                                              #
5 #   Licensed under the Apache License, Version 2.0 (the "License");            #
6 #   you may not use this file except in compliance with the License.           #
7 #   You may obtain a copy of the License at                                    #
8 #                                                                              #
9 #       http://www.apache.org/licenses/LICENSE-2.0                             #
10 #                                                                              #
11 #   Unless required by applicable law or agreed to in writing, software        #
12 #   distributed under the License is distributed on an "AS IS" BASIS,          #
13 #   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   #
14 #   See the License for the specific language governing permissions and        #
15 #   limitations under the License.                                             #
16 ################################################################################
17 *******************************************************************************/
18
19 /* This file contains UnixSocketServer class that listens for Netconf Alarm 
20    messages on a Unix socket from ODU. It calls the AlarmManager functions
21    for raising or clearing the alarms based on the actions received 
22 */
23
24 #include "UnixSocketServer.hpp"
25 #include "Alarm.hpp"
26 #include "AlarmManager.hpp"
27 #include "ConfigInterface.h"
28 #include "GlobalDefs.hpp"
29 #include <iostream>
30 #include <cstdio>
31 #include <cerrno>
32 #include <cstdlib>
33 #include <unistd.h>
34 #include <sys/types.h>
35 #include <sys/socket.h>
36 #include <netinet/in.h>
37 #include <netdb.h>
38 #include <arpa/inet.h>
39 #include <sys/un.h>
40 #include "InitConfig.hpp"
41
42
43 using std::map;
44 using std::pair;
45
46 /*******************************************************************
47  *
48  * @brief Constructor
49  *
50  * @details
51  *
52  *    Function : UnixSocketServer
53  *
54  *    Functionality:
55  *      - Constructor intialization
56  *
57  * @params[in] socket path
58  * @return None
59  ******************************************************************/
60 UnixSocketServer::UnixSocketServer(const string& sockPath)
61                                    : mSockPath(sockPath),
62                                      mIsRunning(false)
63 {
64
65 }  
66   
67 /*******************************************************************
68  *
69  * @brief Destructor
70  *
71  * @details
72  *
73  *    Function : ~UnixSocketServer
74  *
75  *    Functionality:
76  *      - Destructor
77  *
78  * @params[in] None
79  * @return None
80  ******************************************************************/
81 UnixSocketServer::~UnixSocketServer()
82 {
83
84 }
85
86
87 /*******************************************************************
88  *
89  * @brief Read the data from the connected client application
90  *
91  * @details
92  *
93  *    Function : readMessage
94  *
95  *    Functionality:
96  *      - Reads the data from the connected client application
97  *
98  * @params[in] File descriptor
99  * @return No. of bytes read
100  *
101  ******************************************************************/
102 int UnixSocketServer::readMessage(int fd)
103 {
104    AlarmRecord *alrmRec = NULL;
105    char recvBuf[BUFLEN];
106    Alarm alrm;
107    bzero(&recvBuf,sizeof(recvBuf));
108    
109    int nbytes = read (fd, &recvBuf, sizeof(recvBuf));
110    
111    if (nbytes > 0)
112    {
113       MsgHeader *msgHdr = (MsgHeader*)recvBuf;
114
115       O1_LOG("\nO1 UnixSocketServer :\nMsgType %d",msgHdr->msgType);
116       
117       if ( msgHdr->msgType == ALARM ){
118          uint16_t alrmId;
119          alrmRec = (AlarmRecord*) recvBuf;
120          O1_LOG("\nO1 UnixSocketServer :\n"
121                    "Action %d\n"
122                    "Alarm ID %s\n" 
123                    "Severity %d\n" 
124                    "Additional Text %s\n"
125                    "Specific Problem %s\n"
126                    "Additional Info %s\n"
127                    "Alarm Raise Time %s\n",
128                    alrmRec->msgHeader.action,
129                    alrmRec->alarmId,
130                    alrmRec->perceivedSeverity,
131                    alrmRec->additionalText,
132                    alrmRec->specificProblem,
133                    alrmRec->additionalInfo,
134                    alrmRec->alarmRaiseTime
135                 );
136       
137          /*Fill the alarm structure */
138          sscanf(alrmRec->alarmId,"%hu",&alrmId);
139          alrm.setAlarmId(alrmId);
140          alrm.setPerceivedSeverity(alrmRec->perceivedSeverity);
141          alrm.setAdditionalText(alrmRec->additionalText);
142          alrm.setEventType(alrmRec->eventType);
143          alrm.setSpecificProblem(alrmRec->specificProblem);
144          alrm.setAdditionalInfo(alrmRec->additionalInfo);
145       }
146
147       switch(msgHdr->action)
148       {
149          case RAISE_ALARM: 
150                      if(AlarmManager::instance().raiseAlarm(alrm))
151                      {
152                         O1_LOG("\nO1 UnixSocketServer : "
153                                "Alarm raised for alarm Id %s",
154                                 alrmRec->alarmId);
155                      }
156                      else
157                      {
158                         O1_LOG("\nO1 UnixSocketServer : "
159                                "Error in raising alarm for alrm Id %s",
160                                 alrmRec->alarmId);
161                      }
162                      break;  
163          case CLEAR_ALARM: 
164                      if(AlarmManager::instance().clearAlarm(alrm))
165                      {
166                         O1_LOG("\nO1 UnixSocketServer : "
167                                "Alarm cleared for alarm Id %s",
168                                 alrmRec->alarmId);
169                      }
170                      else
171                      {
172                         O1_LOG("\nO1 UnixSocketServer : "
173                                "Error in clearing alarm for alarm Id %s",
174                                 alrmRec->alarmId);
175                      }
176                      break;
177 #if 0
178          case GET_STARTUP_CONFIG:
179                      {
180                         StartupConfig cfg;
181                                        InitConfig::instance().getCurrInterfaceConfig(cfg);
182                         O1_LOG("\nO1 UnixSocketServer : "
183                                "cfg.DU_IPV4_Addr [%s]",
184                                 cfg.DU_IPV4_Addr);
185                         O1_LOG("\nO1 UnixSocketServer : "
186                                "cfg.DU_Port [%d]", 
187                                 cfg.DU_Port);
188                         O1_LOG("\nO1 UnixSocketServer : "
189                                "cfg.CU_IPV4_Addr [%s]", 
190                                 cfg.CU_IPV4_Addr);
191                         O1_LOG("\nO1 UnixSocketServer : "
192                                "cfg.CU_Port [%d]", 
193                                 cfg.CU_Port);
194                         O1_LOG("\nO1 UnixSocketServer : "
195                                "cfg.RIC_IPV4_Addr [%s]", 
196                                 cfg.RIC_IPV4_Addr);
197                         O1_LOG("\nO1 UnixSocketServer : "
198                                "cfg.RIC_Port [%d]", 
199                                 cfg.RIC_Port);
200                         if (write (fd, &cfg, sizeof(cfg)) < 0)
201                         {
202                            O1_LOG("\nO1 UnixSocketServer : "
203                                   "Error sending startup configuration \n");
204                         }
205                         break; 
206                      }
207 #endif
208          default:    
209                      O1_LOG("\nO1 UnixSocketServer : No action performed"); 
210                      break;
211       }
212
213    }
214    return nbytes;
215 }
216
217
218 /*******************************************************************
219  *
220  * @brief Open a Unix socket and bind on the port
221  *
222  * @details
223  *
224  *    Function : makeSocket
225  *
226  *    Functionality:
227  *      -  Opens a Unix socket and bind on the port
228  *
229  * @params[in] void
230  * @return O1:SUCCESS - success
231  *         O1:FAILURE - failure
232  ******************************************************************/
233
234 int UnixSocketServer::makeSocket() 
235 {
236    struct sockaddr_un name;
237    /* Create the socket. */
238    mSock = socket (AF_UNIX, SOCK_STREAM, 0);
239    if (mSock < 0)
240    {
241       O1_LOG("\nO1 UnixSocketServer : Socket error");
242       return O1::FAILURE;
243    }
244    /* Give the socket a name. */
245    bzero(&name, sizeof(name));
246    name.sun_family = AF_UNIX;
247
248    /* Remove the socket file if it already exists */ 
249    if ( unlink(mSockPath.c_str()) == 0)
250    {
251       O1_LOG("\nO1 UnixSocketServer : "
252              "Removing the existing socket path %s",
253               mSockPath.c_str());
254    }        
255    strcpy(name.sun_path, mSockPath.c_str());
256    if (bind (mSock, (struct sockaddr *) &name, sizeof (name)) < 0)
257    {
258       close(mSock);
259       O1_LOG("\nO1 UnixSocketServer : Bind error");
260       return O1::FAILURE;
261    }
262    return O1::SUCCESS;
263 }
264
265
266 /*******************************************************************
267  *
268  * @brief A Unix server to handle multiple connection
269  *
270  * @details
271  *
272  *    Function : run
273  *
274  *    Functionality:
275  *      -  A Unix server to handle multiple connection 
276  *         Uses select multiplexing
277  *
278  * @params[in] void
279  * @return true  - success
280  *         false - failure
281  ******************************************************************/
282 bool UnixSocketServer::run()
283 {
284
285    fd_set active_fd_set, read_fd_set;
286    int i;
287    struct sockaddr_un clientName;
288    socklen_t size;
289    mIsRunning = true;
290
291    /* Create the socket and set it up to accept connections. */
292    if( makeSocket() == O1::SUCCESS )
293    {
294       if (listen (mSock, 1) < 0)
295       {
296          O1_LOG("\nO1 UnixSocketServer : Listen error");
297          close(mSock);
298          mIsRunning = false;
299       }
300       else
301       {
302          /* Initialize the set of active sockets. */
303          FD_ZERO (&active_fd_set);
304          FD_SET (mSock, &active_fd_set);
305
306          while (1)
307          {
308             /* Block until input arrives on one or more active sockets. */
309             read_fd_set = active_fd_set;
310             if (select (FD_SETSIZE, &read_fd_set, NULL, NULL, NULL) < 0)
311             {
312                O1_LOG("\nO1 UnixSocketServer : Select error");
313                close(mSock);
314                mIsRunning = false;
315                break;
316             }
317
318             /* Service all the sockets with input pending. */
319             for (i = 0; i < FD_SETSIZE; ++i)
320             {
321                 if (FD_ISSET (i, &read_fd_set))
322                 {
323                    if (i == mSock)
324                    {
325                       /* Connection request on original socket. */
326                       int newFd;
327                       bzero(&clientName, sizeof(clientName));
328                       size = sizeof (clientName);
329                       newFd = accept(mSock,(struct sockaddr *) &clientName,&size);
330                       if (newFd < 0)
331                       {
332                          O1_LOG("\nO1 UnixSocketServer : Accept error");
333                          close(mSock);
334                          mIsRunning = false;
335                          break;
336                       }
337                       O1_LOG("\nO1 UnixSocketServer : Connected from client\n");
338                       FD_SET (newFd, &active_fd_set);
339                    }      
340                    else
341                    {
342                       /* Data arriving on an already-connected socket. */
343                       if (readMessage(i) < 0)
344                       {
345                          close (i);
346                          FD_CLR (i, &active_fd_set);
347                       }
348                    }
349                 }    
350              }/* for loop ends */     
351           } /* while(1) ends */
352       } /* else ends */
353    } /* outer if ends */
354    else
355    {
356       mIsRunning = false;
357    }
358    return mIsRunning;
359 }
360
361
362 /*******************************************************************
363  *
364  * @brief Clean up open socket
365  *
366  * @details
367  *
368  *    Function : cleanUp
369  *
370  *    Functionality:
371  *      -  Performs any clean ups before stopping the thread
372  *
373  * @params[in] void
374  * @return void
375  ******************************************************************/
376 void UnixSocketServer::cleanUp(void)
377 {
378    close(mSock);
379    O1_LOG("\nO1 UnixSocketServer : Cleaning up Closing socket \n");
380 }
381
382 /*******************************************************************
383  *
384  * @brief Check if the server is running
385  *
386  * @details
387  *
388  *    Function : isRunning
389  *
390  *    Functionality:
391  *      -  Returns the running status of the server
392  *
393  * @params[in] void
394  * @return true : running
395  *         false: not running
396  ******************************************************************/
397 bool UnixSocketServer::isRunning() const
398 {
399    return mIsRunning;
400 }
401
402 /**********************************************************************
403          End of file
404 **********************************************************************/