Coverage Report

Created: 2025-11-24 06:09

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/opensips/tsend.c
Line
Count
Source
1
/*
2
 * Copyright (C) 2001-2003 FhG Fokus
3
 *
4
 * This file is part of opensips, a free SIP server.
5
 *
6
 * opensips is free software; you can redistribute it and/or modify
7
 * it under the terms of the GNU General Public License as published by
8
 * the Free Software Foundation; either version 2 of the License, or
9
 * (at your option) any later version
10
 *
11
 * opensips is distributed in the hope that it will be useful,
12
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
 * GNU General Public License for more details.
15
 *
16
 * You should have received a copy of the GNU General Public License
17
 * along with this program; if not, write to the Free Software
18
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301  USA
19
 *
20
 *
21
 * send with timeout for stream and datagram sockets
22
 *
23
 * History:
24
 * --------
25
 *  2004-02-26  created by andrei
26
 *  2003-03-03  switched to heavy macro use, added tsend_dgram_ev (andrei)
27
 */
28
29
#include <string.h>
30
#include <errno.h>
31
#include <sys/poll.h>
32
33
#include <sys/types.h>
34
#include <sys/socket.h>
35
#include <sys/uio.h>
36
37
#include "dprint.h"
38
39
/* the functions below are very similar => some generic macros */
40
#define TSEND_INIT \
41
0
  int n; \
42
0
  struct pollfd pf; \
43
0
  pf.fd=fd; \
44
0
  pf.events=POLLOUT
45
46
0
#define TSEND_POLL(f_name) \
47
0
poll_loop: \
48
0
  while(1){ \
49
0
    n=poll(&pf, 1, timeout); \
50
0
    if (n<0){ \
51
0
      if (errno==EINTR) continue; /* signal, ignore */ \
52
0
      LM_ERR(f_name ": poll failed: %s [%d]\n", \
53
0
          strerror(errno), errno); \
54
0
      goto error; \
55
0
    }else if (n==0){ \
56
0
      /* timeout */ \
57
0
      LM_ERR(f_name ": send timeout (%d)\n", timeout); \
58
0
      goto error; \
59
0
    } \
60
0
    if (pf.revents&POLLOUT){ \
61
0
      /* we can write again */ \
62
0
      goto again; \
63
0
    }else if (pf.revents&(POLLERR|POLLHUP|POLLNVAL)){ \
64
0
      LM_ERR(f_name ": bad poll flags %x\n", \
65
0
          pf.revents); \
66
0
      goto error; \
67
0
    } \
68
0
    /* if POLLIN or POLLPRI or other non-harmful events happened,    \
69
0
     * continue ( although poll should never signal them since we're  \
70
0
     * not interested in them => we should never reach this point) */ \
71
0
  }
72
73
74
#define TSEND_ERR_CHECK(f_name)\
75
0
  if (n<0){ \
76
0
    if (errno==EINTR) goto again; \
77
0
    else if (errno!=EAGAIN && errno!=EWOULDBLOCK){ \
78
0
      LM_ERR(f_name ": failed to send: (%d) %s\n", \
79
0
          errno, strerror(errno)); \
80
0
      goto error; \
81
0
    }else goto poll_loop; \
82
0
  }
83
84
85
86
/*! \brief sends on fd (which must be O_NONBLOCK); if it cannot send any data
87
 * in timeout milliseconds it will return ERROR
88
 * \return -1 on error, or number of bytes written
89
 *  (if less than len => couldn't send all)
90
 *  bugs: signals will reset the timer
91
 */
92
int tsend_stream(int fd, char* buf, unsigned int len, int timeout)
93
0
{
94
0
  int written;
95
0
  TSEND_INIT;
96
97
0
  written=0;
98
0
again:
99
0
  n=send(fd, buf, len,
100
0
#ifdef HAVE_MSG_NOSIGNAL
101
0
      MSG_NOSIGNAL
102
#else
103
      0
104
#endif
105
0
    );
106
0
  TSEND_ERR_CHECK("tsend_stream");
107
0
  written+=n;
108
0
  if ((unsigned int)n<len){
109
    /* partial write */
110
0
    buf+=n;
111
0
    len-=n;
112
0
  }else{
113
    /* successful full write */
114
0
    return written;
115
0
  }
116
0
  TSEND_POLL("tsend_stream");
117
0
error:
118
0
  return -1;
119
0
}
120
121
122
123
/*! \brief sends on dgram fd (which must be O_NONBLOCK); if it cannot send any data
124
 * in timeout milliseconds it will return ERROR
125
 * \return -1 on error, or number of bytes written
126
 *  (if less than len => couldn't send all)
127
 *  bugs: signals will reset the timer
128
 */
129
int tsend_dgram(int fd, char* buf, unsigned int len,
130
        const struct sockaddr* to, socklen_t tolen, int timeout)
131
0
{
132
0
  TSEND_INIT;
133
0
again:
134
0
  n=sendto(fd, buf, len, 0, to, tolen);
135
0
  TSEND_ERR_CHECK("tsend_dgram");
136
  /* we don't care about partial writes: they shouldn't happen on
137
   * a datagram socket */
138
0
  return n;
139
0
  TSEND_POLL("tsend_datagram");
140
0
error:
141
0
  return -1;
142
0
}
143
144
145
/*! \brief sends on connected datagram fd (which must be O_NONBLOCK);
146
 * if it cannot send any data in timeout milliseconds it will return ERROR
147
 * \return -1 on error, or number of bytes written
148
 *  (if less than len => couldn't send all)
149
 *  bugs: signals will reset the timer
150
 */
151
int tsend_dgram_ev(int fd, const struct iovec* v, int count, int timeout)
152
0
{
153
0
  TSEND_INIT;
154
0
again:
155
0
  n=writev(fd, v, count);
156
0
  TSEND_ERR_CHECK("tsend_datagram_ev");
157
0
  return n;
158
0
  TSEND_POLL("tsend_datagram_ev");
159
0
error:
160
0
  return -1;
161
0
}
162
163
164
/*! \brief writes a vector on fd (which must be O_NONBLOCK); if it cannot
165
 * send any data in timeout milliseconds it will return ERROR
166
 * \return -1 on error, or number of bytes written
167
 *  (if less than len => couldn't send all)
168
 *  bugs: signals will reset the timer
169
 */
170
int tsend_stream_ev(int fd, struct iovec *iov, int iovcnt, int timeout)
171
0
{
172
0
  int written;
173
0
  int i, len = 0;
174
0
  TSEND_INIT;
175
176
0
  for (i = 0; i < iovcnt; i++)
177
0
    len += iov[i].iov_len;
178
179
0
  written=0;
180
0
  i = 0;
181
0
again:
182
0
  n=writev(fd, &iov[i], iovcnt);
183
0
  TSEND_ERR_CHECK("tsend_stream");
184
0
  written+=n;
185
0
  if ((unsigned int)n<len){
186
    /* partial write */
187
0
    len-=n;
188
0
    while (n > iov[i].iov_len) {
189
0
      i++;
190
0
      n -= iov[i].iov_len;
191
0
      iovcnt--;
192
0
    }
193
0
  }else{
194
    /* successful full write */
195
0
    return written;
196
0
  }
197
0
  TSEND_POLL("tsend_stream");
198
0
error:
199
0
  return -1;
200
0
}