1 /*
2 net_utilities.c
3 --------------
4 A bunch of useful functions that I keep using all the time.
5
6 Copyright (C) 2000 Eu-Jin Goh
7
8 This program is free software; you can redistribute it and/or
9 modify it under the terms of the GNU General Public License
10 as published by the Free Software Foundation; either version 2
11 of the License, or (at your option) any later version.
12
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
17
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
21 USA.
22 */
23
24 /* necessary header files and defines */
25
26 #include <stdio.h>
27
28 #include "net_utilities.h"
29 #include "general_utilities.h"
30
31 /* ------------- Networking Functions ------------- */
32
33 /*
34 Creates a ipv4 stream socket
35 */
36 int
utlnet_CreateIPV4StreamSocket()37 utlnet_CreateIPV4StreamSocket()
38 {
39 int fd;
40
41 /* set up the socket */
42 if((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
43 {
44 utl_HandleError("utlnet_CreateIPV4StreamSocket");
45 }
46
47 return fd;
48 }
49
50 /*
51 Set socket to be reusable.
52 Returns -1 on failure
53 */
54 int
utlnet_SetSocketReusable(int sock_fd)55 utlnet_SetSocketReusable(int sock_fd)
56 {
57 int sock_opt = 1;
58
59 /*
60 sets the socket so that it can be reused. this enables another
61 application to make use of the same socket
62 */
63 if(setsockopt(sock_fd, SOL_SOCKET,SO_REUSEADDR,
64 (void *)&sock_opt,sizeof(int)) < 0)
65 {
66 perror("utlnet_SetSocketReusable");
67 return UTL_FAILURE;
68 }
69 return UTL_SUCCESS;
70 }
71
72 /*
73 It first tries to convert it assuming that it is a dotted
74 decimal number and if that fails, it uses gethostbyname to convert it.
75
76 Returns -1 on resolve failure.
77 */
78 int
utlnet_SetIP(struct sockaddr_in * addr,const char * host_name)79 utlnet_SetIP(struct sockaddr_in *addr, const char *host_name)
80 {
81 unsigned long in_addr; /* Binary IP address */
82 struct hostent *hostent_ptr; /* used with gethostbyname() */
83
84 /*
85 First try to convert the host name as a dotted-decimal number.
86 Only if that fails we call gethostbyname().
87 */
88 if((in_addr = inet_addr(host_name)) != INADDR_NONE)
89 {
90 addr->sin_addr.s_addr = in_addr; /* conversion succeeded */
91 }
92 else
93 {
94 if ((hostent_ptr = gethostbyname(host_name)) == NULL)
95 {
96 fprintf(stderr, "utlnet_SetIP: %s", hstrerror(h_errno));
97 return UTL_FAILURE;
98 }
99
100 memcpy((char *) &(addr->sin_addr), (char *)hostent_ptr->h_addr,
101 hostent_ptr->h_length);
102 }
103
104 return UTL_SUCCESS;
105 }
106
107 struct hostent *
utlnet_GetHostName(struct sockaddr_in * addr)108 utlnet_GetHostName(struct sockaddr_in *addr)
109 {
110 return gethostbyaddr((char *)&(addr->sin_addr),sizeof(addr->sin_addr),
111 addr->sin_family);
112 }
113
114 /*
115 Set the port number in a socket addr struct
116 */
117 void
utlnet_SetPort(struct sockaddr_in * addr,const short port)118 utlnet_SetPort(struct sockaddr_in *addr, const short port)
119 {
120 addr->sin_port = htons(port);
121 }
122
123 /*
124 Set the protocol type in a socket addr struct
125 */
126 void
utlnet_SetIPV4Protocol(struct sockaddr_in * addr)127 utlnet_SetIPV4Protocol(struct sockaddr_in *addr)
128 {
129 addr->sin_family = AF_INET;
130 }
131
132 /*
133 sets the IP, port and protocol for a IPV4 connection.
134 returns -1 on failure
135 */
136 int
utlnet_InitIPV4ClientSockAddrStruct(struct sockaddr_in * addr,const short port,const char * host_name)137 utlnet_InitIPV4ClientSockAddrStruct(struct sockaddr_in *addr,
138 const short port,
139 const char *host_name)
140 {
141 memset( (char*) addr, 0, sizeof(*addr));
142 utlnet_SetPort(addr, port);
143 utlnet_SetIPV4Protocol(addr);
144
145 return utlnet_SetIP(addr, host_name);
146 }
147
148 /*
149 sets the port, protocol and server ip. the serverIP is typically
150 set to INADDR_ANY to allow kernel selection.
151 */
152 void
utlnet_InitIPV4ServerSockAddrStruct(struct sockaddr_in * addr,const short port,const unsigned int server_ip)153 utlnet_InitIPV4ServerSockAddrStruct(struct sockaddr_in *addr,
154 const short port,
155 const unsigned int server_ip)
156 {
157 memset( (char*) addr, 0, sizeof(*addr));
158 utlnet_SetPort(addr, port);
159 utlnet_SetIPV4Protocol(addr);
160 addr->sin_addr.s_addr = htonl(server_ip);
161 }
162
163 /*
164 Sets up the listening socket for the given port and IP address
165 in servAddr. Also sets the queue backlog and the socket option
166 if the port number needs to be reusable.
167 */
168 int
utlnet_InitIPV4ServerSocket(const int sock_fd,struct sockaddr_in * addr,int sock_queue_backlog,char reusable)169 utlnet_InitIPV4ServerSocket(const int sock_fd,
170 struct sockaddr_in *addr,
171 int sock_queue_backlog,
172 char reusable)
173 {
174 if(reusable && (utlnet_SetSocketReusable(sock_fd) == UTL_FAILURE))
175 {
176 exit(UTL_FAILURE);
177 }
178
179 if(bind(sock_fd,(struct sockaddr *)addr, sizeof(*addr)) < 0)
180 {
181 utl_HandleError("utlnet_InitIPV4ServerSocket");
182 }
183 listen(sock_fd, sock_queue_backlog);
184
185 return UTL_SUCCESS;
186 }
187
188 /*
189 Connect to a remote host using an IPV4 sockaddr.
190 Returns -1 on failure
191 */
192 int
utlnet_IPV4Connect(int sock_fd,struct sockaddr_in * to_addr)193 utlnet_IPV4Connect(int sock_fd, struct sockaddr_in *to_addr)
194 {
195 if(connect(sock_fd,(struct sockaddr *) to_addr,
196 sizeof(struct sockaddr)) < 0)
197 {
198 return UTL_FAILURE;
199 }
200
201 return UTL_SUCCESS;
202 }
203
204 int
utlnet_Accept(const int sock_fd,struct sockaddr_in * from_addr)205 utlnet_Accept(const int sock_fd, struct sockaddr_in *from_addr)
206 {
207 int conn_fd;
208 socklen_t size;
209
210 size = sizeof(*from_addr);
211 memset( (char *) from_addr, 0, size);
212
213 if((conn_fd = accept(sock_fd,(struct sockaddr *) from_addr, &size)) < 0)
214 {
215 utl_HandleError("utlnet_Accept");
216 }
217 return conn_fd;
218 }
219
220 /* Write/Read to the socket.
221 Returns bytes sent/read or -1 on error */
222 int
utlnet_WriteToSocket(int sock_fd,char * buffer,int length)223 utlnet_WriteToSocket(int sock_fd, char *buffer, int length)
224 {
225 int bytes_sent;
226
227 if((bytes_sent = write(sock_fd, buffer, length)) < length)
228 {
229 perror("utlnet_WriteToSocket");
230 return UTL_FAILURE;
231 }
232 return bytes_sent;
233 }
234
235 int
utlnet_ReadFromSocket(int sock_fd,char * buffer,int length)236 utlnet_ReadFromSocket(int sock_fd, char *buffer, int length)
237 {
238 int bytes_read;
239
240 if((bytes_read = read(sock_fd, buffer, length)) < 0)
241 {
242 perror("utlnet_ReadFromSocket");
243 return UTL_FAILURE;
244 }
245 return bytes_read;
246 }
247
248 int
utlnet_WritenBytesToSocket(int sock_fd,char * buffer,int n_bytes)249 utlnet_WritenBytesToSocket(int sock_fd, char *buffer, int n_bytes)
250 {
251 int bytes_sent;
252 int total_sent = 0;
253
254 while((bytes_sent =
255 write(sock_fd, buffer + total_sent, n_bytes - total_sent)) > 0)
256 {
257 total_sent += bytes_sent;
258 if(total_sent >= n_bytes)
259 {
260 break;
261 }
262 }
263
264 if(total_sent < n_bytes)
265 {
266 /* this would be the error code returned by write */
267 return bytes_sent;
268 }
269
270 return total_sent;
271 }
272
273 int
utlnet_ReadnBytesFromSocket(int sock_fd,char * buffer,int n_bytes)274 utlnet_ReadnBytesFromSocket(int sock_fd, char *buffer, int n_bytes)
275 {
276 int bytes_read;
277 int total_read = 0;
278
279 while((bytes_read =
280 read(sock_fd, buffer + total_read, n_bytes - total_read)) > 0)
281 {
282 total_read += bytes_read;
283 if(total_read >= n_bytes)
284 {
285 break;
286 }
287 }
288
289 if(total_read < n_bytes)
290 {
291 /* this would be the error code returned by read */
292 return bytes_read;
293 }
294
295 return total_read;
296 }
297
298 int
utlnet_PeekAtnBytesFromSocket(int sock_fd,char * buffer,int n_bytes)299 utlnet_PeekAtnBytesFromSocket(int sock_fd, char *buffer, int n_bytes)
300 {
301 return recv(sock_fd, buffer, n_bytes, MSG_PEEK);
302 }
303