modules/sk/sk_socket.c
/* [<][>][^][v][top][bottom][index][help] */
FUNCTIONS
This source file includes following functions.
- SK_atoport
- SK_close
- SK_getsock
- SK_accept_connection
- SK_connect
- SK_read
- SK_write
- SK_gets
- SK_puts
- SK_putc
- SK_getc
- SK_getpeername
- SK_getpeerip
1 /***************************************
2 $Revision: 1.14 $
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) {
/* [<][>][^][v][top][bottom][index][help] */
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) {
/* [<][>][^][v][top][bottom][index][help] */
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,
/* [<][>][^][v][top][bottom][index][help] */
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) {
/* [<][>][^][v][top][bottom][index][help] */
181 int connected_socket = -1;
182 int num_errors = 0;
183
184 #define MAX_ACCEPT_ERRORS 3
185
186 while(connected_socket < 0) {
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 die;
214 }
215 }
216 }
217 }
218 else { /* success */
219 ER_dbg_va(FAC_SK, ASP_SK_GEN, "client connected on socket %d",
220 connected_socket
221 );
222
223 return connected_socket;
224 }
225 } /* while */
226 }
227
228
229 /*++++++++++++++++++++++++++++++++++++++
230
231 er_ret_t SK_connect wrapper around connect(), doing non-blocking
232 connection with timeout
233
234 int *sock pointer to the storage for socket descriptor
235
236 char *hostname host to connect to
237
238 int port port to connect to
239
240 int timeout in seconds
241
242 Author: marek
243
244 ++++++++++++++++++++++++++++++++++++++*/
245 er_ret_t SK_connect(int *sock, char *hostname, unsigned int port, unsigned int timeout)
/* [<][>][^][v][top][bottom][index][help] */
246 {
247 struct sockaddr_in sin;
248 struct hostent *hp;
249 int s;
250 int flags;
251 struct timeval ptm;
252 fd_set rset, wset;
253 int gs, sel, er, erlen=sizeof(er);
254 int error;
255 struct hostent result;
256 char aliasbuf[8192]; /* Stevens, UNIX net. prog., p.304 */
257
258 /* look up the host name */
259 #ifdef __linux__
260 er = (gethostbyname_r(hostname, &result, aliasbuf,
261 sizeof(aliasbuf), &hp, &error) < 0 );
262 #else /* default is Solaris implementation */
263 hp = gethostbyname_r(hostname, &result, aliasbuf,
264 sizeof(aliasbuf), &error);
265 er = ( hp == NULL );
266 #endif
267
268 if( er ) {
269 return SK_BADHOST;
270 }
271
272 /* create a socket */
273 s = socket(AF_INET, SOCK_STREAM, 0);
274 if (s < 0) {
275 return SK_SOCKET;
276 }
277
278 /* bind to it */
279 bzero((caddr_t)&sin, sizeof (sin));
280 sin.sin_family = hp->h_addrtype;
281 if (bind(s, (struct sockaddr *)&sin, sizeof(sin)) < 0) {
282 close(s);
283 return SK_BIND;
284 }
285 bcopy(hp->h_addr, (char *)&sin.sin_addr, hp->h_length);
286 sin.sin_port=htons(port);
287
288 /* connect in non-blocking mode */
289 flags = fcntl(s, F_GETFL, 0);
290 fcntl(s, F_SETFL, flags | O_NONBLOCK );
291
292 if (connect(s, (struct sockaddr *)&sin, sizeof(sin)) < 0
293 && errno != EINPROGRESS ) {
294 close(s);
295 return SK_CONNECT;
296 }
297
298 /* now wait for success */
299 FD_ZERO( &rset );
300 FD_SET( s, &rset );
301 wset = rset;
302 ptm.tv_usec = 0;
303 ptm.tv_sec = timeout;
304
305 if( (sel=select(s+1, &rset, &wset, NULL, &ptm)) == 0 ) {
306 /* timeout */
307 close(s);
308 return SK_TIMEOUT;
309 }
310 dieif( sel < 0 ); /* we don't expect problems with select */
311
312 gs = getsockopt(s, SOL_SOCKET, SO_ERROR, &er, &erlen);
313
314 if( gs < 0 || er ) { /* Stevens code, p.411 is exceptionally crappy */
315 close(s);
316 return SK_CONNECT;
317 } /* if error */
318
319 fcntl(s, F_SETFL, flags);
320 *sock = s;
321
322 return SK_OK;
323 }
324
325
326 /* SK_read() */
327 /*++++++++++++++++++++++++++++++++++++++
328
329 This is just like the read() system call, except that it will make
330 sure that all your data goes through the socket.
331
332 int SK_read Returns the number of bytes read.
333
334 int sockfd The socket file descriptor.
335
336 char *buf The buffer to be read from the socket.
337
338 size_t count The number of bytes in the buffer.
339
340 Author:
341 ottrey
342
343 ++++++++++++++++++++++++++++++++++++++*/
344 int SK_read(int sockfd, char *buf, size_t count) {
/* [<][>][^][v][top][bottom][index][help] */
345 size_t bytes_read = 0;
346 int this_read;
347
348 while (bytes_read < count) {
349 do
350 this_read = read(sockfd, buf, count - bytes_read);
351 while ( (this_read < 0) && (errno == EINTR) );
352 if (this_read < 0)
353 return this_read;
354 else if (this_read == 0)
355 return bytes_read;
356 bytes_read += this_read;
357 buf += this_read;
358 }
359
360 return count;
361
362 } /* SK_read() */
363
364
365 /* SK_write() */
366 /*++++++++++++++++++++++++++++++++++++++
367
368 This is just like the write() system call, except that it will
369 make sure that all data is transmitted.
370
371 int SK_write Returns the number of bytes written.
372
373 int sockfd The socket file descriptor.
374
375 char *buf The buffer to be written to the socket.
376
377 size_t count The number of bytes in the buffer.
378
379 Author:
380 ottrey
381
382 ++++++++++++++++++++++++++++++++++++++*/
383 int SK_write(int sockfd, const char *buf, size_t count) {
/* [<][>][^][v][top][bottom][index][help] */
384 size_t bytes_sent = 0;
385 int this_write;
386
387
388 ER_dbg_va(FAC_SK, ASP_SK_WRIT,
389 "SK_write = { sockfd=[%d], buf=[%s], count=[%d]",
390 sockfd, buf, count);
391
392 while (bytes_sent < count) {
393 do
394 this_write = write(sockfd, buf, count - bytes_sent);
395 while ( (this_write < 0) && (errno == EINTR) );
396 if (this_write <= 0)
397 return this_write;
398 bytes_sent += this_write;
399 buf += this_write;
400 }
401 return count;
402 } /* SK_write() */
403
404
405 /* SK_gets() */
406 /*++++++++++++++++++++++++++++++++++++++
407
408 This function reads from a socket, until it recieves a linefeed
409 character. It fills the buffer "str" up to the maximum size "count".
410
411 int SK_gets Returns the total_count of bytes read.
412
413 int sockfd The socket file descriptor.
414
415 char *str The buffer to be written from the socket.
416
417 size_t count The number of bytes in the buffer.
418
419
420 Authors:
421 ottrey,
422 marek (modified for meaningful error codes).
423
424 Side Effects:
425 This function will return -1 if the socket is closed during the read operation.
426
427 Note that if a single line exceeds the length of count, the extra data
428 will be read and discarded! You have been warned.
429
430 ++++++++++++++++++++++++++++++++++++++*/
431 int SK_gets(int sockfd, char *str, size_t count) {
/* [<][>][^][v][top][bottom][index][help] */
432 int bytes_read;
433 int total_count = 0;
434 char *current_position;
435 char last_read = 0;
436
437 int control_c = 0;
438
439 current_position = str;
440 while (last_read != 10) {
441
442 bytes_read = read(sockfd, &last_read, 1);
443 if (bytes_read <= 0) {
444 /* The other side may have closed unexpectedly */
445 return SK_DISCONNECT;
446 /* Is this effective on other platforms than linux? */
447 }
448 if ( (total_count < count) && (last_read != 10) && (last_read !=13) ) {
449 *current_position = last_read;
450 current_position++;
451 total_count++;
452 }
453
454 if (last_read == -1) {
455 bytes_read = read(sockfd, &last_read, 1);
456 if (last_read == -12) {
457 ER_dbg_va(FAC_SK, ASP_SK_GEN,"Client pressed Control-c");
458 control_c = 1;
459 ER_dbg_va(FAC_SK, ASP_SK_GEN,"returning SK_INTERRUPT");
460 return SK_INTERRUPT;
461 }
462 }
463 }
464 if (count > 0) {
465 *current_position = 0;
466 }
467
468 return total_count;
469
470 } /* SK_gets() */
471
472
473 /* SK_puts() */
474 /*++++++++++++++++++++++++++++++++++++++
475
476 This function writes a character string out to a socket.
477
478 int SK_puts The total_count of bytes written,
479 or errors (represented as negative numbers)
480
481 int sockfd The socket file descriptor.
482
483 char *str The buffer to be written from the socket.
484
485 More:
486 +html+ <PRE>
487 Authors:
488 ottrey
489
490 Side Effects:
491 This function will return -1 if the socket is closed during the write operation.
492 +html+ </PRE>
493
494 ++++++++++++++++++++++++++++++++++++++*/
495 int SK_puts(int sockfd, const char *str) {
/* [<][>][^][v][top][bottom][index][help] */
496
497 return SK_write(sockfd, str, strlen(str));
498
499 } /* SK_puts() */
500
501 /* SK_putc() */
502 /*++++++++++++++++++++++++++++++++++++++
503
504 This function writes a single character out to a socket.
505
506 int SK_putc Returns the number of characters written.
507
508 int sockfd socket
509
510 char ch character
511
512 ++++++++++++++++++++++++++++++++++++++*/
513 int SK_putc(int sockfd, char ch) {
/* [<][>][^][v][top][bottom][index][help] */
514 return SK_write(sockfd, &ch, 1);
515 }/* SK_putc() */
516
517 /*++++++++++++++++++++++++++++++++++++++
518
519 This function reads a single character from a socket.
520
521 returns EOF when no character can be read.
522
523 ++++++++++++++++++++++++++++++++++++++*/
524 int SK_getc(int sockfd) {
/* [<][>][^][v][top][bottom][index][help] */
525 char ch;
526
527 if( read(sockfd, &ch, 1) <= 0 ) {
528 return EOF;
529 }
530 else {
531 return ch;
532 }
533 }/* SK_getc() */
534
535 /* SK_getpeername() */
536 /*++++++++++++++++++++++++++++++++++++++
537
538 This function will tell you who is at the other end of a connected stream socket.
539
540 char *SK_getpeername Returns allocated string with the IP in it,
541 or "--" if the descriptor is not a socket,
542 or NULL on error.
543
544 int sockfd The socket or file descriptor.
545
546 +html+ <PRE>
547 Authors:
548 ottrey,
549 marek (modified error handling, made MT-Safe).
550 +html+ </PRE>
551
552 ++++++++++++++++++++++++++++++++++++++*/
553 char *SK_getpeername(int sockfd)
/* [<][>][^][v][top][bottom][index][help] */
554 {
555 char *hostaddress=NULL;
556 struct sockaddr_in addr_in;
557 int namelen=sizeof(addr_in);
558
559 if (getpeername(sockfd, (struct sockaddr *)&addr_in, &namelen) == 0) {
560
561 dieif( wr_malloc((void **)&hostaddress, INET_ADDRSTRLEN) != UT_OK);
562 inet_ntop(AF_INET, &(addr_in.sin_addr), hostaddress, INET_ADDRSTRLEN);
563 }
564 else {
565 int er = errno;
566
567 if( er == ENOTSOCK ) {
568 hostaddress = wr_string("--");
569 }
570 else {
571 return NULL;
572 }
573 }
574
575 return hostaddress;
576
577 } /* SK_getpeername() */
578
579
580 /* SK_getpeerip */
581 /*++++++++++++++++++++++++++++++++++++++
582
583 This function will check the ip of the connected peer and store it in the
584 ip_addr_t structure defined in the IP module.
585
586 int SK_getpeerip returns 0 on success, -1 on failure.
587
588 int sockfd The socket descriptor (file will result in -1)
589
590 ip_addr_t *ip Pointer to where the address should be stored.
591
592 +html+ <PRE>
593 Author:
594 marek
595 +html+ </PRE>
596 ++++++++++++++++++++++++++++++++++++++*/
597
598 int SK_getpeerip(int sockfd, ip_addr_t *ip) {
/* [<][>][^][v][top][bottom][index][help] */
599 struct sockaddr_in addr_in;
600 int namelen=sizeof(addr_in);
601 int ret=-1;
602
603 memset(& addr_in, 0, sizeof(struct sockaddr_in));
604
605 if (getpeername(sockfd, (struct sockaddr *)(& addr_in), &namelen) != -1) {
606 ret=0;
607 IP_addr_s2b(ip, &addr_in, namelen);
608 }
609
610 return ret;
611 }
612