* @brief Create and connect a new TCP/IP socket * * This function returns a working client TCP/IP socket. * * @param host The host the socket will be connected to (everything resolvable, * e.g. "::1", "8.8.8.8", "example.com") * @param service The host's port, either numeric or as service name ("http"). * @param proto_osi3 `LIBSOCKET_IPv4` or `LIBSOCKET_IPv6`. * @param flags Flags to be pa
| 155 | * @return A valid socket file descriptor. |
| 156 | */ |
| 157 | int create_inet_stream_socket(const char *host, const char *service, |
| 158 | char proto_osi3, int flags) { |
| 159 | int sfd, return_value; |
| 160 | struct addrinfo hint, *result, *result_check; |
| 161 | #ifdef VERBOSE |
| 162 | const char *errstring; |
| 163 | #endif |
| 164 | |
| 165 | if (host == NULL || service == NULL) return -1; |
| 166 | |
| 167 | memset(&hint, 0, sizeof hint); |
| 168 | |
| 169 | // set address family |
| 170 | switch (proto_osi3) { |
| 171 | case LIBSOCKET_IPv4: |
| 172 | hint.ai_family = AF_INET; |
| 173 | break; |
| 174 | case LIBSOCKET_IPv6: |
| 175 | hint.ai_family = AF_INET6; |
| 176 | break; |
| 177 | case LIBSOCKET_BOTH: |
| 178 | hint.ai_family = AF_UNSPEC; |
| 179 | break; |
| 180 | default: |
| 181 | return -1; |
| 182 | } |
| 183 | |
| 184 | // Transport protocol is TCP |
| 185 | hint.ai_socktype = SOCK_STREAM; |
| 186 | |
| 187 | if (0 != (return_value = getaddrinfo(host, service, &hint, &result))) { |
| 188 | #ifdef VERBOSE |
| 189 | errstring = gai_strerror(return_value); |
| 190 | debug_write(errstring); |
| 191 | #endif |
| 192 | return -1; |
| 193 | } |
| 194 | |
| 195 | // As described in "The Linux Programming Interface", Michael Kerrisk 2010, |
| 196 | // chapter 59.11 (p. 1220ff) |
| 197 | |
| 198 | for (result_check = result; result_check != NULL; |
| 199 | result_check = result_check->ai_next) // go through the linked list of |
| 200 | // struct addrinfo elements |
| 201 | { |
| 202 | sfd = socket(result_check->ai_family, result_check->ai_socktype | flags, |
| 203 | result_check->ai_protocol); |
| 204 | |
| 205 | if (sfd < 0) // Error!!! |
| 206 | continue; |
| 207 | |
| 208 | if (-1 != connect(sfd, result_check->ai_addr, |
| 209 | result_check->ai_addrlen)) // connected without error |
| 210 | break; |
| 211 | |
| 212 | close(sfd); |
| 213 | } |
| 214 |