qLibc
qsocket.c
Go to the documentation of this file.
1/******************************************************************************
2 * qLibc
3 *
4 * Copyright (c) 2010-2015 Seungyoung Kim.
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions are met:
9 *
10 * 1. Redistributions of source code must retain the above copyright notice,
11 * this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright notice,
13 * this list of conditions and the following disclaimer in the documentation
14 * and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
20 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26 * POSSIBILITY OF SUCH DAMAGE.
27 *****************************************************************************/
28
29/**
30 * @file qsocket.c Socket dandling APIs.
31 */
32
33#ifndef _WIN32
34
35#include <stdio.h>
36#include <stdlib.h>
37#include <stdbool.h>
38#include <string.h>
39#include <stdarg.h>
40#include <netdb.h>
41#include <fcntl.h>
42#include <unistd.h>
43#include <errno.h>
44#include <arpa/inet.h>
45#include <netinet/in.h>
46#include <sys/socket.h>
47#include "qinternal.h"
48#include "utilities/qio.h"
49#include "utilities/qstring.h"
50#include "utilities/qsocket.h"
51
52/**
53 * Create a TCP socket for the remote host and port.
54 *
55 * @param hostname remote hostname
56 * @param port remote port
57 * @param timeoutms wait timeout milliseconds. if set to negative value,
58 * wait indefinitely.
59 *
60 * @return the new socket descriptor, or
61 * -1 in case of invalid hostname,
62 * -2 in case of socket creation failure,
63 * -3 in case of connection failure.
64 */
65int qsocket_open(const char *hostname, int port, int timeoutms) {
66 /* host conversion */
67 struct sockaddr_in addr;
68 if (qsocket_get_addr(&addr, hostname, port) == false) {
69 return -1; /* invalid hostname */
70 }
71
72 /* create new socket */
73 int sockfd;
74 if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
75 return -2; /* sockfd creation fail */
76 }
77
78 /* set to non-block socket*/
79 int flags = fcntl(sockfd, F_GETFL, 0);
80 if (timeoutms >= 0)
81 fcntl(sockfd, F_SETFL, flags | O_NONBLOCK);
82
83 /* try to connect */
84 int status = connect(sockfd, (struct sockaddr *) &addr, sizeof(addr));
85 if (status < 0
86 && (errno != EINPROGRESS
87 || qio_wait_writable(sockfd, timeoutms) <= 0)) {
88 close(sockfd);
89 return -3; /* connection failed */
90 }
91
92 /* restore to block socket */
93 if (timeoutms >= 0)
94 fcntl(sockfd, F_SETFL, flags);
95
96 return sockfd;
97}
98
99/**
100 * Close socket.
101 *
102 * @param sockfd socket descriptor
103 * @param timeoutms if timeoutms >= 0, shut down write connection first then
104 * wait and throw out input stream data. set to -1 to close
105 * socket immediately.
106 *
107 * @return true on success, or false if an error occurred.
108 */
109bool qsocket_close(int sockfd, int timeoutms) {
110 // close connection
111 if (timeoutms >= 0 && shutdown(sockfd, SHUT_WR) == 0) {
112 char buf[1024];
113 while (true) {
114 ssize_t read = qio_read(sockfd, buf, sizeof(buf), timeoutms);
115 DEBUG("Throw %zu bytes from dummy input stream.", read);
116 if (read <= 0)
117 break;
118 }
119 }
120
121 if (close(sockfd) == 0)
122 return true;
123 return false;
124}
125
126/**
127 * Convert hostname to sockaddr_in structure.
128 *
129 * @param addr sockaddr_in structure pointer
130 * @param hostname IP string address or hostname
131 * @param port port number
132 *
133 * @return true if successful, otherwise returns false.
134 */
135bool qsocket_get_addr(struct sockaddr_in *addr, const char *hostname, int port) {
136 /* here we assume that the hostname argument contains ip address */
137 memset((void *) addr, 0, sizeof(struct sockaddr_in));
138 if (!inet_aton(hostname, &addr->sin_addr)) { /* fail then try another way */
139 struct hostent *hp;
140 if ((hp = gethostbyname(hostname)) == 0)
141 return false;
142 memcpy(&addr->sin_addr, hp->h_addr, sizeof(struct in_addr));
143 }
144 addr->sin_family = AF_INET;
145 addr->sin_port = htons(port);
146
147 return true;
148}
149
150/**
151 * Return local IP address.
152 *
153 * @return malloced string pointer which contains IP address string if
154 * successful, otherwise returns NULL
155 */
156char *qsocket_get_localaddr(char *buf, size_t bufsize) {
157 char hostname[63 + 1];
158 if (gethostname(hostname, sizeof(hostname)) != 0)
159 return NULL;
160
161 struct hostent *hostentry = gethostbyname(hostname);
162 if (hostentry == NULL)
163 return NULL;
164
165 char *localip = inet_ntoa(*(struct in_addr *) *hostentry->h_addr_list);
166 if (localip == NULL)
167 return NULL;
168
169 qstrcpy(buf, bufsize, localip);
170 return buf;
171}
172
173#endif /* _WIN32 */
ssize_t qio_read(int fd, void *buf, size_t nbytes, int timeoutms)
Read from a file descriptor.
Definition qio.c:118
int qio_wait_writable(int fd, int timeoutms)
Test & wait until the file descriptor is ready for writing.
Definition qio.c:87
bool qsocket_get_addr(struct sockaddr_in *addr, const char *hostname, int port)
Convert hostname to sockaddr_in structure.
Definition qsocket.c:135
bool qsocket_close(int sockfd, int timeoutms)
Close socket.
Definition qsocket.c:109
int qsocket_open(const char *hostname, int port, int timeoutms)
Create a TCP socket for the remote host and port.
Definition qsocket.c:65
char * qsocket_get_localaddr(char *buf, size_t bufsize)
Return local IP address.
Definition qsocket.c:156
char * qstrcpy(char *dst, size_t size, const char *src)
Copy src string to dst.
Definition qstring.c:325