1 /*
2  * socket.c - socket utilities for the gofish gopher daemon
3  * Copyright (C) 2000,2002  Sean MacLennan <seanm@seanm.ca>
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 2 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this project; see the file COPYING.  If not, write to
17  * the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18  * Boston, MA 02111-1307, USA.
19  */
20 /*
21  * All knowledge of sockets should be isolated to this file.
22  */
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <string.h>
26 #include <unistd.h>
27 #include <fcntl.h>
28 #include <sys/socket.h>
29 #include <netinet/in.h>
30 #include <netinet/tcp.h>
31 #include <arpa/inet.h>
32 #include <netdb.h>
33 
34 #include "gofish.h"
35 
36 /* We cannot define this anywhere else */
37 static in_addr_t listen_addr = INADDR_ANY;
38 
39 
set_listen_address(char * addr)40 void set_listen_address(char *addr)
41 {
42 	listen_addr = inet_addr(addr);
43 }
44 
45 
listen_socket(int port)46 int listen_socket(int port)
47 {
48  	struct sockaddr_in sock_name;
49 	int s, optval;
50 
51  	sock_name.sin_family = AF_INET;
52 	sock_name.sin_addr.s_addr = listen_addr; /* already network addr */
53 	sock_name.sin_port = htons(port);
54 	optval = 1;
55 
56 	if((s = socket(AF_INET, SOCK_STREAM, 0)) == -1)
57 		return -1;
58 
59 	if(setsockopt(s, SOL_SOCKET, SO_REUSEADDR,
60 				  (char *)&optval, sizeof (optval)) == -1 ||
61 	   bind (s, (struct sockaddr *)&sock_name, sizeof(sock_name)) == -1 ||
62 	   listen(s, GOPHER_BACKLOG) == -1) {
63 		close(s);
64 		return -1;
65 	}
66 
67 	if((optval = fcntl(s, F_GETFL, 0)) == -1 ||
68 	   fcntl(s, F_SETFL, optval | O_NONBLOCK)) {
69 		close(s);
70 		return -1;
71 	}
72 
73 	return s;
74 }
75 
accept_socket(int sock,unsigned * addr)76 int accept_socket(int sock, unsigned *addr)
77 {
78 	struct sockaddr_in sock_name;
79 	int addrlen = sizeof(sock_name);
80 	int new, flags;
81 
82 	if((new = accept(sock, (struct sockaddr *)&sock_name, &addrlen)) < 0)
83 		return -1;
84 
85 	if(addr) *addr = htonl(sock_name.sin_addr.s_addr);
86 
87 	flags = fcntl(new, F_GETFL, 0);
88 	if(flags == -1 || fcntl(new, F_SETFL, flags | O_NONBLOCK) == -1) {
89 		printf("fcntl failed\n");
90 		close(new);
91 		return -1;
92 	}
93 
94 	flags = 1;
95 	if(setsockopt(new, IPPROTO_TCP, TCP_NODELAY, &flags, sizeof(flags)))
96 		perror("setsockopt(TCP_NODELAY)"); // not fatal
97 
98 	return new;
99 }
100 
101 
102 // network byte order
ntoa(unsigned n)103 char *ntoa(unsigned n)
104 {
105 	static char a[16];
106 
107 	sprintf(a, "%d.%d.%d.%d",
108 			(n >> 24) & 0xff,
109 			(n >> 16) & 0xff,
110 			(n >>  8) & 0xff,
111 			n & 0xff);
112 
113 	return a;
114 }
115