00001 #include "streams.h"
00002 #include "wvstring.h"
00003 #include <assert.h>
00004 #include <errno.h>
00005 #include <conio.h>
00006 #include <stdio.h>
00007 #include <io.h>
00008
00009 #if _MSC_VER
00010
00011 # define DPRINTF
00012 #else
00013 #if 0
00014 # define DPRINTF(x, args...) do { \
00015 printf(x, ## args); fflush(stdout); \
00016 } while (0)
00017 #else
00018 # define DPRINTF(x, args...) do { } while(0)
00019 #endif
00020 #endif
00021
00022
00023
00024
00025
00026 class FixLibcIoBuffers
00027 {
00028 public:
00029 FixLibcIoBuffers()
00030 {
00031 setvbuf(stdout, NULL, _IOLBF, 0);
00032 setvbuf(stderr, NULL, _IONBF, 0);
00033 }
00034 };
00035 static FixLibcIoBuffers fixbufs;
00036
00037
00038
00039
00040
00041
00042
00043 static void errcode(int err)
00044 {
00045 if (err == EIO)
00046 err = EBADF;
00047 if (err == WSAENOTSOCK)
00048 err = EBADF;
00049 SetLastError(err);
00050 errno = err;
00051 }
00052
00053
00054 static bool is_socket(int fd)
00055 {
00056
00057
00058 return (HANDLE)_get_osfhandle(fd) == INVALID_HANDLE_VALUE;
00059 }
00060
00061
00062 int close(int fd)
00063 {
00064 int ret;
00065 if (is_socket(fd))
00066 {
00067 ret = closesocket(fd);
00068 errcode(GetLastError());
00069 }
00070 else
00071 {
00072 ret = _close(fd);
00073 errcode(errno);
00074 }
00075 return ret;
00076 }
00077
00078
00079 int read(int fd, void *buf, size_t count)
00080 {
00081 int ret;
00082 if (is_socket(fd))
00083 {
00084 ret = recv(fd, (char *)buf, count, 0);
00085 errcode(GetLastError());
00086 }
00087 else
00088 {
00089 ret = _read(fd, buf, count);
00090 errcode(errno);
00091 }
00092 return ret;
00093 }
00094
00095
00096 int write(int fd, const void *buf, size_t count)
00097 {
00098 int ret;
00099 if (is_socket(fd))
00100 {
00101 ret = send(fd, (char *)buf, count, 0);
00102 errcode(GetLastError());
00103 }
00104 else
00105 {
00106 ret = _write(fd, buf, count);
00107 errcode(errno);
00108 }
00109 return ret;
00110 }
00111
00112
00113 int socketpair(int family, int type, int protocol, int *sb)
00114 {
00115 SOCKET insock, outsock, newsock;
00116 struct sockaddr_in sock_in;
00117
00118 if (type != SOCK_STREAM)
00119 return -1;
00120
00121 newsock = socket(AF_INET, type, 0);
00122 if (newsock == INVALID_SOCKET)
00123 return -1;
00124
00125 sock_in.sin_family = AF_INET;
00126 sock_in.sin_port = 0;
00127 sock_in.sin_addr.s_addr = INADDR_ANY;
00128 if (bind(newsock, (struct sockaddr *) &sock_in, sizeof (sock_in)) < 0)
00129 return -1;
00130
00131 int len = sizeof (sock_in);
00132 if (getsockname(newsock, (struct sockaddr *)&sock_in, &len) < 0)
00133 return -1;
00134
00135 if (listen(newsock, 2) < 0)
00136 return -1;
00137
00138 outsock = socket(AF_INET, type, 0);
00139 if (outsock == INVALID_SOCKET)
00140 return -1;
00141
00142 sock_in.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
00143 if (connect(outsock, (struct sockaddr *)&sock_in, sizeof(sock_in)) < 0)
00144 return -1;
00145
00146
00147 len = sizeof(sock_in);
00148 insock = accept(newsock, (struct sockaddr *)&sock_in, &len);
00149 if (insock == INVALID_SOCKET)
00150 return -1;
00151
00152 if (closesocket(newsock) < 0)
00153 return -1;
00154
00155 sb[0] = insock;
00156 sb[1] = outsock;
00157 return 0;
00158 }
00159
00160
00161 static void CALLBACK completion(DWORD error, DWORD nread, LPOVERLAPPED ov)
00162 {
00163 }
00164
00165
00166 static size_t fake_read(int fd, void *buf, size_t len)
00167 {
00168 HANDLE h = (HANDLE)_get_osfhandle(fd);
00169 INPUT_RECORD p;
00170 DPRINTF("fake_read(%d/%d,%p,%d) = ", fd, (int)h, buf, (int)len);
00171
00172 DWORD ret = 0;
00173 OVERLAPPED ov;
00174 memset(&ov, 0, sizeof(ov));
00175 ov.Offset = SetFilePointer(h, 0, NULL, FILE_CURRENT);
00176
00177 if (PeekNamedPipe(h, NULL, 0, NULL, &ret, NULL))
00178 {
00179
00180
00181
00182 DPRINTF("(stdin is a pipe)\n");
00183 while (PeekNamedPipe(h, NULL, 0, NULL, &ret, NULL) && !ret)
00184 {
00185 DPRINTF(".");
00186 Sleep(100);
00187 }
00188 ReadFile(h, buf, len, &ret, NULL);
00189 }
00190 else if (PeekConsoleInput(h, &p, 1, &ret))
00191 {
00192
00193
00194
00195
00196
00197
00198
00199 DPRINTF("(stdin is a console)\n");
00200
00201 size_t used = 0;
00202 char *xbuf = (char *)buf;
00203 HANDLE hout = CreateFile("CONOUT$", GENERIC_READ | GENERIC_WRITE,
00204 FILE_SHARE_READ | FILE_SHARE_WRITE,
00205 NULL, OPEN_EXISTING, 0, 0);
00206
00207 DWORD conmode = 0;
00208 GetConsoleMode(h, &conmode);
00209 SetConsoleMode(h, conmode &
00210 ~(ENABLE_LINE_INPUT | ENABLE_MOUSE_INPUT | ENABLE_ECHO_INPUT));
00211
00212 while (PeekConsoleInput(h, &p, 1, &ret))
00213 {
00214 DWORD tmp;
00215 if (ret)
00216 {
00217 ReadConsoleInput(h, &p, 1, &ret);
00218 assert(ret);
00219 if (p.EventType == KEY_EVENT && p.Event.KeyEvent.bKeyDown)
00220 {
00221 int key = p.Event.KeyEvent.uChar.AsciiChar;
00222 if (key == '\r')
00223 {
00224 xbuf[used++] = '\n';
00225 WriteConsole(hout, "\r\n", 2, &tmp, NULL);
00226 ret = used;
00227 break;
00228 }
00229 else if (key == '\b' && used > 0)
00230 {
00231 used--;
00232 WriteConsole(hout, "\b \b", 3, &tmp, NULL);
00233 }
00234 else if (key && used < len-1)
00235 {
00236 xbuf[used++] = key;
00237 WriteConsole(hout, xbuf+used-1, 1, &tmp, NULL);
00238 }
00239 }
00240 }
00241 else
00242 {
00243 DPRINTF(".");
00244 WaitForSingleObjectEx(h, 1000, true);
00245 }
00246 }
00247
00248 CloseHandle(hout);
00249 }
00250 else
00251 {
00252
00253
00254
00255 DPRINTF("(stdin is a file)\n");
00256 while (!ret)
00257 {
00258 DPRINTF(".");
00259 int rv = 0;
00260 if (ReadFileEx(h, buf, 0, &ov, &completion))
00261 {
00262 rv = SleepEx(1000, true);
00263 CancelIo(h);
00264 DPRINTF("(rv is %d)\n", rv);
00265 if (rv == WAIT_IO_COMPLETION)
00266 {
00267 ReadFile(h, buf, len, &ret, NULL);
00268 break;
00269 }
00270 else if (!rv)
00271 Sleep(1);
00272 else
00273 return 0;
00274 }
00275 else
00276 {
00277
00278 ReadFile(h, buf, len, &ret, NULL);
00279 break;
00280 }
00281 }
00282 }
00283
00284 DPRINTF("[%d]\n", ret);
00285 return ret;
00286 }
00287
00288
00289 DWORD WINAPI fd2socket_fwd(LPVOID lpThreadParameter)
00290 {
00291
00292 DWORD retval = 0;
00293 const int BUFSIZE = 512;
00294 socket_fd_pair *pair = (socket_fd_pair *)lpThreadParameter;
00295
00296
00297
00298
00299 char buf[BUFSIZE];
00300 while (true)
00301 {
00302 char *ptr = buf;
00303
00304 size_t bytes = fake_read(pair->fd, ptr, BUFSIZE);
00305 if (bytes <= 0) { retval = bytes; break; }
00306 while (bytes > 0)
00307 {
00308 int written = send(pair->socket, ptr, bytes, 0);
00309 if (written < 0) { retval = written; break; }
00310
00311 bytes -= written;
00312 ptr += written;
00313 }
00314 }
00315
00316 shutdown(pair->socket, SD_BOTH);
00317 closesocket(pair->socket);
00318
00319 return retval;
00320 }
00321
00322
00323 DWORD WINAPI socket2fd_fwd(LPVOID lpThreadParameter)
00324 {
00325 DWORD retval = 0;
00326 const int BUFSIZE = 512;
00327 socket_fd_pair *pair = (socket_fd_pair *)lpThreadParameter;
00328
00329 char buf[BUFSIZE];
00330 while (true)
00331 {
00332 char *ptr = buf;
00333 int bytes = recv(pair->socket, ptr, BUFSIZE, 0);
00334 if (bytes <= 0) { retval = bytes; break; }
00335 while (bytes > 0)
00336 {
00337 int written = _write(pair->fd, ptr, bytes);
00338 if (written < 0) { retval = written; break; }
00339 bytes -= written;
00340 ptr += written;
00341 }
00342 }
00343 shutdown(pair->socket, SD_BOTH);
00344 closesocket(pair->socket);
00345
00346 return retval;
00347 }
00348
00349
00350 SocketFromFDMaker::SocketFromFDMaker(int fd,
00351 LPTHREAD_START_ROUTINE lpStartAddress, bool wait)
00352 : m_hThread(0), m_socket(INVALID_SOCKET), m_wait(wait)
00353 {
00354
00355 WSAData wsaData;
00356 WSAStartup(MAKEWORD(2,0), &wsaData);
00357
00358 int s[2], result;
00359 result = socketpair(AF_INET, SOCK_STREAM, 0, s);
00360 assert(result == 0);
00361
00362 m_pair.fd = fd;
00363 m_pair.socket = s[0];
00364 m_socket = s[1];
00365
00366 DWORD threadid;
00367 m_hThread = CreateThread(
00368 NULL,
00369 0,
00370 lpStartAddress,
00371 &m_pair,
00372 0,
00373 &threadid
00374 );
00375 assert(m_hThread);
00376 }
00377
00378
00379 SocketFromFDMaker::~SocketFromFDMaker()
00380 {
00381 int result;
00382
00383 if (m_socket != INVALID_SOCKET)
00384 {
00385 result = shutdown(m_socket, SD_BOTH);
00386
00387
00388
00389
00390
00391 if (result != 0)
00392 {
00393 int e = GetLastError();
00394 if (e == WSASYSNOTREADY)
00395 {
00396 fprintf(stderr, "Abnormal termination. Skipping cleanup.\n");
00397 _exit(42);
00398 }
00399 else
00400 {
00401 fprintf(stderr,
00402 "ERROR! Socket #%d was already shut down! (%d)\n",
00403 m_socket, e);
00404 assert(result == 0);
00405 }
00406 }
00407
00408 if (m_wait)
00409 {
00410
00411
00412
00413 WaitForSingleObject(m_hThread, INFINITE);
00414 }
00415 else
00416 {
00417
00418
00419
00420
00421
00422
00423
00424
00425
00426
00427
00428
00429 }
00430
00431 close(m_socket);
00432 }
00433 CloseHandle(m_hThread);
00434 }