Check-in [8372cc0b81]
Not logged in
Overview

SHA1 Hash:8372cc0b8125d2c52332021a3e0a2cbbf9b2506f
Date: 2007-09-22 18:34:49
User: jnc
Comment:Socket operations now functional in Win32 port. Added quotes around the filename portion of the command to edit thus working of windows in paths where the temp directory contains spaces. Added -all flag to clean command. If not specified each file is prompted for before removing.
Timelines: ancestors | descendants | both | trunk
Other Links: files | ZIP archive | manifest

Tags And Properties
Changes
[hide diffs]

Modified Makefile from [32e9920702] to [7035415b04].

@@ -34,15 +34,15 @@
 #    other dependencies.  We sometimes add the -static option here
 #    so that we can build a static executable that will run in a
 #    chroot jail.
 #
 #LIB = -lz
-LIB = -lz -lwsock32
+LIB = -lz -lws2_32
 
 
 #### Tcl shell for use in running the fossil testsuite.
 #
 TCLSH = tclsh
 
 # You should not need to change anything below this line
 ###############################################################################
 include $(SRCDIR)/main.mk

Modified src/cgi.c from [1e442c1fca] to [57f4d7daa3].

@@ -28,11 +28,11 @@
 ** decode strings in HTML or HTTP.
 */
 #include "config.h"
 #ifdef __MINGW32__
 #  include <windows.h>           /* for Sleep once server works again */
-#  include <winsock.h>           /* socket operations */
+#  include <winsock2.h>          /* socket operations */
 #  define sleep Sleep            /* windows does not have sleep, but Sleep */
 #else
 #  include <sys/socket.h>
 #  include <netinet/in.h>
 #  include <arpa/inet.h>

Modified src/checkin.c from [08fa2df4cf] to [39235e7847].

@@ -162,18 +162,24 @@
   db_finalize(&q);
 }
 
 /*
 ** COMMAND: clean
-** Usage: %fossil clean
+** Usage: %fossil clean ?-all
 ** Delete all "extra" files in the source tree.  "Extra" files are
 ** files that are not officially part of the checkout.  See also
-** the "extra" command.
+** the "extra" command. This operation cannot be undone.
+**
+** You will be prompted before removing each file. If you are
+** sure you wish to remove all "extra" files you can specify the
+** optional -all flag.
 */
 void clean_cmd(void){
+  int allFlag;
   Blob path;
   Stmt q;
+  allFlag = find_option("all","a",0)!=0;
   db_must_be_within_tree();
   db_multi_exec("CREATE TEMP TABLE sfile(x TEXT PRIMARY KEY)");
   chdir(g.zLocalRoot);
   blob_zero(&path);
   vfile_scan(0, &path);
@@ -180,11 +186,23 @@
   db_prepare(&q,
       "SELECT %Q || x FROM sfile"
       " WHERE x NOT IN ('manifest','manifest.uuid','_FOSSIL_')"
       " ORDER BY 1", g.zLocalRoot);
   while( db_step(&q)==SQLITE_ROW ){
-    unlink(db_column_text(&q, 0));
+    if( allFlag ){
+      unlink(db_column_text(&q, 0));
+      continue;
+    }
+
+    Blob ans;
+    char *prompt = mprintf("remove unmanaged file \"%s\" [y/N]? ",
+      db_column_text(&q, 0));
+    blob_zero(&ans);
+    prompt_user(prompt, &ans);
+    if( blob_str(&ans)[0]=='y' ){
+      unlink(db_column_text(&q, 0));
+    }
   }
   db_finalize(&q);
 }
 
 /*
@@ -218,11 +236,11 @@
     zEditor = "ed";
   }
   zFile = db_text(0, "SELECT '%qci-comment-' || hex(randomblob(6)) || '.txt'",
                    g.zLocalRoot);
   blob_write_to_file(&text, zFile);
-  zCmd = mprintf("%s %s", zEditor, zFile);
+  zCmd = mprintf("%s \"%s\"", zEditor, zFile);
   printf("%s\n", zCmd);
   if( system(zCmd) ){
     fossil_panic("editor aborted");
   }
   blob_reset(&text);

Modified src/http.c from [02357907c7] to [54410d4f2b].

@@ -25,11 +25,11 @@
 */
 #include "config.h"
 #include "http.h"
 #ifdef __MINGW32__
 #  include <windows.h>
