File: tcp.c

package info (click to toggle)
httping 1.5.8-1
  • links: PTS
  • area: main
  • in suites: jessie, jessie-kfreebsd
  • size: 188 kB
  • ctags: 79
  • sloc: ansic: 1,695; makefile: 76
file content (167 lines) | stat: -rw-r--r-- 3,462 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
/* Released under GPLv2 with exception for the OpenSSL library. See license.txt */

#include <sys/types.h>
#include <sys/time.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <errno.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>

#include "gen.h"
#include "io.h"
#include "tcp.h"

int connect_to(struct sockaddr *bind_to, struct addrinfo *ai, int timeout, char *tfo, char *msg, int msg_len, int *msg_accepted)
{
	int     fd;
	int 	rc;
	struct timeval to;
	fd_set wfds;

	/* create socket */
	fd = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
	if (fd == -1)
	{
		snprintf(last_error, sizeof last_error, "problem creating socket (%s)", strerror(errno));
		return -1;
	}

	/* go through a specific interface? */
	if (bind_to)
	{
		int set = 1;

		/* set reuse flags */
		if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &set, sizeof(set)) == -1)
		{
			close(fd);
			snprintf(last_error, sizeof last_error, "error setting sockopt to interface (%s)", strerror(errno));
			return -1;
		}

		if (bind(fd, bind_to, sizeof(*bind_to)) == -1)
		{
			close(fd);
			snprintf(last_error, sizeof last_error, "error binding to interface (%s)", strerror(errno));
			return -1;
		}
	}

	/* make fd nonblocking */
	if (set_fd_nonblocking(fd) == -1)
	{
		close(fd);
		return -1;
	}

	/* wait for connection */
	FD_ZERO(&wfds);
	FD_SET(fd, &wfds);

	to.tv_sec  = timeout / 1000;
	to.tv_usec = (timeout - (to.tv_sec * 1000)) * 1000;

	/* connect to peer */
#ifdef TCP_TFO
	if (*tfo)
	{
		rc = sendto(fd, msg, msg_len, MSG_FASTOPEN, ai -> ai_addr, ai -> ai_addrlen);
		
		if(rc == msg_len)
			*msg_accepted = 1;
		if(errno == 0)
			return fd;
		if(errno == ENOTSUP)
		{
			printf("TCP TFO Not Supported. Please check if \"/proc/sys/net/ipv4/tcp_fastopen\" is 1. Disabling TFO for now.\n");
			*tfo = 0;
		}
	}
			
	else
#endif
	{
		int rc = connect(fd, ai -> ai_addr, ai -> ai_addrlen);

		if (rc == 0)
		{
			/* connection made, return */
			return fd;
		}

		if (rc == -1)
		{
			// problem connecting
			if (errno != EINPROGRESS)
			{
				snprintf(last_error, sizeof last_error, "problem connecting to host: %s\n", strerror(errno));
				close(fd);
				return -1;
			}
		}
	}

	/* wait for connection */
	rc = select(fd + 1, NULL, &wfds, NULL, &to);
	if (rc == 0)
	{
		snprintf(last_error, sizeof last_error, "connect time out\n");
		close(fd);
		return RC_TIMEOUT;	/* timeout */
	}
	else if (rc == -1)
	{
		close(fd);

		if (errno == EINTR)
			return RC_CTRLC;/* ^C pressed */

		snprintf(last_error, sizeof last_error, "select() failed: %s\n", strerror(errno));

		return -1;	/* error */
	}
	else
	{
		int optval=0;
		socklen_t optvallen=sizeof(optval);

		/* see if the connect succeeded or failed */
		if (getsockopt(fd, SOL_SOCKET, SO_ERROR, &optval, &optvallen) == -1)
		{
			snprintf(last_error, sizeof last_error, "getsockopt failed (%s)\n", strerror(errno));
			close(fd);
			return -1;
		}

		/* no error? */
		if (optval == 0)
			return fd;

		/* don't ask */
		errno = optval;
	}

	close(fd);

	snprintf(last_error, sizeof last_error, "could not connect (%s)\n", strerror(errno));

	return -1;
}

int set_tcp_low_latency(int sock)
{
	int flag = 1;

	if (setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, (char *)&flag, sizeof(int)) < 0)
	{
		snprintf(last_error, sizeof last_error, "could not set TCP_NODELAY on socket (%s)\n", strerror(errno));
		return -1;
	}

	return 0;
}