1 // vim: noet sw=4 ts=4:
3 ==================================================================================
4 Copyright (c) 2020-2021 Nokia
5 Copyright (c) 2020-2021 AT&T Intellectual Property.
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
11 http://www.apache.org/licenses/LICENSE-2.0
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 ==================================================================================
22 *****************************************************************************
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 * must be a minimum of 64 bytes long.
34 * buflen-Length of the receive buffer
35 * delay- Value to pass to poll (time out) -1 == block until data
36 * Returns: SI_ERROR - (SIerrno will contain reason) if failure, else the
37 * number of bytes read. If the number read is 0 SIerrno will indicate
38 * why: time out exceeded, signal received.
40 * Author: E. Scott Daniels
41 * Mods: 26 Mar 20001 - Changed to support UDP reads
43 ******************************************************************************
45 #include "sisetup.h" // get start up stuff
46 #include "sitransport.h"
48 extern int SIrcv( struct ginfo_blk *gptr, int sid, char *buf, int buflen, char *abuf, int delay ) {
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
57 struct sockaddr *uaddr; // pointer to udp address
58 char *acbuf; // pointer to converted address
61 if( gptr->magicnum != MAGICNUM ) { // if not a valid ginfo block
65 for( tpptr = gptr->tplist; tpptr != NULL && tpptr->fd != sid; tpptr = tpptr->next ) { // find transport block
70 return SI_ERROR; // signal bad block
73 uaddr = (struct sockaddr *) malloc( sizeof( struct sockaddr ) );
74 addrlen = sizeof( *uaddr );
76 if( ! (gptr->flags & GIF_SHUTDOWN) ) { // if not in shutdown and no signal flags
77 FD_ZERO( &readfds ); // clear select info
78 FD_SET( tpptr->fd, &readfds ); // set to check read status
80 FD_ZERO( &execpfds ); // clear select info
81 FD_SET( tpptr->fd, &execpfds ); // set to check read status
83 if( delay >= 0 ) { // user asked for a fininte time limit
84 tptr = &time; // point at the local struct
85 tptr->tv_sec = 0; // setup time for select call
86 tptr->tv_usec = delay;
89 if( (select( tpptr->fd + 1, &readfds, NULL, &execpfds, tptr ) < 0 ) ) {
90 gptr->flags |= GIF_SHUTDOWN; // we must shut on error or signal
91 } else { // poll was successful - see if data ?
92 if( FD_ISSET( tpptr->fd, &execpfds ) ) { // session error?
93 SIterm( gptr, tpptr ); // clean up our end of things
95 if( (FD_ISSET( tpptr->fd, &readfds )) ) { // process data if no signal
96 if( tpptr->type == SOCK_DGRAM ) { // raw data received
97 status = RECVFROM( sid, buf, buflen, 0, uaddr, &addrlen );
99 SIaddress( uaddr, (void **) &acbuf, AC_TODOT ); // address returns pointer to buf now rather than filling
100 strncpy( abuf, acbuf, 64 ); // must be back compat with old versions
103 if( status < 0 ) { // session terminated?
104 SIterm( gptr, tpptr ); // so close our end
106 } else { // cooked data received
107 status = RECV( sid, buf, buflen, 0 ); // read data into user buf
108 if( status < 0 ) { // session terminated?
109 SIterm( gptr, tpptr ); // so close our end
112 } else { // end event was received
113 status = 0; // status is just ok
115 } // end else - not in shutdown mode after poll
116 } // end else pole was successful
117 } // end if not already signal shutdown
119 if( gptr->flags & GIF_SHUTDOWN && gptr->tplist != NULL ) { // shutdown received but sessions not cleaned up
125 return status; // send back the status