The R Project SVN R

Rev

Rev 62770 | Rev 68392 | Go to most recent revision | Show entire file | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed

Rev 62770 Rev 65805
Line 56... Line 56...
56
#define HttpdServerActivity 8
56
#define HttpdServerActivity 8
57
#define HttpdWorkerActivity 9
57
#define HttpdWorkerActivity 9
58
 
58
 
59
/* this is orignally from sisock.h - system independent sockets */
59
/* this is orignally from sisock.h - system independent sockets */
60
 
60
 
61
#ifndef WIN32
61
#ifndef _WIN32
62
# include <R_ext/eventloop.h>
62
# include <R_ext/eventloop.h>
63
# include <sys/types.h>
63
# include <sys/types.h>
64
# ifdef HAVE_UNISTD_H
64
# ifdef HAVE_UNISTD_H
65
#  include <unistd.h>
65
#  include <unistd.h>
66
# endif
66
# endif
Line 124... Line 124...
124
}
124
}
125
 
125
 
126
# define donesocks() WSACleanup()
126
# define donesocks() WSACleanup()
127
typedef int socklen_t;
127
typedef int socklen_t;
128
 
128
 
129
#endif /* WIN32 */
129
#endif /* _WIN32 */
130
 
130
 
131
/* --- system-independent part --- */
131
/* --- system-independent part --- */
132
 
132
 
133
#define SA struct sockaddr
133
#define SA struct sockaddr
134
#define SAIN struct sockaddr_in
134
#define SAIN struct sockaddr_in
Line 181... Line 181...
181
 
181
 
