/* * TCP/IP stream emulation for GNU Emacs. * Copyright (C) 1988, 1989, 1992, 1993 Free Software Foundation, Inc. * Author: Masanobu Umeda * Maintainer: umerin@mse.kyutech.ac.jp * Ported to Windows NT 3.51 rjf@infograph.com (Jun 6, 1995) This file is part of GNU Emacs. GNU Emacs is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. GNU Emacs is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNU Emacs; see the file COPYING. If not, write to the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. * * Yasunari, Itoh at PFU limited contributed for Fujitsu UTS and SX/A. * * Thu Apr 6 13:47:37 JST 1989 * USG fixes by Sakaeda * * For Fujitsu UTS compile with: * cc -O -o tcp tcp.c -DFUJITSU_UTS -lu -lsocket * * Tue Apr 6 1995 Port to Windows NT * For Windows NT compile with: * cl -DWIN32 -W3 -Ox nttcp.c -link wsock32.lib * * In your _emacs file, add the following lines: * * (setq tcp-program-name "nttcp") * * If using 19.28 and Gnus 4.x, please add these as well: * * (setq nntp-buggy-select t) * (setq nntp-maximum-request 10) * */ #include #include #include #include #include #include #ifndef DEBUG #undef OutputDebugString #define OutputDebugString(a) /* */ #endif #define bcopy(f, t, n) memcpy (t, f, n) #define bcmp(b1, b2, n) (memcmp (b1, b2, n) != 0) #define bzero(b, n) memset (b, 0, n) SOCKET server; /* NNTP Server */ int emacs_in; /* Emacs intput */ int emacs_out; /* Emacs output */ typedef enum {writing, reading} TestType; /* Print the last socket error. */ void pserror (const char *str) { printf ("%s: last error %d\n", str, WSAGetLastError ()); } /* Wait for a socket to be ready to read or write... */ BOOL wait_for_socket (SOCKET s, TestType t) { const int MAX_RETRIES = 100; struct timeval timeout = {60, 0}; fd_set fd; int ret; int result = 0; int retries = 0; while (1) { FD_ZERO (&fd); FD_SET (s,&fd); if (t == reading) ret = select (32, &fd, NULL, NULL, &timeout); else ret = select (32, NULL, &fd, NULL, &timeout); if (ret != 0) break; else ++retries; if (retries > MAX_RETRIES) { OutputDebugString ("Too many retries waiting for socket!\n"); retries = 0; } Sleep(10); } return (ret != 0); } /* This thread reads the stdin stream, which is data from Emacs, and sends it out the socket. */ DWORD WINAPI from_emacs_thread (LPVOID parm) { char buffer[8*1024]; int nbuffer; /* Number of bytes in buffer */ int wret; char *retry; /* retry bufferp */ while (1) { /* If there is some data from emacs, send it through the socket * to the server... */ nbuffer = read (emacs_in, buffer, sizeof buffer-1); if (nbuffer != -1) { OutputDebugString ("Read block from emacs...\n"); for (retry = buffer; nbuffer > 0; nbuffer -= wret, retry += wret) { wait_for_socket (server, writing); wret = send (server, retry, nbuffer, 0); if (wret == SOCKET_ERROR) { pserror ("send(server)"); goto finish; } } OutputDebugString ("Write block to server...\n"); } else { perror ("read(emacs_in)"); goto finish; } Sleep (25); } finish: return 0; } /* This thread reads the socket, which is data from some server, and sends it back to emacs. */ DWORD WINAPI from_server_thread (LPVOID parm) { char buffer[8*1024]; int nbuffer; /* Number of bytes in buffer */ int wret; char *retry; /* retry bufferp */ while (1) { /* If there is some data from the server, send it through stdout to the emacs... */ wait_for_socket (server, reading); nbuffer = recv (server, buffer, sizeof buffer-1, 0); OutputDebugString ("Read block from server...\n"); if (nbuffer != SOCKET_ERROR) { for (retry = buffer; nbuffer > 0; nbuffer -= wret, retry += wret) { wret = write (emacs_out, retry, nbuffer); if (wret < 0) { perror ("write(emacs_out)"); goto finish; } } OutputDebugString ("Wrote block to emacs...\n"); } else { pserror ("recv(server)"); goto finish; } Sleep (25); } finish: return 0; } int main (int argc, char *argv[]) { WSADATA WSAData; HANDLE hThreads[2]; DWORD dummy = 1; struct hostent *host; struct sockaddr_in sockin, sockme; struct servent *serv; char *hostname = NULL; char *service = "nntp"; short port; int false = 0; /* FALSE flag for setsockopt () */ int err; emacs_in = fileno (stdin); emacs_out = fileno (stdout); if (argc < 2) { fprintf (stderr, "Usage: %s HOST [SERVICE]\n", argv[0]); return (1); } if (argc >= 2) hostname = argv[1]; if (argc >= 3) service = argv[2]; if ((err = WSAStartup (MAKEWORD (2, 0), &WSAData)) != 0) { printf ("WSAStartup error - %d\n", err); return (1); } if ((host = gethostbyname (hostname)) == NULL) { pserror ("gethostbyname"); return (1); } if (isdigit (service[0])) port = htons ((short) atoi (service)); else { serv = getservbyname (service, "tcp"); if (serv == NULL) { pserror ("getservbyname"); return (1); } port = serv->s_port; } bzero (&sockin, sizeof (sockin)); sockin.sin_family = host->h_addrtype; bcopy (host->h_addr, &sockin.sin_addr, host->h_length); sockin.sin_port = port; if ((server = socket (AF_INET, SOCK_STREAM, 0)) < 0) { pserror ("socket"); return (1); } if (setsockopt (server, SOL_SOCKET, SO_REUSEADDR, (const char *) &false, sizeof (false)) != 0) { pserror ("setsockopt"); return (1); } bzero (&sockme, sizeof (sockme)); sockme.sin_family = sockin.sin_family; sockme.sin_addr.s_addr = htonl (INADDR_ANY); if (bind (server, (struct sockaddr *)&sockme, sizeof (sockme)) != 0) { pserror ("bind"); return (1); } if (connect (server, (struct sockaddr *)&sockin, sizeof (sockin)) != 0) { pserror ("connect"); close (server); return (1); } /* Create the theads that transfer data between emacs and the server. */ hThreads[0] = CreateThread (NULL, 0, from_emacs_thread, &dummy, 0, &dummy); hThreads[1] = CreateThread (NULL, 0, from_server_thread, &dummy, 0, &dummy); /* Wait for one or both threads to die... */ WaitForMultipleObjects (2, hThreads, FALSE, INFINITE); shutdown (server,2); closesocket (server); WSACleanup (); OutputDebugString ("*** Exitting tcp...\n"); return (0); }