void Account::SetType(int32 type) { if (type < INBOUND_TYPE || type > IN_AND_OUTBOUND_TYPE) return; int32 index = gListView->IndexOf(fAccountItem) + 1; // missing inbound if ((type == INBOUND_TYPE || type == IN_AND_OUTBOUND_TYPE) && !Inbound()) { if (!fInbound) CreateInbound(); if (fInbound) gListView->AddItem(fInboundItem,index); } if (Inbound()) index++; // missing outbound if ((type == OUTBOUND_TYPE || type == IN_AND_OUTBOUND_TYPE) && !Outbound()) { if (!fOutbound) CreateOutbound(); if (fOutbound) gListView->AddItem(fOutboundItem,index); } if (Outbound()) index++; // missing filter if (!gListView->HasItem(fFilterItem)) gListView->AddItem(fFilterItem,index); // remove inbound if (type == OUTBOUND_TYPE && Inbound()) gListView->RemoveItem(fInboundItem); // remove outbound if (type == INBOUND_TYPE && Outbound()) gListView->RemoveItem(fOutboundItem); }
static void tcpThread(void *context) { Socket *sock = (Socket*) context; TCPSocket *tcpsock = (TCPSocket*) context; Semaphore *sems[4] = {&tcpsock->semConnected, &tcpsock->semStop, &tcpsock->semAck, &tcpsock->semAckOut}; Semaphore *semsOut[3] = {&tcpsock->semStop, &tcpsock->semAckOut, &tcpsock->semSendFetch}; detachMe(); uint16_t srcport, dstport; if (sock->domain == AF_INET) { const struct sockaddr_in *inaddr = (const struct sockaddr_in*) &tcpsock->peername; struct sockaddr_in *inname = (struct sockaddr_in*) &tcpsock->sockname; srcport = inname->sin_port; dstport = inaddr->sin_port; } else { const struct sockaddr_in6 *inaddr = (const struct sockaddr_in6*) &tcpsock->peername; struct sockaddr_in6 *inname = (struct sockaddr_in6*) &tcpsock->sockname; inname->sin6_family = AF_INET6; srcport = inname->sin6_port; dstport = inaddr->sin6_port; }; int connectDone = 0; if (tcpsock->state == TCP_ESTABLISHED) { sems[0] = NULL; connectDone = 1; }; int wantExit = 0; while (1) { if (wantExit) break; uint64_t deadline = getNanotime() + sock->options[GSO_SNDTIMEO]; if (sock->options[GSO_SNDTIMEO] == 0) { deadline = 0; }; int sendOK = 0; int retransCount = 16; while (((getNanotime() < deadline) || (deadline == 0)) && (retransCount--)) { tcpsock->currentOut->segment->ackno = htonl(tcpsock->nextAckNo); ChecksumOutbound(tcpsock->currentOut); int status = sendPacketEx(&tcpsock->sockname, &tcpsock->peername, tcpsock->currentOut->segment, tcpsock->currentOut->size, IPPROTO_TCP, sock->options, sock->ifname); if (status != 0) { tcpsock->sockErr = -status; if (tcpsock->state == TCP_CONNECTING) { semSignal(&tcpsock->semConnected); }; tcpsock->state = TCP_TERMINATED; kfree(tcpsock->currentOut); wantExit = 1; break; }; uint8_t bitmap = 0; if (semPoll(4, sems, &bitmap, 0, TCP_RETRANS_TIMEOUT) == 0) { continue; }; if (bitmap & (1 << 1)) { kfree(tcpsock->currentOut); tcpsock->state = TCP_TERMINATED; wantExit = 1; break; }; if (bitmap & (1 << 2)) { semWait(&tcpsock->semAck); sendOK = 1; break; }; if (bitmap & (1 << 3)) { semWaitGen(&tcpsock->semAckOut, -1, 0, 0); }; }; if (wantExit) break; int wasFin = tcpsock->currentOut->segment->flags & TCP_FIN; kfree(tcpsock->currentOut); if (!sendOK) { tcpsock->sockErr = ETIMEDOUT; if (tcpsock->state == TCP_CONNECTING) { semSignal(&tcpsock->semConnected); }; tcpsock->state = TCP_TERMINATED; return; }; if (!connectDone) { while ((getNanotime() < deadline) || (deadline == 0)) { uint8_t bitmap = 0; semPoll(3, sems, &bitmap, 0, sock->options[GSO_SNDTIMEO]); if (bitmap & (1 << 1)) { tcpsock->state = TCP_TERMINATED; return; }; if (bitmap & (1 << 0)) { connectDone = 1; break; }; }; if (!connectDone) { tcpsock->sockErr = ETIMEDOUT; semSignal(&tcpsock->semConnected); tcpsock->state = TCP_TERMINATED; return; }; sems[0] = NULL; tcpsock->state = TCP_ESTABLISHED; }; if (wasFin) break; while (1) { uint8_t bitmap = 0; semPoll(3, semsOut, &bitmap, 0, 0); if (bitmap & (1 << 2)) { if (bitmap & (1 << 1)) { semWaitGen(&tcpsock->semAckOut, -1, 0, 0); }; int count = semWaitGen(&tcpsock->semSendFetch, 512, 0, 0); TCPOutbound *ob = CreateOutbound(&tcpsock->sockname, &tcpsock->peername, (size_t)count); ob->segment->srcport = srcport; ob->segment->dstport = dstport; ob->segment->seqno = htonl(tcpsock->nextSeqNo); // ackno filled in at the start of the loop iteration ob->segment->dataOffsetNS = 0x50; ob->segment->flags = TCP_PSH | TCP_ACK; // a count of zero means end of data, so send FIN. if (count == 0) { ob->segment->flags = TCP_FIN | TCP_ACK; tcpsock->nextSeqNo++; }; ob->segment->winsz = htons(TCP_BUFFER_SIZE); uint8_t *put = (uint8_t*) &ob->segment[1]; uint32_t size = (uint32_t)count; while (count--) { *put++ = tcpsock->bufSend[tcpsock->idxSendFetch]; tcpsock->idxSendFetch = (tcpsock->idxSendFetch+1) % TCP_BUFFER_SIZE; }; tcpsock->nextSeqNo += size; tcpsock->expectedAck = tcpsock->nextSeqNo; tcpsock->currentOut = ob; semSignal2(&tcpsock->semSendPut, (int)size); break; // continues the outer loop }; if (bitmap & (1 << 1)) { semWaitGen(&tcpsock->semAckOut, -1, 0, 0); TCPOutbound *ob = CreateOutbound(&tcpsock->sockname, &tcpsock->peername, 0); TCPSegment *ack = ob->segment; ack->srcport = srcport; ack->dstport = dstport; ack->seqno = htonl(tcpsock->nextSeqNo); ack->ackno = htonl(tcpsock->nextAckNo); ack->dataOffsetNS = 0x50; ack->flags = TCP_ACK; ack->winsz = htons(TCP_BUFFER_SIZE); ChecksumOutbound(ob); sendPacketEx(&tcpsock->sockname, &tcpsock->peername, ob->segment, ob->size, IPPROTO_TCP, sock->options, sock->ifname); kfree(ob); }; if (bitmap & (1 << 0)) { tcpsock->state = TCP_TERMINATED; wantExit = 1; break; }; }; }; // wait up to 4 minutes, acknowledging any packets if necessary (during a clean exit) uint64_t deadline = getNanotime() + 4UL * 60UL * 1000000000UL; uint64_t currentTime; Semaphore *semsClosing[2] = {&tcpsock->semStop, &tcpsock->semAckOut}; while ((currentTime = getNanotime()) < deadline) { uint8_t bitmap = 0; semPoll(2, semsClosing, &bitmap, 0, deadline - currentTime); if (bitmap & (1 << 0)) { wantExit = 1; semsClosing[0] = NULL; }; if (bitmap & (1 << 1)) { if (!wantExit) { semWaitGen(&tcpsock->semAckOut, -1, 0, 0); TCPOutbound *ob = CreateOutbound(&tcpsock->sockname, &tcpsock->peername, 0); TCPSegment *ack = ob->segment; ack->srcport = srcport; ack->dstport = dstport; ack->seqno = htonl(tcpsock->nextSeqNo); ack->ackno = htonl(tcpsock->nextAckNo); ack->dataOffsetNS = 0x50; ack->flags = TCP_FIN | TCP_ACK; ack->winsz = htons(TCP_BUFFER_SIZE); ChecksumOutbound(ob); sendPacketEx(&tcpsock->sockname, &tcpsock->peername, ob->segment, ob->size, IPPROTO_TCP, sock->options, sock->ifname); kfree(ob); }; }; }; // wait for the socket to actually be closed by the application (in case it wasn't already) while (semWaitGen(&tcpsock->semSendFetch, 512, 0, 0) != 0); // free the port and socket FreePort(srcport); FreeSocket(sock); };
static int tcpsock_connect(Socket *sock, const struct sockaddr *addr, size_t size) { TCPSocket *tcpsock = (TCPSocket*) sock; if (addr->sa_family != sock->domain) { ERRNO = EAFNOSUPPORT; return -1; }; if (size != INET_SOCKADDR_LEN) { ERRNO = EAFNOSUPPORT; return -1; }; semWait(&tcpsock->lock); if (tcpsock->state == TCP_CONNECTING) { semSignal(&tcpsock->lock); ERRNO = EALREADY; return -1; }; if (tcpsock->state != TCP_CLOSED) { semSignal(&tcpsock->lock); ERRNO = EISCONN; return -1; }; uint16_t srcport, dstport; if (sock->domain == AF_INET) { const struct sockaddr_in *inaddr = (const struct sockaddr_in*) addr; struct sockaddr_in *inname = (struct sockaddr_in*) &tcpsock->sockname; if (inname->sin_family == AF_UNSPEC) { inname->sin_family = AF_INET; getDefaultAddr4(&inname->sin_addr, &inaddr->sin_addr, sock->ifname); inname->sin_port = AllocPort(); srcport = inname->sin_port; } else { srcport = inname->sin_port; }; dstport = inaddr->sin_port; } else { const struct sockaddr_in6 *inaddr = (const struct sockaddr_in6*) addr; struct sockaddr_in6 *inname = (struct sockaddr_in6*) &tcpsock->sockname; if (inname->sin6_family == AF_UNSPEC) { inname->sin6_family = AF_INET6; getDefaultAddr6(&inname->sin6_addr, &inaddr->sin6_addr, sock->ifname); inname->sin6_port = AllocPort(); srcport = inname->sin6_port; } else { srcport = inname->sin6_port; } dstport = inaddr->sin6_port; }; memcpy(&tcpsock->peername, addr, INET_SOCKADDR_LEN); tcpsock->state = TCP_CONNECTING; tcpsock->nextSeqNo = (uint32_t) getRandom(); tcpsock->currentOut = CreateOutbound(&tcpsock->sockname, &tcpsock->peername, 0); tcpsock->expectedAck = tcpsock->nextSeqNo; TCPSegment *syn = tcpsock->currentOut->segment; syn->srcport = srcport; syn->dstport = dstport; syn->seqno = htonl(tcpsock->nextSeqNo-1); syn->dataOffsetNS = 0x50; syn->flags = TCP_SYN; syn->winsz = htons(TCP_BUFFER_SIZE); ChecksumOutbound(tcpsock->currentOut); KernelThreadParams pars; memset(&pars, 0, sizeof(KernelThreadParams)); pars.stackSize = DEFAULT_STACK_SIZE; pars.name = "TCP Thread"; tcpsock->thread = CreateKernelThread(tcpThread, &pars, tcpsock); semSignal(&tcpsock->lock); uint8_t bitmap = 0; Semaphore *semConn = &tcpsock->semConnected; if (semPoll(1, &semConn, &bitmap, SEM_W_FILE(sock->fp->oflags), 0) == 0) { // we caught an interrupt before the connection was completed ERRNO = EINPROGRESS; return -1; } else { // report the error synchronously if there is one; otherwise success if (tcpsock->sockErr == 0) { return 0; } else { ERRNO = tcpsock->sockErr; return -1; }; }; };
static Socket* tcpsock_accept(Socket *sock, struct sockaddr *addr, size_t *addrlenptr) { TCPSocket *tcpsock = (TCPSocket*) sock; if (tcpsock->state != TCP_LISTENING) { ERRNO = EINVAL; return NULL; }; if (addrlenptr != NULL) { if ((*addrlenptr) < INET_SOCKADDR_LEN) { ERRNO = EINVAL; return NULL; }; }; int count = semWaitGen(&tcpsock->semConnWaiting, 1, SEM_W_FILE(sock->fp->oflags), sock->options[GSO_RCVTIMEO]); if (count < 0) { ERRNO = -count; return NULL; }; // a connection is pending, create the socket. // TODO: there is a race condition where we remove the pending connection from the list, // and another SYN arrives before we add the socket to the list, causing another connection // request to be created. We must work on that somehow. Socket *client = CreateTCPSocket(); client->domain = sock->domain; client->type = SOCK_STREAM; client->proto = IPPROTO_TCP; memset(client->options, 0, 8*GSO_COUNT); TCPSocket *tcpclient = (TCPSocket*) client; semWait(&tcpsock->lock); TCPPending *pend = tcpsock->firstPending; tcpsock->firstPending = pend->next; semSignal(&tcpsock->lock); semWait(&tcpclient->lock); memcpy(&tcpclient->sockname, &pend->local, sizeof(struct sockaddr)); memcpy(&tcpclient->peername, &pend->peer, sizeof(struct sockaddr)); tcpclient->state = TCP_ESTABLISHED; tcpclient->nextSeqNo = (uint32_t) getRandom(); tcpclient->nextAckNo = pend->ackno; tcpclient->currentOut = CreateOutbound(&tcpclient->sockname, &tcpclient->peername, 0); tcpclient->expectedAck = tcpclient->nextSeqNo; TCPSegment *syn = tcpclient->currentOut->segment; if (sock->domain == AF_INET) { syn->srcport = ((struct sockaddr_in*)&pend->local)->sin_port; syn->dstport = ((struct sockaddr_in*)&pend->peer)->sin_port; } else { syn->srcport = ((struct sockaddr_in6*)&pend->local)->sin6_port; syn->dstport = ((struct sockaddr_in6*)&pend->peer)->sin6_port; }; syn->seqno = htonl(tcpclient->nextSeqNo-1); syn->ackno = htonl(pend->ackno); syn->dataOffsetNS = 0x50; syn->flags = TCP_SYN | TCP_ACK; syn->winsz = htons(TCP_BUFFER_SIZE); ChecksumOutbound(tcpclient->currentOut); KernelThreadParams pars; memset(&pars, 0, sizeof(KernelThreadParams)); pars.stackSize = DEFAULT_STACK_SIZE; pars.name = "TCP Thread"; tcpclient->thread = CreateKernelThread(tcpThread, &pars, tcpclient); semSignal(&tcpclient->lock); semSignal(&tcpclient->semConnected); if (addrlenptr != NULL) *addrlenptr = INET_SOCKADDR_LEN; if (addr != NULL) { memcpy(addr, &pend->peer, INET_SOCKADDR_LEN); }; kfree(pend); return client; };