Address multi-threading issues in SI95
[ric-plt/lib/rmr.git] / src / rmr / si / src / si95 / sircv.c
1 // vim: noet sw=4 ts=4:
2 /*
3 ==================================================================================
4     Copyright (c) 2020 Nokia
5     Copyright (c) 2020 AT&T Intellectual Property.
6
7    Licensed under the Apache License, Version 2.0 (the "License");
8    you may not use this file except in compliance with the License.
9    You may obtain a copy of the License at
10
11        http://www.apache.org/licenses/LICENSE-2.0
12
13    Unless required by applicable law or agreed to in writing, software
14    distributed under the License is distributed on an "AS IS" BASIS,
15    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16    See the License for the specific language governing permissions and
17    limitations under the License.
18 ==================================================================================
19 */
20
21 /* X
22 *****************************************************************************
23 *
24 *  Mnemonic: SIrcv
25 *  Abstract: This routine allows the user program to receive data on a
26 *            session without using the callback structure of the library.
27 *            It is the caller's responsibility to provide a buffer large
28 *            enough to handle the received data.
29 *  Parms:    gptr - The SIHANDLE that the user received on init call
30 *            sid  - The session id that the user wants to check
31 *            buf  - Pointer to buffer to receive data in
32 *            abuf - Pointer to buffer to return address of UDP sender in (!null)
33 *            buflen-Length of the receive buffer
34 *            delay- Value to pass to poll (time out) -1 == block until data
35 *  Returns:  SI_ERROR - (SIerrno will contain reason) if failure, else the
36 *            number of bytes read. If the number read is 0 SIerrno will indicate
37 *            why: time out exceeded, signal received.
38 *  Date:     26 March 1995
39 *  Author:   E. Scott Daniels
40 *  Mods:     26 Mar 20001 - Changed to support UDP reads
41 *
42 ******************************************************************************
43 */
44 #include "sisetup.h"    //  get start up stuff 
45 #include "sitransport.h"
46
47 extern int SIrcv( struct ginfo_blk *gptr, int sid, char *buf, int buflen, char *abuf, int delay ) {
48  //extern int sigflags;           //  signal flags 
49  int status = SI_ERROR;         //  assume the worst to return to caller 
50  struct tp_blk *tpptr;          //  pointer to transport provider info 
51  int flags = 0;                 //  receive flags 
52  int remainder;                 //  # of bytes remaining after rcv if more 
53  fd_set readfds;                //  special set of read fds for this call 
54  fd_set execpfds;               //  special set of read fds for this call 
55  struct timeval *tptr = NULL;   //  time info for select call 
56  struct timeval time;
57  struct sockaddr *uaddr;       //  pointer to udp address 
58         char    *acbuf;         //  pointer to converted address 
59  int addrlen;
60
61  if( gptr->magicnum != MAGICNUM )     //  if not a valid ginfo block 
62   return SI_ERROR;
63
64  for( tpptr = gptr->tplist; tpptr != NULL && tpptr->fd != sid;
65       tpptr = tpptr->next );      //  find transport block 
66  if( tpptr == NULL )
67   return SI_ERROR;                      //  signal bad block 
68
69  uaddr = (struct sockaddr *) malloc( sizeof( struct sockaddr ) );
70  addrlen = sizeof( *uaddr );
71
72  if( ! (gptr->flags & GIF_SHUTDOWN) )
73   {                        //  if not in shutdown and no signal flags  
74    FD_ZERO( &readfds );               //  clear select info 
75    FD_SET( tpptr->fd, &readfds );     //  set to check read status 
76
77    FD_ZERO( &execpfds );               //  clear select info 
78    FD_SET( tpptr->fd, &execpfds );     //  set to check read status 
79
80    if( delay >= 0 )                //  user asked for a fininte time limit 
81     {
82      tptr = &time;                 //  point at the local struct 
83      tptr->tv_sec = 0;             //  setup time for select call 
84      tptr->tv_usec = delay;
85     }
86
87    if( (select( tpptr->fd + 1, &readfds, NULL, &execpfds, tptr ) < 0 ) )
88     gptr->flags |= GIF_SHUTDOWN;     //  we must shut on error or signal 
89    else
90     {                                //  poll was successful - see if data ? 
91      if( FD_ISSET( tpptr->fd, &execpfds ) )   //  session error? 
92       {
93        SIterm( gptr, tpptr );                 //  clean up our end of things 
94       }
95      else
96       {
97        if( (FD_ISSET( tpptr->fd, &readfds )) )
98         {                                       //  process data if no signal 
99                 if( tpptr->type == SOCK_DGRAM )        //  raw data received 
100                 {
101                         status = RECVFROM( sid, buf, buflen, 0, uaddr, &addrlen );
102                         if( abuf )
103                         {
104                                 SIaddress( uaddr, (void **) &acbuf, AC_TODOT ); //  address returns pointer to buf now rather than filling 
105                                 strcpy( abuf, acbuf );                  //  must be back compat with old versions 
106                                 free( acbuf );
107                         }
108                         if( status < 0 )                        //  session terminated? 
109                                 SIterm( gptr, tpptr );                   //  so close our end 
110                 }
111                 else                                      //  cooked data received 
112                 {
113                         status = RECV( sid, buf, buflen, 0 );   //  read data into user buf 
114                         if( status < 0 )                        //  session terminated? 
115                                 SIterm( gptr, tpptr );                 //  so close our end 
116                 }
117         }                                         //  end event was received 
118        else                                       //  no event was received  
119         status = 0;                               //  status is just ok 
120       }                       //  end else - not in shutdown mode after poll 
121     }                     //  end else pole was successful 
122   }                                 //  end if not already signal shutdown 
123
124  if( gptr->flags & GIF_SHUTDOWN  &&  gptr->tplist != NULL )
125   {             //  shutdown received but sessions not cleaned up 
126    SIshutdown( gptr );
127    status = SI_ERROR;                //  indicate failure on return 
128   }                                  //  end if shut but not clean 
129
130  free( uaddr );
131  return status;          //  send back the status 
132 }                           //  SIrcv