kinetic-c  v0.12.0
Seagate Kinetic Protocol Client Library for C
kinetic_socket.c
Go to the documentation of this file.
1 /*
2 * kinetic-c
3 * Copyright (C) 2015 Seagate Technology.
4 *
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License
7 * as published by the Free Software Foundation; either version 2
8 * of the License, or (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18 *
19 */
20 
21 #include "kinetic_socket.h"
22 #include "kinetic_logger.h"
23 #include "kinetic_types_internal.h"
24 #include "kinetic.pb-c.h"
25 #include "protobuf-c/protobuf-c.h"
26 
27 #include <stdlib.h>
28 #include <errno.h>
29 #include <string.h>
30 #include <stdio.h>
31 #include <string.h>
32 #include <sys/types.h>
33 #include <unistd.h>
34 #include <fcntl.h>
35 #include <sys/socket.h>
36 #include <netinet/in.h>
37 #include <netinet/tcp.h>
38 #include <sys/select.h>
39 #include <sys/ioctl.h>
40 #include <arpa/inet.h>
41 #include <netdb.h>
42 #include <signal.h>
43 #include <unistd.h>
44 #include <poll.h>
45 #include "socket99.h"
46 
47 int KineticSocket_Connect(const char* host, int port)
48 {
49  char port_str[32];
50  struct addrinfo hints;
51  struct addrinfo* ai_result = NULL;
52  struct addrinfo* ai = NULL;
53  socket99_result result;
54 
55  // Setup server address info
56  socket99_config cfg = {
57  .host = (char*)host,
58  .port = port,
59  .nonblocking = true,
60  };
61  sprintf(port_str, "%d", port);
62 
63  // Open socket
64  LOGF1("Connecting to %s:%d", host, port);
65  if (!socket99_open(&cfg, &result)) {
66  char err_buf[256];
67  socket99_snprintf(err_buf, 256, &result);
68  LOGF0("Failed to open socket connection with host: %s", err_buf);
70  }
71 
72  // Configure the socket
73  socket99_set_hints(&cfg, &hints);
74  if (getaddrinfo(cfg.host, port_str, &hints, &ai_result) != 0) {
75  LOGF0("Failed to get socket address info: errno %d", errno);
76  close(result.fd);
78  }
79 
81 
82  for (ai = ai_result; ai != NULL; ai = ai->ai_next) {
83  int setsockopt_result;
84  int buffer_size = KINETIC_OBJ_SIZE;
85 
86 #if defined(SO_NOSIGPIPE) && !defined(__APPLE__)
87  // On BSD-like systems we can set SO_NOSIGPIPE on the socket to
88  // prevent it from sending a PIPE signal and bringing down the whole
89  // application if the server closes the socket forcibly
90  int enable = 1;
91  setsockopt_result = setsockopt(result.fd,
92  SOL_SOCKET, SO_NOSIGPIPE,
93  &enable, sizeof(enable));
94  // Allow ENOTSOCK because it allows tests to use pipes instead of
95  // real sockets
96  if (setsockopt_result != 0 && setsockopt_result != ENOTSOCK) {
97  LOG0("Failed to set SO_NOSIGPIPE on socket");
98  continue;
99  }
100 #endif
101 
102  // Increase send buffer to KINETIC_OBJ_SIZE
103  // Note: OS allocates 2x this value for its overhead
104  setsockopt_result = setsockopt(result.fd,
105  SOL_SOCKET, SO_SNDBUF,
106  &buffer_size, sizeof(buffer_size));
107  if (setsockopt_result == -1) {
108  LOG0("Error setting socket send buffer size");
109  continue;
110  }
111 
112  // Increase receive buffer to KINETIC_OBJ_SIZE
113  // Note: OS allocates 2x this value for its overheadbuffer_size
114  setsockopt_result = setsockopt(result.fd,
115  SOL_SOCKET, SO_RCVBUF,
116  &buffer_size, sizeof(buffer_size));
117  if (setsockopt_result == -1) {
118  LOG0("Error setting socket receive buffer size");
119  continue;
120  }
121 
122  break;
123  }
124 
125  freeaddrinfo(ai_result);
126 
127  if (ai == NULL || result.fd == KINETIC_SOCKET_DESCRIPTOR_INVALID) {
128  // we went through all addresses without finding one we could bind to
129  LOGF0("Could not connect to %s:%d", host, port);
131  }
132  else {
133  LOGF1("Successfully connected to %s:%d (fd=%d)", host, port, result.fd);
134  return result.fd;
135  }
136 }
137 
138 void KineticSocket_Close(int socket)
139 {
140  if (socket == -1) {
141  LOG1("Not connected so no cleanup needed");
142  }
143  else {
144  LOGF0("Closing socket with fd=%d", socket);
145  if (close(socket) == 0) {
146  LOG2("Socket closed successfully");
147  }
148  else {
149  LOGF0("Error closing socket file descriptor!"
150  " (fd=%d, errno=%d, desc='%s')",
151  socket, errno, strerror(errno));
152  }
153  }
154 }
155 
157 {
158  int on = 1;
159  setsockopt(socket, IPPROTO_TCP, TCP_NODELAY, &on, sizeof(on));
160 }
161 
163 {
164 #if !defined(__APPLE__) /* TCP_CORK is NOT available on OSX */
165  int on = 1;
166  setsockopt(socket, IPPROTO_TCP, TCP_CORK, &on, sizeof(on));
167 #else
168  (void)socket;
169 #endif
170 }
171 
173 {
174 #if !defined(__APPLE__) /* TCP_CORK is NOT available on OSX */
175  int off = 0;
176  setsockopt(socket, IPPROTO_TCP, TCP_CORK, &off, sizeof(off));
177 #else
178  (void)socket;
179 #endif
180 }
void KineticSocket_EnableTCPNoDelay(int socket)
#define LOGF1(message,...)
#define KINETIC_OBJ_SIZE
Max object/value size.
Definition: kinetic_types.h:47
void KineticSocket_BeginPacket(int socket)
int KineticSocket_Connect(const char *host, int port)
#define KINETIC_SOCKET_DESCRIPTOR_INVALID
#define LOG0(message)
#define LOG2(message)
#define LOGF0(message,...)
void KineticSocket_FinishPacket(int socket)
void KineticSocket_Close(int socket)
#define LOG1(message)