20cf7b3a326d97d8de3554ef552c53e0eeba97d3
[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         }
104
105         return status;
106 }
107
108 /*
109         This routine will send a datagram to the TCP session partner
110         that is connected via the FD number that is passed in.
111         If the send would cause the process to block, the send is
112         queued on the tp_blk for the session and is sent later as
113         a function of the SIwait process.  If the buffer must be
114         queued, a copy of the buffer is created such that the
115         user program may free, or reuse, the buffer upon return.
116
117         Parms:i         gptr - The pointer to the global info structure (context)
118                     fd   - File descriptor (session number)
119                     ubuf - User buffer to send.
120                     ulen - Lenght of the user buffer.
121
122         Returns:  SI_OK if sent, SI_QUEUED if queued for later, SI_ERROR if error.
123 */
124 #ifdef KEEP
125 extern int new_SIsendt( struct ginfo_blk *gptr, int fd, char *ubuf, int ulen ) {
126         int status = SI_OK;         //  status of processing 
127         fd_set writefds;            //  local write fdset to check blockage 
128         fd_set execpfds;            //  exception fdset to check errors 
129         struct tp_blk *tpptr;       //  pointer at the tp_blk for the session 
130         struct ioq_blk *qptr;       //  pointer at i/o queue block 
131         struct timeval time;        //  delay time parameter for select call 
132
133         gptr->sierr = SI_ERR_HANDLE;
134
135         //if( gptr->magicnum == MAGICNUM ) {     //  ensure cookie is good  -- we need to be too performant for this
136         //{                                   //  mmmm oatmeal, my favorite 
137                 gptr->sierr = SI_ERR_SESSID;
138
139                 if( fd < MAX_FDS ) {                                    // straight from map if possible
140                         tpptr = gptr->tp_map[fd];
141                 } else {
142                         for( tpptr = gptr->tplist; tpptr != NULL && tpptr->fd != fd; tpptr = tpptr->next ); //  find the block if out of map's range
143                 }
144
145                 if( tpptr != NULL ) {
146                         tpptr->sent++;
147
148                         FD_ZERO( &writefds );       //  clear for select call 
149                         FD_SET( fd, &writefds );    //  set to see if this one was writable 
150                         FD_ZERO( &execpfds );       //  clear and set execptions fdset 
151                         FD_SET( fd, &execpfds );
152
153                         time.tv_sec = 0;                        //  set both to 0 if we just want a poll, else we block at max this amount
154                         time.tv_usec = 1;                       // small pause on check to help drain things
155
156                         if( select( fd + 1, NULL, &writefds, &execpfds, &time ) > 0 ) {         //  see if it would block
157                                 gptr->sierr = SI_ERR_TP;
158                                 if( FD_ISSET( fd, &execpfds ) ) {   //  error? 
159                                         SIterm( gptr, tpptr );                          //  clean up our portion of the session 
160                                         return SI_ERROR;                                        // and bail from this sinking ship
161                                 } else {
162                                         if( tpptr->squeue ) {
163                                                 SIsend( gptr, tpptr );                  //  something queued; send off queue and queue this
164                                         } else {
165                                                 return SEND( tpptr->fd, ubuf, (unsigned int) ulen, 0 );   //  done after send 
166                                         }
167                                 }
168                         }
169
170                         gptr->sierr = SI_ERR_NOMEM;
171
172                         tpptr->qcount++;
173                         if( (qptr = SInew( IOQ_BLK )) != NULL ) {               //  alloc a queue block 
174                                 if( tpptr->sqtail == NULL ) {                           //  if nothing on the queue 
175                                         tpptr->squeue = qptr;         //  simple add to the tp blk q 
176                                         tpptr->sqtail = qptr;
177                                 } else  {                                       //  else - add at end of the q 
178                                         tpptr->sqtail->next = qptr;             
179                                         tpptr->sqtail = qptr;   
180                                         qptr->next = NULL;              //  new block is the last one now 
181                                 }                                      //  end add block at end of queue 
182
183                                 qptr->dlen = ulen;           //  copy info to queue block 
184                                 qptr->data = (char *) malloc( ulen );  //  get buffer 
185                                 memcpy( qptr->data, (const char*) ubuf, ulen );
186         
187                                 gptr->sierr = SI_QUEUED;                //  indicate queued to caller 
188                                 status = SI_QUEUED;                                             // for return
189                         }
190                 }                                                       //  end if tpptr was not found 
191         //}                                                             //  ginfo pointer was corrupted 
192
193         return status;
194 }
195 #endif