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  */
65 int 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  */
109 bool 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  if (read <= 0)
116  break;DEBUG("Throw %zu bytes from dummy input stream.", read);
117  }
118  }
119 
120  if (close(sockfd) == 0)
121  return true;
122  return false;
123 }
124 
125 /**
126  * Convert hostname to sockaddr_in structure.
127  *
128  * @param addr sockaddr_in structure pointer
129  * @param hostname IP string address or hostname
130  * @param port port number
131  *
132  * @return true if successful, otherwise returns false.
133  */
134 bool qsocket_get_addr(struct sockaddr_in *addr, const char *hostname, int port) {
135  /* here we assume that the hostname argument contains ip address */
136  memset((void *) addr, 0, sizeof(struct sockaddr_in));
137  if (!inet_aton(hostname, &addr->sin_addr)) { /* fail then try another way */
138  struct hostent *hp;
139  if ((hp = gethostbyname(hostname)) == 0)
140  return false;
141  memcpy(&addr->sin_addr, hp->h_addr, sizeof(struct in_addr));
142  }
143  addr->sin_family = AF_INET;
144  addr->sin_port = htons(port);
145 
146  return true;
147 }
148 
149 /**
150  * Return local IP address.
151  *
152  * @return malloced string pointer which contains IP address string if
153  * successful, otherwise returns NULL
154  */
155 char *qsocket_get_localaddr(char *buf, size_t bufsize) {
156  char hostname[63 + 1];
157  if (gethostname(hostname, sizeof(hostname)) != 0)
158  return NULL;
159 
160  struct hostent *hostentry = gethostbyname(hostname);
161  if (hostentry == NULL)
162  return NULL;
163 
164  char *localip = inet_ntoa(*(struct in_addr *) *hostentry->h_addr_list);
165  if (localip == NULL)
166  return NULL;
167 
168  qstrcpy(buf, bufsize, localip);
169  return buf;
170 }
171 
172 #endif /* _WIN32 */
bool qsocket_get_addr(struct sockaddr_in *addr, const char *hostname, int port)
Convert hostname to sockaddr_in structure.
Definition: qsocket.c:134
char * qsocket_get_localaddr(char *buf, size_t bufsize)
Return local IP address.
Definition: qsocket.c:155
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 * qstrcpy(char *dst, size_t size, const char *src)
Copy src string to dst.
Definition: qstring.c:320
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_close(int sockfd, int timeoutms)
Close socket.
Definition: qsocket.c:109