752a9554caaac6bdd9cb028f78674a07587b46b9
[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
60         if( fd < 0 ) {
61                 errno = EBADFD;
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                 // list should be locked before traversing
69                 for( tpptr = gptr->tplist; tpptr != NULL && tpptr->fd != fd; tpptr = tpptr->next ) ; //  find the block if out of map's range
70         }
71         if( tpptr != NULL ) {
72                 if( (fd = tpptr->fd) < 0 || (fd = tpptr->fd) >= FD_SETSIZE ) {                  // fd user given might not be real, and this might be closed already
73                         errno = EBADFD;
74                         return SI_ERROR;
75                 }
76
77                 tpptr->sent++;                          // investigate: this may over count
78
79                 FD_ZERO( &writefds );       //  clear for select call
80                 FD_SET( fd, &writefds );    //  set to see if this one was writable
81                 FD_ZERO( &execpfds );       //  clear and set execptions fdset
82                 FD_SET( fd, &execpfds );
83
84                 time.tv_sec = 0;                        //  set both to 0 if we just want a poll, else we block at max this amount
85                 time.tv_usec = 1;                       // small pause on check to help drain things
86
87                 if( select( fd + 1, NULL, &writefds, &execpfds, &time ) > 0 ) {         //  would block if <= 0
88                         if( FD_ISSET( fd, &execpfds ) ) {               //  error?
89                                 errno = EBADFD;
90                                 SIterm( gptr, tpptr );                          // mark block for deletion when safe
91                                 return SI_ERROR;                                        // and bail from this sinking ship
92                         } else {
93                                 errno = 0;
94                                 while( ulen > 0 ) {                             // once we start, we must ensure that it all goes out
95                                         status =  SEND( tpptr->fd, ubuf+sidx, (unsigned int) ulen, 0 );
96                                         if( status >= 0 ) {
97                                                 sidx += status;
98                                                 ulen -= status;
99                                                 status = SI_OK;
100                                         } else {
101                                                 if( errno != EINTR || errno != EAGAIN ) {
102                                                         status = SI_ERROR;
103                                                         break;
104                                                 }
105                                         }
106                                 }
107                         }
108                 } else {
109                         errno = EBUSY;
110                         status = SI_ERR_BLOCKED;
111                 }
112         } else {
113                 errno = EBADFD;                 // fd in a bad state (probably lost)
114         }
115
116         return status;
117 }
118