]>
Commit | Line | Data |
---|---|---|
85ce9d3e | 1 | /* |
2 | * This file is provided for use with the unix-socket-faq. It is public | |
3 | * domain, and may be copied freely. There is no copyright on it. The | |
4 | * original work was by Vic Metcalfe (vic@brutus.tlug.org), and any | |
5 | * modifications made to that work were made with the understanding that | |
6 | * the finished work would be in the public domain. | |
7 | * | |
8 | * If you have found a bug, please pass it on to me at the above address | |
9 | * acknowledging that there will be no copyright on your work. | |
10 | * | |
11 | * The most recent version of this file, and the unix-socket-faq can be | |
12 | * found at http://www.interlog.com/~vic/sock-faq/. | |
13 | */ | |
14 | ||
15 | #include "sockhelp.h" | |
9f8c2acc | 16 | #include "extern.h" |
85ce9d3e | 17 | |
18 | /* Take a service name, and a service type, and return a port number. If | |
19 | the | |
20 | service name is not found, it tries it as a decimal number. The number | |
21 | returned is byte ordered for the network. */ | |
69db6f3f | 22 | int atoport(const string &service, const string &proto) |
85ce9d3e | 23 | { |
24 | int port; | |
25 | long int lport; | |
85ce9d3e | 26 | char *errpos; |
27 | ||
69db6f3f | 28 | lport = strtol(service.c_str(),&errpos,0); |
85ce9d3e | 29 | if ( (errpos[0] != 0) || (lport < 1) || (lport > 65535) ) |
30 | return -1; /* Invalid port address */ | |
eb7608de | 31 | |
85ce9d3e | 32 | port = htons(lport); |
eb7608de | 33 | |
85ce9d3e | 34 | return port; |
35 | } | |
36 | ||
37 | /* Converts ascii text to in_addr struct. NULL is returned if the address | |
38 | can not be found. */ | |
39 | struct in_addr *atoaddr(char *address) | |
40 | { | |
41 | struct hostent *host; | |
85ce9d3e | 42 | |
85ce9d3e | 43 | host = gethostbyname(address); |
44 | if (host != NULL) { | |
45 | return (struct in_addr *) *host->h_addr_list; | |
46 | } | |
47 | return NULL; | |
48 | } | |
49 | ||
50 | /* This function listens on a port, and returns connections. It forks | |
51 | returns off internally, so your main function doesn't have to worry | |
52 | about that. This can be confusing if you don't know what is going on. | |
53 | The function will create a new process for every incoming connection, | |
54 | so in the listening process, it will never return. Only when a | |
55 | connection | |
56 | comes in, and we create a new process for it will the function return. | |
57 | This means that your code that calls it should _not_ loop. | |
58 | ||
59 | The parameters are as follows: | |
60 | socket_type: SOCK_STREAM or SOCK_DGRAM (TCP or UDP sockets) | |
61 | port: The port to listen on. Remember that ports < 1024 are | |
62 | reserved for the root user. Must be passed in network byte | |
63 | order (see "man htons"). | |
64 | listener: This is a pointer to a variable for holding the file | |
65 | descriptor of the socket which is being used to listen. It | |
66 | is provided so that you can write a signal handler to close | |
67 | it in the event of program termination. If you aren't interested, | |
68 | just pass NULL. Note that all modern unixes will close file | |
69 | descriptors for you on exit, so this is not required. */ | |
70 | int get_connection(int socket_type, u_short port, int *listener) | |
71 | { | |
72 | struct sockaddr_in address; | |
73 | int listening_socket; | |
74 | int connected_socket = -1; | |
75 | int new_process; | |
76 | int reuse_addr = 1; | |
77 | ||
78 | /* Setup internet address information. | |
79 | This is used with the bind() call */ | |
80 | memset((char *) &address, 0, sizeof(address)); | |
81 | address.sin_family = AF_INET; | |
82 | address.sin_port = port; | |
83 | address.sin_addr.s_addr = htonl(INADDR_ANY); | |
84 | ||
85 | listening_socket = socket(AF_INET, socket_type, 0); | |
86 | if (listening_socket < 0) { | |
87 | perror("socket"); | |
88 | exit(EXIT_FAILURE); | |
89 | } | |
90 | ||
91 | if (listener != NULL) | |
92 | *listener = listening_socket; | |
93 | ||
94 | setsockopt(listening_socket, SOL_SOCKET, SO_REUSEADDR, &reuse_addr, | |
95 | sizeof(reuse_addr)); | |
96 | ||
97 | if (bind(listening_socket, (struct sockaddr *) &address, | |
98 | sizeof(address)) < 0) { | |
99 | perror("bind"); | |
100 | close(listening_socket); | |
101 | exit(EXIT_FAILURE); | |
102 | } | |
103 | ||
104 | if (socket_type == SOCK_STREAM) { | |
105 | listen(listening_socket, 5); /* Queue up to five connections before | |
106 | having them automatically rejected. */ | |
107 | ||
108 | while(connected_socket < 0) { | |
109 | connected_socket = accept(listening_socket, NULL, NULL); | |
110 | if (connected_socket < 0) { | |
111 | /* Either a real error occured, or blocking was interrupted for | |
112 | some reason. Only abort execution if a real error occured. */ | |
113 | if (errno != EINTR) { | |
114 | perror("accept"); | |
115 | close(listening_socket); | |
116 | exit(EXIT_FAILURE); | |
117 | } else { | |
118 | continue; /* don't fork - do the accept again */ | |
119 | } | |
120 | } | |
121 | ||
122 | new_process = fork(); | |
123 | if (new_process < 0) { | |
124 | perror("fork"); | |
125 | close(connected_socket); | |
126 | connected_socket = -1; | |
127 | } | |
128 | else { /* We have a new process... */ | |
129 | if (new_process == 0) { | |
130 | /* This is the new process. */ | |
131 | close(listening_socket); /* Close our copy of this socket */ | |
132 | if (listener != NULL) | |
133 | *listener = -1; /* Closed in this process. We are not | |
134 | responsible for it. */ | |
135 | } | |
136 | else { | |
137 | /* This is the main loop. Close copy of connected socket, and | |
138 | continue loop. */ | |
139 | close(connected_socket); | |
140 | connected_socket = -1; | |
141 | } | |
142 | } | |
143 | } | |
144 | return connected_socket; | |
145 | } | |
146 | else | |
147 | return listening_socket; | |
148 | } | |
285f72cf | 149 | #if !HAVE_GETHOSTBYNAME |
85ce9d3e | 150 | |
285f72cf | 151 | /* Translate an IP dotted-quad address to a 4-byte character string. |
152 | * Return NULL if the given string is not in dotted-quad format. | |
153 | */ | |
154 | ||
155 | static char *pack_ip(const char *ipaddr) | |
156 | { | |
157 | static char ipbuf[4]; | |
158 | int tmp[4], i; | |
159 | ||
160 | if (sscanf(ipaddr, "%d.%d.%d.%d", &tmp[0], &tmp[1], &tmp[2], &tmp[3]) | |
161 | != 4) | |
162 | return NULL; | |
163 | for (i = 0; i < 4; i++) { | |
164 | if (tmp[i] < 0 || tmp[i] > 255) | |
165 | return NULL; | |
166 | ipbuf[i] = tmp[i]; | |
167 | } | |
168 | return ipbuf; | |
169 | } | |
170 | ||
171 | #endif | |
172 | ||
173 | /*************************************************************************/ | |
174 | ||
175 | /*************************************************************************/ | |
176 | ||
177 | /* lhost/lport specify the local side of the connection. If they are not | |
178 | * given (lhost==NULL, lport==0), then they are left free to vary. | |
179 | */ | |
180 | ||
181 | int conn(const char *host, int port, const char *lhost, int lport) | |
182 | { | |
183 | #if HAVE_GETHOSTBYNAME | |
184 | struct hostent *hp; | |
185 | #else | |
186 | char *addr; | |
187 | #endif | |
188 | struct sockaddr_in sa, lsa; | |
189 | int sock; | |
190 | ||
191 | memset(&lsa, 0, sizeof(lsa)); | |
192 | if (lhost) | |
193 | { | |
194 | #if HAVE_GETHOSTBYNAME | |
195 | if ((hp = gethostbyname(lhost)) != NULL) | |
196 | { | |
197 | memcpy((char *) &lsa.sin_addr, hp->h_addr, hp->h_length); | |
198 | lsa.sin_family = hp->h_addrtype; | |
199 | #else | |
200 | if (addr = pack_ip(lhost)) | |
201 | { | |
202 | memcpy((char *) &lsa.sin_addr, addr, 4); | |
203 | lsa.sin_family = AF_INET; | |
204 | #endif | |
205 | } | |
206 | else | |
207 | { | |
208 | lhost = NULL; | |
209 | } | |
210 | } | |
211 | if (lport) | |
212 | { | |
213 | lsa.sin_port = htons((unsigned short) lport); | |
214 | } | |
215 | ||
216 | memset(&sa, 0, sizeof(sa)); | |
217 | #if HAVE_GETHOSTBYNAME | |
218 | if (!(hp = gethostbyname(host))) | |
219 | { | |
220 | return -1; | |
221 | } | |
222 | memcpy((char *) &sa.sin_addr, hp->h_addr, hp->h_length); | |
223 | sa.sin_family = hp->h_addrtype; | |
224 | #else | |
225 | if (!(addr = pack_ip(host))) | |
226 | { | |
227 | log("conn(): `%s' is not a valid IP address", host); | |
228 | errno = EINVAL; | |
229 | return -1; | |
230 | } | |
231 | memcpy((char *) &sa.sin_addr, addr, 4); | |
232 | sa.sin_family = AF_INET; | |
233 | #endif | |
234 | sa.sin_port = htons((unsigned short) port); | |
235 | ||
236 | if ((sock = socket(sa.sin_family, SOCK_STREAM, 0)) < 0) | |
237 | { | |
238 | return -1; | |
239 | } | |
240 | ||
241 | if ((lhost || lport) | |
242 | && bind(sock, (struct sockaddr *) &lsa, sizeof(lsa)) < 0) | |
243 | { | |
244 | int errno_save = errno; | |
245 | close(sock); | |
246 | errno = errno_save; | |
247 | return -1; | |
248 | } | |
249 | ||
250 | if (connect(sock, (struct sockaddr *) &sa, sizeof(sa)) < 0) | |
251 | { | |
252 | int errno_save = errno; | |
253 | close(sock); | |
254 | errno = errno_save; | |
255 | return -1; | |
256 | } | |
257 | ||
258 | return sock; | |
259 | } | |
260 | ||
261 | ||
85ce9d3e | 262 | /* This is a generic function to make a connection to a given server/port. |
263 | service is the port name/number, | |
264 | type is either SOCK_STREAM or SOCK_DGRAM, and | |
265 | netaddress is the host name to connect to. | |
266 | The function returns the socket, ready for action.*/ | |
267 | int make_connection(char *service, int type, char *netaddress) | |
268 | { | |
269 | /* First convert service from a string, to a number... */ | |
270 | int port = -1; | |
271 | struct in_addr *addr; | |
272 | int sock, connected; | |
273 | struct sockaddr_in address; | |
274 | ||
275 | if (type == SOCK_STREAM) | |
276 | port = atoport(service, "tcp"); | |
277 | if (type == SOCK_DGRAM) | |
278 | port = atoport(service, "udp"); | |
279 | if (port == -1) { | |
280 | fprintf(stderr,"make_connection: Invalid socket type.\n"); | |
281 | return -1; | |
282 | } | |
283 | addr = atoaddr(netaddress); | |
284 | if (addr == NULL) { | |
285 | fprintf(stderr,"make_connection: Invalid network address.\n"); | |
286 | return -1; | |
287 | } | |
288 | ||
289 | memset((char *) &address, 0, sizeof(address)); | |
290 | address.sin_family = AF_INET; | |
291 | address.sin_port = (port); | |
292 | address.sin_addr.s_addr = addr->s_addr; | |
293 | ||
294 | sock = socket(AF_INET, type, 0); | |
295 | ||
9f8c2acc | 296 | log("Connecting to %s on port %d.",inet_ntoa(*addr),htons(port)); |
85ce9d3e | 297 | |
298 | if (type == SOCK_STREAM) { | |
299 | connected = connect(sock, (struct sockaddr *) &address, | |
300 | sizeof(address)); | |
301 | if (connected < 0) { | |
302 | perror("connect"); | |
303 | return -1; | |
304 | } | |
305 | return sock; | |
306 | } | |
307 | /* Otherwise, must be for udp, so bind to address. */ | |
308 | if (bind(sock, (struct sockaddr *) &address, sizeof(address)) < 0) { | |
309 | perror("bind"); | |
310 | return -1; | |
311 | } | |
312 | return sock; | |
313 | } | |
314 | ||
315 | /* This is just like the read() system call, accept that it will make | |
316 | sure that all your data goes through the socket. */ | |
317 | int sock_read(int sockfd, char *buf, size_t count) | |
318 | { | |
319 | size_t bytes_read = 0; | |
320 | int this_read; | |
321 | ||
322 | while (bytes_read < count) { | |
323 | do | |
324 | this_read = read(sockfd, buf, count - bytes_read); | |
325 | while ( (this_read < 0) && (errno == EINTR) ); | |
326 | if (this_read < 0) | |
327 | return this_read; | |
328 | else if (this_read == 0) | |
329 | return bytes_read; | |
330 | bytes_read += this_read; | |
331 | buf += this_read; | |
332 | } | |
333 | return count; | |
334 | } | |
335 | ||
336 | /* This function reads from a socket, until it recieves a linefeed | |
337 | character. It fills the buffer "str" up to the maximum size "count". | |
338 | ||
339 | This function will return -1 if the socket is closed during the read | |
340 | operation. | |
341 | ||
342 | Note that if a single line exceeds the length of count, the extra data | |
343 | will be read and discarded! You have been warned. */ | |
344 | int sock_gets(int sockfd, char *str, size_t count) | |
345 | { | |
346 | int bytes_read; | |
28f552b8 | 347 | unsigned int total_count = 0; |
85ce9d3e | 348 | char *current_position; |
349 | char last_read = 0; | |
350 | ||
351 | current_position = str; | |
352 | while (last_read != 10) { | |
353 | bytes_read = read(sockfd, &last_read, 1); | |
354 | if (bytes_read <= 0) { | |
355 | /* The other side may have closed unexpectedly */ | |
356 | return -1; /* Is this effective on other platforms than linux? */ | |
357 | } | |
358 | if ( (total_count < count) && (last_read != 10) && (last_read !=13) ) | |
359 | { | |
360 | current_position[0] = last_read; | |
361 | current_position++; | |
362 | total_count++; | |
363 | } | |
364 | } | |
365 | if (count > 0) | |
366 | current_position[0] = 0; | |
367 | return total_count; | |
368 | } | |
369 | ||
370 | /* This is just like the write() system call, accept that it will | |
371 | make sure that all data is transmitted. */ | |
372 | int sock_write(int sockfd, const char *buf, size_t count) | |
373 | { | |
374 | size_t bytes_sent = 0; | |
375 | int this_write; | |
376 | ||
377 | while (bytes_sent < count) { | |
378 | do | |
379 | this_write = write(sockfd, buf, count - bytes_sent); | |
380 | while ( (this_write < 0) && (errno == EINTR) ); | |
381 | if (this_write <= 0) | |
382 | return this_write; | |
383 | bytes_sent += this_write; | |
384 | buf += this_write; | |
385 | } | |
386 | return count; | |
387 | } | |
388 | ||
389 | /* This function writes a character string out to a socket. It will | |
390 | return -1 if the connection is closed while it is trying to write. */ | |
391 | int sock_puts(int sockfd, const char *str) | |
392 | { | |
393 | return sock_write(sockfd, str, strlen(str)); | |
394 | } | |
395 | ||
396 | /* This ignores the SIGPIPE signal. This is usually a good idea, since | |
397 | the default behaviour is to terminate the application. SIGPIPE is | |
398 | sent when you try to write to an unconnected socket. You should | |
399 | check your return codes to make sure you catch this error! */ | |
400 | void ignore_pipe(void) | |
401 | { | |
402 | struct sigaction sig; | |
403 | ||
404 | sig.sa_handler = SIG_IGN; | |
405 | sig.sa_flags = 0; | |
406 | sigemptyset(&sig.sa_mask); | |
407 | sigaction(SIGPIPE,&sig,NULL); | |
408 | } | |
409 |