pupnp (libupnp) snapshot from SourceForge: git clone git://pupnp.git.sourceforge...
[igd2-for-linux:pandonghui1211s-igd2-for-linux.git] / pupnp_branch-1.6.x / upnp / src / genlib / net / sock.c
1 ///////////////////////////////////////////////////////////////////////////
2 //
3 // Copyright (c) 2000-2003 Intel Corporation 
4 // All rights reserved. 
5 //
6 // Redistribution and use in source and binary forms, with or without 
7 // modification, are permitted provided that the following conditions are met: 
8 //
9 // * Redistributions of source code must retain the above copyright notice, 
10 // this list of conditions and the following disclaimer. 
11 // * Redistributions in binary form must reproduce the above copyright notice, 
12 // this list of conditions and the following disclaimer in the documentation 
13 // and/or other materials provided with the distribution. 
14 // * Neither name of Intel Corporation nor the names of its contributors 
15 // may be used to endorse or promote products derived from this software 
16 // without specific prior written permission.
17 // 
18 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 
19 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 
20 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 
21 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL INTEL OR 
22 // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 
23 // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 
24 // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 
25 // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 
26 // OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
27 // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 
28 // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 //
30 ///////////////////////////////////////////////////////////////////////////
31
32 /************************************************************************
33 * Purpose: This file implements the sockets functionality 
34 ************************************************************************/
35
36 #include "config.h"
37 #include <assert.h>
38 #include <errno.h>
39 #include <time.h>
40 #include <string.h>
41
42 #include "sock.h"
43 #include "upnp.h"
44 #ifndef WIN32
45  #include <arpa/inet.h>
46  #include <netinet/in.h>
47  #include <sys/types.h>
48  #include <sys/socket.h>
49  #include <sys/time.h>
50  #include <unistd.h>
51 #else
52  #include <winsock2.h>
53 #endif
54 #include "unixutil.h"
55
56 #ifndef MSG_NOSIGNAL
57  #define MSG_NOSIGNAL 0
58 #endif
59
60 /************************************************************************
61 *       Function :      sock_init
62 *
63 *       Parameters :
64 *               OUT SOCKINFO* info ;    Socket Information Object
65 *               IN int sockfd ;                 Socket Descriptor
66 *
67 *       Description :   Assign the passed in socket descriptor to socket 
68 *               descriptor in the SOCKINFO structure.
69 *
70 *       Return : int;
71 *               UPNP_E_SUCCESS  
72 *               UPNP_E_OUTOF_MEMORY
73 *               UPNP_E_SOCKET_ERROR
74 *
75 *       Note :
76 ************************************************************************/
77 int
78 sock_init( OUT SOCKINFO * info,
79            IN int sockfd )
80 {
81     assert( info );
82
83     memset( info, 0, sizeof( SOCKINFO ) );
84
85     info->socket = sockfd;
86
87     return UPNP_E_SUCCESS;
88 }
89
90 /************************************************************************
91 *       Function :      sock_init_with_ip
92 *
93 *       Parameters :
94 *               OUT SOCKINFO* info ;                            Socket Information Object
95 *               IN int sockfd ;                                         Socket Descriptor
96 *               IN struct in_addr foreign_ip_addr ;     Remote IP Address
97 *               IN unsigned short foreign_ip_port ;     Remote Port number
98 *
99 *       Description :   Calls the sock_init function and assigns the passed in
100 *               IP address and port to the IP address and port in the SOCKINFO
101 *               structure.
102 *
103 *       Return : int;
104 *               UPNP_E_SUCCESS  
105 *               UPNP_E_OUTOF_MEMORY
106 *               UPNP_E_SOCKET_ERROR
107 *
108 *       Note :
109 ************************************************************************/
110 int
111 sock_init_with_ip( OUT SOCKINFO * info,
112                    IN int sockfd,
113                    IN struct in_addr foreign_ip_addr,
114                    IN unsigned short foreign_ip_port )
115 {
116     int ret;
117
118     ret = sock_init( info, sockfd );
119     if( ret != UPNP_E_SUCCESS ) {
120         return ret;
121     }
122
123     info->foreign_ip_addr = foreign_ip_addr;
124     info->foreign_ip_port = foreign_ip_port;
125
126     return UPNP_E_SUCCESS;
127 }
128
129 /************************************************************************
130 *       Function :      sock_destroy
131 *
132 *       Parameters :
133 *               INOUT SOCKINFO* info ;  Socket Information Object
134 *               int ShutdownMethod ;    How to shutdown the socket. Used by  
135 *                                                               sockets's shutdown() 
136 *
137 *       Description :   Shutsdown the socket using the ShutdownMethod to 
138 *               indicate whether sends and receives on the socket will be 
139 *               dis-allowed. After shutting down the socket, closesocket is called
140 *               to release system resources used by the socket calls.
141 *
142 *       Return : int;
143 *               UPNP_E_SOCKET_ERROR on failure
144 *               UPNP_E_SUCCESS on success
145 *
146 *       Note :
147 ************************************************************************/
148 int
149 sock_destroy( INOUT SOCKINFO * info,
150               int ShutdownMethod )
151 {
152     shutdown( info->socket, ShutdownMethod );
153     if( UpnpCloseSocket( info->socket ) == -1 ) {
154         return UPNP_E_SOCKET_ERROR;
155     }
156
157     return UPNP_E_SUCCESS;
158 }
159
160 /************************************************************************
161 *       Function :      sock_read_write
162 *
163 *       Parameters :
164 *               IN SOCKINFO *info ;     Socket Information Object
165 *               OUT char* buffer ;      Buffer to get data to or send data from 
166 *               IN size_t bufsize ;     Size of the buffer
167 *           IN int *timeoutSecs ;       timeout value
168 *               IN xboolean bRead ;     Boolean value specifying read or write option
169 *
170 *       Description :   Receives or sends data. Also returns the time taken
171 *               to receive or send data.
172 *
173 *       Return :int ;
174 *               numBytes - On Success, no of bytes received or sent             
175 *               UPNP_E_TIMEDOUT - Timeout
176 *               UPNP_E_SOCKET_ERROR - Error on socket calls
177 *
178 *       Note :
179 ************************************************************************/
180 static int
181 sock_read_write( IN SOCKINFO * info,
182                  OUT char *buffer,
183                  IN size_t bufsize,
184                  IN int *timeoutSecs,
185                  IN xboolean bRead )
186 {
187     int retCode;
188     fd_set readSet;
189     fd_set writeSet;
190     struct timeval timeout;
191     int numBytes;
192     time_t start_time = time( NULL );
193     int sockfd = info->socket;
194     long bytes_sent = 0,
195       byte_left = 0,
196       num_written;
197
198     if( *timeoutSecs < 0 ) {
199         return UPNP_E_TIMEDOUT;
200     }
201
202     FD_ZERO( &readSet );
203     FD_ZERO( &writeSet );
204     if( bRead ) {
205         FD_SET( ( unsigned )sockfd, &readSet );
206     } else {
207         FD_SET( ( unsigned )sockfd, &writeSet );
208     }
209
210     timeout.tv_sec = *timeoutSecs;
211     timeout.tv_usec = 0;
212
213     while( TRUE ) {
214         if( *timeoutSecs == 0 ) {
215             retCode =
216                 select( sockfd + 1, &readSet, &writeSet, NULL, NULL );
217         } else {
218             retCode =
219                 select( sockfd + 1, &readSet, &writeSet, NULL, &timeout );
220         }
221
222         if( retCode == 0 ) {
223             return UPNP_E_TIMEDOUT;
224         }
225         if( retCode == -1 ) {
226             if( errno == EINTR )
227                 continue;
228             return UPNP_E_SOCKET_ERROR; // error
229         } else {
230             break;              // read or write
231         }
232     }
233
234 #ifdef SO_NOSIGPIPE
235     {
236         int old;
237         int set = 1;
238         socklen_t olen = sizeof(old);
239         getsockopt(sockfd, SOL_SOCKET, SO_NOSIGPIPE, &old, &olen);
240         setsockopt(sockfd, SOL_SOCKET, SO_NOSIGPIPE, &set, sizeof(set));
241 #endif
242
243     if( bRead ) {
244         // read data
245         numBytes = recv( sockfd, buffer, bufsize,MSG_NOSIGNAL);
246     } else {
247         byte_left = bufsize;
248         bytes_sent = 0;
249         while( byte_left > 0 ) {
250             // write data
251             num_written =
252                 send( sockfd, buffer + bytes_sent, byte_left,
253                       MSG_DONTROUTE|MSG_NOSIGNAL);
254             if( num_written == -1 ) {
255 #ifdef SO_NOSIGPIPE
256                 setsockopt(sockfd, SOL_SOCKET, SO_NOSIGPIPE, &old, olen);
257 #endif
258                 return num_written;
259             }
260
261             byte_left = byte_left - num_written;
262             bytes_sent += num_written;
263         }
264
265         numBytes = bytes_sent;
266     }
267
268 #ifdef SO_NOSIGPIPE
269         setsockopt(sockfd, SOL_SOCKET, SO_NOSIGPIPE, &old, olen);
270     }
271 #endif
272
273     if( numBytes < 0 ) {
274         return UPNP_E_SOCKET_ERROR;
275     }
276     // subtract time used for reading/writing
277     if( *timeoutSecs != 0 ) {
278         *timeoutSecs -= time( NULL ) - start_time;
279     }
280
281     return numBytes;
282 }
283
284 /************************************************************************
285 *       Function :      sock_read
286 *
287 *       Parameters :
288 *               IN SOCKINFO *info ;     Socket Information Object
289 *               OUT char* buffer ;      Buffer to get data to  
290 *               IN size_t bufsize ;     Size of the buffer
291 *           IN int *timeoutSecs ;       timeout value
292 *
293 *       Description :   Calls sock_read_write() for reading data on the 
294 *               socket
295 *
296 *       Return : int;
297 *               Values returned by sock_read_write() 
298 *
299 *       Note :
300 ************************************************************************/
301 int
302 sock_read( IN SOCKINFO * info,
303            OUT char *buffer,
304            IN size_t bufsize,
305            INOUT int *timeoutSecs )
306 {
307     return sock_read_write( info, buffer, bufsize, timeoutSecs, TRUE );
308 }
309
310 /************************************************************************
311 *       Function :      sock_write
312 *
313 *       Parameters :
314 *               IN SOCKINFO *info ;     Socket Information Object
315 *               IN char* buffer ;       Buffer to send data from 
316 *               IN size_t bufsize ;     Size of the buffer
317 *           IN int *timeoutSecs ;       timeout value
318 *
319 *       Description :   Calls sock_read_write() for writing data on the 
320 *               socket
321 *
322 *       Return : int;
323 *               sock_read_write()
324 *
325 *       Note :
326 ************************************************************************/
327 int
328 sock_write( IN SOCKINFO * info,
329             IN char *buffer,
330             IN size_t bufsize,
331             INOUT int *timeoutSecs )
332 {
333     return sock_read_write( info, buffer, bufsize, timeoutSecs, FALSE );
334 }