00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00022 #include "config.h"
00023 #include <time.h>
00024 #include <stdio.h>
00025 #include <string.h>
00026
00027 #include "pcsclite.h"
00028 #include "winscard.h"
00029 #include "debuglog.h"
00030 #include "winscard_msg.h"
00031 #include "winscard_svc.h"
00032 #include "sys_generic.h"
00033 #include "thread_generic.h"
00034 #include "readerfactory.h"
00035
00041 static struct _psContext
00042 {
00043 SCARDCONTEXT hContext;
00044 SCARDHANDLE hCard[PCSCLITE_MAX_APPLICATION_CONTEXT_CHANNELS];
00045 DWORD dwClientID;
00046 PCSCLITE_THREAD_T pthThread;
00047 sharedSegmentMsg msgStruct;
00048 int protocol_major, protocol_minor;
00049 } psContext[PCSCLITE_MAX_APPLICATIONS_CONTEXTS];
00050
00051 LONG MSGCheckHandleAssociation(SCARDHANDLE, DWORD);
00052 LONG MSGFunctionDemarshall(psharedSegmentMsg, DWORD);
00053 LONG MSGAddContext(SCARDCONTEXT, DWORD);
00054 LONG MSGRemoveContext(SCARDCONTEXT, DWORD);
00055 LONG MSGAddHandle(SCARDCONTEXT, SCARDHANDLE, DWORD);
00056 LONG MSGRemoveHandle(SCARDHANDLE, DWORD);
00057 LONG MSGCleanupClient(DWORD);
00058
00059 static void ContextThread(LPVOID pdwIndex);
00060
00061 LONG ContextsInitialize(void)
00062 {
00063 memset(psContext, 0, sizeof(struct _psContext)*PCSCLITE_MAX_APPLICATIONS_CONTEXTS);
00064 return 1;
00065 }
00066
00077 LONG CreateContextThread(PDWORD pdwClientID)
00078 {
00079 int i;
00080
00081 for (i = 0; i < PCSCLITE_MAX_APPLICATIONS_CONTEXTS; i++)
00082 {
00083 if (psContext[i].dwClientID == 0)
00084 {
00085 psContext[i].dwClientID = *pdwClientID;
00086 *pdwClientID = 0;
00087 break;
00088 }
00089 }
00090
00091 if (i == PCSCLITE_MAX_APPLICATIONS_CONTEXTS)
00092 {
00093 SYS_CloseFile(psContext[i].dwClientID);
00094 psContext[i].dwClientID = 0;
00095 Log2(PCSC_LOG_CRITICAL, "No more context available (max: %d)",
00096 PCSCLITE_MAX_APPLICATIONS_CONTEXTS);
00097 return SCARD_F_INTERNAL_ERROR;
00098 }
00099
00100 if (SYS_ThreadCreate(&psContext[i].pthThread, THREAD_ATTR_DETACHED,
00101 (PCSCLITE_THREAD_FUNCTION( )) ContextThread,
00102 (LPVOID) i) != 1)
00103 {
00104 SYS_CloseFile(psContext[i].dwClientID);
00105 psContext[i].dwClientID = 0;
00106 Log1(PCSC_LOG_CRITICAL, "SYS_ThreadCreate failed");
00107 return SCARD_E_NO_MEMORY;
00108 }
00109
00110 return SCARD_S_SUCCESS;
00111 }
00112
00113
00114
00115
00116
00117
00126 static void ContextThread(LPVOID dwIndex)
00127 {
00128 LONG rv;
00129 sharedSegmentMsg msgStruct;
00130 DWORD dwContextIndex = (DWORD)dwIndex;
00131
00132 Log2(PCSC_LOG_DEBUG, "Thread is started: %d",
00133 psContext[dwContextIndex].dwClientID);
00134
00135 while (1)
00136 {
00137 switch (rv = SHMProcessEventsContext(&psContext[dwContextIndex].dwClientID, &msgStruct, 0))
00138 {
00139 case 0:
00140 if (msgStruct.mtype == CMD_CLIENT_DIED)
00141 {
00142
00143
00144
00145 Log2(PCSC_LOG_DEBUG, "Client die: %d",
00146 psContext[dwContextIndex].dwClientID);
00147 MSGCleanupClient(dwContextIndex);
00148 SYS_ThreadExit((LPVOID) NULL);
00149 }
00150 break;
00151
00152 case 1:
00153 if (msgStruct.mtype == CMD_FUNCTION)
00154 {
00155
00156
00157
00158 MSGFunctionDemarshall(&msgStruct, dwContextIndex);
00159
00160
00161
00162 if ((msgStruct.command != SCARD_TRANSMIT_EXTENDED)
00163 && (msgStruct.command != SCARD_CONTROL_EXTENDED))
00164 rv = SHMMessageSend(&msgStruct, sizeof(msgStruct),
00165 psContext[dwContextIndex].dwClientID,
00166 PCSCLITE_SERVER_ATTEMPTS);
00167 }
00168 else
00169
00170 if (msgStruct.mtype == CMD_VERSION)
00171 {
00172 version_struct *veStr;
00173 veStr = (version_struct *) msgStruct.data;
00174
00175
00176 psContext[dwContextIndex].protocol_major = veStr->major;
00177 psContext[dwContextIndex].protocol_minor = veStr->minor;
00178
00179 Log3(PCSC_LOG_DEBUG,
00180 "Client is protocol version %d:%d",
00181 veStr->major, veStr->minor);
00182
00183 veStr->rv = SCARD_S_SUCCESS;
00184
00185
00186 if ((veStr->major > PROTOCOL_VERSION_MAJOR)
00187 || (veStr->major == PROTOCOL_VERSION_MAJOR
00188 && veStr->minor > PROTOCOL_VERSION_MINOR))
00189 {
00190 Log3(PCSC_LOG_CRITICAL,
00191 "Client protocol is too new %d:%d",
00192 veStr->major, veStr->minor);
00193 Log3(PCSC_LOG_CRITICAL,
00194 "Server protocol is %d:%d",
00195 PROTOCOL_VERSION_MAJOR, PROTOCOL_VERSION_MINOR);
00196 veStr->rv = SCARD_E_NO_SERVICE;
00197 }
00198
00199
00200 veStr->major = PROTOCOL_VERSION_MAJOR;
00201 veStr->minor = PROTOCOL_VERSION_MINOR;
00202
00203
00204 rv = SHMMessageSend(&msgStruct, sizeof(msgStruct),
00205 psContext[dwContextIndex].dwClientID,
00206 PCSCLITE_SERVER_ATTEMPTS);
00207 }
00208 else
00209 continue;
00210
00211 break;
00212
00213 case 2:
00214
00215
00216
00217
00218
00219 break;
00220
00221 case -1:
00222 Log1(PCSC_LOG_ERROR, "Error in SHMProcessEventsContext");
00223 break;
00224
00225 default:
00226 Log2(PCSC_LOG_ERROR,
00227 "SHMProcessEventsContext unknown retval: %d", rv);
00228 break;
00229 }
00230 }
00231 }
00232
00248 LONG MSGFunctionDemarshall(psharedSegmentMsg msgStruct, DWORD dwContextIndex)
00249 {
00250 LONG rv;
00251 establish_struct *esStr;
00252 release_struct *reStr;
00253 connect_struct *coStr;
00254 reconnect_struct *rcStr;
00255 disconnect_struct *diStr;
00256 begin_struct *beStr;
00257 cancel_struct *caStr;
00258 end_struct *enStr;
00259 status_struct *stStr;
00260 transmit_struct *trStr;
00261 control_struct *ctStr;
00262 getset_struct *gsStr;
00263
00264
00265
00266
00267 rv = 0;
00268 switch (msgStruct->command)
00269 {
00270
00271 case SCARD_ESTABLISH_CONTEXT:
00272 esStr = ((establish_struct *) msgStruct->data);
00273 esStr->rv = SCardEstablishContext(esStr->dwScope, 0, 0,
00274 &esStr->phContext);
00275
00276 if (esStr->rv == SCARD_S_SUCCESS)
00277 esStr->rv =
00278 MSGAddContext(esStr->phContext, dwContextIndex);
00279 break;
00280
00281 case SCARD_RELEASE_CONTEXT:
00282 reStr = ((release_struct *) msgStruct->data);
00283 reStr->rv = SCardReleaseContext(reStr->hContext);
00284
00285 if (reStr->rv == SCARD_S_SUCCESS)
00286 reStr->rv =
00287 MSGRemoveContext(reStr->hContext, dwContextIndex);
00288
00289 break;
00290
00291 case SCARD_CONNECT:
00292 coStr = ((connect_struct *) msgStruct->data);
00293 coStr->rv = SCardConnect(coStr->hContext, coStr->szReader,
00294 coStr->dwShareMode, coStr->dwPreferredProtocols,
00295 &coStr->phCard, &coStr->pdwActiveProtocol);
00296
00297 if (coStr->rv == SCARD_S_SUCCESS)
00298 coStr->rv =
00299 MSGAddHandle(coStr->hContext, coStr->phCard, dwContextIndex);
00300
00301 break;
00302
00303 case SCARD_RECONNECT:
00304 rcStr = ((reconnect_struct *) msgStruct->data);
00305 rv = MSGCheckHandleAssociation(rcStr->hCard, dwContextIndex);
00306 if (rv != 0) return rv;
00307
00308 rcStr->rv = SCardReconnect(rcStr->hCard, rcStr->dwShareMode,
00309 rcStr->dwPreferredProtocols,
00310 rcStr->dwInitialization, &rcStr->pdwActiveProtocol);
00311 break;
00312
00313 case SCARD_DISCONNECT:
00314 diStr = ((disconnect_struct *) msgStruct->data);
00315 rv = MSGCheckHandleAssociation(diStr->hCard, dwContextIndex);
00316 if (rv != 0) return rv;
00317 diStr->rv = SCardDisconnect(diStr->hCard, diStr->dwDisposition);
00318
00319 if (diStr->rv == SCARD_S_SUCCESS)
00320 diStr->rv =
00321 MSGRemoveHandle(diStr->hCard, dwContextIndex);
00322 break;
00323
00324 case SCARD_BEGIN_TRANSACTION:
00325 beStr = ((begin_struct *) msgStruct->data);
00326 rv = MSGCheckHandleAssociation(beStr->hCard, dwContextIndex);
00327 if (rv != 0) return rv;
00328 beStr->rv = SCardBeginTransaction(beStr->hCard);
00329 break;
00330
00331 case SCARD_END_TRANSACTION:
00332 enStr = ((end_struct *) msgStruct->data);
00333 rv = MSGCheckHandleAssociation(enStr->hCard, dwContextIndex);
00334 if (rv != 0) return rv;
00335 enStr->rv =
00336 SCardEndTransaction(enStr->hCard, enStr->dwDisposition);
00337 break;
00338
00339 case SCARD_CANCEL_TRANSACTION:
00340 caStr = ((cancel_struct *) msgStruct->data);
00341 rv = MSGCheckHandleAssociation(caStr->hCard, dwContextIndex);
00342 if (rv != 0) return rv;
00343 caStr->rv = SCardCancelTransaction(caStr->hCard);
00344 break;
00345
00346 case SCARD_STATUS:
00347 stStr = ((status_struct *) msgStruct->data);
00348 rv = MSGCheckHandleAssociation(stStr->hCard, dwContextIndex);
00349 if (rv != 0) return rv;
00350 stStr->rv = SCardStatus(stStr->hCard, stStr->mszReaderNames,
00351 &stStr->pcchReaderLen, &stStr->pdwState,
00352 &stStr->pdwProtocol, stStr->pbAtr, &stStr->pcbAtrLen);
00353 break;
00354
00355 case SCARD_TRANSMIT:
00356 trStr = ((transmit_struct *) msgStruct->data);
00357 rv = MSGCheckHandleAssociation(trStr->hCard, dwContextIndex);
00358 if (rv != 0) return rv;
00359 trStr->rv = SCardTransmit(trStr->hCard, &trStr->pioSendPci,
00360 trStr->pbSendBuffer, trStr->cbSendLength,
00361 &trStr->pioRecvPci, trStr->pbRecvBuffer,
00362 &trStr->pcbRecvLength);
00363 break;
00364
00365 case SCARD_CONTROL:
00366 ctStr = ((control_struct *) msgStruct->data);
00367 rv = MSGCheckHandleAssociation(ctStr->hCard, dwContextIndex);
00368 if (rv != 0) return rv;
00369 ctStr->rv = SCardControl(ctStr->hCard, ctStr->dwControlCode,
00370 ctStr->pbSendBuffer, ctStr->cbSendLength,
00371 ctStr->pbRecvBuffer, ctStr->cbRecvLength,
00372 &ctStr->dwBytesReturned);
00373 break;
00374
00375 case SCARD_GET_ATTRIB:
00376 gsStr = ((getset_struct *) msgStruct->data);
00377 rv = MSGCheckHandleAssociation(gsStr->hCard, dwContextIndex);
00378 if (rv != 0) return rv;
00379 gsStr->rv = SCardGetAttrib(gsStr->hCard, gsStr->dwAttrId,
00380 gsStr->pbAttr, &gsStr->cbAttrLen);
00381 break;
00382
00383 case SCARD_SET_ATTRIB:
00384 gsStr = ((getset_struct *) msgStruct->data);
00385 rv = MSGCheckHandleAssociation(gsStr->hCard, dwContextIndex);
00386 if (rv != 0) return rv;
00387 gsStr->rv = SCardSetAttrib(gsStr->hCard, gsStr->dwAttrId,
00388 gsStr->pbAttr, gsStr->cbAttrLen);
00389 break;
00390
00391 case SCARD_TRANSMIT_EXTENDED:
00392 {
00393 transmit_struct_extended *treStr;
00394 unsigned char pbSendBuffer[MAX_BUFFER_SIZE_EXTENDED];
00395 unsigned char pbRecvBuffer[MAX_BUFFER_SIZE_EXTENDED];
00396
00397 treStr = ((transmit_struct_extended *) msgStruct->data);
00398 rv = MSGCheckHandleAssociation(treStr->hCard, dwContextIndex);
00399 if (rv != 0) return rv;
00400
00401
00402 if (treStr->size > PCSCLITE_MAX_MESSAGE_SIZE)
00403 {
00404
00405 memcpy(pbSendBuffer, treStr->data,
00406 PCSCLITE_MAX_MESSAGE_SIZE-sizeof(*treStr));
00407
00408
00409 rv = SHMMessageReceive(
00410 pbSendBuffer+PCSCLITE_MAX_MESSAGE_SIZE-sizeof(*treStr),
00411 treStr->size - PCSCLITE_MAX_MESSAGE_SIZE,
00412 psContext[dwContextIndex].dwClientID,
00413 PCSCLITE_SERVER_ATTEMPTS);
00414 if (rv)
00415 Log1(PCSC_LOG_CRITICAL, "reception failed");
00416 }
00417 else
00418 memcpy(pbSendBuffer, treStr->data, treStr->cbSendLength);
00419
00420 treStr->rv = SCardTransmit(treStr->hCard, &treStr->pioSendPci,
00421 pbSendBuffer, treStr->cbSendLength,
00422 &treStr->pioRecvPci, pbRecvBuffer,
00423 &treStr->pcbRecvLength);
00424
00425 treStr->size = sizeof(*treStr) + treStr->pcbRecvLength;
00426 if (treStr->size > PCSCLITE_MAX_MESSAGE_SIZE)
00427 {
00428
00429 memcpy(treStr->data, pbRecvBuffer, PCSCLITE_MAX_MESSAGE_SIZE
00430 - sizeof(*treStr));
00431
00432 rv = SHMMessageSend(msgStruct, sizeof(*msgStruct),
00433 psContext[dwContextIndex].dwClientID,
00434 PCSCLITE_SERVER_ATTEMPTS);
00435 if (rv)
00436 Log1(PCSC_LOG_CRITICAL, "transmission failed");
00437
00438 rv = SHMMessageSend(pbRecvBuffer + PCSCLITE_MAX_MESSAGE_SIZE
00439 - sizeof(*treStr),
00440 treStr->size - PCSCLITE_MAX_MESSAGE_SIZE,
00441 psContext[dwContextIndex].dwClientID,
00442 PCSCLITE_SERVER_ATTEMPTS);
00443 if (rv)
00444 Log1(PCSC_LOG_CRITICAL, "transmission failed");
00445 }
00446 else
00447 {
00448
00449 memcpy(treStr->data, pbRecvBuffer, treStr->pcbRecvLength);
00450
00451 rv = SHMMessageSend(msgStruct, sizeof(*msgStruct),
00452 psContext[dwContextIndex].dwClientID,
00453 PCSCLITE_SERVER_ATTEMPTS);
00454 if (rv)
00455 Log1(PCSC_LOG_CRITICAL, "transmission failed");
00456 }
00457 }
00458 break;
00459
00460 case SCARD_CONTROL_EXTENDED:
00461 {
00462 control_struct_extended *cteStr;
00463 unsigned char pbSendBuffer[MAX_BUFFER_SIZE_EXTENDED];
00464 unsigned char pbRecvBuffer[MAX_BUFFER_SIZE_EXTENDED];
00465
00466 cteStr = ((control_struct_extended *) msgStruct->data);
00467 rv = MSGCheckHandleAssociation(cteStr->hCard, dwContextIndex);
00468 if (rv != 0) return rv;
00469
00470
00471 if (cteStr->size > PCSCLITE_MAX_MESSAGE_SIZE)
00472 {
00473
00474 memcpy(pbSendBuffer, cteStr->data,
00475 PCSCLITE_MAX_MESSAGE_SIZE-sizeof(*cteStr));
00476
00477
00478 rv = SHMMessageReceive(
00479 pbSendBuffer+PCSCLITE_MAX_MESSAGE_SIZE-sizeof(*cteStr),
00480 cteStr->size - PCSCLITE_MAX_MESSAGE_SIZE,
00481 psContext[dwContextIndex].dwClientID,
00482 PCSCLITE_SERVER_ATTEMPTS);
00483 if (rv)
00484 Log1(PCSC_LOG_CRITICAL, "reception failed");
00485 }
00486 else
00487 memcpy(pbSendBuffer, cteStr->data, cteStr->cbSendLength);
00488
00489 cteStr->rv = SCardControl(cteStr->hCard, cteStr->dwControlCode,
00490 pbSendBuffer, cteStr->cbSendLength,
00491 pbRecvBuffer, cteStr->cbRecvLength,
00492 &cteStr->pdwBytesReturned);
00493
00494 cteStr->size = sizeof(*cteStr) + cteStr->pdwBytesReturned;
00495 if (cteStr->size > PCSCLITE_MAX_MESSAGE_SIZE)
00496 {
00497
00498 memcpy(cteStr->data, pbRecvBuffer, PCSCLITE_MAX_MESSAGE_SIZE
00499 - sizeof(*cteStr));
00500
00501 rv = SHMMessageSend(msgStruct, sizeof(*msgStruct),
00502 psContext[dwContextIndex].dwClientID,
00503 PCSCLITE_SERVER_ATTEMPTS);
00504 if (rv)
00505 Log1(PCSC_LOG_CRITICAL, "transmission failed");
00506
00507 rv = SHMMessageSend(pbRecvBuffer + PCSCLITE_MAX_MESSAGE_SIZE
00508 - sizeof(*cteStr),
00509 cteStr->size - PCSCLITE_MAX_MESSAGE_SIZE,
00510 psContext[dwContextIndex].dwClientID,
00511 PCSCLITE_SERVER_ATTEMPTS);
00512 if (rv)
00513 Log1(PCSC_LOG_CRITICAL, "transmission failed");
00514 }
00515 else
00516 {
00517
00518 memcpy(cteStr->data, pbRecvBuffer, cteStr->pdwBytesReturned);
00519
00520 rv = SHMMessageSend(msgStruct, sizeof(*msgStruct),
00521 psContext[dwContextIndex].dwClientID,
00522 PCSCLITE_SERVER_ATTEMPTS);
00523 if (rv)
00524 Log1(PCSC_LOG_CRITICAL, "transmission failed");
00525 }
00526 }
00527 break;
00528
00529 default:
00530 Log2(PCSC_LOG_CRITICAL, "Unknown command: %d", msgStruct->command);
00531 return -1;
00532 }
00533
00534 return 0;
00535 }
00536
00537 LONG MSGAddContext(SCARDCONTEXT hContext, DWORD dwContextIndex)
00538 {
00539 psContext[dwContextIndex].hContext = hContext;
00540 return SCARD_S_SUCCESS;
00541 }
00542
00543 LONG MSGRemoveContext(SCARDCONTEXT hContext, DWORD dwContextIndex)
00544 {
00545 int i;
00546 LONG rv;
00547
00548 if (psContext[dwContextIndex].hContext == hContext)
00549 {
00550 for (i = 0; i < PCSCLITE_MAX_APPLICATION_CONTEXT_CHANNELS; i++)
00551 {
00552
00553
00554
00555
00556 if (psContext[dwContextIndex].hCard[i] != 0)
00557 {
00558 PREADER_CONTEXT rContext = NULL;
00559 DWORD dwLockId;
00560
00561
00562
00563
00564 rv = RFReaderInfoById(psContext[dwContextIndex].hCard[i],
00565 &rContext);
00566 if (rv != SCARD_S_SUCCESS)
00567 return rv;
00568
00569 dwLockId = rContext->dwLockId;
00570 rContext->dwLockId = 0;
00571
00572 if (psContext[dwContextIndex].hCard[i] != dwLockId)
00573 {
00574
00575
00576
00577
00578 rv = SCARD_W_REMOVED_CARD;
00579 }
00580 else
00581 {
00582
00583
00584
00585
00586
00587 rv = SCardStatus(psContext[dwContextIndex].hCard[i], NULL,
00588 NULL, NULL, NULL, NULL, NULL);
00589 }
00590
00591 if (rv == SCARD_W_RESET_CARD || rv == SCARD_W_REMOVED_CARD)
00592 SCardDisconnect(psContext[dwContextIndex].hCard[i],
00593 SCARD_LEAVE_CARD);
00594 else
00595 SCardDisconnect(psContext[dwContextIndex].hCard[i],
00596 SCARD_RESET_CARD);
00597
00598 psContext[dwContextIndex].hCard[i] = 0;
00599 }
00600 }
00601
00602 psContext[dwContextIndex].hContext = 0;
00603 return SCARD_S_SUCCESS;
00604 }
00605
00606 return SCARD_E_INVALID_VALUE;
00607 }
00608
00609 LONG MSGAddHandle(SCARDCONTEXT hContext, SCARDHANDLE hCard, DWORD dwContextIndex)
00610 {
00611 int i;
00612
00613 if (psContext[dwContextIndex].hContext == hContext)
00614 {
00615
00616
00617
00618
00619 for (i = 0; i < PCSCLITE_MAX_APPLICATION_CONTEXT_CHANNELS; i++)
00620 {
00621 if (psContext[dwContextIndex].hCard[i] == 0)
00622 {
00623 psContext[dwContextIndex].hCard[i] = hCard;
00624 break;
00625 }
00626 }
00627
00628 if (i == PCSCLITE_MAX_APPLICATION_CONTEXT_CHANNELS)
00629 {
00630 return SCARD_F_INTERNAL_ERROR;
00631 } else
00632 {
00633 return SCARD_S_SUCCESS;
00634 }
00635
00636 }
00637
00638 return SCARD_E_INVALID_VALUE;
00639 }
00640
00641 LONG MSGRemoveHandle(SCARDHANDLE hCard, DWORD dwContextIndex)
00642 {
00643 int i;
00644
00645 for (i = 0; i < PCSCLITE_MAX_APPLICATION_CONTEXT_CHANNELS; i++)
00646 {
00647 if (psContext[dwContextIndex].hCard[i] == hCard)
00648 {
00649 psContext[dwContextIndex].hCard[i] = 0;
00650 return SCARD_S_SUCCESS;
00651 }
00652 }
00653
00654 return SCARD_E_INVALID_VALUE;
00655 }
00656
00657
00658 LONG MSGCheckHandleAssociation(SCARDHANDLE hCard, DWORD dwContextIndex)
00659 {
00660 int i;
00661
00662 for (i = 0; i < PCSCLITE_MAX_APPLICATION_CONTEXT_CHANNELS; i++)
00663 {
00664 if (psContext[dwContextIndex].hCard[i] == hCard)
00665 {
00666 return 0;
00667 }
00668 }
00669
00670
00671 Log1(PCSC_LOG_ERROR, "Client failed to authenticate");
00672 SYS_Sleep(2);
00673
00674 return -1;
00675 }
00676
00677 LONG MSGCleanupClient(DWORD dwContextIndex)
00678 {
00679 if (psContext[dwContextIndex].hContext != 0)
00680 {
00681 SCardReleaseContext(psContext[dwContextIndex].hContext);
00682 MSGRemoveContext(psContext[dwContextIndex].hContext, dwContextIndex);
00683 }
00684
00685 psContext[dwContextIndex].dwClientID = 0;
00686 psContext[dwContextIndex].protocol_major = 0;
00687 psContext[dwContextIndex].protocol_minor = 0;
00688
00689 return 0;
00690 }