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 |