1/*************************************************************************** 2 * _ _ ____ _ 3 * Project ___| | | | _ \| | 4 * / __| | | | |_) | | 5 * | (__| |_| | _ <| |___ 6 * \___|\___/|_| \_\_____| 7 * 8 * Copyright (C) 1998 - 2010, Daniel Stenberg, <daniel@haxx.se>, et al. 9 * 10 * This software is licensed as described in the file COPYING, which 11 * you should have received as part of this distribution. The terms 12 * are also available at http://curl.haxx.se/docs/copyright.html. 13 * 14 * You may opt to use, copy, modify, merge, publish, distribute and/or sell 15 * copies of the Software, and permit persons to whom the Software is 16 * furnished to do so, under the terms of the COPYING file. 17 * 18 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY 19 * KIND, either express or implied. 20 * 21 ***************************************************************************/ 22 23#define CURL_NO_OLDIES 24 25#include "setup.h" /* portability help from the lib directory */ 26 27#ifdef HAVE_SIGNAL_H 28#include <signal.h> 29#endif 30#ifdef HAVE_UNISTD_H 31#include <unistd.h> 32#endif 33#ifdef HAVE_SYS_SOCKET_H 34#include <sys/socket.h> 35#endif 36#ifdef HAVE_NETINET_IN_H 37#include <netinet/in.h> 38#endif 39#ifdef _XOPEN_SOURCE_EXTENDED 40/* This define is "almost" required to build on HPUX 11 */ 41#include <arpa/inet.h> 42#endif 43#ifdef HAVE_NETDB_H 44#include <netdb.h> 45#endif 46#ifdef HAVE_SYS_POLL_H 47#include <sys/poll.h> 48#elif defined(HAVE_POLL_H) 49#include <poll.h> 50#endif 51 52#define ENABLE_CURLX_PRINTF 53/* make the curlx header define all printf() functions to use the curlx_* 54 versions instead */ 55#include "curlx.h" /* from the private lib dir */ 56#include "getpart.h" 57#include "util.h" 58#include "timeval.h" 59 60#if defined(ENABLE_IPV6) && defined(__MINGW32__) 61const struct in6_addr in6addr_any = {{ IN6ADDR_ANY_INIT }}; 62#endif 63 64void logmsg(const char *msg, ...) 65{ 66 va_list ap; 67 char buffer[2048 + 1]; 68 FILE *logfp; 69 int error; 70 struct timeval tv; 71 time_t sec; 72 struct tm *now; 73 char timebuf[20]; 74 static time_t epoch_offset; 75 static int known_offset; 76 77 if (!serverlogfile) { 78 fprintf(stderr, "Error: serverlogfile not set\n"); 79 return; 80 } 81 82 tv = curlx_tvnow(); 83 if(!known_offset) { 84 epoch_offset = time(NULL) - tv.tv_sec; 85 known_offset = 1; 86 } 87 sec = epoch_offset + tv.tv_sec; 88 now = localtime(&sec); /* not thread safe but we don't care */ 89 90 snprintf(timebuf, sizeof(timebuf), "%02d:%02d:%02d.%06ld", 91 (int)now->tm_hour, (int)now->tm_min, (int)now->tm_sec, (long)tv.tv_usec); 92 93 va_start(ap, msg); 94 vsnprintf(buffer, sizeof(buffer), msg, ap); 95 va_end(ap); 96 97 logfp = fopen(serverlogfile, "ab"); 98 if(logfp) { 99 fprintf(logfp, "%s %s\n", timebuf, buffer); 100 fclose(logfp); 101 } 102 else { 103 error = ERRNO; 104 fprintf(stderr, "fopen() failed with error: %d %s\n", 105 error, strerror(error)); 106 fprintf(stderr, "Error opening file: %s\n", serverlogfile); 107 fprintf(stderr, "Msg not logged: %s %s\n", timebuf, buffer); 108 } 109} 110 111#ifdef WIN32 112/* use instead of perror() on generic windows */ 113void win32_perror (const char *msg) 114{ 115 char buf[512]; 116 DWORD err = SOCKERRNO; 117 118 if (!FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL, err, 119 LANG_NEUTRAL, buf, sizeof(buf), NULL)) 120 snprintf(buf, sizeof(buf), "Unknown error %lu (%#lx)", err, err); 121 if (msg) 122 fprintf(stderr, "%s: ", msg); 123 fprintf(stderr, "%s\n", buf); 124} 125#endif /* WIN32 */ 126 127#ifdef USE_WINSOCK 128void win32_init(void) 129{ 130 WORD wVersionRequested; 131 WSADATA wsaData; 132 int err; 133 wVersionRequested = MAKEWORD(USE_WINSOCK, USE_WINSOCK); 134 135 err = WSAStartup(wVersionRequested, &wsaData); 136 137 if (err != 0) { 138 perror("Winsock init failed"); 139 logmsg("Error initialising winsock -- aborting"); 140 exit(1); 141 } 142 143 if ( LOBYTE( wsaData.wVersion ) != USE_WINSOCK || 144 HIBYTE( wsaData.wVersion ) != USE_WINSOCK ) { 145 146 WSACleanup(); 147 perror("Winsock init failed"); 148 logmsg("No suitable winsock.dll found -- aborting"); 149 exit(1); 150 } 151} 152 153void win32_cleanup(void) 154{ 155 WSACleanup(); 156} 157#endif /* USE_WINSOCK */ 158 159/* set by the main code to point to where the test dir is */ 160const char *path="."; 161 162char *test2file(long testno) 163{ 164 static char filename[256]; 165 snprintf(filename, sizeof(filename), TEST_DATA_PATH, path, testno); 166 return filename; 167} 168 169/* 170 * Portable function used for waiting a specific amount of ms. 171 * Waiting indefinitely with this function is not allowed, a 172 * zero or negative timeout value will return immediately. 173 * 174 * Return values: 175 * -1 = system call error, or invalid timeout value 176 * 0 = specified timeout has elapsed 177 */ 178int wait_ms(int timeout_ms) 179{ 180#if !defined(MSDOS) && !defined(USE_WINSOCK) 181#ifndef HAVE_POLL_FINE 182 struct timeval pending_tv; 183#endif 184 struct timeval initial_tv; 185 int pending_ms; 186 int error; 187#endif 188 int r = 0; 189 190 if(!timeout_ms) 191 return 0; 192 if(timeout_ms < 0) { 193 SET_SOCKERRNO(EINVAL); 194 return -1; 195 } 196#if defined(MSDOS) 197 delay(timeout_ms); 198#elif defined(USE_WINSOCK) 199 Sleep(timeout_ms); 200#else 201 pending_ms = timeout_ms; 202 initial_tv = curlx_tvnow(); 203 do { 204#if defined(HAVE_POLL_FINE) 205 r = poll(NULL, 0, pending_ms); 206#else 207 pending_tv.tv_sec = pending_ms / 1000; 208 pending_tv.tv_usec = (pending_ms % 1000) * 1000; 209 r = select(0, NULL, NULL, NULL, &pending_tv); 210#endif /* HAVE_POLL_FINE */ 211 if(r != -1) 212 break; 213 error = SOCKERRNO; 214 if(error && (error != EINTR)) 215 break; 216 pending_ms = timeout_ms - (int)curlx_tvdiff(curlx_tvnow(), initial_tv); 217 if(pending_ms <= 0) 218 break; 219 } while(r == -1); 220#endif /* USE_WINSOCK */ 221 if(r) 222 r = -1; 223 return r; 224} 225 226int write_pidfile(const char *filename) 227{ 228 FILE *pidfile; 229 long pid; 230 231 pid = (long)getpid(); 232 pidfile = fopen(filename, "wb"); 233 if(!pidfile) { 234 logmsg("Couldn't write pid file: %s %s", filename, strerror(ERRNO)); 235 return 0; /* fail */ 236 } 237 fprintf(pidfile, "%ld\n", pid); 238 fclose(pidfile); 239 logmsg("Wrote pid %ld to %s", pid, filename); 240 return 1; /* success */ 241} 242 243void set_advisor_read_lock(const char *filename) 244{ 245 FILE *lockfile; 246 int error = 0; 247 int res; 248 249 do { 250 lockfile = fopen(filename, "wb"); 251 } while((lockfile == NULL) && ((error = ERRNO) == EINTR)); 252 if(lockfile == NULL) { 253 logmsg("Error creating lock file %s error: %d %s", 254 filename, error, strerror(error)); 255 return; 256 } 257 258 do { 259 res = fclose(lockfile); 260 } while(res && ((error = ERRNO) == EINTR)); 261 if(res) 262 logmsg("Error closing lock file %s error: %d %s", 263 filename, error, strerror(error)); 264} 265 266void clear_advisor_read_lock(const char *filename) 267{ 268 int error = 0; 269 int res; 270 271 /* 272 ** Log all removal failures. Even those due to file not existing. 273 ** This allows to detect if unexpectedly the file has already been 274 ** removed by a process different than the one that should do this. 275 */ 276 277 do { 278 res = unlink(filename); 279 } while(res && ((error = ERRNO) == EINTR)); 280 if(res) 281 logmsg("Error removing lock file %s error: %d %s", 282 filename, error, strerror(error)); 283} 284