1 // vim: noet sw=4 ts=4:
3 ==================================================================================
4 Copyright (c) 2020 Nokia
5 Copyright (c) 2020 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 module contains various send functions:
26 * SIsendt -- send tcp with queuing if would block
27 * SIsendt_nq - send tcp without queuing if blocking
30 * Author: E. Scott Daniels
31 * Mod: 22 Feb 2002 - To better process queued data
33 *****************************************************************************
36 #include "sisetup.h" // get setup stuff
37 #include "sitransport.h"
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
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
58 gptr->sierr = SI_ERR_SESSID;
60 if( fd < MAX_FDS ) { // straight from map if possible
61 tpptr = gptr->tp_map[fd];
63 for( tpptr = gptr->tplist; tpptr != NULL && tpptr->fd != fd; tpptr = tpptr->next ); // find the block if out of map's range
67 tpptr->sent++; // investigate: this may over count
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 );
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
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?
81 SIterm( gptr, tpptr ); // clean up our portion of the session
82 return SI_ERROR; // and bail from this sinking ship
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 );
92 if( errno != EINTR || errno != EAGAIN ) {
101 status = SI_ERR_BLOCKED;
104 errno = EBADFD; // fd in a bad state (probably losed)
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.
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.
124 Returns: SI_OK if sent, SI_QUEUED if queued for later, SI_ERROR if error.
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
135 gptr->sierr = SI_ERR_HANDLE;
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;
141 if( fd < MAX_FDS ) { // straight from map if possible
142 tpptr = gptr->tp_map[fd];
144 for( tpptr = gptr->tplist; tpptr != NULL && tpptr->fd != fd; tpptr = tpptr->next ); // find the block if out of map's range
147 if( tpptr != NULL ) {
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 );
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
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
164 if( tpptr->squeue ) {
165 SIsend( gptr, tpptr ); // something queued; send off queue and queue this
167 return SEND( tpptr->fd, ubuf, (unsigned int) ulen, 0 ); // done after send
172 gptr->sierr = SI_ERR_NOMEM;
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
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 );
189 gptr->sierr = SI_QUEUED; // indicate queued to caller
190 status = SI_QUEUED; // for return
192 } // end if tpptr was not found
193 //} // ginfo pointer was corrupted