1 /**
2 * Copyright (C) 2008 Happy Fish / YuQing
3 *
4 * FastDFS may be copied only under the terms of the GNU General
5 * Public License V3, which may be found in the FastDFS source kit.
6 * Please visit the FastDFS Home Page http://www.fastken.com/ for more detail.
7 **/
8 
9 //socketopt.h
10 
11 #ifndef _SOCKETOPT_H_
12 #define _SOCKETOPT_H_
13 
14 #include <net/if.h>
15 #include <string.h>
16 #include <fcntl.h>
17 #include <sys/types.h>
18 #include <sys/stat.h>
19 #include <sys/socket.h>
20 #include "common_define.h"
21 
22 #define FAST_WRITE_BUFF_SIZE  (256 * 1024)
23 
24 typedef struct fast_if_config {
25     char name[IF_NAMESIZE];    //if name
26     char mac[32];
27     char ipv4[IP_ADDRESS_SIZE];
28     char ipv6[48];
29 } FastIFConfig;
30 
31 typedef struct ip_addr_s {
32     char ip_addr[INET6_ADDRSTRLEN];
33     int socket_domain;
34 } ip_addr_t;
35 
36 typedef struct sockaddr_convert_s {
37     socklen_t len;
38     union {
39         struct sockaddr addr;
40         struct sockaddr_in addr4;
41         struct sockaddr_in6 addr6;
42     } sa;
43 } sockaddr_convert_t;
44 
45 #ifdef SO_NOSIGPIPE
46 #define SET_SOCKOPT_NOSIGPIPE(sock) \
47     do { \
48     int set = 1;  \
49     setsockopt(sock, SOL_SOCKET, SO_NOSIGPIPE, &set, sizeof(int)); \
50     } while (0)
51 #else
52 #define SET_SOCKOPT_NOSIGPIPE(sock)
53 #endif
54 
55 #ifdef __cplusplus
56 extern "C" {
57 #endif
58 
59 typedef int (*getnamefunc)(int socket, struct sockaddr *address, \
60 		socklen_t *address_len);
61 
62 typedef int (*tcpsenddatafunc)(int sock, void* data, const int size, \
63 		const int timeout);
64 
65 typedef int (*tcprecvdata_exfunc)(int sock, void *data, const int size, \
66 		const int timeout, int *count);
67 
68 #define getSockIpaddr(sock, buff, bufferSize) \
69 	getIpaddr(getsockname, sock, buff, bufferSize)
70 
71 #define getPeerIpaddr(sock, buff, bufferSize) \
72 	getIpaddr(getpeername, sock, buff, bufferSize)
73 
74 /** get a line from socket
75  *  parameters:
76  *          sock: the socket
77  *          s: the buffer
78  *          size: buffer size (max bytes can receive)
79  *          timeout: read timeout
80  *  return: error no, 0 success, != 0 fail
81 */
82 int tcpgets(int sock, char *s, const int size, const int timeout);
83 
84 /** recv data (block mode)
85  *  parameters:
86  *          sock: the socket
87  *          data: the buffer
88  *          size: buffer size (max bytes can receive)
89  *          timeout: read timeout
90  *          count: store the bytes recveived
91  *  return: error no, 0 success, != 0 fail
92 */
93 int tcprecvdata_ex(int sock, void *data, const int size, \
94 		const int timeout, int *count);
95 
96 /** recv data (non-block mode)
97  *  parameters:
98  *          sock: the socket
99  *          data: the buffer
100  *          size: buffer size (max bytes can receive)
101  *          timeout: read timeout in seconds
102  *          count: store the bytes recveived
103  *  return: error no, 0 success, != 0 fail
104 */
105 int tcprecvdata_nb_ex(int sock, void *data, const int size, \
106 		const int timeout, int *count);
107 
108 /** recv data (non-block mode) in ms
109  *  parameters:
110  *          sock: the socket
111  *          data: the buffer
112  *          size: buffer size (max bytes can receive)
113  *          timeout: read timeout in milliseconds
114  *          count: store the bytes recveived
115  *  return: error no, 0 success, != 0 fail
116 */
117 int tcprecvdata_nb_ms(int sock, void *data, const int size, \
118 		const int timeout_ms, int *count);
119 
120 /** send data (block mode)
121  *  parameters:
122  *          sock: the socket
123  *          data: the buffer to send
124  *          size: buffer size
125  *          timeout: write timeout
126  *  return: error no, 0 success, != 0 fail
127 */
128 int tcpsenddata(int sock, void* data, const int size, const int timeout);
129 
130 /** send data (non-block mode)
131  *  parameters:
132  *          sock: the socket
133  *          data: the buffer to send
134  *          size: buffer size
135  *          timeout: write timeout
136  *  return: error no, 0 success, != 0 fail
137 */
138 int tcpsenddata_nb(int sock, void* data, const int size, const int timeout);
139 
140 /** connect to server by block mode
141  *  parameters:
142  *          sock: the socket
143  *          server_ip: ip address of the server
144  *          server_port: port of the server
145  *  return: error no, 0 success, != 0 fail
146 */
147 int connectserverbyip(int sock, const char *server_ip, const short server_port);
148 
149 /** connect to server by non-block mode
150  *  parameters:
151  *          sock: the socket
152  *          server_ip: ip address of the server
153  *          server_port: port of the server
154  *          timeout: connect timeout in seconds
155  *          auto_detect: if detect and adjust the block mode of the socket
156  *  return: error no, 0 success, != 0 fail
157 */
158 int connectserverbyip_nb_ex(int sock, const char *server_ip, \
159 		const short server_port, const int timeout, \
160 		const bool auto_detect);
161 
162 /** connect to server by non-block mode, the socket must be set to non-block
163  *  parameters:
164  *          sock: the socket,  must be set to non-block
165  *          server_ip: ip address of the server
166  *          server_port: port of the server
167  *          timeout: connect timeout in seconds
168  *  return: error no, 0 success, != 0 fail
169 */
170 #define connectserverbyip_nb(sock, server_ip, server_port, timeout) \
171 	connectserverbyip_nb_ex(sock, server_ip, server_port, timeout, false)
172 
173 /** connect to server by non-block mode, auto detect socket block mode
174  *  parameters:
175  *          sock: the socket, can be block mode
176  *          server_ip: ip address of the server
177  *          server_port: port of the server
178  *          timeout: connect timeout in seconds
179  *  return: error no, 0 success, != 0 fail
180 */
181 #define connectserverbyip_nb_auto(sock, server_ip, server_port, timeout) \
182 	connectserverbyip_nb_ex(sock, server_ip, server_port, timeout, true)
183 
184 /** accept client connect request
185  *  parameters:
186  *          sock: the server socket
187  *          timeout: read timeout
188  *          err_no: store the error no, 0 for success
189  *  return: client socket, < 0 for error
190 */
191 int nbaccept(int sock, const int timeout, int *err_no);
192 
193 /** set socket options
194  *  parameters:
195  *          sock: the socket
196  *          timeout: read & write timeout
197  *  return: error no, 0 success, != 0 fail
198 */
199 int tcpsetserveropt(int fd, const int timeout);
200 
201 /** set socket non-block options
202  *  parameters:
203  *          sock: the socket
204  *  return: error no, 0 success, != 0 fail
205 */
206 int tcpsetnonblockopt(int fd);
207 
208 /** set socket no delay on send data
209  *  parameters:
210  *          sock: the socket
211  *          timeout: read & write timeout
212  *  return: error no, 0 success, != 0 fail
213 */
214 int tcpsetnodelay(int fd, const int timeout);
215 
216 /** set socket keep-alive
217  *  parameters:
218  *          sock: the socket
219  *          idleSeconds: max idle time (seconds)
220  *  return: error no, 0 success, != 0 fail
221 */
222 int tcpsetkeepalive(int fd, const int idleSeconds);
223 
224 /** print keep-alive related parameters
225  *  parameters:
226  *          sock: the socket
227  *  return: error no, 0 success, != 0 fail
228 */
229 int tcpprintkeepalive(int fd);
230 
231 /** get ip address
232  *  parameters:
233  *          getname: the function name, should be getpeername or getsockname
234  *          sock: the socket
235  *          buff: buffer to store the ip address
236  *          bufferSize: the buffer size (max bytes)
237  *  return: in_addr_t, INADDR_NONE for fail
238 */
239 in_addr_t getIpaddr(getnamefunc getname, int sock, \
240 		char *buff, const int bufferSize);
241 
242 /** get hostname by it's ip address
243  *  parameters:
244  *          szIpAddr: the ip address
245  *          buff: buffer to store the hostname
246  *          bufferSize: the buffer size (max bytes)
247  *  return: hostname, empty buffer for error
248 */
249 char *getHostnameByIp(const char *szIpAddr, char *buff, const int bufferSize);
250 
251 /** get by IPv4 address by it's hostname
252  *  parameters:
253  *          name: the hostname
254  *          buff: buffer to store the ip address
255  *          bufferSize: the buffer size (max bytes)
256  *  return: in_addr_t, INADDR_NONE for fail
257 */
258 in_addr_t getIpaddrByName(const char *name, char *buff, const int bufferSize);
259 
260 /** get by ip addresses by it's hostname
261  *  parameters:
262  *          name: the hostname
263  *          ip_addr_arr: ip address array to store the ip address
264  *          ip_addr_arr_size: ip address array size
265  *  return: ip address count
266 */
267 int getIpaddrsByName(const char *name, ip_addr_t *ip_addr_arr, const int ip_addr_arr_size);
268 
269 /** bind wrapper for IPv4
270  *  parameters:
271  *          sock: the socket
272  *          bind_ipaddr: the ip address to bind
273  *          port: the port to bind
274  *  return: error no, 0 success, != 0 fail
275 */
276 int socketBind(int sock, const char *bind_ipaddr, const int port);
277 
278 /** bind wrapper for IPv6
279  *  parameters:
280  *          sock: the socket
281  *          bind_ipaddr: the ip address to bind
282  *          port: the port to bind
283  *  return: error no, 0 success, != 0 fail
284 */
285 int socketBindIPv6(int sock, const char *bind_ipaddr, const int port);
286 
287 /** bind wrapper for IPv4 or IPv6
288  *  parameters:
289  *          af: family, AF_INET or AF_INET6
290  *          sock: the socket
291  *          bind_ipaddr: the ip address to bind
292  *          port: the port to bind
293  *  return: error no, 0 success, != 0 fail
294 */
295 int socketBind2(int af, int sock, const char *bind_ipaddr, const int port);
296 
297 /** start a socket server for IPv4 (socket, bind and listen)
298  *  parameters:
299  *          sock: the socket
300  *          bind_ipaddr: the ip address to bind
301  *          port: the port to bind
302  *          err_no: store the error no
303  *  return: >= 0 server socket, < 0 fail
304 */
305 int socketServer(const char *bind_ipaddr, const int port, int *err_no);
306 
307 /** start a socket server for IPv6 (socket, bind and listen)
308  *  parameters:
309  *          sock: the socket
310  *          bind_ipaddr: the ip address to bind
311  *          port: the port to bind
312  *          err_no: store the error no
313  *  return: >= 0 server socket, < 0 fail
314 */
315 int socketServerIPv6(const char *bind_ipaddr, const int port, int *err_no);
316 
317 /** start a socket server for IPv4 or IPv6 (socket, bind and listen)
318  *  parameters:
319  *          af: family, AF_INET or AF_INET6
320  *          sock: the socket
321  *          bind_ipaddr: the ip address to bind
322  *          port: the port to bind
323  *          err_no: store the error no
324  *  return: >= 0 server socket, < 0 fail
325 */
326 int socketServer2(int af, const char *bind_ipaddr, const int port, int *err_no);
327 
328 /** create socket (NOT connect to server yet)
329  *  parameters:
330  *          af: family, AF_UNSPEC (auto dectect), AF_INET or AF_INET6
331  *          server_ip: ip address of the server to detect family when af == AF_UNSPEC
332  *          timeout: connect timeout in seconds
333  *          flags: socket flags such as O_NONBLOCK for non-block socket
334  *          bind_ipaddr: the ip address to bind, NULL or empty for bind ANY
335  *          err_no: store the error no
336  *  return: >= 0 server socket, < 0 fail
337 */
338 int socketCreateEx2(int af, const char *server_ip,
339 		const int timeout, const int flags,
340         const char *bind_ipaddr, int *err_no);
341 
342 /** create socket (NOT connect to server yet)
343  *  parameters:
344  *          server_ip: ip address of the server to detect family
345  *          timeout: connect timeout in seconds
346  *          flags: socket flags such as O_NONBLOCK for non-block socket
347  *          bind_ipaddr: the ip address to bind, NULL or empty for bind ANY
348  *          err_no: store the error no
349  *  return: >= 0 server socket, < 0 fail
350 */
socketCreateExAuto(const char * server_ip,const int timeout,const int flags,const char * bind_ipaddr,int * err_no)351 static inline int socketCreateExAuto(const char *server_ip,
352 		const int timeout, const int flags,
353         const char *bind_ipaddr, int *err_no)
354 {
355     return socketCreateEx2(AF_UNSPEC, server_ip, timeout, flags,
356             bind_ipaddr, err_no);
357 }
358 
359 /** connect to server
360  *  parameters:
361  *          af: family, AF_UNSPEC (auto dectect), AF_INET or AF_INET6
362  *          server_ip: ip address of the server
363  *          server_port: port of the server
364  *          timeout: connect timeout in seconds
365  *          flags: socket flags such as O_NONBLOCK for non-block socket
366  *          bind_ipaddr: the ip address to bind, NULL or empty for bind ANY
367  *          err_no: store the error no
368  *  return: >= 0 server socket, < 0 fail
369 */
370 int socketClientEx2(int af, const char *server_ip,
371 		const short server_port, const int timeout,
372 		const int flags, const char *bind_ipaddr, int *err_no);
373 
374 /** connect to server
375  *  parameters:
376  *          server_ip: ip address of the server
377  *          server_port: port of the server
378  *          timeout: connect timeout in seconds
379  *          flags: socket flags such as O_NONBLOCK for non-block socket
380  *          bind_ipaddr: the ip address to bind, NULL or empty for bind ANY
381  *          err_no: store the error no
382  *  return: >= 0 server socket, < 0 fail
383 */
socketClientExAuto(const char * server_ip,const short server_port,const int timeout,const int flags,const char * bind_ipaddr,int * err_no)384 static inline int socketClientExAuto(const char *server_ip,
385 		const short server_port, const int timeout,
386 		const int flags, const char *bind_ipaddr, int *err_no)
387 {
388     return socketClientEx2(AF_UNSPEC, server_ip, server_port,
389             timeout, flags, bind_ipaddr, err_no);
390 }
391 
392 /** connect to server
393  *  parameters:
394  *          server_ip: ip address of the server
395  *          server_port: port of the server
396  *          timeout: connect timeout in seconds
397  *          flags: socket flags such as O_NONBLOCK for non-block socket
398  *          bind_ipaddr: the ip address to bind, NULL or empty for bind ANY
399  *          err_no: store the error no
400  *  return: >= 0 server socket, < 0 fail
401 */
socketClientAuto(const char * server_ip,const short server_port,const int timeout,const int flags,int * err_no)402 static inline int socketClientAuto(const char *server_ip,
403 		const short server_port, const int timeout,
404 		const int flags, int *err_no)
405 {
406     return socketClientEx2(AF_UNSPEC, server_ip, server_port,
407             timeout, flags, NULL, err_no);
408 }
409 
410 /** connect to server
411  *  parameters:
412  *          af: family, AF_UNSPEC (auto dectect), AF_INET or AF_INET6
413  *          server_ip: ip address of the server
414  *          server_port: port of the server
415  *          timeout: connect timeout in seconds
416  *          flags: socket flags such as O_NONBLOCK for non-block socket
417  *          err_no: store the error no
418  *  return: >= 0 server socket, < 0 fail
419 */
socketClient2(int af,const char * server_ip,const short server_port,const int timeout,const int flags,int * err_no)420 static inline int socketClient2(int af, const char *server_ip,
421 		const short server_port, const int timeout,
422 		const int flags, int *err_no)
423 {
424     return socketClientEx2(af, server_ip, server_port,
425             timeout, flags, NULL, err_no);
426 }
427 
428 /** connect to server with IPv4 socket
429  *  parameters:
430  *          server_ip: ip address of the server
431  *          server_port: port of the server
432  *          timeout: connect timeout in seconds
433  *          flags: socket flags such as O_NONBLOCK for non-block socket
434  *          err_no: store the error no
435  *  return: >= 0 server socket, < 0 fail
436 */
socketClient(const char * server_ip,const short server_port,const int timeout,const int flags,int * err_no)437 static inline int socketClient(const char *server_ip,
438 		const short server_port, const int timeout,
439 		const int flags, int *err_no)
440 {
441     return socketClient2(AF_INET, server_ip, server_port,
442             timeout, flags, err_no);
443 }
444 
445 /** connect to server with IPv6 socket
446  *  parameters:
447  *          server_ip: ip address of the server
448  *          server_port: port of the server
449  *          timeout: connect timeout in seconds
450  *          flags: socket flags such as O_NONBLOCK for non-block socket
451  *          err_no: store the error no
452  *  return: >= 0 server socket, < 0 fail
453 */
socketClientIPv6(const char * server_ip,const short server_port,const int timeout,const int flags,int * err_no)454 static inline int socketClientIPv6(const char *server_ip,
455 		const short server_port, const int timeout,
456 		const int flags, int *err_no)
457 {
458     return socketClient2(AF_INET6, server_ip, server_port,
459             timeout, flags, err_no);
460 }
461 
462 #define tcprecvdata(sock, data, size, timeout) \
463 	tcprecvdata_ex(sock, data, size, timeout, NULL)
464 
465 #define tcpsendfile(sock, filename, file_bytes, timeout, total_send_bytes) \
466 	tcpsendfile_ex(sock, filename, 0, file_bytes, timeout, total_send_bytes)
467 
468 #define tcprecvdata_nb(sock, data, size, timeout) \
469 	tcprecvdata_nb_ex(sock, data, size, timeout, NULL)
470 
471 /** send a file
472  *  parameters:
473  *          sock: the socket
474  *          filename: the file to send
475  *          file_offset: file offset, start position
476  *          file_bytes: send file length
477  *          timeout: write timeout
478  *          total_send_bytes: store the send bytes
479  *  return: error no, 0 success, != 0 fail
480 */
481 int tcpsendfile_ex(int sock, const char *filename, const int64_t file_offset, \
482 	const int64_t file_bytes, const int timeout, int64_t *total_send_bytes);
483 
484 /** receive data to a file
485  *  parameters:
486  *          sock: the socket
487  *          filename: the file to write
488  *          file_bytes: file size (bytes)
489  *          fsync_after_written_bytes: call fsync every x bytes
490  *          timeout: read/recv timeout
491  *          true_file_bytes: store the true file bytes
492  *  return: error no, 0 success, != 0 fail
493 */
494 int tcprecvfile(int sock, const char *filename, const int64_t file_bytes, \
495 		const int fsync_after_written_bytes, const int timeout, \
496 		int64_t *true_file_bytes);
497 
498 
499 #define tcprecvinfinitefile(sock, filename, fsync_after_written_bytes, \
500 			timeout, file_bytes) \
501 	tcprecvfile(sock, filename, INFINITE_FILE_SIZE, \
502 		fsync_after_written_bytes, timeout, file_bytes)
503 
504 
505 /** receive data to a file
506  *  parameters:
507  *          sock: the socket
508  *          filename: the file to write
509  *          file_bytes: file size (bytes)
510  *          fsync_after_written_bytes: call fsync every x bytes
511  *          hash_codes: return hash code of file content
512  *          timeout: read/recv timeout
513  *  return: error no, 0 success, != 0 fail
514 */
515 int tcprecvfile_ex(int sock, const char *filename, const int64_t file_bytes, \
516 		const int fsync_after_written_bytes, \
517 		unsigned int *hash_codes, const int timeout);
518 
519 /** receive specified data and discard
520  *  parameters:
521  *          sock: the socket
522  *          bytes: data bytes to discard
523  *          timeout: read timeout
524  *          total_recv_bytes: store the total recv bytes
525  *  return: error no, 0 success, != 0 fail
526 */
527 int tcpdiscard(int sock, const int bytes, const int timeout, \
528 		int64_t *total_recv_bytes);
529 
530 /** get local host ip addresses
531  *  parameters:
532  *          ip_addrs: store the ip addresses
533  *          max_count: max ip address (max ip_addrs elements)
534  *          count: store the ip address count
535  *  return: error no, 0 success, != 0 fail
536 */
537 int getlocaladdrs(char ip_addrs[][IP_ADDRESS_SIZE], \
538 	const int max_count, int *count);
539 
540 /** get local host ip addresses by if alias prefix
541  *  parameters:
542  *          if_alias_prefixes: if alias prefixes, such as eth, bond etc.
543  *          prefix_count: if alias prefix count
544  *          ip_addrs: store the ip addresses
545  *          max_count: max ip address (max ip_addrs elements)
546  *          count: store the ip address count
547  *  return: error no, 0 success, != 0 fail
548 */
549 int gethostaddrs(char **if_alias_prefixes, const int prefix_count, \
550 	char ip_addrs[][IP_ADDRESS_SIZE], const int max_count, int *count);
551 
552 /** get local if configs
553  *  parameters:
554  *          if_configs: store the if configs
555  *          max_count: max ifconfig elements
556  *          count: store the ifconfig count
557  *  return: error no, 0 success, != 0 fail
558 */
559 int getifconfigs(FastIFConfig *if_configs, const int max_count, int *count);
560 
561 /** set socket address by ip and port
562  *  parameters:
563  *          ip: the ip address
564  *          port: the port
565  *          convert: the convert struct for IPv4 and IPv6 compatibility
566  *  return: error no, 0 success, != 0 fail
567 */
568 int setsockaddrbyip(const char *ip, const short port, sockaddr_convert_t *convert);
569 
is_ipv6_addr(const char * ip)570 static inline bool is_ipv6_addr(const char *ip)
571 {
572     return (*ip == ':' || strchr(ip, ':') != NULL); //ipv6
573 }
574 
575 void tcp_set_try_again_when_interrupt(const bool value);
576 
tcp_dont_try_again_when_interrupt()577 static inline void tcp_dont_try_again_when_interrupt()
578 {
579     tcp_set_try_again_when_interrupt(false);
580 }
581 
582 #ifdef __cplusplus
583 }
584 #endif
585 
586 #endif
587 
588