1 /* net.c */
2 
3 /*    Copyright 2009-2011 10gen Inc.
4  *
5  *    Licensed under the Apache License, Version 2.0 (the "License");
6  *    you may not use this file except in compliance with the License.
7  *    You may obtain a copy of the License at
8  *
9  *    http://www.apache.org/licenses/LICENSE-2.0
10  *
11  *    Unless required by applicable law or agreed to in writing, software
12  *    distributed under the License is distributed on an "AS IS" BASIS,
13  *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  *    See the License for the specific language governing permissions and
15  *    limitations under the License.
16  */
17 
18 /* Implementation for generic version of net.h */
19 #include "net.h"
20 #include <errno.h>
21 #include <string.h>
22 
23 #ifndef NI_MAXSERV
24 # define NI_MAXSERV 32
25 #endif
26 
mongo_write_socket(mongo * conn,const void * buf,int len)27 int mongo_write_socket( mongo *conn, const void *buf, int len ) {
28     const char *cbuf = buf;
29 #ifdef _WIN32
30     int flags = 0;
31 #else
32     int flags = MSG_NOSIGNAL;
33 #endif
34 
35     while ( len ) {
36         int sent = send( conn->sock, cbuf, len, flags );
37         if ( sent == -1 ) {
38             if (errno == EPIPE)
39                 conn->connected = 0;
40             conn->err = MONGO_IO_ERROR;
41             return MONGO_ERROR;
42         }
43         cbuf += sent;
44         len -= sent;
45     }
46 
47     return MONGO_OK;
48 }
49 
mongo_read_socket(mongo * conn,void * buf,int len)50 int mongo_read_socket( mongo *conn, void *buf, int len ) {
51     char *cbuf = buf;
52     while ( len ) {
53         int sent = recv( conn->sock, cbuf, len, 0 );
54         if ( sent == 0 || sent == -1 ) {
55             conn->err = MONGO_IO_ERROR;
56             return MONGO_ERROR;
57         }
58         cbuf += sent;
59         len -= sent;
60     }
61 
62     return MONGO_OK;
63 }
64 
65 /* This is a no-op in the generic implementation. */
mongo_set_socket_op_timeout(mongo * conn,int millis)66 int mongo_set_socket_op_timeout( mongo *conn, int millis ) {
67     return MONGO_OK;
68 }
69 
70 #ifdef _MONGO_USE_GETADDRINFO
mongo_socket_connect(mongo * conn,const char * host,int port)71 int mongo_socket_connect( mongo *conn, const char *host, int port ) {
72     char port_str[NI_MAXSERV];
73     int status;
74 
75     struct addrinfo ai_hints;
76     struct addrinfo *ai_list = NULL;
77     struct addrinfo *ai_ptr = NULL;
78 
79     conn->sock = 0;
80     conn->connected = 0;
81 
82     bson_sprintf( port_str, "%d", port );
83 
84     memset( &ai_hints, 0, sizeof( ai_hints ) );
85 #ifdef AI_ADDRCONFIG
86     ai_hints.ai_flags = AI_ADDRCONFIG;
87 #endif
88     ai_hints.ai_family = AF_UNSPEC;
89     ai_hints.ai_socktype = SOCK_STREAM;
90 
91     status = getaddrinfo( host, port_str, &ai_hints, &ai_list );
92     if ( status != 0 ) {
93         bson_errprintf( "getaddrinfo failed: %s", gai_strerror( status ) );
94         conn->err = MONGO_CONN_ADDR_FAIL;
95         return MONGO_ERROR;
96     }
97 
98     for ( ai_ptr = ai_list; ai_ptr != NULL; ai_ptr = ai_ptr->ai_next ) {
99         conn->sock = socket( ai_ptr->ai_family, ai_ptr->ai_socktype, ai_ptr->ai_protocol );
100         if ( conn->sock < 0 ) {
101             conn->sock = 0;
102             continue;
103         }
104 
105         status = connect( conn->sock, ai_ptr->ai_addr, ai_ptr->ai_addrlen );
106         if ( status != 0 ) {
107             mongo_close_socket( conn->sock );
108             conn->sock = 0;
109             continue;
110         }
111 
112         if ( ai_ptr->ai_protocol == IPPROTO_TCP ) {
113             int flag = 1;
114 
115             setsockopt( conn->sock, IPPROTO_TCP, TCP_NODELAY,
116                         ( void * ) &flag, sizeof( flag ) );
117             if ( conn->op_timeout_ms > 0 )
118                 mongo_set_socket_op_timeout( conn, conn->op_timeout_ms );
119         }
120 
121         conn->connected = 1;
122         break;
123     }
124 
125     freeaddrinfo( ai_list );
126 
127     if ( ! conn->connected ) {
128         conn->err = MONGO_CONN_FAIL;
129         return MONGO_ERROR;
130     }
131 
132     return MONGO_OK;
133 }
134 #else
mongo_socket_connect(mongo * conn,const char * host,int port)135 int mongo_socket_connect( mongo *conn, const char *host, int port ) {
136     struct sockaddr_in sa;
137     socklen_t addressSize;
138     int flag = 1;
139 
140     if ( ( conn->sock = socket( AF_INET, SOCK_STREAM, 0 ) ) < 0 ) {
141         conn->sock = 0;
142         conn->err = MONGO_CONN_NO_SOCKET;
143         return MONGO_ERROR;
144     }
145 
146     memset( sa.sin_zero , 0 , sizeof( sa.sin_zero ) );
147     sa.sin_family = AF_INET;
148     sa.sin_port = htons( port );
149     sa.sin_addr.s_addr = inet_addr( host );
150     addressSize = sizeof( sa );
151 
152     if ( connect( conn->sock, ( struct sockaddr * )&sa, addressSize ) == -1 ) {
153         mongo_close_socket( conn->sock );
154         conn->connected = 0;
155         conn->sock = 0;
156         conn->err = MONGO_CONN_FAIL;
157         return MONGO_ERROR;
158     }
159 
160     setsockopt( conn->sock, IPPROTO_TCP, TCP_NODELAY, ( char * ) &flag, sizeof( flag ) );
161 
162     if( conn->op_timeout_ms > 0 )
163         mongo_set_socket_op_timeout( conn, conn->op_timeout_ms );
164 
165     conn->connected = 1;
166 
167     return MONGO_OK;
168 }
169 
170 #endif
171 
mongo_sock_init()172 MONGO_EXPORT int mongo_sock_init() {
173 
174 #if defined(_WIN32)
175     WSADATA wsaData;
176     WORD wVers;
177 #elif defined(SIGPIPE)
178     struct sigaction act;
179 #endif
180 
181     static int called_once;
182     static int retval;
183     if (called_once) return retval;
184     called_once = 1;
185 
186 #if defined(_WIN32)
187     wVers = MAKEWORD(1, 1);
188     retval = (WSAStartup(wVers, &wsaData) == 0);
189 #elif defined(MACINTOSH)
190     GUSISetup(GUSIwithInternetSockets);
191     retval = 1;
192 #elif defined(SIGPIPE)
193     retval = 1;
194     if (sigaction(SIGPIPE, (struct sigaction *)NULL, &act) < 0)
195         retval = 0;
196     else if (act.sa_handler == SIG_DFL) {
197         act.sa_handler = SIG_IGN;
198         if (sigaction(SIGPIPE, &act, (struct sigaction *)NULL) < 0)
199             retval = 0;
200     }
201 #endif
202     return retval;
203 }
204