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