1 /*******************************************************************************
2 ################################################################################
3 # Copyright (c) [2017-2019] [Radisys] #
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 #
9 # http://www.apache.org/licenses/LICENSE-2.0 #
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 *******************************************************************************/
19 /* This file contains all SCTP related functionality */
24 #include <sys/types.h>
25 #include <sys/socket.h>
30 #include "du_common.h"
32 /* Global variable declaration */
33 S8 sockFd; /* Socket file descriptor */
34 U8 socket_type; /* Socket type */
35 Bool nonblocking; /* Blocking/Non-blocking socket */
36 Bool connUp; /* Is connection up */
37 int assocId; /* Assoc Id of connected assoc */
39 sockaddr_storage_t local_addr; /* Local Address */
40 sockaddr_storage_t remote_addr; /* Remote Address */
41 U8 la_len; /* Local Address length */
42 U8 ra_len; /* Remote Address length */
43 F1SctpParams *sctpCfg; /* SCTP configurations at DU */
45 /**************************************************************************
46 * @brief Task Initiation callback function.
50 * Function : sctpActvInit
53 * This function is supplied as one of parameters during SCTP's
54 * task registration. SSI will invoke this function once, after
55 * it creates and attaches this TAPA Task to a system task.
57 * @param[in] Ent entity, the entity ID of this task.
58 * @param[in] Inst inst, the instance ID of this task.
59 * @param[in] Region region, the region ID registered for memory
61 * @param[in] Reason reason.
62 * @return ROK - success
64 ***************************************************************************/
65 S16 sctpActvInit(Ent entity, Inst inst, Region region, Reason reason)
71 sctpCfg = &(ducfgparam.sctpParams);
76 /**************************************************************************
77 * @brief Task Activation callback function.
81 * Function : sctpActvTsk
84 * This function handles all SCTP messages received
85 * This API is registered with SSI during the
86 * Task Registration of DU APP.
88 * @param[in] Pst *pst, Post structure of the primitive.
89 * @param[in] Buffer *mBuf, Packed primitive parameters in the
91 * @return ROK - success
94 ***************************************************************************/
95 S16 sctpActvTsk(Pst *pst, Buffer *mBuf)
102 /*******************************************************************
104 * @brief Converts internet address to sockaddr type
108 * Function : getSockAddr
111 * Converts internet address to sockaddr type
114 * @return ROK - success
117 * ****************************************************************/
119 S16 getSockAddr(char *hostIp, U16 portNum, Bool ipv4Pres, Bool local)
121 sockaddr_storage_t address;
122 struct hostent *host;
125 /* Getting the transport address for local host name */
128 host = gethostbyname(hostIp);
129 if (host == NULL || host->h_length < 1)
131 printf("\nBad hostname: %s", hostIp);
134 la_raw = &address.v4.sin_addr;
135 address.v4.sin_family = AF_INET;
136 address.v4.sin_port = htons(portNum);
140 host = gethostbyname2(hostIp, AF_INET6);
141 if (host == NULL || host->h_length < 1)
143 printf("\n Bad hostname: %s", hostIp);
146 la_raw = &address.v6.sin6_addr;
147 address.v6.sin6_family = AF_INET6;
148 address.v6.sin6_port = htons(portNum);
149 address.v6.sin6_scope_id = 0;
152 memcpy((U8 *)la_raw, (U8 *)host->h_addr_list[0], host->h_length);
156 local_addr = address;
160 remote_addr = address;
164 } /* End of getSockAddr() */
166 /*******************************************************************
168 * @brief Opens a non-blocking socket and binds to local address
172 * Function : openSctpEndp
175 * Opens a non-blocking socket and binds to local address
178 * @return ROK - success
181 * ****************************************************************/
184 sa_family_t la_family;
188 /* Getting the transport address for local host name */
189 if(sctpCfg->duIpAddr.ipV4Pres)
191 if(getSockAddr(sctpCfg->duIpAddr.ipV4Addr, sctpCfg->duPort, TRUE, TRUE) != ROK )
193 printf("\nUnable to get local address");
200 if(getSockAddr(sctpCfg->duIpAddr.ipV6Addr, sctpCfg->duPort, FALSE, TRUE) != ROK )
202 printf("\nUnable to get local address");
205 la_family = AF_INET6;
208 socket_type = SOCK_STREAM;
210 /* Creating new end point */
211 sockFd = socket(la_family, socket_type, IPPROTO_SCTP);
214 printf("\n Failed to create socket %s", strerror(errno));
218 /* Binding socket to local address and port */
219 error = bind(sockFd, &local_addr.sa, la_len);
222 printf("\n Failed to bind to socket. Error [%s]", strerror(errno));
226 /* Setting socket as non-blocking*/
227 error = fcntl(sockFd, F_SETFL, O_NONBLOCK);
230 printf("\n Failed to set socket as non blocking. Error [%s]", strerror(errno));
240 } /* End of openSctpEndp() */
242 /*******************************************************************
244 * @brief Initiates connection with peer SCTP
248 * Function : sctpConnect
251 * Establishes SCTP connection with peer.
252 * Here, DU-SCTP will initate connection towards CU-SCTP
255 * @return ROK - success
258 * ****************************************************************/
264 /* Getting the transport address for remote host name */
265 if(sctpCfg->cuIpAddr.ipV4Pres)
267 ret = getSockAddr(sctpCfg->cuIpAddr.ipV4Addr, sctpCfg->cuPort, TRUE, FALSE);
271 ret = getSockAddr(sctpCfg->cuIpAddr.ipV6Addr, sctpCfg->cuPort, FALSE, FALSE);
275 printf("\nUnable to get remote address");
279 /* Initiating connection establishment with remote */
282 error = sctp_connectx(sockFd, &remote_addr.sa, 1, &assocId);
285 printf("\nError connecting to peer. Error[%s]", strerror(errno));
290 /* Mark SCTP connection UP */
296 }/* End of sctpConnect() */
298 /*******************************************************************
300 * @brief Handles an incoming message
304 * Function : sctpInmsgHdlr
307 * Handles an incoming message
309 * @params[in] Socket file descriptor
310 * Incoming message header
313 * @return ROK - success
316 * ****************************************************************/
317 S16 sctpInmsgHdlr(struct msghdr *msg, size_t msgLen)
319 sctp_cmsg_data_t *data;
320 struct cmsghdr *cmsg;
321 union sctp_notification *sn;
325 for (cmsg = CMSG_FIRSTHDR(msg); cmsg != NULL; cmsg = CMSG_NXTHDR(msg, cmsg))
327 data = (sctp_cmsg_data_t *)CMSG_DATA(cmsg);
330 printf("\nReceived Message");
332 /* if incoming message is data */
333 if (!(MSG_NOTIFICATION & msg->msg_flags))
335 /* Extract message */
338 char *temp = recvBuf;
345 temp = msg->msg_iov[index].iov_base;
346 temp_len = msg->msg_iov[index].iov_len;
348 if(temp_len > msgLen)
350 temp[(temp_len = msgLen) - 1] = '\0';
353 if((msgLen -= temp_len) > 0)
357 for (i = 0; i < temp_len-1 ; ++i)
359 if (!isprint(temp[i]))
362 printf("\nPrinting temp %s", temp);
363 temp = temp + temp_len;
366 recvBuf[len - 1] = '\0';
367 printf("\n Message: %s temp %s", recvBuf, temp);
369 /* Post received message to du_App */
370 if(SGetMsg(0, 0, &mBuf) == ROK )
372 if(SAddPstMsgMult((Data *)recvBuf, len, mBuf) == ROK)
376 pst->dstEnt = ENTDUAPP;
378 pst->srcEnt = ENTSCTP;
382 pst->event = EVTSCTPUP;
394 else /* If the incoming message is notification */
396 /* Extract and perform necessary action
397 Change the connUp state accordingly */
398 union sctp_notification *notify;
399 notify = (union sctp_notification *)msg->msg_iov->iov_base;
401 if (SCTP_ASSOC_CHANGE != notify->sn_header.sn_type)
403 printf("\nReceived unexpected notification: %d", notify->sn_header.sn_type);
407 switch(notify->sn_assoc_change.sac_state)
410 printf("Received SCTP_COMM_UP\n");
413 printf("Received SCTP_COMM_LOST\n");
416 printf("Received SCTP_RESTART\n");
418 case SCTP_SHUTDOWN_COMP:
419 printf("Received SCTP_SHUTDOWN_COMP\n");
421 case SCTP_CANT_STR_ASSOC:
422 printf("Received SCTP_CANT_STR_ASSOC\n");
429 /*******************************************************************
431 * @brief Receives message on the socket
435 * Function : sctpSockPoll
438 * Receives message on the socket
441 * @return ROK - success
444 * ****************************************************************/
448 struct msghdr inmessage;
450 char incmsg[CMSG_SPACE(sizeof(_sctp_cmsg_data_t))];
451 sockaddr_storage_t msgname;
453 /* Initialize inmessage with enough space for DATA... */
454 memset(&inmessage, 0, sizeof(inmessage));
455 if ((iov.iov_base = malloc(REALLY_BIG)) == NULL)
457 printf("\n malloc not enough memory!!!");
462 iov.iov_len = REALLY_BIG;
463 inmessage.msg_iov = &iov;
464 inmessage.msg_iovlen = 1;
465 /* or a control message. */
466 inmessage.msg_control = incmsg;
467 inmessage.msg_controllen = sizeof(incmsg);
468 inmessage.msg_name = &msgname;
469 inmessage.msg_namelen = sizeof(msgname);
473 error = recvmsg(sockFd, &inmessage, MSG_WAITALL);
476 if (nonblocking && (EAGAIN == errno))
481 if (socket_type == SOCK_STREAM)
483 if (ENOTCONN != errno)
487 printf("No association is present now!!\n");
495 sctpInmsgHdlr(&inmessage, error);
497 inmessage.msg_control = incmsg;
498 inmessage.msg_controllen = sizeof(incmsg);
499 inmessage.msg_name = &msgname;
500 inmessage.msg_namelen = sizeof(msgname);
501 iov.iov_len = REALLY_BIG;
503 }/* End of while(connUp) */
506 }/* End of sctpSockPoll() */
508 /*******************************************************************
510 * @brief Send message on SCTP socket
514 * Function : sctpOutMsgSend
517 * Send message on SCTP socket
520 * @return ROK - success
523 * ****************************************************************/
524 S16 sctpOutMsgSend(char *message, U8 msglen)
526 struct msghdr outmsg;
531 if(connUp && msglen != 0)
533 iov.iov_base = message;
534 iov.iov_len = msglen;
536 outmsg.msg_iov = &iov;
537 outmsg.msg_iovlen = 1;
538 outmsg.msg_control = NULL;
539 outmsg.msg_controllen = 0;
540 outmsg.msg_name = &remote_addr;
541 outmsg.msg_namelen = ra_len;
542 outmsg.msg_flags = 0;
544 error = sendmsg(sockFd, &outmsg, 0);
549 if(nonblocking && EAGAIN == errno)
555 printf("\n Error [%s] while sending message on SCTP assoc", strerror(errno));
563 }while(error != msglen);
567 } /* End of sctpOutMsgSend */
569 /*******************************************************************
571 * @brief SCTP Assoc establishment request from DU
575 * Function : sctpAssocReq
578 * This function opens a socket at DU and
579 * intiates SCTP connection.
582 * @return ROK - success
585 * ****************************************************************/
589 /* Open SCTP socket and bind to local address */
590 if(openSctpEndp() != ROK)
592 printf("\nFailed while opening SCTP endpoint");
598 /* TODO : Send Assoc establishment failure to du_app if needed*/
600 else if(sctpConnect() != ROK) /* send connection request */
602 printf("\nFailed while connecting to peer");
607 /* TODO : Send Assoc establishment failure to du_app */
611 /* Send AssocCfm to du_app */
612 if(sctpSockPoll() != ROK)
614 printf("\nFailed while polling");
615 /* Send failure to du_app */
618 } /* End of sctpAssocReq */
620 /**********************************************************************
622 **********************************************************************/