1 | /***************************************
2 | $Revision: 1.3 $
3 |
4 | Example code: A socket module.
5 |
6 | Status: NOT REVUED, NOT TESTED
7 |
8 | +html+ <DL COMPACT>
9 | +html+ <DT>Online References:
10 | +html+ <DD><UL>
11 | +html+ <LI>Adapted from <A HREF="http://www.ibrado.com/sock-faq/sfaq.html#faq65">sample source code</A>.
12 | +html+ </UL>
13 | +html+ </DL>
14 | +html+ <PRE>
15 | +html+ </PRE>
16 |
17 | ******************/ /******************
18 | Modification History:
19 | ottrey (08/03/1999) Created from sockhelp.c.
20 | ottrey (08/03/1998) Heavily butchered.
21 | joao (22/06/1999) Modified socket creation and accepts.
22 | ******************/ /******************
23 | REMINDER: PUT THE PROPER COPYRIGHT NOTICE HERE
24 | ***************************************/
25 | #include "socket.h"
26 | #include "constants.h"
27 |
28 |
29 | /*+ String sizes +*/
30 | #define STR_S 63
31 | #define STR_M 255
32 | #define STR_L 1023
33 | #define STR_XL 4095
34 | #define STR_XXL 16383
35 |
36 | static void log_print(const char *arg) {
37 | FILE *logf;
38 | char *str;
39 |
40 | if (CO_get_socket_logging() == 1) {
41 | if (strcmp(CO_get_socket_logfile(), "stdout") == 0) {
42 | printf(arg);
43 | }
44 | else {
45 | logf = fopen(CO_get_socket_logfile(), "a");
46 | fprintf(logf, arg);
47 | fclose(logf);
48 | }
49 | }
50 |
51 | } /* log_print() */
52 |
53 | /* SK_atoport() */
54 | /*++++++++++++++++++++++++++++++++++++++
55 | Take a service name, and a service type, and return a port number. If the
56 | service name is not found, it tries it as a decimal number. The number
57 | returned is byte ordered for the network.
58 |
59 | char *service Service name (or port number).
60 |
61 | char *proto Protocol (eg "tcp").
62 |
63 | More:
64 | +html+ <PRE>
65 | Authors:
66 | ottrey
67 |
68 | +html+ </PRE><DL COMPACT>
69 | +html+ <DT>Online References:
70 | +html+ <DD><UL>
71 | +html+ </UL></DL>
72 |
73 | ++++++++++++++++++++++++++++++++++++++*/
74 | int SK_atoport(const char *service, const char *proto) {
75 | int port;
76 | long int lport;
77 | struct servent *serv;
78 | char *errpos;
79 |
80 | /* First try to read it from /etc/services */
81 | serv = getservbyname(service, proto);
82 | if (serv != NULL)
83 | port = serv->s_port;
84 | else { /* Not in services, maybe a number? */
85 | lport = strtol(service,&errpos,0);
86 | if ( (errpos[0] != 0) || (lport < 1) || (lport > 65535) )
87 | return -1; /* Invalid port address */
88 | port = htons(lport);
89 | }
90 | return port;
91 | } /* SK_atoport() */
92 |
93 |
94 | /* SK_close_listening_socket() */
95 | /*++++++++++++++++++++++++++++++++++++++
96 | XXX Note: Not sure how long this function will last. Shouldn't _really_ need it.
97 |
98 | More:
99 | +html+ <PRE>
100 | Authors:
101 | ottrey
102 |
103 | +html+ </PRE><DL COMPACT>
104 | +html+ <DT>Online References:
105 | +html+ <DD><UL>
106 | +html+ </UL></DL>
107 |
108 | ++++++++++++++++++++++++++++++++++++++*/
109 | /*void SK_close_listening_socket() {
110 | close(listening_socket);
111 | } */ /* SK_close_listening_socket */
112 |
113 | static void func_atexit(void) {
114 | printf("SK: func_atexit() called\n");
115 | }
116 |
117 | static void func_sighup(int n) {
118 | printf("SK: func_sighup(%d) called\n", n);
119 | }
120 |
121 | static void func_sigint(int n) {
122 | printf("SK: func_sigint(%d) called\n", n);
123 | }
124 |
125 |
126 | void SK_close(int socket) {
127 | char print_buf[STR_M];
128 |
129 | sprintf(print_buf, "Closing socket... %d\n", socket); log_print(print_buf); strcpy(print_buf, "");
130 |
131 | close(socket);
132 | }
133 |
134 | /* SK_getsock() */
135 | /*++++++++++++++++++++++++++++++++++++++
136 |
137 | This function creates a socket and binds to it
138 |
139 | int SK_getsock The new socket
140 |
141 | int socket_type SOCK_STREAM or SOCK_DGRAM (TCP or UDP sockets)
142 |
143 | u_short port The port to listen on. Remember that ports < 1024 are
144 | reserved for the root user. Must be passed in network byte
145 | order (see "man htons").
146 |
147 | uint32_t bind_address Address to bind to, in network order.
148 | More:
149 | +html+ <PRE>
150 | Authors:
151 | ottrey
152 | joao
153 |
154 | +html+ </PRE><DL COMPACT>
155 | +html+ <DT>Online References:
156 | +html+ <DD><UL>
157 | +html+ </UL></DL>
158 |
159 | ++++++++++++++++++++++++++++++++++++++*/
160 | int SK_getsock(int socket_type, u_short port, uint32_t bind_address) {
161 | struct sockaddr_in address;
162 | int listening_socket;
163 | int new_process;
164 | int reuse_addr = 1;
165 |
166 | /* Setup internet address information.
167 | This is used with the bind() call */
168 | memset((char *) &address, 0, sizeof(address));
169 | address.sin_family = AF_INET;
170 | address.sin_port = port;
171 | address.sin_addr.s_addr = bind_address;
172 |
173 | /* Map all of the signals and exit routine */
174 | atexit(func_atexit);
175 | /* signal.h has a full list of signal names */
176 | signal(SIGHUP, func_sighup);
177 | signal(SIGINT, func_sigint);
178 |
179 | listening_socket = socket(AF_INET, socket_type, 0);
180 | if (listening_socket < 0) {
181 | perror("socket");
182 | exit(EXIT_FAILURE);
183 | }
184 |
185 | setsockopt(listening_socket, SOL_SOCKET, SO_REUSEADDR, (void *)&reuse_addr, sizeof(reuse_addr));
186 |
187 | if (bind(listening_socket, (struct sockaddr *) &address, sizeof(address)) < 0) {
188 | perror("bind");
189 | close(listening_socket);
190 | exit(EXIT_FAILURE);
191 | }
192 |
193 |
194 | if (socket_type == SOCK_STREAM) {
195 | listen(listening_socket, 5); /* Queue up to five connections before
196 | having them automatically rejected. */
197 | }
198 |
199 | return listening_socket;
200 | } /* SK_getsock() */
201 |
202 | /*++++++++++++++++++++++++++++++++++++++
203 |
204 | Wait for an incoming connection on the specified socket
205 |
206 | int SK_accept_connection The socket for communicating to the client
207 |
208 | int listening_socket The socket that the server is bound to
209 |
210 | More:
211 | +html+ <PRE>
212 | Authors:
213 | joao
214 | +html+ </PRE>
215 | ++++++++++++++++++++++++++++++++++++++*/
216 | int SK_accept_connection(int listening_socket) {
217 | int connected_socket = -1;
218 | char print_buf[STR_L];
219 |
220 | while(connected_socket < 0) {
221 | sprintf(print_buf, "Going to accept connections on socket : %d\n",listening_socket); log_print(print_buf); strcpy(print_buf, "");
222 | /* XXX joao - ? - why is this here?
223 | fflush(NULL);
224 | */
225 | connected_socket = accept(listening_socket, NULL, NULL);
226 | if (connected_socket < 0) {
227 | /* Either a real error occured, or blocking was interrupted for
228 | some reason. Only abort execution if a real error occured. */
229 | if (errno != EINTR) {
230 | perror("accept");
231 | close(listening_socket);
232 | exit(EXIT_FAILURE);
233 | } else {
234 | continue; /* don't return - do the accept again */
235 | }
236 | }
237 | }
238 | sprintf(print_buf, "connected_socket=%d\n", connected_socket); log_print(print_buf); strcpy(print_buf, "");
239 |
240 | return connected_socket;
241 | }
242 |
243 | /* sock_read() */
244 | /*++++++++++++++++++++++++++++++++++++++
245 |
246 | This is just like the read() system call, except that it will make
247 | sure that all your data goes through the socket.
248 |
249 | int sock_read The number of bytes read.
250 |
251 | int sockfd The socket file descriptor.
252 |
253 | char *buf The buffer to be read from the socket.
254 |
255 | size_t count The number of bytes in the buffer.
256 |
257 | More:
258 | +html+ <PRE>
259 | Authors:
260 | ottrey
261 | +html+ </PRE>
262 | ++++++++++++++++++++++++++++++++++++++*/
263 | static int sock_read(int sockfd, char *buf, size_t count) {
264 | size_t bytes_read = 0;
265 | int this_read;
266 |
267 | while (bytes_read < count) {
268 | do
269 | this_read = read(sockfd, buf, count - bytes_read);
270 | while ( (this_read < 0) && (errno == EINTR) );
271 | if (this_read < 0)
272 | return this_read;
273 | else if (this_read == 0)
274 | return bytes_read;
275 | bytes_read += this_read;
276 | buf += this_read;
277 | }
278 |
279 | return count;
280 |
281 | } /* sock_read() */
282 |
283 |
284 | /* sock_write() */
285 | /*++++++++++++++++++++++++++++++++++++++
286 |
287 | This is just like the write() system call, accept that it will
288 | make sure that all data is transmitted.
289 |
290 | int sockfd The socket file descriptor.
291 |
292 | char *buf The buffer to be written to the socket.
293 |
294 | size_t count The number of bytes in the buffer.
295 |
296 | More:
297 | +html+ <PRE>
298 | Authors:
299 | ottrey
300 |
301 | +html+ </PRE><DL COMPACT>
302 | +html+ <DT>Online References:
303 | +html+ <DD><UL>
304 | +html+ </UL></DL>
305 |
306 | ++++++++++++++++++++++++++++++++++++++*/
307 | static int sock_write(int sockfd, const char *buf, size_t count) {
308 | size_t bytes_sent = 0;
309 | int this_write;
310 |
311 | /*
312 | printf("sock_write = { sockfd=[%d], buf=[%s], count=[%d]\n", sockfd, buf, count);
313 | */
314 | while (bytes_sent < count) {
315 | do
316 | this_write = write(sockfd, buf, count - bytes_sent);
317 | while ( (this_write < 0) && (errno == EINTR) );
318 | if (this_write <= 0)
319 | return this_write;
320 | bytes_sent += this_write;
321 | buf += this_write;
322 | }
323 | return count;
324 | } /* sock_write() */
325 |
326 |
327 | /* SK_gets() */
328 | /*++++++++++++++++++++++++++++++++++++++
329 |
330 | This function reads from a socket, until it recieves a linefeed
331 | character. It fills the buffer "str" up to the maximum size "count".
332 |
333 | int SK_gets The total_count of bytes read.
334 |
335 | int sockfd The socket file descriptor.
336 |
337 | char *str The buffer to be written from the socket.
338 |
339 | size_t count The number of bytes in the buffer.
340 |
341 | More:
342 | +html+ <PRE>
343 | Authors:
344 | ottrey
345 |
346 | Side Effects:
347 | This function will return -1 if the socket is closed during the read operation.
348 |
349 | Note that if a single line exceeds the length of count, the extra data
350 | will be read and discarded! You have been warned.
351 |
352 | To Do:
353 | Capture the control-c properly!
354 |
355 | +html+ </PRE>
356 |
357 | ++++++++++++++++++++++++++++++++++++++*/
358 | int SK_gets(int sockfd, char *str, size_t count) {
359 | int bytes_read;
360 | int total_count = 0;
361 | char *current_position;
362 | char last_read = 0;
363 |
364 | int control_c = 0;
365 |
366 | current_position = str;
367 | while (last_read != 10) {
368 | bytes_read = read(sockfd, &last_read, 1);
369 | if (bytes_read <= 0) {
370 | /* The other side may have closed unexpectedly */
371 | return -1; /* Is this effective on other platforms than linux? */
372 | }
373 | if ( (total_count < count) && (last_read != 10) && (last_read !=13) ) {
374 | *current_position = last_read;
375 | current_position++;
376 | total_count++;
377 | }
378 |
379 | if (last_read == -1) {
380 | bytes_read = read(sockfd, &last_read, 1);
381 | if (last_read == -12) {
382 | printf("Client pressed Control-c.\n");
383 | control_c = 1;
384 | printf("returning a -2\n");
385 | return -2;
386 | }
387 | }
388 | }
389 | if (count > 0) {
390 | *current_position = 0;
391 | }
392 |
393 | return total_count;
394 |
395 | } /* SK_gets() */
396 |
397 |
398 | /* SK_puts() */
399 | /*++++++++++++++++++++++++++++++++++++++
400 |
401 | This function writes a character string out to a socket.
402 |
403 | int SK_puts The total_count of bytes read.
404 |
405 | int sockfd The socket file descriptor.
406 |
407 | char *str The buffer to be written from the socket.
408 |
409 | More:
410 | +html+ <PRE>
411 | Authors:
412 | ottrey
413 |
414 | Side Effects:
415 | This function will return -1 if the socket is closed during the write operation.
416 |
417 | Note that if a single line exceeds the length of count, the extra data
418 | will be read and discarded! You have been warned.
419 |
420 | +html+ </PRE>
421 |
422 | ++++++++++++++++++++++++++++++++++++++*/
423 | int SK_puts(int sockfd, const char *str) {
424 |
425 | return sock_write(sockfd, str, strlen(str));
426 |
427 | } /* SK_puts() */
428 |