1 | /***************************************
2 | $Revision: 1.15 $
3 |
4 | Socket module - routines facilitating calls to socket library.
5 |
6 | Status: NOT REVUED, TESTED
7 |
8 | Basic code adapted by Chris Ottrey from
9 | http://www.ibrado.com/sock-faq/sfaq.html#faq65 - sample source code.
10 | ******************/ /******************
11 | Modification History:
12 | ottrey (08/03/1999) Created from sockhelp.c.
13 | ottrey (08/03/1998) Heavily butchered.
14 | joao (22/06/1999) Modified socket creation and accepts.
15 | marek (December 2000) Added connection function w/timeout.
16 | ******************/ /******************
17 | Copyright (c) 1999, 2000 RIPE NCC
18 |
19 | All Rights Reserved
20 |
21 | Permission to use, copy, modify, and distribute this software and its
22 | documentation for any purpose and without fee is hereby granted,
23 | provided that the above copyright notice appear in all copies and that
24 | both that copyright notice and this permission notice appear in
25 | supporting documentation, and that the name of the author not be
26 | used in advertising or publicity pertaining to distribution of the
27 | software without specific, written prior permission.
28 |
29 | THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
30 | ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS; IN NO EVENT SHALL
31 | AUTHOR BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY
32 | DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
33 | AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
34 | OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
35 | ***************************************/
36 |
37 | #include "sk.h"
38 | #include "constants.h"
39 | #include "stubs.h"
40 |
41 | #include "memwrap.h"
42 |
43 | /*+ String sizes +*/
44 | #define STR_S 63
45 | #define STR_XXL 16383
46 |
47 | /* SK_atoport() */
48 | /*++++++++++++++++++++++++++++++++++++++
49 | Take a service name, and a service type, and return a port number. If the
50 | service name is not found, it tries it as a decimal number. The number
51 | returned is byte ordered for the network.
52 |
53 | char *service Service name (or port number).
54 |
55 | char *proto Protocol (eg "tcp").
56 |
57 | Author:
58 | ottrey.
59 |
60 | ++++++++++++++++++++++++++++++++++++++*/
61 | int SK_atoport(const char *service, const char *proto) {
62 | unsigned port;
63 | long int lport;
64 | struct servent *serv;
65 | char *errpos;
66 | struct servent result;
67 | char buffer[STR_XXL];
68 |
69 | /* First try to read it from /etc/services */
70 |
71 | #ifdef __linux__
72 | if(getservbyname_r(service, proto, &result, buffer, sizeof(buffer), &serv) < 0) serv = NULL;
73 | #else
74 | serv = getservbyname_r(service, proto, &result, buffer, sizeof(buffer));
75 | #endif
76 |
77 | if (serv != NULL)
78 | port = serv->s_port;
79 | else { /* Not in services, maybe a number? */
80 | lport = strtol(service,&errpos,0);
81 | if ( (errpos[0] != 0) || (lport < 1) || (lport > 65535) )
82 | return -1; /* Invalid port address */
83 | port = htons(lport);
84 | }
85 | return port;
86 | } /* SK_atoport() */
87 |
88 |
89 | /* SK_close() */
90 | /*++++++++++++++++++++++++++++++++++++++
91 |
92 | int SK_close wrapper around closing the socket. Returns the value
93 | returned by close(2)
94 |
95 | int socket socket to be closed
96 |
97 | Author:
98 | ottrey
99 | ++++++++++++++++++++++++++++++++++++++*/
100 | int SK_close(int socket) {
101 | ER_dbg_va(FAC_SK, ASP_SK_GEN, "Closing socket... %d", socket);
102 |
103 | return close(socket);
104 | }
105 |
106 | /* SK_getsock() */
107 | /*++++++++++++++++++++++++++++++++++++++
108 |
109 | int SK_getsock This function creates a socket and binds to it.
110 | Returns the number of the created
111 | descriptor/listening socket.
112 |
113 | int socket_type SOCK_STREAM or SOCK_DGRAM (TCP or UDP sockets)
114 |
115 | unsigned port The port to listen on. Ports < 1024 are
116 | reserved for the root user. Host byte order.
117 |
118 | int backlog Size of the backlog queue to be set on that
119 | socket.
120 |
121 | uint32_t bind_address Address to bind to, in network order.
122 |
123 | Authors:
124 | ottrey,
125 | joao,
126 | marek (added htons conversion for port).
127 |
128 | ++++++++++++++++++++++++++++++++++++++*/
129 | int SK_getsock(int socket_type, unsigned h_port, int backlog,
130 | uint32_t bind_address) {
131 | struct sockaddr_in address;
132 | int listening_socket;
133 | int reuse_addr = 1;
134 | u_short port = htons(h_port);
135 |
136 | /* Setup internet address information.
137 | This is used with the bind() call */
138 | memset((char *) &address, 0, sizeof(address));
139 | address.sin_family = AF_INET;
140 | address.sin_port = port;
141 | address.sin_addr.s_addr = bind_address;
142 |
143 | /* Map all of the signals and exit routine */
144 |
145 | listening_socket = socket(AF_INET, socket_type, 0);
146 | if (listening_socket < 0) {
147 | perror("socket");
148 | exit(EXIT_FAILURE);
149 | }
150 |
151 | setsockopt(listening_socket, SOL_SOCKET, SO_REUSEADDR, (void *)&reuse_addr, sizeof(reuse_addr));
152 |
153 | if (bind(listening_socket, (struct sockaddr *) &address, sizeof(address)) < 0) {
154 | perror("bind");
155 | close(listening_socket);
156 | exit(EXIT_FAILURE);
157 | }
158 |
159 |
160 | if (socket_type == SOCK_STREAM) {
161 | listen(listening_socket, backlog); /* Queue up to five connections before
162 | having them automatically rejected. */
163 | }
164 |
165 | return listening_socket;
166 | } /* SK_getsock() */
167 |
168 | /*++++++++++++++++++++++++++++++++++++++
169 |
170 | Wait for an incoming connection on the specified socket
171 |
172 | int SK_accept_connection The socket for communicating to the client
173 |
174 | int listening_socket The socket that the server is bound to
175 |
176 | Authors:
177 | joao,
178 | marek.
179 | ++++++++++++++++++++++++++++++++++++++*/
180 | int SK_accept_connection(int listening_socket) {
181 | int connected_socket = -1;
182 | int num_errors = 0;
183 |
184 | #define MAX_ACCEPT_ERRORS 3
185 |
186 | for (;;) {
187 |
188 | ER_dbg_va(FAC_SK, ASP_SK_GEN,
189 | "Going to accept connections on socket : %d",listening_socket);
190 |
191 | connected_socket = accept(listening_socket, NULL, NULL);
192 | if (connected_socket < 0) {
193 | /* Either a real error occured, or blocking was interrupted for
194 | some reason. Only abort execution if a real error occured. */
195 | switch(errno) {
196 | case EINTR: /* Interrupted system call */
197 | case ECONNABORTED: /* Software caused connection abort */
198 | /* no warning */
199 | continue; /* don't return - do the accept again */
200 | default:
201 | /* special case: shutdown of the server - just return */
202 | if( CO_get_do_server() == 0 ) {
203 | return -1;
204 | }
205 | else { /* real error */
206 | if( ++num_errors < MAX_ACCEPT_ERRORS ) {
207 | /* warn */
208 | ER_perror(FAC_SK, SK_ACERW, "(%d) %s", errno, strerror(errno));
209 | }
210 | else {
211 | /* crash */
212 | ER_perror(FAC_SK, SK_ACERF,
213 | "too many accept() errors (maximum is %d)", MAX_ACCEPT_ERRORS);
214 | die;
215 | }
216 | }
217 | }
218 | }
219 | else { /* success */
220 | ER_dbg_va(FAC_SK, ASP_SK_GEN, "client connected on socket %d",
221 | connected_socket
222 | );
223 |
224 | return connected_socket;
225 | }
226 |
227 | }
228 | }
229 |
230 |
231 | /*++++++++++++++++++++++++++++++++++++++
232 |
233 | er_ret_t SK_connect wrapper around connect(), doing non-blocking
234 | connection with timeout
235 |
236 | int *sock pointer to the storage for socket descriptor
237 |
238 | char *hostname host to connect to
239 |
240 | int port port to connect to
241 |
242 | int timeout in seconds
243 |
244 | Author: marek
245 |
246 | ++++++++++++++++++++++++++++++++++++++*/
247 | er_ret_t SK_connect(int *sock, char *hostname, unsigned int port, unsigned int timeout)
248 | {
249 | struct sockaddr_in sin;
250 | struct hostent *hp;
251 | int s;
252 | int flags;
253 | struct timeval ptm;
254 | fd_set rset, wset;
255 | int gs, sel, er, erlen=sizeof(er);
256 | int error;
257 | struct hostent result;
258 | char aliasbuf[8192]; /* Stevens, UNIX net. prog., p.304 */
259 |
260 | /* look up the host name */
261 | #ifdef __linux__
262 | er = (gethostbyname_r(hostname, &result, aliasbuf,
263 | sizeof(aliasbuf), &hp, &error) < 0 );
264 | #else /* default is Solaris implementation */
265 | hp = gethostbyname_r(hostname, &result, aliasbuf,
266 | sizeof(aliasbuf), &error);
267 | er = ( hp == NULL );
268 | #endif
269 |
270 | if( er ) {
271 | return SK_BADHOST;
272 | }
273 |
274 | /* create a socket */
275 | s = socket(AF_INET, SOCK_STREAM, 0);
276 | if (s < 0) {
277 | return SK_SOCKET;
278 | }
279 |
280 | /* bind to it */
281 | bzero((caddr_t)&sin, sizeof (sin));
282 | sin.sin_family = hp->h_addrtype;
283 | if (bind(s, (struct sockaddr *)&sin, sizeof(sin)) < 0) {
284 | close(s);
285 | return SK_BIND;
286 | }
287 | bcopy(hp->h_addr, (char *)&sin.sin_addr, hp->h_length);
288 | sin.sin_port=htons(port);
289 |
290 | /* connect in non-blocking mode */
291 | flags = fcntl(s, F_GETFL, 0);
292 | fcntl(s, F_SETFL, flags | O_NONBLOCK );
293 |
294 | if (connect(s, (struct sockaddr *)&sin, sizeof(sin)) < 0
295 | && errno != EINPROGRESS ) {
296 | close(s);
297 | return SK_CONNECT;
298 | }
299 |
300 | /* now wait for success */
301 | FD_ZERO( &rset );
302 | FD_SET( s, &rset );
303 | wset = rset;
304 | ptm.tv_usec = 0;
305 | ptm.tv_sec = timeout;
306 |
307 | if( (sel=select(s+1, &rset, &wset, NULL, &ptm)) == 0 ) {
308 | /* timeout */
309 | close(s);
310 | return SK_TIMEOUT;
311 | }
312 | dieif( sel < 0 ); /* we don't expect problems with select */
313 |
314 | gs = getsockopt(s, SOL_SOCKET, SO_ERROR, &er, &erlen);
315 |
316 | if( gs < 0 || er ) { /* Stevens code, p.411 is exceptionally crappy */
317 | close(s);
318 | return SK_CONNECT;
319 | } /* if error */
320 |
321 | fcntl(s, F_SETFL, flags);
322 | *sock = s;
323 |
324 | return SK_OK;
325 | }
326 |
327 |
328 | /* SK_read() */
329 | /*++++++++++++++++++++++++++++++++++++++
330 |
331 | This is just like the read() system call, except that it will make
332 | sure that all your data goes through the socket.
333 |
334 | int SK_read Returns the number of bytes read.
335 |
336 | int sockfd The socket file descriptor.
337 |
338 | char *buf The buffer to be read from the socket.
339 |
340 | size_t count The number of bytes in the buffer.
341 |
342 | Author:
343 | ottrey
344 |
345 | ++++++++++++++++++++++++++++++++++++++*/
346 | int SK_read(int sockfd, char *buf, size_t count) {
347 | size_t bytes_read = 0;
348 | int this_read;
349 |
350 | while (bytes_read < count) {
351 | do
352 | this_read = read(sockfd, buf, count - bytes_read);
353 | while ( (this_read < 0) && (errno == EINTR) );
354 | if (this_read < 0)
355 | return this_read;
356 | else if (this_read == 0)
357 | return bytes_read;
358 | bytes_read += this_read;
359 | buf += this_read;
360 | }
361 |
362 | return count;
363 |
364 | } /* SK_read() */
365 |
366 |
367 | /* SK_write() */
368 | /*++++++++++++++++++++++++++++++++++++++
369 |
370 | This is just like the write() system call, except that it will
371 | make sure that all data is transmitted.
372 |
373 | int SK_write Returns the number of bytes written.
374 |
375 | int sockfd The socket file descriptor.
376 |
377 | char *buf The buffer to be written to the socket.
378 |
379 | size_t count The number of bytes in the buffer.
380 |
381 | Author:
382 | ottrey
383 |
384 | ++++++++++++++++++++++++++++++++++++++*/
385 | int SK_write(int sockfd, const char *buf, size_t count) {
386 | size_t bytes_sent = 0;
387 | int this_write;
388 |
389 |
390 | ER_dbg_va(FAC_SK, ASP_SK_WRIT,
391 | "SK_write = { sockfd=[%d], buf=[%s], count=[%d]",
392 | sockfd, buf, count);
393 |
394 | while (bytes_sent < count) {
395 | do
396 | this_write = write(sockfd, buf, count - bytes_sent);
397 | while ( (this_write < 0) && (errno == EINTR) );
398 | if (this_write <= 0)
399 | return this_write;
400 | bytes_sent += this_write;
401 | buf += this_write;
402 | }
403 | return count;
404 | } /* SK_write() */
405 |
406 |
407 | /* SK_gets() */
408 | /*++++++++++++++++++++++++++++++++++++++
409 |
410 | This function reads from a socket, until it recieves a linefeed
411 | character. It fills the buffer "str" up to the maximum size "count".
412 |
413 | int SK_gets Returns the total_count of bytes read.
414 |
415 | int sockfd The socket file descriptor.
416 |
417 | char *str The buffer to be written from the socket.
418 |
419 | size_t count The number of bytes in the buffer.
420 |
421 |
422 | Authors:
423 | ottrey,
424 | marek (modified for meaningful error codes).
425 |
426 | Side Effects:
427 | This function will return -1 if the socket is closed during the read operation.
428 |
429 | Note that if a single line exceeds the length of count, the extra data
430 | will be read and discarded! You have been warned.
431 |
432 | ++++++++++++++++++++++++++++++++++++++*/
433 | int SK_gets(int sockfd, char *str, size_t count) {
434 | int bytes_read;
435 | int total_count = 0;
436 | char *current_position;
437 | char last_read = 0;
438 |
439 | int control_c = 0;
440 |
441 | current_position = str;
442 | while (last_read != 10) {
443 |
444 | bytes_read = read(sockfd, &last_read, 1);
445 | if (bytes_read <= 0) {
446 | /* The other side may have closed unexpectedly */
447 | return SK_DISCONNECT;
448 | /* Is this effective on other platforms than linux? */
449 | }
450 | if ( (total_count < count) && (last_read != 10) && (last_read !=13) ) {
451 | *current_position = last_read;
452 | current_position++;
453 | total_count++;
454 | }
455 |
456 | if (last_read == -1) {
457 | bytes_read = read(sockfd, &last_read, 1);
458 | if (last_read == -12) {
459 | ER_dbg_va(FAC_SK, ASP_SK_GEN,"Client pressed Control-c");
460 | control_c = 1;
461 | ER_dbg_va(FAC_SK, ASP_SK_GEN,"returning SK_INTERRUPT");
462 | return SK_INTERRUPT;
463 | }
464 | }
465 | }
466 | if (count > 0) {
467 | *current_position = 0;
468 | }
469 |
470 | return total_count;
471 |
472 | } /* SK_gets() */
473 |
474 |
475 | /* SK_puts() */
476 | /*++++++++++++++++++++++++++++++++++++++
477 |
478 | This function writes a character string out to a socket.
479 |
480 | int SK_puts The total_count of bytes written,
481 | or errors (represented as negative numbers)
482 |
483 | int sockfd The socket file descriptor.
484 |
485 | char *str The buffer to be written from the socket.
486 |
487 | More:
488 | +html+ <PRE>
489 | Authors:
490 | ottrey
491 |
492 | Side Effects:
493 | This function will return -1 if the socket is closed during the write operation.
494 | +html+ </PRE>
495 |
496 | ++++++++++++++++++++++++++++++++++++++*/
497 | int SK_puts(int sockfd, const char *str) {
498 |
499 | return SK_write(sockfd, str, strlen(str));
500 |
501 | } /* SK_puts() */
502 |
503 | /* SK_putc() */
504 | /*++++++++++++++++++++++++++++++++++++++
505 |
506 | This function writes a single character out to a socket.
507 |
508 | int SK_putc Returns the number of characters written.
509 |
510 | int sockfd socket
511 |
512 | char ch character
513 |
514 | ++++++++++++++++++++++++++++++++++++++*/
515 | int SK_putc(int sockfd, char ch) {
516 | return SK_write(sockfd, &ch, 1);
517 | }/* SK_putc() */
518 |
519 | /*++++++++++++++++++++++++++++++++++++++
520 |
521 | This function reads a single character from a socket.
522 |
523 | returns EOF when no character can be read.
524 |
525 | ++++++++++++++++++++++++++++++++++++++*/
526 | int SK_getc(int sockfd) {
527 | char ch;
528 |
529 | if( read(sockfd, &ch, 1) <= 0 ) {
530 | return EOF;
531 | }
532 | else {
533 | return ch;
534 | }
535 | }/* SK_getc() */
536 |
537 | /* SK_getpeername() */
538 | /*++++++++++++++++++++++++++++++++++++++
539 |
540 | This function will tell you who is at the other end of a connected stream socket.
541 |
542 | char *SK_getpeername Returns allocated string with the IP in it,
543 | or "--" if the descriptor is not a socket,
544 | or NULL on error.
545 |
546 | int sockfd The socket or file descriptor.
547 |
548 | +html+ <PRE>
549 | Authors:
550 | ottrey,
551 | marek (modified error handling, made MT-Safe).
552 | +html+ </PRE>
553 |
554 | ++++++++++++++++++++++++++++++++++++++*/
555 | char *SK_getpeername(int sockfd)
556 | {
557 | char *hostaddress=NULL;
558 | struct sockaddr_in addr_in;
559 | int namelen=sizeof(addr_in);
560 |
561 | if (getpeername(sockfd, (struct sockaddr *)&addr_in, &namelen) == 0) {
562 |
563 | dieif( wr_malloc((void **)&hostaddress, INET_ADDRSTRLEN) != UT_OK);
564 | inet_ntop(AF_INET, &(addr_in.sin_addr), hostaddress, INET_ADDRSTRLEN);
565 | }
566 | else {
567 | int er = errno;
568 |
569 | if( er == ENOTSOCK ) {
570 | hostaddress = wr_string("--");
571 | }
572 | else {
573 | return NULL;
574 | }
575 | }
576 |
577 | return hostaddress;
578 |
579 | } /* SK_getpeername() */
580 |
581 |
582 | /* SK_getpeerip */
583 | /*++++++++++++++++++++++++++++++++++++++
584 |
585 | This function will check the ip of the connected peer and store it in the
586 | ip_addr_t structure defined in the IP module.
587 |
588 | int SK_getpeerip returns 0 on success, -1 on failure.
589 |
590 | int sockfd The socket descriptor (file will result in -1)
591 |
592 | ip_addr_t *ip Pointer to where the address should be stored.
593 |
594 | +html+ <PRE>
595 | Author:
596 | marek
597 | +html+ </PRE>
598 | ++++++++++++++++++++++++++++++++++++++*/
599 |
600 | int SK_getpeerip(int sockfd, ip_addr_t *ip) {
601 | struct sockaddr_in addr_in;
602 | int namelen=sizeof(addr_in);
603 | int ret=-1;
604 |
605 | memset(& addr_in, 0, sizeof(struct sockaddr_in));
606 |
607 | if (getpeername(sockfd, (struct sockaddr *)(& addr_in), &namelen) != -1) {
608 | ret=0;
609 | IP_addr_s2b(ip, &addr_in, namelen);
610 | }
611 |
612 | return ret;
613 | }
614 |