File: tcp.c

package info (click to toggle)
httping 1.2.6-1
  • links: PTS
  • area: main
  • in suites: lenny
  • size: 160 kB
  • ctags: 57
  • sloc: ansic: 1,329; makefile: 63
file content (129 lines) | stat: -rw-r--r-- 3,091 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
/* The GPL applies to this program.
  In addition, as a special exception, the copyright holders give
  permission to link the code of portions of this program with the
  OpenSSL library under certain conditions as described in each
  individual source file, and distribute linked combinations
  including the two.
  You must obey the GNU General Public License in all respects
  for all of the code used other than OpenSSL.  If you modify
  file(s) with this exception, you may extend this exception to your
  version of the file(s), but you are not obligated to do so.  If you
  do not wish to do so, delete this exception statement from your
  version.  If you delete this exception statement from all source
  files in the program, then also delete it here.
*/

#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"

extern char last_error[];

int connect_to(struct sockaddr *bind_to, struct sockaddr_in *addr, int portnr, int timeout)
{
	int     fd;
	int 	rc;
	struct timeval to;
	fd_set wfds;

	/* create socket */
	fd = socket(AF_INET, SOCK_STREAM, 0);
	if (fd == -1)
	{
		snprintf(last_error, ERROR_BUFFER_SIZE, "problem creating socket (%s)", strerror(errno));
		return -1;
	}

	/* go through a specific interface? */
	if (bind_to)
	{
		if (bind(fd, bind_to, sizeof(*bind_to)) == -1)
		{
			snprintf(last_error, ERROR_BUFFER_SIZE, "error binding to interface (%s)", strerror(errno));
			return -1;
		}
	}

	/* initialize address structure */
	addr -> sin_port   = htons(portnr);

	/* make fd nonblocking */
	if (set_fd_nonblocking(fd) == -1)
		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 */
	if (connect(fd, (struct sockaddr *)addr, sizeof(struct sockaddr)) == 0)
	{
		/* connection made, return */
		return fd;
	}

	/* wait for connection */
	rc = select(fd + 1, NULL, &wfds, NULL, &to);
	if (rc == 0)
		return -2;	/* timeout */
	else if (rc == -1)
	{
		if (errno == EINTR)
			return -3;	/* ^C pressed */
		else
			return -1;	/* error */
	}
	else
	{
		int optval=0;
		int optvallen=sizeof(optval);

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

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

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

	close(fd);

	snprintf(last_error, ERROR_BUFFER_SIZE, "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, ERROR_BUFFER_SIZE, "could not set TCP_NODELAY on socket (%s)\n", strerror(errno));
		return -1;
	}

	return 0;
}