int glb_socket_create (const struct sockaddr_in* addr) { int sock; // size_t buf_size = 1024; /* Create the socket. */ sock = socket (PF_INET, SOCK_STREAM, 0); if (sock < 0) { glb_log_error ("Failed to create listening socket: %d (%s)", errno, strerror (errno)); return -errno; } #if 0 /* probably a good place to specify some socket options */ if (setsockopt (sock, SOL_SOCKET, SO_RCVBUF, &buf_size, sizeof(buf_size))) { glb_log_error ("setsockopt() failed: %d (%s)", -errno, strerror(errno)); close (sock); return -errno; } if (setsockopt (sock, SOL_SOCKET, SO_SNDBUF, &buf_size, sizeof(buf_size))) { glb_log_error ("setsockopt() failed: %d (%s)", -errno, strerror(errno)); close (sock); return -errno; } #endif /* Give the socket a name. */ if (bind (sock, (struct sockaddr *) addr, sizeof (*addr)) < 0) { glb_log_error ("Failed to bind listening socket: %d (%s)", errno, strerror (errno)); close (sock); return -errno; } return sock; }
// returns socket number or negative error code int glb_router_connect (glb_router_t* router, glb_sockaddr_t* dst_addr) { int sock, ret; // prepare a socket sock = glb_socket_create (&router->sock_out); if (sock < 0) { glb_log_error ("glb_socket_create() failed"); return sock; } // attmept to connect until we run out of destinations ret = router_connect_dst (router, sock, dst_addr); // avoid socket leak if (ret < 0) { glb_log_error ("router_connect_dst() failed"); close (sock); sock = ret; } return sock; }
// Initialize glb_sockaddr_t struct long glb_socket_addr_init (glb_sockaddr_t* addr, const char* hostname, uint16_t port) { struct hostent *host; host = gethostbyname (hostname); if (host == NULL) { glb_log_error ("Unknown host %s.\n", hostname); return -EINVAL; } addr->sin_addr = *(struct in_addr *) host->h_addr; addr->sin_port = htons (port); addr->sin_family = AF_INET; return 0; }
// parses addr:port:weight string, stores in dst // returns number of parsed fields or negative error code long glb_dst_parse (glb_dst_t* dst, const char* s, uint16_t default_port) { const char* token; char* endptr; char addr_str[dst_ip_len_max + 1] = { 0, }; ptrdiff_t addr_len; ulong port = default_port; long ret = 0; dst->weight = dst_default_weight; // parse IP address endptr = strchr (s, dst_separator); if (NULL != endptr) addr_len = endptr - s; else addr_len = strlen (s); if (addr_len > dst_ip_len_max) { glb_log_error ("Host address too long: %s\n", s); return -EINVAL; } strncpy (addr_str, s, addr_len); // this now contains only host address ret = 1; if (NULL == endptr) // string is over goto end; // parse port assert (*endptr == dst_separator); token = endptr + 1; port = strtoul (token, &endptr, 10); if (*endptr != dst_separator && *endptr != '\0') { glb_log_error ("Port field doesn't consist only of numbers"); return -EINVAL; } if (port > dst_port_max) { // value of 0 means no setting, don't check glb_log_error ("Port value exceeds maximum port number"); return -EINVAL; } ret = 2; if (*endptr == '\0') // string is over goto end; // parse weight assert (*endptr == dst_separator); token = endptr + 1; dst->weight = strtod (token, &endptr); if (*endptr != '\0') { glb_log_error ("Weight field doesn't consist only of numbers"); return -EINVAL; } ret = 3; end: if (glb_sockaddr_init (&dst->addr, addr_str, port)) { glb_log_error ("%s", strerror (EINVAL)); return -EINVAL; } return ret; }