tcpConnect.c

C

Public Domain

Create a TCP connection in POSIX C

Download (right click, save as, rename as appropriate)

Embed

 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
#include <string.h> /* strerror */
#include <errno.h>
#include <unistd.h>  /* close */
#include <sys/socket.h>
#include <netdb.h>
#include <netinet/in.h>  /* IPPROTO_TCP */

/* ``tcpConnect(host, port, errFunc, errMsg)'' looks up the IP addresses for
 * host `host' (including IPv6 and any other address families if your system
 * supports them) and the port that provides service `port' (e.g., "http" or
 * "gopher"; a number as a decimal string is also acceptable).  It then
 * attempts to create a TCP connection to the given port of each IP address in
 * turn, and, if successful, returns a socket descriptor for the new
 * connection.  If any part of the process is unsuccessful, -1 is returned.  If
 * an error occurs and they are non-NULL, *errFunc and *errMsg will hold 
 * pointers to static strings giving the name of the failed function and an
 * error message, respectively.  If tcpConnect() returns successfully, the
 * values of *errFunc and *errMsg are indeterminate.
 *
 * Note that tcpConnect() relies upon the somewhat modern yet incredibly 
 * useful getaddrinfo(3).  If your system does not have this function, feel
 * free to cry in the corner.
 */

int tcpConnect(const char* host, const char* port, const char** errFunc,
 const char** errMsg) {
 static struct addrinfo hints = {.ai_family = AF_UNSPEC, .ai_socktype
  = SOCK_STREAM, .ai_protocol = IPPROTO_TCP};
 struct addrinfo* addrs;
 int retval = getaddrinfo(host, port, &hints, &addrs);
 if (retval != 0) {
  if (errFunc != NULL) *errFunc = "getaddrinfo";
  if (errMsg != NULL) *errMsg = gai_strerror(retval);
  return -1;
 }
 int sock = -1;
 for (struct addrinfo* res = addrs; res != NULL; res = res->ai_next) {
  sock = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
  if (sock < 0) {
   if (errFunc != NULL) *errFunc = "socket";
   if (errMsg != NULL) *errMsg = strerror(errno);
   continue;
  }
  if (connect(sock, res->ai_addr, res->ai_addrlen) < 0) {
   close(sock);
   sock = -1;
   if (errFunc != NULL) *errFunc = "connect";
   if (errMsg != NULL) *errMsg = strerror(errno);
   continue;
  }
  break;
 }
 /* Every specification of getaddrinfo() I've read says that addr points to at
  * least one struct addrinfo, so if an implementation assigns it a NULL value,
  * causing sock to be -1 with *errMsg == NULL, that's not my fault. */
 freeaddrinfo(addrs);
 return sock;
}