Fix session discconnect bug in interface to SI95
[ric-plt/lib/rmr.git] / src / rmr / si / src / si95 / sisendt.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 /*
22 ****************************************************************************
23 *
24 *  Mnemonic: SIsendt
25 *  Abstract: This module contains various send functions:
26 *                               SIsendt -- send tcp with queuing if would block
27 *                               SIsendt_nq - send tcp without queuing if blocking
28
29 *  Date:     27 March 1995
30 *  Author:   E. Scott Daniels
31 *  Mod:         22 Feb 2002 - To better process queued data 
32 *
33 *****************************************************************************
34 */
35
36 #include "sisetup.h"     //  get setup stuff 
37 #include "sitransport.h"
38
39 /*
40         Send a message on what is assumed to be a tcp connection. If the session
41         would block, then SI_ERR_BLOCKED is returned. Else, SI_OK or SI_ERROR
42         is returned to indicate state. Errno should be set to reflect error state:
43                 EBADFD - error from system; fd was closed
44                 EBUSY   - system would block the send call
45                 EINVAL  - fd was not valid or did not reference an open session
46 */
47 //extern int SIsendt_nq( struct ginfo_blk *gptr, int fd, char *ubuf, int ulen ) {
48 extern int SIsendt( struct ginfo_blk *gptr, int fd, char *ubuf, int ulen ) {
49         int status = SI_ERROR;      //  assume we fail
50         fd_set writefds;            //  local write fdset to check blockage 
51         fd_set execpfds;            //  exception fdset to check errors 
52         struct tp_blk *tpptr;       //  pointer at the tp_blk for the session 
53         struct ioq_blk *qptr;       //  pointer at i/o queue block 
54         struct timeval time;        //  delay time parameter for select call 
55         int     sidx = 0;                               // send index
56
57         errno = EINVAL;
58         gptr->sierr = SI_ERR_SESSID;
59
60         if( fd < MAX_FDS ) {                                    // straight from map if possible
61                 tpptr = gptr->tp_map[fd];
62         } else {
63                 for( tpptr = gptr->tplist; tpptr != NULL && tpptr->fd != fd; tpptr = tpptr->next ); //  find the block if out of map's range
64         }
65
66         if( tpptr != NULL ) {
67                 tpptr->sent++;                          // investigate: this may over count
68
69                 FD_ZERO( &writefds );       //  clear for select call 
70                 FD_SET( fd, &writefds );    //  set to see if this one was writable 
71                 FD_ZERO( &execpfds );       //  clear and set execptions fdset 
72                 FD_SET( fd, &execpfds );
73
74                 time.tv_sec = 0;                        //  set both to 0 if we just want a poll, else we block at max this amount
75                 time.tv_usec = 1;                       // small pause on check to help drain things
76
77                 if( select( fd + 1, NULL, &writefds, &execpfds, &time ) > 0 ) {         //  would block if <= 0
78                         gptr->sierr = SI_ERR_TP;
79                         if( FD_ISSET( fd, &execpfds ) ) {       //  error? 
80                                 errno = EBADFD;
81                                 SIterm( gptr, tpptr );                          //  clean up our portion of the session 
82                                 return SI_ERROR;                                        // and bail from this sinking ship
83                         } else {
84                                 errno = 0;
85                                 while( ulen > 0 ) {                             // once we start, we must ensure that it all goes out
86                                         status =  SEND( tpptr->fd, ubuf+sidx, (unsigned int) ulen, 0 );
87                                         if( status >= 0 ) {
88                                                 sidx += status;
89                                                 ulen -= status;
90                                                 status = SI_OK;
91                                         } else {
92                                                 if( errno != EINTR || errno != EAGAIN ) {
93                                                         status = SI_ERROR;
94                                                         break;
95                                                 }
96                                         }
97                                 }
98                         }
99                 } else {
100                         errno = EBUSY;
101                         status = SI_ERR_BLOCKED;
102                 }
103         } else {
104                 errno = EBADFD;                 // fd in a bad state (probably losed)
105         }
106
107         return status;
108 }
109
110 /*
111         This routine will send a datagram to the TCP session partner
112         that is connected via the FD number that is passed in.
113         If the send would cause the process to block, the send is
114         queued on the tp_blk for the session and is sent later as
115         a function of the SIwait process.  If the buffer must be
116         queued, a copy of the buffer is created such that the
117         user program may free, or reuse, the buffer upon return.
118
119         Parms:i         gptr - The pointer to the global info structure (context)
120                     fd   - File descriptor (session number)
121                     ubuf - User buffer to send.
122                     ulen - Lenght of the user buffer.
123
124         Returns:  SI_OK if sent, SI_QUEUED if queued for later, SI_ERROR if error.
125 */
126 #ifdef KEEP
127 extern int new_SIsendt( struct ginfo_blk *gptr, int fd, char *ubuf, int ulen ) {
128         int status = SI_OK;         //  status of processing 
129         fd_set writefds;            //  local write fdset to check blockage 
130         fd_set execpfds;            //  exception fdset to check errors 
131         struct tp_blk *tpptr;       //  pointer at the tp_blk for the session 
132         struct ioq_blk *qptr;       //  pointer at i/o queue block 
133         struct timeval time;        //  delay time parameter for select call 
134
135         gptr->sierr = SI_ERR_HANDLE;
136
137         //if( gptr->magicnum == MAGICNUM ) {     //  ensure cookie is good  -- we need to be too performant for this
138         //{                                   //  mmmm oatmeal, my favorite 
139                 gptr->sierr = SI_ERR_SESSID;
140
141                 if( fd < MAX_FDS ) {                                    // straight from map if possible
142                         tpptr = gptr->tp_map[fd];
143                 } else {
144                         for( tpptr = gptr->tplist; tpptr != NULL && tpptr->fd != fd; tpptr = tpptr->next ); //  find the block if out of map's range
145                 }
146
147                 if( tpptr != NULL ) {
148                         tpptr->sent++;
149
150                         FD_ZERO( &writefds );       //  clear for select call 
151                         FD_SET( fd, &writefds );    //  set to see if this one was writable 
152                         FD_ZERO( &execpfds );       //  clear and set execptions fdset 
153                         FD_SET( fd, &execpfds );
154
155                         time.tv_sec = 0;                        //  set both to 0 if we just want a poll, else we block at max this amount
156                         time.tv_usec = 1;                       // small pause on check to help drain things
157
158                         if( select( fd + 1, NULL, &writefds, &execpfds, &time ) > 0 ) {         //  see if it would block
159                                 gptr->sierr = SI_ERR_TP;
160                                 if( FD_ISSET( fd, &execpfds ) ) {   //  error? 
161                                         SIterm( gptr, tpptr );                          //  clean up our portion of the session 
162                                         return SI_ERROR;                                        // and bail from this sinking ship
163                                 } else {
164                                         if( tpptr->squeue ) {
165                                                 SIsend( gptr, tpptr );                  //  something queued; send off queue and queue this
166                                         } else {
167                                                 return SEND( tpptr->fd, ubuf, (unsigned int) ulen, 0 );   //  done after send 
168                                         }
169                                 }
170                         }
171
172                         gptr->sierr = SI_ERR_NOMEM;
173
174                         tpptr->qcount++;
175                         if( (qptr = SInew( IOQ_BLK )) != NULL ) {               //  alloc a queue block 
176                                 if( tpptr->sqtail == NULL ) {                           //  if nothing on the queue 
177                                         tpptr->squeue = qptr;         //  simple add to the tp blk q 
178                                         tpptr->sqtail = qptr;
179                                 } else  {                                       //  else - add at end of the q 
180                                         tpptr->sqtail->next = qptr;             
181                                         tpptr->sqtail = qptr;   
182                                         qptr->next = NULL;              //  new block is the last one now 
183                                 }                                      //  end add block at end of queue 
184
185                                 qptr->dlen = ulen;           //  copy info to queue block 
186                                 qptr->data = (char *) malloc( ulen );  //  get buffer 
187                                 memcpy( qptr->data, (const char*) ubuf, ulen );
188         
189                                 gptr->sierr = SI_QUEUED;                //  indicate queued to caller 
190                                 status = SI_QUEUED;                                             // for return
191                         }
192                 }                                                       //  end if tpptr was not found 
193         //}                                                             //  ginfo pointer was corrupted 
194
195         return status;
196 }
197 #endif