Fossil SCM

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.

jnc 2007-09-22 18:34 trunk
Commit 8372cc0b8125d2c52332021a3e0a2cbbf9b2506f
5 files changed +1 -1 +1 -1 +22 -4 +121 -11 +6 -21
+1 -1
--- Makefile
+++ Makefile
@@ -34,11 +34,11 @@
3434
# other dependencies. We sometimes add the -static option here
3535
# so that we can build a static executable that will run in a
3636
# chroot jail.
3737
#
3838
#LIB = -lz
39
-LIB = -lz -lwsock32
39
+LIB = -lz -lws2_32
4040
4141
4242
#### Tcl shell for use in running the fossil testsuite.
4343
#
4444
TCLSH = tclsh
4545
--- Makefile
+++ Makefile
@@ -34,11 +34,11 @@
34 # other dependencies. We sometimes add the -static option here
35 # so that we can build a static executable that will run in a
36 # chroot jail.
37 #
38 #LIB = -lz
39 LIB = -lz -lwsock32
40
41
42 #### Tcl shell for use in running the fossil testsuite.
43 #
44 TCLSH = tclsh
45
--- Makefile
+++ Makefile
@@ -34,11 +34,11 @@
34 # other dependencies. We sometimes add the -static option here
35 # so that we can build a static executable that will run in a
36 # chroot jail.
37 #
38 #LIB = -lz
39 LIB = -lz -lws2_32
40
41
42 #### Tcl shell for use in running the fossil testsuite.
43 #
44 TCLSH = tclsh
45
+1 -1
--- src/cgi.c
+++ src/cgi.c
@@ -28,11 +28,11 @@
2828
** decode strings in HTML or HTTP.
2929
*/
3030
#include "config.h"
3131
#ifdef __MINGW32__
3232
# include <windows.h> /* for Sleep once server works again */
33
-# include <winsock.h> /* socket operations */
33
+# include <winsock2.h> /* socket operations */
3434
# define sleep Sleep /* windows does not have sleep, but Sleep */
3535
#else
3636
# include <sys/socket.h>
3737
# include <netinet/in.h>
3838
# include <arpa/inet.h>
3939
--- src/cgi.c
+++ src/cgi.c
@@ -28,11 +28,11 @@
28 ** decode strings in HTML or HTTP.
29 */
30 #include "config.h"
31 #ifdef __MINGW32__
32 # include <windows.h> /* for Sleep once server works again */
33 # include <winsock.h> /* socket operations */
34 # define sleep Sleep /* windows does not have sleep, but Sleep */
35 #else
36 # include <sys/socket.h>
37 # include <netinet/in.h>
38 # include <arpa/inet.h>
39
--- src/cgi.c
+++ src/cgi.c
@@ -28,11 +28,11 @@
28 ** decode strings in HTML or HTTP.
29 */
30 #include "config.h"
31 #ifdef __MINGW32__
32 # include <windows.h> /* for Sleep once server works again */
33 # include <winsock2.h> /* socket operations */
34 # define sleep Sleep /* windows does not have sleep, but Sleep */
35 #else
36 # include <sys/socket.h>
37 # include <netinet/in.h>
38 # include <arpa/inet.h>
39
+22 -4
--- src/checkin.c
+++ src/checkin.c
@@ -162,18 +162,24 @@
162162
db_finalize(&q);
163163
}
164164
165165
/*
166166
** COMMAND: clean
167
-** Usage: %fossil clean
167
+** Usage: %fossil clean ?-all
168168
** Delete all "extra" files in the source tree. "Extra" files are
169169
** files that are not officially part of the checkout. See also
170
-** the "extra" command.
170
+** the "extra" command. This operation cannot be undone.
171
+**
172
+** You will be prompted before removing each file. If you are
173
+** sure you wish to remove all "extra" files you can specify the
174
+** optional -all flag.
171175
*/
172176
void clean_cmd(void){
177
+ int allFlag;
173178
Blob path;
174179
Stmt q;
180
+ allFlag = find_option("all","a",0)!=0;
175181
db_must_be_within_tree();
176182
db_multi_exec("CREATE TEMP TABLE sfile(x TEXT PRIMARY KEY)");
177183
chdir(g.zLocalRoot);
178184
blob_zero(&path);
179185
vfile_scan(0, &path);
@@ -180,11 +186,23 @@
180186
db_prepare(&q,
181187
"SELECT %Q || x FROM sfile"
182188
" WHERE x NOT IN ('manifest','manifest.uuid','_FOSSIL_')"
183189
" ORDER BY 1", g.zLocalRoot);
184190
while( db_step(&q)==SQLITE_ROW ){
185
- unlink(db_column_text(&q, 0));
191
+ if( allFlag ){
192
+ unlink(db_column_text(&q, 0));
193
+ continue;
194
+ }
195
+
196
+ Blob ans;
197
+ char *prompt = mprintf("remove unmanaged file \"%s\" [y/N]? ",
198
+ db_column_text(&q, 0));
199
+ blob_zero(&ans);
200
+ prompt_user(prompt, &ans);
201
+ if( blob_str(&ans)[0]=='y' ){
202
+ unlink(db_column_text(&q, 0));
203
+ }
186204
}
187205
db_finalize(&q);
188206
}
189207
190208
/*
@@ -218,11 +236,11 @@
218236
zEditor = "ed";
219237
}
220238
zFile = db_text(0, "SELECT '%qci-comment-' || hex(randomblob(6)) || '.txt'",
221239
g.zLocalRoot);
222240
blob_write_to_file(&text, zFile);
223
- zCmd = mprintf("%s %s", zEditor, zFile);
241
+ zCmd = mprintf("%s \"%s\"", zEditor, zFile);
224242
printf("%s\n", zCmd);
225243
if( system(zCmd) ){
226244
fossil_panic("editor aborted");
227245
}
228246
blob_reset(&text);
229247
--- src/checkin.c
+++ src/checkin.c
@@ -162,18 +162,24 @@
162 db_finalize(&q);
163 }
164
165 /*
166 ** COMMAND: clean
167 ** Usage: %fossil clean
168 ** Delete all "extra" files in the source tree. "Extra" files are
169 ** files that are not officially part of the checkout. See also
170 ** the "extra" command.
 
 
 
 
171 */
172 void clean_cmd(void){
 
173 Blob path;
174 Stmt q;
 
175 db_must_be_within_tree();
176 db_multi_exec("CREATE TEMP TABLE sfile(x TEXT PRIMARY KEY)");
177 chdir(g.zLocalRoot);
178 blob_zero(&path);
179 vfile_scan(0, &path);
@@ -180,11 +186,23 @@
180 db_prepare(&q,
181 "SELECT %Q || x FROM sfile"
182 " WHERE x NOT IN ('manifest','manifest.uuid','_FOSSIL_')"
183 " ORDER BY 1", g.zLocalRoot);
184 while( db_step(&q)==SQLITE_ROW ){
185 unlink(db_column_text(&q, 0));
 
 
 
 
 
 
 
 
 
 
 
 
186 }
187 db_finalize(&q);
188 }
189
190 /*
@@ -218,11 +236,11 @@
218 zEditor = "ed";
219 }
220 zFile = db_text(0, "SELECT '%qci-comment-' || hex(randomblob(6)) || '.txt'",
221 g.zLocalRoot);
222 blob_write_to_file(&text, zFile);
223 zCmd = mprintf("%s %s", zEditor, zFile);
224 printf("%s\n", zCmd);
225 if( system(zCmd) ){
226 fossil_panic("editor aborted");
227 }
228 blob_reset(&text);
229
--- src/checkin.c
+++ src/checkin.c
@@ -162,18 +162,24 @@
162 db_finalize(&q);
163 }
164
165 /*
166 ** COMMAND: clean
167 ** Usage: %fossil clean ?-all
168 ** Delete all "extra" files in the source tree. "Extra" files are
169 ** files that are not officially part of the checkout. See also
170 ** the "extra" command. This operation cannot be undone.
171 **
172 ** You will be prompted before removing each file. If you are
173 ** sure you wish to remove all "extra" files you can specify the
174 ** optional -all flag.
175 */
176 void clean_cmd(void){
177 int allFlag;
178 Blob path;
179 Stmt q;
180 allFlag = find_option("all","a",0)!=0;
181 db_must_be_within_tree();
182 db_multi_exec("CREATE TEMP TABLE sfile(x TEXT PRIMARY KEY)");
183 chdir(g.zLocalRoot);
184 blob_zero(&path);
185 vfile_scan(0, &path);
@@ -180,11 +186,23 @@
186 db_prepare(&q,
187 "SELECT %Q || x FROM sfile"
188 " WHERE x NOT IN ('manifest','manifest.uuid','_FOSSIL_')"
189 " ORDER BY 1", g.zLocalRoot);
190 while( db_step(&q)==SQLITE_ROW ){
191 if( allFlag ){
192 unlink(db_column_text(&q, 0));
193 continue;
194 }
195
196 Blob ans;
197 char *prompt = mprintf("remove unmanaged file \"%s\" [y/N]? ",
198 db_column_text(&q, 0));
199 blob_zero(&ans);
200 prompt_user(prompt, &ans);
201 if( blob_str(&ans)[0]=='y' ){
202 unlink(db_column_text(&q, 0));
203 }
204 }
205 db_finalize(&q);
206 }
207
208 /*
@@ -218,11 +236,11 @@
236 zEditor = "ed";
237 }
238 zFile = db_text(0, "SELECT '%qci-comment-' || hex(randomblob(6)) || '.txt'",
239 g.zLocalRoot);
240 blob_write_to_file(&text, zFile);
241 zCmd = mprintf("%s \"%s\"", zEditor, zFile);
242 printf("%s\n", zCmd);
243 if( system(zCmd) ){
244 fossil_panic("editor aborted");
245 }
246 blob_reset(&text);
247
+121 -11
--- src/http.c
+++ src/http.c
@@ -25,11 +25,11 @@
2525
*/
2626
#include "config.h"
2727
#include "http.h"
2828
#ifdef __MINGW32__
2929
# include <windows.h>
30
-# include <winsock.h>
30
+# include <winsock2.h>
3131
#else
3232
# include <arpa/inet.h>
3333
# include <sys/socket.h>
3434
# include <netdb.h>
3535
# include <netinet/in.h>
@@ -39,24 +39,34 @@
3939
#include <signal.h>
4040
4141
/*
4242
** Persistent information about the HTTP connection.
4343
*/
44
-static FILE *pSocket = 0; /* The socket on which we talk to the server */
4544
4645
#ifdef __MINGW32__
4746
static WSADATA ws_info;
47
+static int pSocket = 0; /* The socket on which we talk to the server on */
48
+#else
49
+static FILE *pSocket = 0; /* The socket filehandle on which we talk to the server */
4850
#endif
4951
52
+/*
53
+** Winsock must be initialize before use. This helper method allows us to
54
+** always call ws_init in our code regardless of platform but only actually
55
+** initialize winsock on the windows platform.
56
+*/
5057
static void ws_init(){
5158
#ifdef __MINGW32__
52
- if (WSAStartup(MAKEWORD(1,1), &ws_info) != 0){
59
+ if (WSAStartup(MAKEWORD(2,0), &ws_info) != 0){
5360
fossil_panic("can't initialize winsock");
5461
}
5562
#endif
5663
}
5764
65
+/*
66
+** Like ws_init, winsock must also be cleaned up after.
67
+*/
5868
static void ws_cleanup(){
5969
#ifdef __MINGW32__
6070
WSACleanup();
6171
#endif
6272
}
@@ -67,13 +77,14 @@
6777
*/
6878
static int http_open_socket(void){
6979
static struct sockaddr_in addr; /* The server address */
7080
static int addrIsInit = 0; /* True once addr is initialized */
7181
int s;
82
+
83
+ ws_init();
7284
7385
if( !addrIsInit ){
74
- ws_init();
7586
7687
addr.sin_family = AF_INET;
7788
addr.sin_port = htons(g.urlPort);
7889
*(int*)&addr.sin_addr = inet_addr(g.urlName);
7990
if( -1 == *(int*)&addr.sin_addr ){
@@ -101,16 +112,65 @@
101112
fossil_panic("cannot create a socket");
102113
}
103114
if( connect(s,(struct sockaddr*)&addr,sizeof(addr))<0 ){
104115
fossil_panic("cannot connect to host %s:%d", g.urlName, g.urlPort);
105116
}
117
+#ifdef __MINGW32__
118
+ pSocket = s;
119
+#else
106120
pSocket = fdopen(s,"r+");
107
-#ifndef __MINGW32__
108121
signal(SIGPIPE, SIG_IGN);
109122
#endif
110123
return 0;
111124
}
125
+
126
+/*
127
+** Read the socket until a newline '\n' is found. Return the number
128
+** of characters read. pSockId contains the socket handel. pOut
129
+** contains a pointer to the buffer to write to. pOutSize contains
130
+** the maximum size of the line that pOut can handle.
131
+*/
132
+static int socket_recv_line(int pSockId, char* pOut, int pOutSize){
133
+ int received=0;
134
+ char letter;
135
+ memset(pOut,0,pOutSize);
136
+ for(; received<pOutSize-1;received++){
137
+ if( recv(pSockId,(char*)&letter,1,0)>0 ){
138
+ pOut[received]=letter;
139
+ if( letter=='\n' ){
140
+ break;
141
+ }
142
+ }else{
143
+ break;
144
+ }
145
+ }
146
+ return received;
147
+}
148
+
149
+/*
150
+** Initialize a blob to the data on an input socket. return
151
+** the number of bytes read into the blob. Any prior content
152
+** of the blob is discarded, not freed.
153
+**
154
+** The function was placed here in http.c due to it's socket
155
+** nature and we did not want to introduce socket headers into
156
+** the socket netural blob.c file.
157
+*/
158
+int socket_read_blob(Blob *pBlob, int pSockId, int nToRead){
159
+ int i=0,read=0;
160
+ char rbuf[50];
161
+ blob_zero(pBlob);
162
+ while ( i<nToRead ){
163
+ read = recv(pSockId, rbuf, 50, 0);
164
+ i += read;
165
+ if( read<0 ){
166
+ return 0;
167
+ }
168
+ blob_append(pBlob, rbuf, read);
169
+ }
170
+ return blob_size(pBlob);
171
+}
112172
113173
/*
114174
** Make a single attempt to talk to the server. Return TRUE on success
115175
** and FALSE on a failure.
116176
**
@@ -120,40 +180,78 @@
120180
**
121181
** If an error occurs, this routine return false, resets pReply and
122182
** closes the persistent connection, if any.
123183
*/
124184
static int http_send_recv(Blob *pHeader, Blob *pPayload, Blob *pReply){
185
+ int closeConnection=1; /* default to closing the connection */
125186
int rc;
126
- int closeConnection;
127187
int iLength;
128188
int iHttpVersion;
129189
int i;
130190
int nRead;
131191
char zLine[2000];
132192
133193
if( pSocket==0 && http_open_socket() ){
134194
return 0;
135195
}
196
+ iLength = -1;
197
+#ifdef __MINGW32__
198
+ /*
199
+ ** Use recv/send on the windows platform as winsock does not allow
200
+ ** sockets to be used as FILE handles, thus fdopen, fwrite, fgets
201
+ ** does not function on windows for sockets.
202
+ */
203
+ rc = send(pSocket, blob_buffer(pHeader), blob_size(pHeader), 0);
204
+ if( rc!=blob_size(pHeader) ) goto write_err;
205
+ rc = send(pSocket, blob_buffer(pPayload), blob_size(pPayload), 0);
206
+ if( rc!=blob_size(pPayload) ) goto write_err;
207
+
208
+ /* Read the response */
209
+ while( socket_recv_line(pSocket, zLine, 2000) ){
210
+ for( i=0; zLine[i] && zLine[i]!='\n' && zLine[i]!='\r'; i++ ){}
211
+ if( i==0 ) break;
212
+ zLine[i] = 0;
213
+ if( strncasecmp(zLine, "http/1.", 7)==0 ){
214
+ if( sscanf(zLine, "HTTP/1.%d %d", &iHttpVersion, &rc)!=2 ) goto write_err;
215
+ if( rc!=200 ) goto write_err;
216
+ if( iHttpVersion==0 ){
217
+ closeConnection = 1;
218
+ }else{
219
+ closeConnection = 0;
220
+ }
221
+ } else if( strncasecmp(zLine, "content-length:", 15)==0 ){
222
+ iLength = atoi(&zLine[16]);
223
+ }else if( strncasecmp(zLine, "connection:", 11)==0 ){
224
+ for(i=12; isspace(zLine[i]); i++){}
225
+ if( zLine[i]=='c' || zLine[i]=='C' ){
226
+ closeConnection = 1;
227
+ }else if( zLine[i]=='k' || zLine[i]=='K' ){
228
+ closeConnection = 0;
229
+ }
230
+ }
231
+ }
232
+ if( iLength<0 ) goto write_err;
233
+ nRead = socket_read_blob(pReply, pSocket, iLength);
234
+#else
136235
rc = fwrite(blob_buffer(pHeader), 1, blob_size(pHeader), pSocket);
137236
if( rc!=blob_size(pHeader) ) goto write_err;
138237
rc = fwrite(blob_buffer(pPayload), 1, blob_size(pPayload), pSocket);
139238
if( rc!=blob_size(pPayload) ) goto write_err;
140239
if( fflush(pSocket) ) goto write_err;
141240
if( fgets(zLine, sizeof(zLine), pSocket)==0 ) goto write_err;
142241
if( sscanf(zLine, "HTTP/1.%d %d", &iHttpVersion, &rc)!=2 ) goto write_err;
143242
if( rc!=200 ) goto write_err;
144243
if( iHttpVersion==0 ){
145
- closeConnection = 1;
244
+ closeConnection = 1; /* Connection: close */
146245
}else{
147
- closeConnection = 0;
246
+ closeConnection = 0; /* Connection: keep-alive */
148247
}
149
- iLength = -1;
150248
while( fgets(zLine, sizeof(zLine), pSocket) ){
151249
for(i=0; zLine[i] && zLine[i]!='\n' && zLine[i]!='\r'; i++){}
152250
if( i==0 ) break;
153251
zLine[i] = 0;
154
- if( strncasecmp(zLine, "content-length:",15)==0 ){
252
+ if( strncasecmp(zLine,"content-length:",15)==0 ){
155253
iLength = atoi(&zLine[16]);
156254
}else if( strncasecmp(zLine, "connection:", 11)==0 ){
157255
for(i=12; isspace(zLine[i]); i++){}
158256
if( zLine[i]=='c' || zLine[i]=='C' ){
159257
closeConnection = 1; /* Connection: close */
@@ -162,10 +260,11 @@
162260
}
163261
}
164262
}
165263
if( iLength<0 ) goto write_err;
166264
nRead = blob_read_from_channel(pReply, pSocket, iLength);
265
+#endif
167266
if( nRead!=iLength ){
168267
blob_reset(pReply);
169268
goto write_err;
170269
}
171270
if( closeConnection ){
@@ -287,10 +386,21 @@
287386
/*
288387
** Make sure the socket to the HTTP server is closed
289388
*/
290389
void http_close(void){
291390
if( pSocket ){
391
+#ifdef __MINGW32__
392
+ closesocket(pSocket);
393
+#else
292394
fclose(pSocket);
395
+#endif
293396
pSocket = 0;
294
- ws_cleanup();
295397
}
398
+ /*
399
+ ** This is counter productive. Each time we open a connection we initialize
400
+ ** winsock and then when closing we cleanup. It would be better to
401
+ ** initialize winsock once at application start when we know we are going to
402
+ ** use the socket interface and then cleanup once at application exit when
403
+ ** we are all done with all socket operations.
404
+ */
405
+ ws_cleanup();
296406
}
297407
--- src/http.c
+++ src/http.c
@@ -25,11 +25,11 @@
25 */
26 #include "config.h"
27 #include "http.h"
28 #ifdef __MINGW32__
29 # include <windows.h>
30 # include <winsock.h>
31 #else
32 # include <arpa/inet.h>
33 # include <sys/socket.h>
34 # include <netdb.h>
35 # include <netinet/in.h>
@@ -39,24 +39,34 @@
39 #include <signal.h>
40
41 /*
42 ** Persistent information about the HTTP connection.
43 */
44 static FILE *pSocket = 0; /* The socket on which we talk to the server */
45
46 #ifdef __MINGW32__
47 static WSADATA ws_info;
 
 
 
48 #endif
49
 
 
 
 
 
50 static void ws_init(){
51 #ifdef __MINGW32__
52 if (WSAStartup(MAKEWORD(1,1), &ws_info) != 0){
53 fossil_panic("can't initialize winsock");
54 }
55 #endif
56 }
57
 
 
 
58 static void ws_cleanup(){
59 #ifdef __MINGW32__
60 WSACleanup();
61 #endif
62 }
@@ -67,13 +77,14 @@
67 */
68 static int http_open_socket(void){
69 static struct sockaddr_in addr; /* The server address */
70 static int addrIsInit = 0; /* True once addr is initialized */
71 int s;
 
 
72
73 if( !addrIsInit ){
74 ws_init();
75
76 addr.sin_family = AF_INET;
77 addr.sin_port = htons(g.urlPort);
78 *(int*)&addr.sin_addr = inet_addr(g.urlName);
79 if( -1 == *(int*)&addr.sin_addr ){
@@ -101,16 +112,65 @@
101 fossil_panic("cannot create a socket");
102 }
103 if( connect(s,(struct sockaddr*)&addr,sizeof(addr))<0 ){
104 fossil_panic("cannot connect to host %s:%d", g.urlName, g.urlPort);
105 }
 
 
 
106 pSocket = fdopen(s,"r+");
107 #ifndef __MINGW32__
108 signal(SIGPIPE, SIG_IGN);
109 #endif
110 return 0;
111 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
112
113 /*
114 ** Make a single attempt to talk to the server. Return TRUE on success
115 ** and FALSE on a failure.
116 **
@@ -120,40 +180,78 @@
120 **
121 ** If an error occurs, this routine return false, resets pReply and
122 ** closes the persistent connection, if any.
123 */
124 static int http_send_recv(Blob *pHeader, Blob *pPayload, Blob *pReply){
 
125 int rc;
126 int closeConnection;
127 int iLength;
128 int iHttpVersion;
129 int i;
130 int nRead;
131 char zLine[2000];
132
133 if( pSocket==0 && http_open_socket() ){
134 return 0;
135 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
136 rc = fwrite(blob_buffer(pHeader), 1, blob_size(pHeader), pSocket);
137 if( rc!=blob_size(pHeader) ) goto write_err;
138 rc = fwrite(blob_buffer(pPayload), 1, blob_size(pPayload), pSocket);
139 if( rc!=blob_size(pPayload) ) goto write_err;
140 if( fflush(pSocket) ) goto write_err;
141 if( fgets(zLine, sizeof(zLine), pSocket)==0 ) goto write_err;
142 if( sscanf(zLine, "HTTP/1.%d %d", &iHttpVersion, &rc)!=2 ) goto write_err;
143 if( rc!=200 ) goto write_err;
144 if( iHttpVersion==0 ){
145 closeConnection = 1;
146 }else{
147 closeConnection = 0;
148 }
149 iLength = -1;
150 while( fgets(zLine, sizeof(zLine), pSocket) ){
151 for(i=0; zLine[i] && zLine[i]!='\n' && zLine[i]!='\r'; i++){}
152 if( i==0 ) break;
153 zLine[i] = 0;
154 if( strncasecmp(zLine, "content-length:",15)==0 ){
155 iLength = atoi(&zLine[16]);
156 }else if( strncasecmp(zLine, "connection:", 11)==0 ){
157 for(i=12; isspace(zLine[i]); i++){}
158 if( zLine[i]=='c' || zLine[i]=='C' ){
159 closeConnection = 1; /* Connection: close */
@@ -162,10 +260,11 @@
162 }
163 }
164 }
165 if( iLength<0 ) goto write_err;
166 nRead = blob_read_from_channel(pReply, pSocket, iLength);
 
167 if( nRead!=iLength ){
168 blob_reset(pReply);
169 goto write_err;
170 }
171 if( closeConnection ){
@@ -287,10 +386,21 @@
287 /*
288 ** Make sure the socket to the HTTP server is closed
289 */
290 void http_close(void){
291 if( pSocket ){
 
 
 
292 fclose(pSocket);
 
293 pSocket = 0;
294 ws_cleanup();
295 }
 
 
 
 
 
 
 
 
296 }
297
--- src/http.c
+++ src/http.c
@@ -25,11 +25,11 @@
25 */
26 #include "config.h"
27 #include "http.h"
28 #ifdef __MINGW32__
29 # include <windows.h>
30 # include <winsock2.h>
31 #else
32 # include <arpa/inet.h>
33 # include <sys/socket.h>
34 # include <netdb.h>
35 # include <netinet/in.h>
@@ -39,24 +39,34 @@
39 #include <signal.h>
40
41 /*
42 ** Persistent information about the HTTP connection.
43 */
 
44
45 #ifdef __MINGW32__
46 static WSADATA ws_info;
47 static int pSocket = 0; /* The socket on which we talk to the server on */
48 #else
49 static FILE *pSocket = 0; /* The socket filehandle on which we talk to the server */
50 #endif
51
52 /*
53 ** Winsock must be initialize before use. This helper method allows us to
54 ** always call ws_init in our code regardless of platform but only actually
55 ** initialize winsock on the windows platform.
56 */
57 static void ws_init(){
58 #ifdef __MINGW32__
59 if (WSAStartup(MAKEWORD(2,0), &ws_info) != 0){
60 fossil_panic("can't initialize winsock");
61 }
62 #endif
63 }
64
65 /*
66 ** Like ws_init, winsock must also be cleaned up after.
67 */
68 static void ws_cleanup(){
69 #ifdef __MINGW32__
70 WSACleanup();
71 #endif
72 }
@@ -67,13 +77,14 @@
77 */
78 static int http_open_socket(void){
79 static struct sockaddr_in addr; /* The server address */
80 static int addrIsInit = 0; /* True once addr is initialized */
81 int s;
82
83 ws_init();
84
85 if( !addrIsInit ){
 
86
87 addr.sin_family = AF_INET;
88 addr.sin_port = htons(g.urlPort);
89 *(int*)&addr.sin_addr = inet_addr(g.urlName);
90 if( -1 == *(int*)&addr.sin_addr ){
@@ -101,16 +112,65 @@
112 fossil_panic("cannot create a socket");
113 }
114 if( connect(s,(struct sockaddr*)&addr,sizeof(addr))<0 ){
115 fossil_panic("cannot connect to host %s:%d", g.urlName, g.urlPort);
116 }
117 #ifdef __MINGW32__
118 pSocket = s;
119 #else
120 pSocket = fdopen(s,"r+");
 
121 signal(SIGPIPE, SIG_IGN);
122 #endif
123 return 0;
124 }
125
126 /*
127 ** Read the socket until a newline '\n' is found. Return the number
128 ** of characters read. pSockId contains the socket handel. pOut
129 ** contains a pointer to the buffer to write to. pOutSize contains
130 ** the maximum size of the line that pOut can handle.
131 */
132 static int socket_recv_line(int pSockId, char* pOut, int pOutSize){
133 int received=0;
134 char letter;
135 memset(pOut,0,pOutSize);
136 for(; received<pOutSize-1;received++){
137 if( recv(pSockId,(char*)&letter,1,0)>0 ){
138 pOut[received]=letter;
139 if( letter=='\n' ){
140 break;
141 }
142 }else{
143 break;
144 }
145 }
146 return received;
147 }
148
149 /*
150 ** Initialize a blob to the data on an input socket. return
151 ** the number of bytes read into the blob. Any prior content
152 ** of the blob is discarded, not freed.
153 **
154 ** The function was placed here in http.c due to it's socket
155 ** nature and we did not want to introduce socket headers into
156 ** the socket netural blob.c file.
157 */
158 int socket_read_blob(Blob *pBlob, int pSockId, int nToRead){
159 int i=0,read=0;
160 char rbuf[50];
161 blob_zero(pBlob);
162 while ( i<nToRead ){
163 read = recv(pSockId, rbuf, 50, 0);
164 i += read;
165 if( read<0 ){
166 return 0;
167 }
168 blob_append(pBlob, rbuf, read);
169 }
170 return blob_size(pBlob);
171 }
172
173 /*
174 ** Make a single attempt to talk to the server. Return TRUE on success
175 ** and FALSE on a failure.
176 **
@@ -120,40 +180,78 @@
180 **
181 ** If an error occurs, this routine return false, resets pReply and
182 ** closes the persistent connection, if any.
183 */
184 static int http_send_recv(Blob *pHeader, Blob *pPayload, Blob *pReply){
185 int closeConnection=1; /* default to closing the connection */
186 int rc;
 
187 int iLength;
188 int iHttpVersion;
189 int i;
190 int nRead;
191 char zLine[2000];
192
193 if( pSocket==0 && http_open_socket() ){
194 return 0;
195 }
196 iLength = -1;
197 #ifdef __MINGW32__
198 /*
199 ** Use recv/send on the windows platform as winsock does not allow
200 ** sockets to be used as FILE handles, thus fdopen, fwrite, fgets
201 ** does not function on windows for sockets.
202 */
203 rc = send(pSocket, blob_buffer(pHeader), blob_size(pHeader), 0);
204 if( rc!=blob_size(pHeader) ) goto write_err;
205 rc = send(pSocket, blob_buffer(pPayload), blob_size(pPayload), 0);
206 if( rc!=blob_size(pPayload) ) goto write_err;
207
208 /* Read the response */
209 while( socket_recv_line(pSocket, zLine, 2000) ){
210 for( i=0; zLine[i] && zLine[i]!='\n' && zLine[i]!='\r'; i++ ){}
211 if( i==0 ) break;
212 zLine[i] = 0;
213 if( strncasecmp(zLine, "http/1.", 7)==0 ){
214 if( sscanf(zLine, "HTTP/1.%d %d", &iHttpVersion, &rc)!=2 ) goto write_err;
215 if( rc!=200 ) goto write_err;
216 if( iHttpVersion==0 ){
217 closeConnection = 1;
218 }else{
219 closeConnection = 0;
220 }
221 } else if( strncasecmp(zLine, "content-length:", 15)==0 ){
222 iLength = atoi(&zLine[16]);
223 }else if( strncasecmp(zLine, "connection:", 11)==0 ){
224 for(i=12; isspace(zLine[i]); i++){}
225 if( zLine[i]=='c' || zLine[i]=='C' ){
226 closeConnection = 1;
227 }else if( zLine[i]=='k' || zLine[i]=='K' ){
228 closeConnection = 0;
229 }
230 }
231 }
232 if( iLength<0 ) goto write_err;
233 nRead = socket_read_blob(pReply, pSocket, iLength);
234 #else
235 rc = fwrite(blob_buffer(pHeader), 1, blob_size(pHeader), pSocket);
236 if( rc!=blob_size(pHeader) ) goto write_err;
237 rc = fwrite(blob_buffer(pPayload), 1, blob_size(pPayload), pSocket);
238 if( rc!=blob_size(pPayload) ) goto write_err;
239 if( fflush(pSocket) ) goto write_err;
240 if( fgets(zLine, sizeof(zLine), pSocket)==0 ) goto write_err;
241 if( sscanf(zLine, "HTTP/1.%d %d", &iHttpVersion, &rc)!=2 ) goto write_err;
242 if( rc!=200 ) goto write_err;
243 if( iHttpVersion==0 ){
244 closeConnection = 1; /* Connection: close */
245 }else{
246 closeConnection = 0; /* Connection: keep-alive */
247 }
 
248 while( fgets(zLine, sizeof(zLine), pSocket) ){
249 for(i=0; zLine[i] && zLine[i]!='\n' && zLine[i]!='\r'; i++){}
250 if( i==0 ) break;
251 zLine[i] = 0;
252 if( strncasecmp(zLine,"content-length:",15)==0 ){
253 iLength = atoi(&zLine[16]);
254 }else if( strncasecmp(zLine, "connection:", 11)==0 ){
255 for(i=12; isspace(zLine[i]); i++){}
256 if( zLine[i]=='c' || zLine[i]=='C' ){
257 closeConnection = 1; /* Connection: close */
@@ -162,10 +260,11 @@
260 }
261 }
262 }
263 if( iLength<0 ) goto write_err;
264 nRead = blob_read_from_channel(pReply, pSocket, iLength);
265 #endif
266 if( nRead!=iLength ){
267 blob_reset(pReply);
268 goto write_err;
269 }
270 if( closeConnection ){
@@ -287,10 +386,21 @@
386 /*
387 ** Make sure the socket to the HTTP server is closed
388 */
389 void http_close(void){
390 if( pSocket ){
391 #ifdef __MINGW32__
392 closesocket(pSocket);
393 #else
394 fclose(pSocket);
395 #endif
396 pSocket = 0;
 
397 }
398 /*
399 ** This is counter productive. Each time we open a connection we initialize
400 ** winsock and then when closing we cleanup. It would be better to
401 ** initialize winsock once at application start when we know we are going to
402 ** use the socket interface and then cleanup once at application exit when
403 ** we are all done with all socket operations.
404 */
405 ws_cleanup();
406 }
407
+6 -21
--- win32.txt
+++ win32.txt
@@ -11,39 +11,26 @@
1111
Download/compile/install zlib (configure --prefix=/mingw)
1212
Download/compile/install tclsh (configure --prefix=/) (for tests)
1313
1414
All commands were issued in the MSYS shell, not a cmd.exe
1515
16
-
17
-
1816
Outstanding Issues:
1917
----------------------------------------------------------------------
2018
2119
* server is totally non-functional - #if/#end'd out of the code
22
-* all path operations are defunct
23
-* remote network operations are reporting: can't resolve host name: xyz
24
-
25
- Winsock must be initialized before using:
26
-
27
- WSADATA info;
28
- if (WSAStartup(MAKEWORD(1,1), &info) != 0){
29
- fossil_panic("can't initialize winsock");
30
- }
31
-
32
-
3320
3421
Commands status:
3522
----------------------------------------------------------------------
3623
3724
add OK
3825
cgi Not tested
3926
changes OK
4027
checkout BAD #1
4128
clean OK
42
-clone Local Only #2
29
+clone OK
4330
close OK
44
-commit OK (not tested with gpg signing yet)
31
+commit OK
4532
config OK
4633
deconstruct OK
4734
del OK
4835
descendents OK
4936
diff OK
@@ -54,18 +41,18 @@
5441
leaves OK
5542
ls OK
5643
merge OK
5744
new OK
5845
open OK
59
-pull BAD #2
60
-push BAD #2
46
+pull OK
47
+push OK
6148
rebuild OK (didn't have a corrupt file to try on though)
6249
redo BAD #3
6350
rm OK
64
-server BAD #2,#4
51
+server BAD #4
6552
status OK
66
-sync BAD #2
53
+sync OK
6754
timeline OK
6855
tkdiff OK
6956
undo OK
7057
update OK
7158
user capabilities OK
@@ -82,12 +69,10 @@
8269
Make a new dir, fossil open ../repo.fsl && fossil checkout 123abc and
8370
the file appears.
8471
8572
Is that normal operation?
8673
87
-#2 No socket operations are functioning yet
88
-
8974
#3 In test1/ I edited a file, test2/ I updated, type file.txt changes
9075
were there. I then did fossil undo file.txt. The changes were gone
9176
and fossil status said I had edited file.txt. A fossil redo did not
9277
print anything to the screen and the changes for file.txt are not
9378
in the file. fossil status still reports that the file was edited.
9479
--- win32.txt
+++ win32.txt
@@ -11,39 +11,26 @@
11 Download/compile/install zlib (configure --prefix=/mingw)
12 Download/compile/install tclsh (configure --prefix=/) (for tests)
13
14 All commands were issued in the MSYS shell, not a cmd.exe
15
16
17
18 Outstanding Issues:
19 ----------------------------------------------------------------------
20
21 * server is totally non-functional - #if/#end'd out of the code
22 * all path operations are defunct
23 * remote network operations are reporting: can't resolve host name: xyz
24
25 Winsock must be initialized before using:
26
27 WSADATA info;
28 if (WSAStartup(MAKEWORD(1,1), &info) != 0){
29 fossil_panic("can't initialize winsock");
30 }
31
32
33
34 Commands status:
35 ----------------------------------------------------------------------
36
37 add OK
38 cgi Not tested
39 changes OK
40 checkout BAD #1
41 clean OK
42 clone Local Only #2
43 close OK
44 commit OK (not tested with gpg signing yet)
45 config OK
46 deconstruct OK
47 del OK
48 descendents OK
49 diff OK
@@ -54,18 +41,18 @@
54 leaves OK
55 ls OK
56 merge OK
57 new OK
58 open OK
59 pull BAD #2
60 push BAD #2
61 rebuild OK (didn't have a corrupt file to try on though)
62 redo BAD #3
63 rm OK
64 server BAD #2,#4
65 status OK
66 sync BAD #2
67 timeline OK
68 tkdiff OK
69 undo OK
70 update OK
71 user capabilities OK
@@ -82,12 +69,10 @@
82 Make a new dir, fossil open ../repo.fsl && fossil checkout 123abc and
83 the file appears.
84
85 Is that normal operation?
86
87 #2 No socket operations are functioning yet
88
89 #3 In test1/ I edited a file, test2/ I updated, type file.txt changes
90 were there. I then did fossil undo file.txt. The changes were gone
91 and fossil status said I had edited file.txt. A fossil redo did not
92 print anything to the screen and the changes for file.txt are not
93 in the file. fossil status still reports that the file was edited.
94
--- win32.txt
+++ win32.txt
@@ -11,39 +11,26 @@
11 Download/compile/install zlib (configure --prefix=/mingw)
12 Download/compile/install tclsh (configure --prefix=/) (for tests)
13
14 All commands were issued in the MSYS shell, not a cmd.exe
15
 
 
16 Outstanding Issues:
17 ----------------------------------------------------------------------
18
19 * server is totally non-functional - #if/#end'd out of the code
 
 
 
 
 
 
 
 
 
 
 
20
21 Commands status:
22 ----------------------------------------------------------------------
23
24 add OK
25 cgi Not tested
26 changes OK
27 checkout BAD #1
28 clean OK
29 clone OK
30 close OK
31 commit OK
32 config OK
33 deconstruct OK
34 del OK
35 descendents OK
36 diff OK
@@ -54,18 +41,18 @@
41 leaves OK
42 ls OK
43 merge OK
44 new OK
45 open OK
46 pull OK
47 push OK
48 rebuild OK (didn't have a corrupt file to try on though)
49 redo BAD #3
50 rm OK
51 server BAD #4
52 status OK
53 sync OK
54 timeline OK
55 tkdiff OK
56 undo OK
57 update OK
58 user capabilities OK
@@ -82,12 +69,10 @@
69 Make a new dir, fossil open ../repo.fsl && fossil checkout 123abc and
70 the file appears.
71
72 Is that normal operation?
73
 
 
74 #3 In test1/ I edited a file, test2/ I updated, type file.txt changes
75 were there. I then did fossil undo file.txt. The changes were gone
76 and fossil status said I had edited file.txt. A fossil redo did not
77 print anything to the screen and the changes for file.txt are not
78 in the file. fossil status still reports that the file was edited.
79

Keyboard Shortcuts

Open search /
Next entry (timeline) j
Previous entry (timeline) k
Open focused entry Enter
Show this help ?
Toggle theme Top nav button