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