-#  include <winsock.h>
+#  include <winsock2.h>
 #else
 #  include <arpa/inet.h>
 #  include <sys/socket.h>
 #  include <netdb.h>
 #  include <netinet/in.h>
@@ -39,24 +39,34 @@
 #include <signal.h>
 
 /*
 ** Persistent information about the HTTP connection.
 */
-static FILE *pSocket = 0;   /* The socket on which we talk to the server */
 
 #ifdef __MINGW32__
 static WSADATA ws_info;
+static int pSocket = 0;     /* The socket on which we talk to the server on */
+#else
+static FILE *pSocket = 0;   /* The socket filehandle on which we talk to the server */
 #endif
 
+/*
+** Winsock must be initialize before use.  This helper method allows us to
+** always call ws_init in our code regardless of platform but only actually
+** initialize winsock on the windows platform.
+*/
 static void ws_init(){
 #ifdef __MINGW32__
-  if (WSAStartup(MAKEWORD(1,1), &ws_info) != 0){
+  if (WSAStartup(MAKEWORD(2,0), &ws_info) != 0){
     fossil_panic("can't initialize winsock");
   }
 #endif
 }
 
+/*
+** Like ws_init, winsock must also be cleaned up after.
+*/
 static void ws_cleanup(){
 #ifdef __MINGW32__
   WSACleanup();
 #endif
 }
@@ -68,12 +78,13 @@
 static int http_open_socket(void){
   static struct sockaddr_in addr;  /* The server address */
   static int addrIsInit = 0;       /* True once addr is initialized */
   int s;
 
-  if( !addrIsInit ){
-    ws_init();
+  ws_init();
+
+  if( !addrIsInit ){
 
     addr.sin_family = AF_INET;
     addr.sin_port = htons(g.urlPort);
     *(int*)&addr.sin_addr = inet_addr(g.urlName);
     if( -1 == *(int*)&addr.sin_addr ){
@@ -101,15 +112,64 @@
     fossil_panic("cannot create a socket");
   }
   if( connect(s,(struct sockaddr*)&addr,sizeof(addr))<0 ){
     fossil_panic("cannot connect to host %s:%d", g.urlName, g.urlPort);
   }
-  pSocket = fdopen(s,"r+");
-#ifndef __MINGW32__
+#ifdef __MINGW32__
+  pSocket = s;
+#else
+  pSocket = fdopen(s,"r+");
   signal(SIGPIPE, SIG_IGN);
 #endif
   return 0;
+}
+
+/*
+** Read the socket until a newline '\n' is found.  Return the number
+** of characters read. pSockId contains the socket handel.  pOut
+** contains a pointer to the buffer to write to.  pOutSize contains
+** the maximum size of the line that pOut can handle.
+*/
+static int socket_recv_line(int pSockId, char* pOut, int pOutSize){
+  int received=0;
+  char letter;
+  memset(pOut,0,pOutSize);
+  for(; received<pOutSize-1;received++){
+    if( recv(pSockId,(char*)&letter,1,0)>0 ){
+      pOut[received]=letter;
+      if( letter=='\n' ){
+        break;
+      }
+    }else{
+      break;
+    }
+  }
+  return received;
+}
+
+/*
+** Initialize a blob to the data on an input socket.  return
+** the number of bytes read into the blob.  Any prior content
+** of the blob is discarded, not freed.
+**
+** The function was placed here in http.c due to it's socket
+** nature and we did not want to introduce socket headers into
+** the socket netural blob.c file.
+*/
+int socket_read_blob(Blob *pBlob, int pSockId, int nToRead){
+  int i=0,read=0;
+  char rbuf[50];
+  blob_zero(pBlob);
+  while ( i<nToRead ){
+    read = recv(pSockId, rbuf, 50, 0);
+    i += read;
+    if( read<0 ){
+      return 0;
+    }
+    blob_append(pBlob, rbuf, read);
+  }
+  return blob_size(pBlob);
 }
 
 /*
 ** Make a single attempt to talk to the server.  Return TRUE on success
 ** and FALSE on a failure.
@@ -120,40 +180,78 @@
 **
 ** If an error occurs, this routine return false, resets pReply and
 ** closes the persistent connection, if any.
 */
 static int http_send_recv(Blob *pHeader, Blob *pPayload, Blob *pReply){
-  int rc;
-  int closeConnection;
+  int closeConnection=1;   /* default to closing the connection */
+  int rc;
   int iLength;
   int iHttpVersion;
   int i;
   int nRead;
   char zLine[2000];
 
   if( pSocket==0 && http_open_socket() ){
     return 0;
   }
+  iLength = -1;
+#ifdef __MINGW32__
+  /*
+  ** Use recv/send on the windows platform as winsock does not allow
+  ** sockets to be used as FILE handles, thus fdopen, fwrite, fgets
+  ** does not function on windows for sockets.
+  */
+  rc = send(pSocket, blob_buffer(pHeader), blob_size(pHeader), 0);
+  if( rc!=blob_size(pHeader) ) goto write_err;
+  rc = send(pSocket, blob_buffer(pPayload), blob_size(pPayload), 0);
+  if( rc!=blob_size(pPayload) ) goto write_err;
+
+  /* Read the response */
+  while( socket_recv_line(pSocket, zLine, 2000) ){
+    for( i=0; zLine[i] && zLine[i]!='\n' && zLine[i]!='\r'; i++ ){}
+    if( i==0 ) break;
+    zLine[i] = 0;
+    if( strncasecmp(zLine, "http/1.", 7)==0 ){
+      if( sscanf(zLine, "HTTP/1.%d %d", &iHttpVersion, &rc)!=2 ) goto write_err;
+      if( rc!=200 ) goto write_err;
+      if( iHttpVersion==0 ){
+        closeConnection = 1;
+      }else{
+        closeConnection = 0;
+      }
+    } else if( strncasecmp(zLine, "content-length:", 15)==0 ){
+      iLength = atoi(&zLine[16]);
+    }else if( strncasecmp(zLine, "connection:", 11)==0 ){
+      for(i=12; isspace(zLine[i]); i++){}
+      if( zLine[i]=='c' || zLine[i]=='C' ){
+        closeConnection = 1;
+      }else if( zLine[i]=='k' || zLine[i]=='K' ){
+        closeConnection = 0;
+      }
+    }
+  }
+  if( iLength<0 ) goto write_err;
+  nRead = socket_read_blob(pReply, pSocket, iLength);
+#else
   rc = fwrite(blob_buffer(pHeader), 1, blob_size(pHeader), pSocket);
   if( rc!=blob_size(pHeader) ) goto write_err;
   rc = fwrite(blob_buffer(pPayload), 1, blob_size(pPayload), pSocket);
   if( rc!=blob_size(pPayload) ) goto write_err;
   if( fflush(pSocket) ) goto write_err;
   if( fgets(zLine, sizeof(zLine), pSocket)==0 ) goto write_err;
   if( sscanf(zLine, "HTTP/1.%d %d", &iHttpVersion, &rc)!=2 ) goto write_err;
   if( rc!=200 ) goto write_err;
   if( iHttpVersion==0 ){
-    closeConnection = 1;
+    closeConnection = 1;   /* Connection: close */
   }else{
-    closeConnection = 0;
-  }
-  iLength = -1;
+    closeConnection = 0;   /* Connection: keep-alive */
+  }
   while( fgets(zLine, sizeof(zLine), pSocket) ){
     for(i=0; zLine[i] && zLine[i]!='\n' && zLine[i]!='\r'; i++){}
     if( i==0 ) break;
     zLine[i] = 0;
-    if( strncasecmp(zLine, "content-length:",15)==0 ){
+    if( strncasecmp(zLine,"content-length:",15)==0 ){
       iLength = atoi(&zLine[16]);
     }else if( strncasecmp(zLine, "connection:", 11)==0 ){
       for(i=12; isspace(zLine[i]); i++){}
       if( zLine[i]=='c' || zLine[i]=='C' ){
         closeConnection = 1;   /* Connection: close */
@@ -162,10 +260,11 @@
       }
     }
   }
   if( iLength<0 ) goto write_err;
   nRead = blob_read_from_channel(pReply, pSocket, iLength);
+#endif
   if( nRead!=iLength ){
     blob_reset(pReply);
     goto write_err;
   }
   if( closeConnection ){
@@ -287,10 +386,21 @@
 /*
 ** Make sure the socket to the HTTP server is closed
 */
 void http_close(void){
   if( pSocket ){
+#ifdef __MINGW32__
+    closesocket(pSocket);
+#else
     fclose(pSocket);
-    pSocket = 0;
-    ws_cleanup();
+#endif
+    pSocket = 0;
   }
+  /*
+  ** This is counter productive. Each time we open a connection we initialize
+  ** winsock and then when closing we cleanup. It would be better to
+  ** initialize winsock once at application start when we know we are going to
+  ** use the socket interface and then cleanup once at application exit when
+  ** we are all done with all socket operations.
+  */
+  ws_cleanup();
 }

Modified win32.txt from [a31e062bd3] to [f8b38cdb44].

@@ -11,39 +11,26 @@
   Download/compile/install zlib (configure --prefix=/mingw)
   Download/compile/install tclsh (configure --prefix=/) (for tests)
 
   All commands were issued in the MSYS shell, not a cmd.exe
 
-
-
 Outstanding Issues:
 ----------------------------------------------------------------------
 
 * server is totally non-functional - #if/#end'd out of the code
-* all path operations are defunct
-* remote network operations are reporting: can't resolve host name: xyz
-
-  Winsock must be initialized before using:
-
-      WSADATA info;
-      if (WSAStartup(MAKEWORD(1,1), &info) != 0){
-        fossil_panic("can't initialize winsock");
-      }
-
-
 
 Commands status:
 ----------------------------------------------------------------------
 
 add               OK
 cgi               Not tested
 changes           OK
 checkout          BAD #1
 clean             OK
-clone             Local Only #2
+clone             OK
 close             OK
-commit            OK (not tested with gpg signing yet)
+commit            OK
 config            OK
 deconstruct       OK
 del               OK
 descendents       OK
 diff              OK
@@ -54,18 +41,18 @@
 leaves            OK
 ls                OK
 merge             OK
 new               OK
 open              OK
-pull              BAD #2
-push              BAD #2
+pull              OK
+push              OK
 rebuild           OK (didn't have a corrupt file to try on though)
 redo              BAD #3
 rm                OK
-server            BAD #2,#4
+server            BAD #4
 status            OK
-sync              BAD #2
+sync              OK
 timeline          OK
 tkdiff            OK
 undo              OK
 update            OK
 user capabilities OK
@@ -81,12 +68,10 @@
 
    Make a new dir, fossil open ../repo.fsl && fossil checkout 123abc and
    the file appears.
 
    Is that normal operation?
-
-#2 No socket operations are functioning yet
 
 #3 In test1/ I edited a file, test2/ I updated, type file.txt changes
    were there. I then did fossil undo file.txt. The changes were gone
    and fossil status said I had edited file.txt. A fossil redo did not
    print anything to the screen and the changes for file.txt are not