]>
Commit | Line | Data |
---|---|---|
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" | |
16 | #include "extern.h" | |
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. */ | |
22 | int atoport(char *service, char *proto) | |
23 | { | |
24 | int port; | |
25 | long int lport; | |
26 | struct servent *serv; | |
27 | char *errpos; | |
28 | ||
29 | /* First try to read it from /etc/services */ | |
30 | serv = getservbyname(service, proto); | |
31 | if (serv != NULL) | |
32 | port = serv->s_port; | |
33 | else { /* Not in services, maybe a number? */ | |
34 | lport = strtol(service,&errpos,0); | |
35 | if ( (errpos[0] != 0) || (lport < 1) || (lport > 65535) ) | |
36 | return -1; /* Invalid port address */ | |
37 | port = htons(lport); | |
38 | } | |
39 | return port; | |
40 | } | |
41 | ||
42 | /* Converts ascii text to in_addr struct. NULL is returned if the address | |
43 | can not be found. */ | |
44 | struct in_addr *atoaddr(char *address) | |
45 | { | |
46 | struct hostent *host; | |
47 | static struct in_addr saddr; | |
48 | ||
49 | /* First try it as aaa.bbb.ccc.ddd. */ | |
50 | saddr.s_addr = inet_addr(address); | |
51 | if (saddr.s_addr != 0) { | |
52 | return &saddr; | |
53 | } | |
54 | host = gethostbyname(address); | |
55 | if (host != NULL) { | |
56 | return (struct in_addr *) *host->h_addr_list; | |
57 | } | |
58 | return NULL; | |
59 | } | |
60 | ||
61 | /* This function listens on a port, and returns connections. It forks | |
62 | returns off internally, so your main function doesn't have to worry | |
63 | about that. This can be confusing if you don't know what is going on. | |
64 | The function will create a new process for every incoming connection, | |
65 | so in the listening process, it will never return. Only when a | |
66 | connection | |
67 | comes in, and we create a new process for it will the function return. | |
68 | This means that your code that calls it should _not_ loop. | |
69 | ||
70 | The parameters are as follows: | |
71 | socket_type: SOCK_STREAM or SOCK_DGRAM (TCP or UDP sockets) | |
72 | port: The port to listen on. Remember that ports < 1024 are | |
73 | reserved for the root user. Must be passed in network byte | |
74 | order (see "man htons"). | |
75 | listener: This is a pointer to a variable for holding the file | |
76 | descriptor of the socket which is being used to listen. It | |
77 | is provided so that you can write a signal handler to close | |
78 | it in the event of program termination. If you aren't interested, | |
79 | just pass NULL. Note that all modern unixes will close file | |
80 | descriptors for you on exit, so this is not required. */ | |
81 | int get_connection(int socket_type, u_short port, int *listener) | |
82 | { | |
83 | struct sockaddr_in address; | |
84 | int listening_socket; | |
85 | int connected_socket = -1; | |
86 | int new_process; | |
87 | int reuse_addr = 1; | |
88 | ||
89 | /* Setup internet address information. | |
90 | This is used with the bind() call */ | |
91 | memset((char *) &address, 0, sizeof(address)); | |
92 | address.sin_family = AF_INET; | |
93 | address.sin_port = port; | |
94 | address.sin_addr.s_addr = htonl(INADDR_ANY); | |
95 | ||
96 | listening_socket = socket(AF_INET, socket_type, 0); | |
97 | if (listening_socket < 0) { | |
98 | perror("socket"); | |
99 | exit(EXIT_FAILURE); | |
100 | } | |
101 | ||
102 | if (listener != NULL) | |
103 | *listener = listening_socket; | |
104 | ||
105 | setsockopt(listening_socket, SOL_SOCKET, SO_REUSEADDR, &reuse_addr, | |
106 | sizeof(reuse_addr)); | |
107 | ||
108 | if (bind(listening_socket, (struct sockaddr *) &address, | |
109 | sizeof(address)) < 0) { | |
110 | perror("bind"); | |
111 | close(listening_socket); | |
112 | exit(EXIT_FAILURE); | |
113 | } | |
114 | ||
115 | if (socket_type == SOCK_STREAM) { | |
116 | listen(listening_socket, 5); /* Queue up to five connections before | |
117 | having them automatically rejected. */ | |
118 | ||
119 | while(connected_socket < 0) { | |
120 | connected_socket = accept(listening_socket, NULL, NULL); | |
121 | if (connected_socket < 0) { | |
122 | /* Either a real error occured, or blocking was interrupted for | |
123 | some reason. Only abort execution if a real error occured. */ | |
124 | if (errno != EINTR) { | |
125 | perror("accept"); | |
126 | close(listening_socket); | |
127 | exit(EXIT_FAILURE); | |
128 | } else { | |
129 | continue; /* don't fork - do the accept again */ | |
130 | } | |
131 | } | |
132 | ||
133 | new_process = fork(); | |
134 | if (new_process < 0) { | |
135 | perror("fork"); | |
136 | close(connected_socket); | |
137 | connected_socket = -1; | |
138 | } | |
139 | else { /* We have a new process... */ | |
140 | if (new_process == 0) { | |
141 | /* This is the new process. */ | |
142 | close(listening_socket); /* Close our copy of this socket */ | |
143 | if (listener != NULL) | |
144 | *listener = -1; /* Closed in this process. We are not | |
145 | responsible for it. */ | |
146 | } | |
147 | else { | |
148 | /* This is the main loop. Close copy of connected socket, and | |
149 | continue loop. */ | |
150 | close(connected_socket); | |
151 | connected_socket = -1; | |
152 | } | |
153 | } | |
154 | } | |
155 | return connected_socket; | |
156 | } | |
157 | else | |
158 | return listening_socket; | |
159 | } | |
160 | ||
161 | /* This is a generic function to make a connection to a given server/port. | |
162 | service is the port name/number, | |
163 | type is either SOCK_STREAM or SOCK_DGRAM, and | |
164 | netaddress is the host name to connect to. | |
165 | The function returns the socket, ready for action.*/ | |
166 | int make_connection(char *service, int type, char *netaddress) | |
167 | { | |
168 | /* First convert service from a string, to a number... */ | |
169 | int port = -1; | |
170 | struct in_addr *addr; | |
171 | int sock, connected; | |
172 | struct sockaddr_in address; | |
173 | ||
174 | if (type == SOCK_STREAM) | |
175 | port = atoport(service, "tcp"); | |
176 | if (type == SOCK_DGRAM) | |
177 | port = atoport(service, "udp"); | |
178 | if (port == -1) { | |
179 | fprintf(stderr,"make_connection: Invalid socket type.\n"); | |
180 | return -1; | |
181 | } | |
182 | addr = atoaddr(netaddress); | |
183 | if (addr == NULL) { | |
184 | fprintf(stderr,"make_connection: Invalid network address.\n"); | |
185 | return -1; | |
186 | } | |
187 | ||
188 | memset((char *) &address, 0, sizeof(address)); | |
189 | address.sin_family = AF_INET; | |
190 | address.sin_port = (port); | |
191 | address.sin_addr.s_addr = addr->s_addr; | |
192 | ||
193 | sock = socket(AF_INET, type, 0); | |
194 | ||
195 | log("Connecting to %s on port %d.",inet_ntoa(*addr),htons(port)); | |
196 | ||
197 | if (type == SOCK_STREAM) { | |
198 | connected = connect(sock, (struct sockaddr *) &address, | |
199 | sizeof(address)); | |
200 | if (connected < 0) { | |
201 | perror("connect"); | |
202 | return -1; | |
203 | } | |
204 | return sock; | |
205 | } | |
206 | /* Otherwise, must be for udp, so bind to address. */ | |
207 | if (bind(sock, (struct sockaddr *) &address, sizeof(address)) < 0) { | |
208 | perror("bind"); | |
209 | return -1; | |
210 | } | |
211 | return sock; | |
212 | } | |
213 | ||
214 | /* This is just like the read() system call, accept that it will make | |
215 | sure that all your data goes through the socket. */ | |
216 | int sock_read(int sockfd, char *buf, size_t count) | |
217 | { | |
218 | size_t bytes_read = 0; | |
219 | int this_read; | |
220 | ||
221 | while (bytes_read < count) { | |
222 | do | |
223 | this_read = read(sockfd, buf, count - bytes_read); | |
224 | while ( (this_read < 0) && (errno == EINTR) ); | |
225 | if (this_read < 0) | |
226 | return this_read; | |
227 | else if (this_read == 0) | |
228 | return bytes_read; | |
229 | bytes_read += this_read; | |
230 | buf += this_read; | |
231 | } | |
232 | return count; | |
233 | } | |
234 | ||
235 | /* This function reads from a socket, until it recieves a linefeed | |
236 | character. It fills the buffer "str" up to the maximum size "count". | |
237 | ||
238 | This function will return -1 if the socket is closed during the read | |
239 | operation. | |
240 | ||
241 | Note that if a single line exceeds the length of count, the extra data | |
242 | will be read and discarded! You have been warned. */ | |
243 | int sock_gets(int sockfd, char *str, size_t count) | |
244 | { | |
245 | int bytes_read; | |
246 | unsigned int total_count = 0; | |
247 | char *current_position; | |
248 | char last_read = 0; | |
249 | ||
250 | current_position = str; | |
251 | while (last_read != 10) { | |
252 | bytes_read = read(sockfd, &last_read, 1); | |
253 | if (bytes_read <= 0) { | |
254 | /* The other side may have closed unexpectedly */ | |
255 | return -1; /* Is this effective on other platforms than linux? */ | |
256 | } | |
257 | if ( (total_count < count) && (last_read != 10) && (last_read !=13) ) | |
258 | { | |
259 | current_position[0] = last_read; | |
260 | current_position++; | |
261 | total_count++; | |
262 | } | |
263 | } | |
264 | if (count > 0) | |
265 | current_position[0] = 0; | |
266 | return total_count; | |
267 | } | |
268 | ||
269 | /* This is just like the write() system call, accept that it will | |
270 | make sure that all data is transmitted. */ | |
271 | int sock_write(int sockfd, const char *buf, size_t count) | |
272 | { | |
273 | size_t bytes_sent = 0; | |
274 | int this_write; | |
275 | ||
276 | while (bytes_sent < count) { | |
277 | do | |
278 | this_write = write(sockfd, buf, count - bytes_sent); | |
279 | while ( (this_write < 0) && (errno == EINTR) ); | |
280 | if (this_write <= 0) | |
281 | return this_write; | |
282 | bytes_sent += this_write; | |
283 | buf += this_write; | |
284 | } | |
285 | return count; | |
286 | } | |
287 | ||
288 | /* This function writes a character string out to a socket. It will | |
289 | return -1 if the connection is closed while it is trying to write. */ | |
290 | int sock_puts(int sockfd, const char *str) | |
291 | { | |
292 | return sock_write(sockfd, str, strlen(str)); | |
293 | } | |
294 | ||
295 | /* This ignores the SIGPIPE signal. This is usually a good idea, since | |
296 | the default behaviour is to terminate the application. SIGPIPE is | |
297 | sent when you try to write to an unconnected socket. You should | |
298 | check your return codes to make sure you catch this error! */ | |
299 | void ignore_pipe(void) | |
300 | { | |
301 | struct sigaction sig; | |
302 | ||
303 | sig.sa_handler = SIG_IGN; | |
304 | sig.sa_flags = 0; | |
305 | sigemptyset(&sig.sa_mask); | |
306 | sigaction(SIGPIPE,&sig,NULL); | |
307 | } | |
308 |