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;
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.
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.
122 Returns: SI_OK if sent, SI_QUEUED if queued for later, SI_ERROR if error.
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
133 gptr->sierr = SI_ERR_HANDLE;
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;
139 if( fd < MAX_FDS ) { // straight from map if possible
140 tpptr = gptr->tp_map[fd];
142 for( tpptr = gptr->tplist; tpptr != NULL && tpptr->fd != fd; tpptr = tpptr->next ); // find the block if out of map's range
145 if( tpptr != NULL ) {
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 );
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
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
162 if( tpptr->squeue ) {
163 SIsend( gptr, tpptr ); // something queued; send off queue and queue this
165 return SEND( tpptr->fd, ubuf, (unsigned int) ulen, 0 ); // done after send
170 gptr->sierr = SI_ERR_NOMEM;
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
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 );
187 gptr->sierr = SI_QUEUED; // indicate queued to caller
188 status = SI_QUEUED; // for return
190 } // end if tpptr was not found
191 //} // ginfo pointer was corrupted