182
/* --- connection/worker structure holding all data for an active connection --- */
182
/* --- connection/worker structure holding all data for an active connection --- */
183
typedef struct httpd_conn {
183
typedef struct httpd_conn {
184
    SOCKET sock;         /* client socket */
184
    SOCKET sock;         /* client socket */
185
    struct in_addr peer; /* IP address of the peer */
185
    struct in_addr peer; /* IP address of the peer */
186
#ifdef WIN32
186
#ifdef _WIN32
187
    HANDLE thread;       /* worker thread */
187
    HANDLE thread;       /* worker thread */
188
#else
188
#else
189
    InputHandler *ih;    /* worker input handler */
189
    InputHandler *ih;    /* worker input handler */
190
#endif
190
#endif
191
    char line_buf[LINE_BUF_SIZE];  /* line buffer (used for request and headers) */
191
    char line_buf[LINE_BUF_SIZE];  /* line buffer (used for request and headers) */
Line 206... Line 206...
206
static httpd_conn_t *workers[MAX_WORKERS];
206
static httpd_conn_t *workers[MAX_WORKERS];
207
 
207
 
208
/* --- flag determining whether one-time initialization is yet to be performed --- */
208
/* --- flag determining whether one-time initialization is yet to be performed --- */
209
static int needs_init = 1;
209
static int needs_init = 1;
210
 
210
 
211
#ifdef WIN32
211
#ifdef _WIN32
212
#define WM_RHTTP_CALLBACK ( WM_USER + 1 )
212
#define WM_RHTTP_CALLBACK ( WM_USER + 1 )
213
static HWND message_window;
213
static HWND message_window;
214
static LRESULT CALLBACK
214
static LRESULT CALLBACK
215
RhttpdWindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
215
RhttpdWindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
216
#ifndef HWND_MESSAGE
216
#ifndef HWND_MESSAGE
Line 219... Line 219...
219
#endif
219
#endif
220
 
220
 
221
static void first_init()
221
static void first_init()
222
{
222
{
223
    initsocks();
223
    initsocks();
224
#ifdef WIN32
224
#ifdef _WIN32
225
    /* create a dummy message-only window for synchronization with the
225
    /* create a dummy message-only window for synchronization with the
226
     * main event loop */
226
     * main event loop */
227
    HINSTANCE instance = GetModuleHandle(NULL);
227
    HINSTANCE instance = GetModuleHandle(NULL);
228
    LPCTSTR class = "Rhttpd";
228
    LPCTSTR class = "Rhttpd";
229
    WNDCLASS wndclass = { 0, RhttpdWindowProc, 0, 0, instance, NULL, 0, 0,
229
    WNDCLASS wndclass = { 0, RhttpdWindowProc, 0, 0, instance, NULL, 0, 0,
Line 275... Line 275...
275
}
275
}
276
 
276
 
277
static void finalize_worker(httpd_conn_t *c)
277
static void finalize_worker(httpd_conn_t *c)
278
{
278
{
279
    DBG(printf("finalizing worker %p\n", (void*) c));
279
    DBG(printf("finalizing worker %p\n", (void*) c));
280
#ifndef WIN32
280
#ifndef _WIN32
281
    if (c->ih) {
281
    if (c->ih) {
282
	removeInputHandler(&R_InputHandlers, c->ih);
282
	removeInputHandler(&R_InputHandlers, c->ih);
283
	c->ih = NULL;
283
	c->ih = NULL;
284
    }
284
    }
285
#endif
285
#endif
Line 314... Line 314...
314
  */
314
  */
315
static int add_worker(httpd_conn_t *c) {
315
static int add_worker(httpd_conn_t *c) {
316
    unsigned int i = 0;
316
    unsigned int i = 0;
317
    for (; i < MAX_WORKERS; i++)
317
    for (; i < MAX_WORKERS; i++)
318
	if (!workers[i]) {
318
	if (!workers[i]) {
319
#ifdef WIN32
319
#ifdef _WIN32
320
	    DBG(printf("registering worker %p as %d (thread=0x%x)\n", (void*) c, i, (int) c->thread));
320
	    DBG(printf("registering worker %p as %d (thread=0x%x)\n", (void*) c, i, (int) c->thread));
321
#else
321
#else
322
	    DBG(printf("registering worker %p as %d (handler=%p)\n", (void*) c, i, (void*) c->ih));
322
	    DBG(printf("registering worker %p as %d (handler=%p)\n", (void*) c, i, (void*) c->ih));
323
#endif
323
#endif
324
	    workers[i] = c;
324
	    workers[i] = c;
Line 495... Line 495...
495
	UNPROTECT(1);
495
	UNPROTECT(1);
496
	return res;
496
	return res;
497
    }
497
    }
498
}
498
}
499
 
499
 
500
#ifdef WIN32
500
#ifdef _WIN32
501
/* on Windows we have to guarantee that process_request is performed
501
/* on Windows we have to guarantee that process_request is performed
502
 * on the main thread, so we have to dispatch it through a message */
502
 * on the main thread, so we have to dispatch it through a message */
503
static void process_request_main_thread(httpd_conn_t *c);
503
static void process_request_main_thread(httpd_conn_t *c);
504
 
504
 
505
static void process_request(httpd_conn_t *c)
505
static void process_request(httpd_conn_t *c)
Line 747... Line 747...
747
    in_process = 1;
747
    in_process = 1;
748
    R_ToplevelExec(process_request_, c);
748
    R_ToplevelExec(process_request_, c);
749
    in_process = 0;
749
    in_process = 0;
750
}
750
}
751
 
751
 
752
#ifdef WIN32
752
#ifdef _WIN32
753
#undef process_request
753
#undef process_request
754
#endif
754
#endif
755
 
755
 
756
/* this function is called to fetch new data from the client
756
/* this function is called to fetch new data from the client
757
 * connection socket and process it */
757
 * connection socket and process it */
Line 1072... Line 1072...
1072
 
1072
 
1073
static void srv_input_handler(void *data);
1073
static void srv_input_handler(void *data);
1074
 
1074
 
1075
static SOCKET srv_sock = INVALID_SOCKET;
1075
static SOCKET srv_sock = INVALID_SOCKET;
1076
 
1076
 
1077
#ifdef WIN32
1077
#ifdef _WIN32
1078
/* Windows implementation uses threads to accept and serve
1078
/* Windows implementation uses threads to accept and serve
1079
   connections, using the main event loop to synchronize with R
1079
   connections, using the main event loop to synchronize with R
1080
   through a message-only window which is created on the R thread
1080
   through a message-only window which is created on the R thread
1081
 */
1081
 */
1082
static LRESULT CALLBACK RhttpdWindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
1082
static LRESULT CALLBACK RhttpdWindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
Line 1133... Line 1133...
1133
    if (cl_sock == INVALID_SOCKET) /* accept failed, don't bother */
1133
    if (cl_sock == INVALID_SOCKET) /* accept failed, don't bother */
1134
	return;
1134
	return;
1135
    c = (httpd_conn_t*) calloc(1, sizeof(httpd_conn_t));
1135
    c = (httpd_conn_t*) calloc(1, sizeof(httpd_conn_t));
1136
    c->sock = cl_sock;
1136
    c->sock = cl_sock;
1137
    c->peer = peer_sa.sin_addr;
1137
    c->peer = peer_sa.sin_addr;
1138
#ifndef WIN32
1138
#ifndef _WIN32
1139
    c->ih = addInputHandler(R_InputHandlers, cl_sock, &worker_input_handler,
1139
    c->ih = addInputHandler(R_InputHandlers, cl_sock, &worker_input_handler,
1140
			    HttpdWorkerActivity);
1140
			    HttpdWorkerActivity);
1141
    if (c->ih) c->ih->userData = c;
1141
    if (c->ih) c->ih->userData = c;
1142
    add_worker(c);
1142
    add_worker(c);
1143
#else
1143
#else
Line 1150... Line 1150...
1150
#endif
1150
#endif
1151
}
1151
}
1152
 
1152
 
1153
int in_R_HTTPDCreate(const char *ip, int port) 
1153
int in_R_HTTPDCreate(const char *ip, int port) 
1154
{
1154
{
1155
#ifndef WIN32
1155
#ifndef _WIN32
1156
    int reuse = 1;
1156
    int reuse = 1;
1157
#endif
1157
#endif
1158
    SAIN srv_sa;
1158
    SAIN srv_sa;
1159
 
1159
 
1160
    if (needs_init) /* initialization may need to be performed on first use */
1160
    if (needs_init) /* initialization may need to be performed on first use */
Line 1162... Line 1162...
1162
 
1162
 
1163
    /* is already in use, close the current socket */
1163
    /* is already in use, close the current socket */
1164
    if (srv_sock != INVALID_SOCKET)
1164
    if (srv_sock != INVALID_SOCKET)
1165
	closesocket(srv_sock);
1165
	closesocket(srv_sock);
1166
 
1166
 
1167
#ifdef WIN32
1167
#ifdef _WIN32
1168
    /* on Windows stop the server thread if it exists */
1168
    /* on Windows stop the server thread if it exists */
1169
    if (server_thread) {
1169
    if (server_thread) {
1170
	DWORD ts = 0;
1170
	DWORD ts = 0;
1171
	if (GetExitCodeThread(server_thread, &ts) && ts == STILL_ACTIVE)
1171
	if (GetExitCodeThread(server_thread, &ts) && ts == STILL_ACTIVE)
1172
	    TerminateThread(server_thread, 0);
1172
	    TerminateThread(server_thread, 0);
Line 1177... Line 1177...
1177
    /* create a new socket */
1177
    /* create a new socket */
1178
    srv_sock = socket(AF_INET, SOCK_STREAM, 0);
1178
    srv_sock = socket(AF_INET, SOCK_STREAM, 0);
1179
    if (srv_sock == INVALID_SOCKET)
1179
    if (srv_sock == INVALID_SOCKET)
1180
	Rf_error("unable to create socket");
1180
	Rf_error("unable to create socket");
1181
 
1181
 
1182
#ifndef WIN32
1182
#ifndef _WIN32
1183
    /* set socket for reuse so we can re-init if we die */
1183
    /* set socket for reuse so we can re-init if we die */
1184
    /* But on Windows, this lets us stomp on any port already in use, so don't do it. */
1184
    /* But on Windows, this lets us stomp on any port already in use, so don't do it. */
1185
    setsockopt(srv_sock, SOL_SOCKET, SO_REUSEADDR,
1185
    setsockopt(srv_sock, SOL_SOCKET, SO_REUSEADDR,
1186
	       (const char*)&reuse, sizeof(reuse));
1186
	       (const char*)&reuse, sizeof(reuse));
1187
#endif
1187
#endif
Line 1201... Line 1201...
1201
 
1201
 
1202
    /* setup listen */
1202
    /* setup listen */
1203
    if (listen(srv_sock, 8))
1203
    if (listen(srv_sock, 8))
1204
	Rf_error("cannot listen to TCP port %d", port);
1204
	Rf_error("cannot listen to TCP port %d", port);
1205
 
1205
 
1206
#ifndef WIN32
1206
#ifndef _WIN32
1207
    /* all went well, register the socket as a handler */
1207
    /* all went well, register the socket as a handler */
1208
    if (srv_handler) removeInputHandler(&R_InputHandlers, srv_handler);
1208
    if (srv_handler) removeInputHandler(&R_InputHandlers, srv_handler);
1209
    srv_handler = addInputHandler(R_InputHandlers, srv_sock,
1209
    srv_handler = addInputHandler(R_InputHandlers, srv_sock,
1210
				  &srv_input_handler, HttpdServerActivity);
1210
				  &srv_input_handler, HttpdServerActivity);
1211
#else
1211
#else
Line 1218... Line 1218...
1218
void in_R_HTTPDStop(void)
1218
void in_R_HTTPDStop(void)
1219
{
1219
{
1220
    if (srv_sock != INVALID_SOCKET) closesocket(srv_sock);
1220
    if (srv_sock != INVALID_SOCKET) closesocket(srv_sock);
1221
    srv_sock = INVALID_SOCKET;
1221
    srv_sock = INVALID_SOCKET;
1222
 
1222
 
1223
#ifdef WIN32
1223
#ifdef _WIN32
1224
    /* on Windows stop the server thread if it exists */
1224
    /* on Windows stop the server thread if it exists */
1225
    if (server_thread) {
1225
    if (server_thread) {
1226
	DWORD ts = 0;
1226
	DWORD ts = 0;
1227
	if (GetExitCodeThread(server_thread, &ts) && ts == STILL_ACTIVE)
1227
	if (GetExitCodeThread(server_thread, &ts) && ts == STILL_ACTIVE)
1228
	    TerminateThread(server_thread, 0);
1228
	    TerminateThread(server_thread, 0);