sockets.c
1 /******************************************************************** 2 * Description: sockets.c 3 * socket utilites 4 * 5 * Copyright(c) 2001, Joris Robijn 6 * (c) 2003, Rene Wagner 7 * Adapted for EMC by: Eric H. Johnson 8 * License: GPL Version 2 9 * System: Linux 10 * 11 * Copyright (c) 2007 All rights reserved. 12 * 13 * Last change: 14 ********************************************************************/ 15 16 #include "config.h" 17 #include <unistd.h> 18 #include <stddef.h> 19 #include <stdio.h> 20 #include <string.h> 21 #include <errno.h> 22 #include <stdlib.h> 23 #include <sys/types.h> 24 25 #ifndef WINSOCK2 26 #include <sys/socket.h> 27 #include <sys/un.h> 28 #include <netinet/in.h> 29 #include <netdb.h> 30 #include <arpa/inet.h> 31 #else 32 #include <winsock2.h> 33 #endif 34 35 #include <stdarg.h> 36 #include <fcntl.h> 37 38 #include "rcs_print.hh" 39 #include "sockets.h" 40 41 /************************************************** 42 * LCDproc client sockets code... 43 * Note: LCDproc error reporting was replaced 44 * with EMC standard debug reporting. 45 **************************************************/ 46 47 // Length of longest transmission allowed at once... 48 #define MAXMSG 8192 49 50 typedef struct sockaddr_in sockaddr_in; 51 52 static int sockInitSockaddr(sockaddr_in *name, const char *hostname, unsigned short int port) 53 { 54 struct hostent *hostinfo; 55 56 memset(name, '\0', sizeof (*name)); 57 name->sin_family = AF_INET; 58 name->sin_port = htons(port); 59 hostinfo = gethostbyname(hostname); 60 if (hostinfo == NULL) { 61 rcs_print_error("sock_init_sockaddr: Unknown host\n"); 62 return -1; 63 } 64 name->sin_addr = *(struct in_addr *) hostinfo->h_addr; 65 66 return 0; 67 } 68 69 // Client functions... 70 int sockConnect(char *host, unsigned short int port) 71 { 72 struct sockaddr_in servername; 73 int sock; 74 int err = 0; 75 76 rcs_print_error("sock_connect: Creating socket\n"); 77 sock = socket(PF_INET, SOCK_STREAM, 0); 78 #ifdef WINSOCK2 79 if (sock == INVALID_SOCKET) { 80 #else 81 if (sock < 0) { 82 #endif 83 rcs_print_error("sock_connect: Error creating socket\n"); 84 return sock; 85 } 86 rcs_print_error("sock_connect: Created socket\n"); 87 88 if (sockInitSockaddr(&servername, host, port) < 0) 89 return -1; 90 91 err = connect(sock, (struct sockaddr *) &servername, sizeof (servername)); 92 #ifdef WINSOCK2 93 if (err == INVALID_SOCKET) { 94 #else 95 if (err < 0) { 96 #endif 97 rcs_print_error("sock_connect: connect failed\n"); 98 shutdown(sock, SHUT_RDWR); 99 return -1; 100 } 101 102 #ifndef WINSOCK2 103 fcntl(sock, F_SETFL, O_NONBLOCK); 104 #else 105 { 106 unsigned long tmp = 1; 107 if (ioctlsocket(sock, FIONBIO, &tmp) == SOCKET_ERROR) 108 rcs_print_error("sock_connect: Error setting socket to non-blocking\n"); 109 } 110 #endif 111 112 return sock; 113 } 114 115 int sockClose(int fd) 116 { 117 int err; 118 119 err = shutdown(fd, SHUT_RDWR); 120 if (!err) close (fd); 121 122 return err; 123 } 124 125 126 /** send printf-like formatted output */ 127 int sockPrintf(int fd, const char *format, .../*args*/ ) 128 { 129 char buf[MAXMSG]; 130 va_list ap; 131 int size = 0; 132 133 va_start(ap, format); 134 size = vsnprintf(buf, sizeof(buf), format, ap); 135 va_end(ap); 136 137 if (size < 0) { 138 rcs_print_error("sock_printf: vsnprintf failed\n"); 139 return -1; 140 } 141 if (size > sizeof(buf)) { 142 rcs_print_error("sock_printf: vsnprintf truncated message\n"); 143 } 144 return sockSendString(fd, buf); 145 } 146 147 // Send/receive lines of text 148 int sockSendString(int fd, const char *string) 149 { 150 return sockSend(fd, string, strlen(string)); 151 } 152 153 // Recv gives only one line per call... 154 int sockRecvString(int fd, char *dest, size_t maxlen) 155 { 156 char *ptr = dest; 157 int recvBytes = 0; 158 159 if (!dest) return -1; 160 if (maxlen <= 0) return 0; 161 162 while (1) { 163 int err = recv(fd, ptr, 1, 0); 164 if (err == -1) { 165 if (errno == EAGAIN) { 166 if (recvBytes) { 167 // We've begun to read a string, but no bytes are 168 // available. Loop. 169 continue; 170 } 171 return 0; 172 } 173 else { 174 rcs_print_error("sock_recv_string: socket read error"); 175 return err; 176 } 177 } 178 else if (err == 0) { 179 return recvBytes; 180 } 181 182 recvBytes++; 183 184 // stop at max. bytes allowed, at NUL or at LF 185 if (recvBytes == maxlen || *ptr == '\0' || *ptr == '\n') { 186 *ptr = '\0'; 187 break; 188 } 189 ptr++; 190 } 191 192 // Don't return an empty string 193 if (recvBytes == 1 && dest[0] == '\0') 194 return 0; 195 196 if (recvBytes < maxlen - 1) 197 dest[recvBytes] = '\0'; 198 199 return recvBytes; 200 } 201 202 // Send/receive raw data 203 int sockSend(int fd, const void *src, size_t size) 204 { 205 int offset = 0; 206 207 if (!src) return -1; 208 209 while (offset != size) { 210 // write isn't guaranteed to send the entire string at once, 211 // so we have to sent it in a loop like this 212 #ifndef WINSOCK2 213 int sent = write(fd, ((const char *) src) + offset, size - offset); 214 #else 215 int sent = send(fd, ((const char *) src) + offset, size - offset, 0); 216 #endif 217 if (sent == -1) { 218 if (errno != EAGAIN) { 219 rcs_print_error("sock_send: socket write error\n"); 220 // shutdown(fd, SHUT_RDWR); 221 return sent; 222 } 223 continue; 224 } 225 else if (sent == 0) return sent + offset; 226 offset += sent; 227 } // while 228 229 return offset; 230 } 231 232 int sockRecv(int fd, void *dest, size_t maxlen) 233 { 234 int err; 235 236 if (!dest) return -1; 237 if (maxlen <= 0) return 0; 238 239 #ifndef WINSOCK2 240 err = read (fd, dest, maxlen); 241 #else 242 err = recv(fd, dest, maxlen, 0); 243 #endif 244 if (err < 0) { 245 // rcs_print_error("sock_recv: socket read error\n"); 246 // shutdown(fd, SHUT_RDWR); 247 return err; 248 } 249 250 return err; 251 } 252 253 /*****************************************************************************/ 254 255 char* sockGetError(void) 256 { 257 #ifndef WINSOCK2 258 return strerror(errno); 259 #else 260 static char retString[256]; 261 long err; 262 char* tmp; 263 264 err = WSAGetLastError(); 265 266 sprintf(retString, "Error code %ld: ", err); 267 FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | 268 FORMAT_MESSAGE_FROM_SYSTEM | 269 FORMAT_MESSAGE_IGNORE_INSERTS, 270 NULL, 271 err, 272 0, /* Default language */ 273 (LPTSTR) &tmp, 274 0, 275 NULL); 276 277 /* append the message text after the error code and ensure a terminating 278 character ends the string */ 279 strncpy(retString + strlen(retString), tmp, 280 sizeof(retString) - strlen(retString) - 1); 281 retString[sizeof(retString) - 1] = '\0'; 282 283 return retString; 284 #endif 285 } 286 287 /** prints error to logfile and sends it to the client. 288 * @param fd socket 289 * @param message the message to send (without the "huh? ") */ 290 int sockSendError(int fd, const char* message) 291 { 292 // simple: performance penalty isn't worth more work... 293 return sockPrintfError(fd, "%s", message); 294 } 295 296 /** prints printf-like formatted output to logfile and sends it to the 297 * client. 298 * @note don't add a the "huh? " to the message. This is done by this 299 * method 300 * @param fd socket 301 * @param format a printf format */ 302 int sockPrintfError(int fd, const char *format, .../*args*/ ) 303 { 304 static const char huh[] = "huh? "; 305 char buf[MAXMSG]; 306 va_list ap; 307 int size = 0; 308 309 strncpy(buf, huh, sizeof(huh)); // note: sizeof(huh) < MAXMSG 310 311 va_start(ap, format); 312 size = vsnprintf(buf + (sizeof(huh)-1), sizeof(buf) - (sizeof(huh)-1), format, ap); 313 buf[sizeof(buf)-1] = '\0'; 314 va_end(ap); 315 316 if (size < 0) { 317 rcs_print_error("sock_printf_error: vsnprintf failed\n"); 318 return -1; 319 } 320 if (size >= sizeof(buf) - (sizeof(huh)-1)) { 321 rcs_print_error("sock_printf_error: vsnprintf truncated message\n"); 322 } 323 324 return sockSendString(fd, buf); 325 }