1    	// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- 
2    	// vim: ts=8 sw=2 smarttab
3    	/*
4    	 * Ceph - scalable distributed file system
5    	 *
6    	 * Copyright (C) 2014 UnitedStack <haomai@unitedstack.com>
7    	 *
8    	 * Author: Haomai Wang <haomaiwang@gmail.com>
9    	 *
10   	 * This is free software; you can redistribute it and/or
11   	 * modify it under the terms of the GNU Lesser General Public
12   	 * License version 2.1, as published by the Free Software
13   	 * Foundation.  See file COPYING.
14   	 *
15   	 */
16   	
17   	#include <sys/types.h>
18   	#include <sys/socket.h>
19   	#include <netinet/in.h>
20   	#include <netinet/ip.h>
21   	#include <netinet/tcp.h>
22   	#include <arpa/inet.h>
23   	
24   	#include "net_handler.h"
25   	#include "common/debug.h"
26   	#include "common/errno.h"
27   	#include "include/compat.h"
28   	#include "include/sock_compat.h"
29   	
30   	#define dout_subsys ceph_subsys_ms
31   	#undef dout_prefix
32   	#define dout_prefix *_dout << "NetHandler "
33   	
34   	namespace ceph{
35   	
36   	int NetHandler::create_socket(int domain, bool reuse_addr)
37   	{
38   	  int s;
39   	  int r = 0;
40   	
41   	  if ((s = socket_cloexec(domain, SOCK_STREAM, 0)) == -1) {
42   	    r = errno;
43   	    lderr(cct) << __func__ << " couldn't create socket " << cpp_strerror(r) << dendl;
44   	    return -r;
45   	  }
46   	
47   	#if !defined(__FreeBSD__)
48   	  /* Make sure connection-intensive things like the benchmark
49   	   * will be able to close/open sockets a zillion of times */
50   	  if (reuse_addr) {
51   	    int on = 1;
52   	    if (::setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) == -1) {
53   	      r = errno;
54   	      lderr(cct) << __func__ << " setsockopt SO_REUSEADDR failed: "
55   	                 << strerror(r) << dendl;
56   	      close(s);
57   	      return -r;
58   	    }
59   	  }
60   	#endif
61   	
62   	  return s;
63   	}
64   	
65   	int NetHandler::set_nonblock(int sd)
66   	{
67   	  int flags;
68   	  int r = 0;
69   	
70   	  /* Set the socket nonblocking.
71   	   * Note that fcntl(2) for F_GETFL and F_SETFL can't be
72   	   * interrupted by a signal. */
73   	  if ((flags = fcntl(sd, F_GETFL)) < 0 ) {
74   	    r = errno;
75   	    lderr(cct) << __func__ << " fcntl(F_GETFL) failed: " << cpp_strerror(r) << dendl;
76   	    return -r;
77   	  }
78   	  if (fcntl(sd, F_SETFL, flags | O_NONBLOCK) < 0) {
79   	    r = errno;
80   	    lderr(cct) << __func__ << " fcntl(F_SETFL,O_NONBLOCK): " << cpp_strerror(r) << dendl;
81   	    return -r;
82   	  }
83   	
84   	  return 0;
85   	}
86   	
87   	int NetHandler::set_socket_options(int sd, bool nodelay, int size)
88   	{
89   	  int r = 0;
90   	  // disable Nagle algorithm?
91   	  if (nodelay) {
92   	    int flag = 1;
93   	    r = ::setsockopt(sd, IPPROTO_TCP, TCP_NODELAY, (char*)&flag, sizeof(flag));
94   	    if (r < 0) {
95   	      r = errno;
96   	      ldout(cct, 0) << "couldn't set TCP_NODELAY: " << cpp_strerror(r) << dendl;
97   	    }
98   	  }
99   	  if (size) {
100  	    r = ::setsockopt(sd, SOL_SOCKET, SO_RCVBUF, (void*)&size, sizeof(size));
101  	    if (r < 0)  {
102  	      r = errno;
103  	      ldout(cct, 0) << "couldn't set SO_RCVBUF to " << size << ": " << cpp_strerror(r) << dendl;
104  	    }
105  	  }
106  	
107  	  // block ESIGPIPE
108  	#ifdef CEPH_USE_SO_NOSIGPIPE
109  	  int val = 1;
110  	  r = ::setsockopt(sd, SOL_SOCKET, SO_NOSIGPIPE, (void*)&val, sizeof(val));
111  	  if (r) {
112  	    r = errno;
113  	    ldout(cct,0) << "couldn't set SO_NOSIGPIPE: " << cpp_strerror(r) << dendl;
114  	  }
115  	#endif
116  	  return -r;
117  	}
118  	
119  	void NetHandler::set_priority(int sd, int prio, int domain)
120  	{
121  	#ifdef SO_PRIORITY
122  	  if (prio < 0) {
123  	    return;
124  	  }
125  	#ifdef IPTOS_CLASS_CS6
126  	  int iptos = IPTOS_CLASS_CS6;
127  	  int r = -1;
128  	  switch (domain) {
129  	  case AF_INET:
130  	    r = ::setsockopt(sd, IPPROTO_IP, IP_TOS, &iptos, sizeof(iptos));
131  	    break;
132  	  case AF_INET6:
133  	    r = ::setsockopt(sd, IPPROTO_IPV6, IPV6_TCLASS, &iptos, sizeof(iptos));
134  	    break;
135  	  default:
136  	    lderr(cct) << "couldn't set ToS of unknown family (" << domain << ")"
137  		       << " to " << iptos << dendl;
138  	    return;
139  	  }
140  	  if (r < 0) {
141  	    r = errno;
142  	    ldout(cct,0) << "couldn't set TOS to " << iptos
143  			 << ": " << cpp_strerror(r) << dendl;
144  	  }
145  	
146  	#endif	// IPTOS_CLASS_CS6
147  	  // setsockopt(IPTOS_CLASS_CS6) sets the priority of the socket as 0.
148  	  // See http://goo.gl/QWhvsD and http://goo.gl/laTbjT
149  	  // We need to call setsockopt(SO_PRIORITY) after it.
150  	  r = ::setsockopt(sd, SOL_SOCKET, SO_PRIORITY, &prio, sizeof(prio));
151  	  if (r < 0) {
152  	    r = errno;
153  	    ldout(cct, 0) << __func__ << " couldn't set SO_PRIORITY to " << prio
154  			  << ": " << cpp_strerror(r) << dendl;
155  	  }
156  	#else
157  	  return;
158  	#endif	// SO_PRIORITY
159  	}
160  	
161  	int NetHandler::generic_connect(const entity_addr_t& addr, const entity_addr_t &bind_addr, bool nonblock)
162  	{
163  	  int ret;
164  	  int s = create_socket(addr.get_family());
(1) Event cond_false: Condition "s < 0", taking false branch.
165  	  if (s < 0)
(2) Event if_end: End of if statement.
166  	    return s;
167  	
(3) Event cond_true: Condition "nonblock", taking true branch.
168  	  if (nonblock) {
169  	    ret = set_nonblock(s);
(4) Event cond_false: Condition "ret < 0", taking false branch.
170  	    if (ret < 0) {
171  	      close(s);
172  	      return ret;
(5) Event if_end: End of if statement.
173  	    }
174  	  }
175  	
(6) Event check_return: Calling "set_socket_options" without checking return value (as is done elsewhere 5 out of 6 times).
Also see events: [example_assign][example_checked][example_assign][example_checked][example_assign][example_checked][example_assign][example_checked][example_assign][example_checked]
176  	  set_socket_options(s, cct->_conf->ms_tcp_nodelay, cct->_conf->ms_tcp_rcvbuf);
177  	
178  	  {
179  	    entity_addr_t addr = bind_addr;
180  	    if (cct->_conf->ms_bind_before_connect && (!addr.is_blank_ip())) {
181  	      addr.set_port(0);
182  	      ret = ::bind(s, addr.get_sockaddr(), addr.get_sockaddr_len());
183  	      if (ret < 0) {
184  	        ret = errno;
185  	        ldout(cct, 2) << __func__ << " client bind error " << ", " << cpp_strerror(ret) << dendl;
186  	        close(s);
187  	        return -ret;
188  	      }
189  	    }
190  	  }
191  	
192  	  ret = ::connect(s, addr.get_sockaddr(), addr.get_sockaddr_len());
193  	  if (ret < 0) {
194  	    ret = errno;
195  	    if (errno == EINPROGRESS && nonblock)
196  	      return s;
197  	
198  	    ldout(cct, 10) << __func__ << " connect: " << cpp_strerror(ret) << dendl;
199  	    close(s);
200  	    return -ret;
201  	  }
202  	
203  	  return s;
204  	}
205  	
206  	int NetHandler::reconnect(const entity_addr_t &addr, int sd)
207  	{
208  	  int r = 0;
209  	  int ret = ::connect(sd, addr.get_sockaddr(), addr.get_sockaddr_len());
210  	
211  	  if (ret < 0 && errno != EISCONN) {
212  	    r = errno;
213  	    ldout(cct, 10) << __func__ << " reconnect: " << strerror(r) << dendl;
214  	    if (r == EINPROGRESS || r == EALREADY)
215  	      return 1;
216  	    return -r;
217  	  }
218  	
219  	  return 0;
220  	}
221  	
222  	int NetHandler::connect(const entity_addr_t &addr, const entity_addr_t& bind_addr)
223  	{
224  	  return generic_connect(addr, bind_addr, false);
225  	}
226  	
227  	int NetHandler::nonblock_connect(const entity_addr_t &addr, const entity_addr_t& bind_addr)
228  	{
229  	  return generic_connect(addr, bind_addr, true);
230  	}
231  	
232  	
233  	}
234