parser/sdp: more suggestive debug message
[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  *  2006-02-03  tsend* will wait forever if timeout==-1 (andrei)
35  */
36
37 /*!
38  * \file
39  * \brief SIP-router core :: 
40  * \ingroup core
41  * Module: \ref core
42  */
43
44 #include <string.h>
45 #include <errno.h>
46 #include <sys/poll.h>
47
48 #include <sys/types.h>
49 #include <sys/socket.h>
50 #include <sys/uio.h>
51
52 #include "dprint.h"
53 #include "timer.h"
54 #include "timer_ticks.h"
55
56 /* the functions below are very similar => some generic macros */
57 #define TSEND_INIT \
58         int n; \
59         struct pollfd pf; \
60         ticks_t expire; \
61         s_ticks_t diff; \
62         expire=get_ticks_raw()+MS_TO_TICKS((ticks_t)timeout); \
63         pf.fd=fd; \
64         pf.events=POLLOUT
65
66 #define TSEND_POLL(f_name) \
67 poll_loop: \
68         while(1){ \
69                 if (timeout==-1) \
70                         n=poll(&pf, 1, -1); \
71                 else{ \
72                         diff=expire-get_ticks_raw(); \
73                         if (diff<=0){ \
74                                 LOG(L_ERR, "ERROR: " f_name ": send timeout (%d)\n", timeout);\
75                                 goto error; \
76                         } \
77                         n=poll(&pf, 1, TICKS_TO_MS((ticks_t)diff)); \
78                 } \
79                 if (n<0){ \
80                         if (errno==EINTR) continue; /* signal, ignore */ \
81                         LOG(L_ERR, "ERROR: " f_name ": poll failed: %s [%d]\n", \
82                                         strerror(errno), errno); \
83                         goto error; \
84                 }else if (n==0){ \
85                         /* timeout */ \
86                         LOG(L_ERR, "ERROR: " f_name ": send timeout (p %d)\n", timeout); \
87                         goto error; \
88                 } \
89                 if (pf.revents&POLLOUT){ \
90                         /* we can write again */ \
91                         goto again; \
92                 }else if (pf.revents&(POLLERR|POLLHUP|POLLNVAL)){ \
93                         LOG(L_ERR, "ERROR: " f_name ": bad poll flags %x\n", \
94                                         pf.revents); \
95                         goto error; \
96                 } \
97                 /* if POLLIN or POLLPRI or other non-harmful events happened,    \
98                  * continue ( although poll should never signal them since we're  \
99                  * not interested in them => we should never reach this point) */ \
100         } 
101
102
103 #define TSEND_ERR_CHECK(f_name)\
104         if (n<0){ \
105                 if (errno==EINTR) goto again; \
106                 else if (errno!=EAGAIN && errno!=EWOULDBLOCK){ \
107                         LOG(L_ERR, "ERROR: " f_name ": failed to send: (%d) %s\n", \
108                                         errno, strerror(errno)); \
109                         goto error; \
110                 }else goto poll_loop; \
111         }
112         
113
114
115 /* sends on fd (which must be O_NONBLOCK if you want a finite timeout); if it
116  * cannot send any data
117  * in timeout milliseconds it will return ERROR
118  * if timeout==-1, it waits forever
119  * returns: -1 on error, or number of bytes written
120  *  (if less than len => couldn't send all)
121  *  bugs: signals will reset the timer
122  */
123 int tsend_stream(int fd, const char* buf, unsigned int len, int timeout)
124 {
125         int written;
126         TSEND_INIT;
127         
128         written=0;
129 again:
130         n=send(fd, buf, len,
131 #ifdef HAVE_MSG_NOSIGNAL
132                         MSG_NOSIGNAL
133 #else
134                         0
135 #endif
136                 );
137         TSEND_ERR_CHECK("tsend_stream");
138         written+=n; 
139         if (n<(int)len){ 
140                 /* partial write */ 
141                 buf+=n; 
142                 len-=n; 
143         }else{ 
144                 /* successful full write */ 
145                 return written;
146         }
147         TSEND_POLL("tsend_stream");
148 error:
149         return -1;
150 }
151
152
153
154 /* sends on dgram fd (which must be O_NONBLOCK); if it cannot send any data
155  * in timeout milliseconds it will return ERROR
156  * returns: -1 on error, or number of bytes written
157  *  (if less than len => couldn't send all)
158  *  bugs: signals will reset the timer
159  */
160 int tsend_dgram(int fd, const char* buf, unsigned int len, 
161                                 const struct sockaddr* to, socklen_t tolen, int timeout)
162 {
163         TSEND_INIT;
164 again:
165         n=sendto(fd, buf, len, 0, to, tolen);
166         TSEND_ERR_CHECK("tsend_dgram");
167         /* we don't care about partial writes: they shouldn't happen on 
168          * a datagram socket */
169         return n;
170         TSEND_POLL("tsend_datagram");
171 error:
172         return -1;
173 }
174
175         
176 /* sends on connected datagram fd (which must be O_NONBLOCK); 
177  * if it cannot send any data in timeout milliseconds it will return ERROR
178  * returns: -1 on error, or number of bytes written
179  *  (if less than len => couldn't send all)
180  *  bugs: signals will reset the timer
181  */
182
183 int tsend_dgram_ev(int fd, const struct iovec* v, int count, int timeout)
184 {
185         TSEND_INIT;
186 again:
187         n=writev(fd, v, count);
188         TSEND_ERR_CHECK("tsend_datagram_ev");
189         return n;
190         TSEND_POLL("tsend_datagram_ev");
191 error:
192         return -1;
193 }
194