tcpsocket.c: disable Nagle's algorithm for sent commands
[cvsps:cvsps.git] / tcpsocket.c
1 /*
2  * Copyright 2001, 2002, 2003 David Mansfield and Cobite, Inc.
3  * See COPYING file for license information 
4  */
5
6 #ifdef SOLARIS
7 #include <strings.h>
8 #else
9 #include <string.h>
10 #endif
11
12 #ifdef WIN32
13 #include <winsock2.h>
14 #else /* not windows */
15 #include <sys/types.h>
16 #include <sys/socket.h>
17 #include <netinet/in.h>
18 #include <netinet/tcp.h>
19 #include <arpa/inet.h>
20 #include <netdb.h>
21 #include <errno.h>
22
23 #ifdef SOLARIS
24 #include <netinet/tcp.h>
25 #endif
26
27 #endif /* if windows */
28
29 #include "tcpsocket.h"
30 #include "debug.h"
31 #ifdef WIN32
32 #include "win32fd.h"
33 #endif
34
35 int
36 tcp_create_socket(int reuse_addr)
37 {
38   int retval;
39   int yes = 1;
40
41   if ((retval = socket(AF_INET, SOCK_STREAM, 0)) < 0)
42   {
43     debug(DEBUG_ERROR, "tcp: can't create socket");
44   }
45
46   if (reuse_addr)
47   {
48     setsockopt( retval, SOL_SOCKET, SO_REUSEADDR, (char *)&yes, sizeof(int));
49   }
50
51   yes = 1;
52   setsockopt (retval,         /* socket affected */
53               IPPROTO_TCP,    /* set option at TCP level */
54               TCP_NODELAY,    /* name of option */
55               (char *) &yes,  /* the cast is historical
56                                  cruft */
57               sizeof(int));    /* length of option value */
58
59   debug(DEBUG_TCP, "tcp: socket created");
60 #ifdef WIN32
61   return get_fd(retval, WIN32_SOCKET);
62 #else
63   return retval;
64 #endif
65 }
66
67 int
68 tcp_bind_and_listen(int sockfd, unsigned short tcp_port)
69 {
70   struct sockaddr_in addr;
71
72   memset((char *) &addr, 0, sizeof(struct sockaddr_in));
73   addr.sin_family      = AF_INET;
74   addr.sin_addr.s_addr = htonl(INADDR_ANY);
75   addr.sin_port        = htons(tcp_port);
76
77 #ifdef WIN32
78   sockfd = win32_file_table[sockfd].win32id;
79 #endif
80
81   if (bind(sockfd, (struct sockaddr *)&addr, sizeof(addr)) < 0)
82   {
83     debug(DEBUG_ERROR, "tcp: can't bind to socket");
84     return -1;
85   }
86
87
88   if (listen(sockfd, LISTEN_QUEUE_SIZE) < 0)
89   {
90     debug(DEBUG_ERROR, "tcp: can't listen on socket");
91     return -1;
92   }
93
94   debug(DEBUG_TCP, "tcp: socket bound and listening");
95
96   return 0;
97 }
98
99 int
100 tcp_accept_connection(int sockfd)
101 {
102   struct sockaddr_in remaddr;
103   socklen_t addrlen;
104   int retval;
105
106 #ifdef WIN32
107   sockfd = win32_file_table[sockfd].win32id;
108 #endif
109
110   addrlen = sizeof(struct sockaddr_in);
111
112 #ifdef WIN32
113   if ((retval = accept(sockfd, (struct sockaddr *) &remaddr, &addrlen)) == INVALID_SOCKET)
114   {
115           debug(DEBUG_APPERROR, "tcp: error accepting connection");
116           return -1;
117   }
118 #else
119   if ((retval = accept(sockfd, (struct sockaddr *) &remaddr, &addrlen)) < 0)
120   {
121     if (errno != EINTR )
122       debug(DEBUG_ERROR, "tcp: error accepting connection");
123
124     return -1;
125   }
126 #endif
127
128   debug(DEBUG_TCP, "tcp: got connection (fd=%d)", retval);
129
130   return retval;
131 }
132
133 unsigned int
134 tcp_get_client_ip(int fd)
135 {
136   struct sockaddr_in remaddr;
137   socklen_t addrlen;
138   int retval;
139   unsigned int saddr;
140
141 #ifdef WIN32
142   fd = win32_file_table[fd].win32id;
143 #endif
144
145   addrlen = sizeof(struct sockaddr_in);
146
147   if ((retval = getpeername(fd, (struct sockaddr *) &remaddr, &addrlen)) < 0)
148   {
149     debug(DEBUG_ERROR, "tcp: error getting remote's ip address");
150     return 0;
151   }
152
153   saddr = ntohl(remaddr.sin_addr.s_addr);
154
155   return saddr;
156 }
157
158 int
159 tcp_connect(int sockfd, const char *rem_addr, unsigned short port)
160 {
161   struct sockaddr_in addr;
162   int addrlen;
163   long ipno;
164
165 #ifdef WIN32
166   sockfd = win32_file_table[sockfd].win32id;
167 #endif
168
169   if ( convert_address(&ipno , rem_addr) < 0 )
170   {
171     return -1;
172   }
173
174   addrlen = sizeof(struct sockaddr_in);
175
176   memset((char *) &addr, 0, sizeof(struct sockaddr_in));
177   addr.sin_family      = AF_INET;
178   addr.sin_addr.s_addr = ipno;
179   addr.sin_port        = htons(port);
180
181   if (connect(sockfd, (struct sockaddr *)&addr, addrlen) < 0)
182   {
183     debug(DEBUG_ERROR, "connect error");
184     return -1;
185   }
186   
187   debug(DEBUG_STATUS, "tcp: connection established on port %d", port);
188   return 0;
189 }
190
191 int
192 convert_address(long *dest, const char *addr_str)
193 {
194 #ifdef __linux__
195   struct in_addr ip;
196 #endif
197   int retval = 0;
198   char errstr[256];
199   
200   /* first try converting "numbers and dots" notation */
201 #ifdef __linux__
202   if ( inet_aton(addr_str, &ip) )
203   {
204     memcpy(dest, &ip.s_addr, sizeof(ip.s_addr));
205   }
206 #else
207   if ( (*dest = inet_addr(addr_str)) != INADDR_NONE)
208   {
209     /* nothing */
210   }
211 #endif
212   else   /* if it fails, do a gethostbyname() */
213   {
214     struct hostent *host;
215     if ((host = gethostbyname(addr_str)) == NULL)
216     {
217       switch(h_errno)
218       {
219       case HOST_NOT_FOUND:
220         strcpy(errstr, "HOST_NOT_FOUND");
221         break;
222
223       case NO_ADDRESS:
224         strcpy(errstr, "NO_ADDRESS");
225         break;
226
227       case NO_RECOVERY:
228         strcpy(errstr, "NO_RECOVERY");
229         break;
230
231       case TRY_AGAIN:
232         strcpy(errstr, "TRY_AGAIN");
233         break;
234       }
235       
236       debug(DEBUG_ERROR, "gethostbyname failed for %s: %s", addr_str, errstr);
237
238       retval = -1;
239     }
240     
241     memcpy(dest, host->h_addr_list[0], sizeof(unsigned long));
242   }
243   
244   
245   return retval;
246 }
247
248 int tcp_get_local_address(int sockfd, unsigned int *ip, unsigned short *port)
249 {
250     struct sockaddr_in addr;
251     socklen_t addrlen = sizeof(struct sockaddr_in);
252   
253     if(getsockname(sockfd, (struct sockaddr *)&addr, &addrlen) < 0)
254     {
255         debug(DEBUG_SYSERROR, "getsockname failed" );  
256         return -1;
257     }
258
259     *ip = ntohl( addr.sin_addr.s_addr );
260     *port = ntohs( addr.sin_port );
261   
262     return 0;
263 }