📄 sockets.c
字号:
/* * Copyright (C) 2007 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */#include <stdio.h>#include <stdlib.h>#include <unistd.h>#include <errno.h>#include <string.h>#include <ctype.h>#include "sysdeps.h"#define TRACE_TAG TRACE_SOCKETS#include "adb.h"ADB_MUTEX_DEFINE( socket_list_lock );static void local_socket_close_locked(asocket *s);int sendfailmsg(int fd, const char *reason){ char buf[9]; int len; len = strlen(reason); if(len > 0xffff) len = 0xffff; snprintf(buf, sizeof buf, "FAIL%04x", len); if(writex(fd, buf, 8)) return -1; return writex(fd, reason, len);}//extern int online;static unsigned local_socket_next_id = 1;static asocket local_socket_list = { .next = &local_socket_list, .prev = &local_socket_list,};asocket *find_local_socket(unsigned id){ asocket *s; asocket *result = NULL; adb_mutex_lock(&socket_list_lock); for(s = local_socket_list.next; s != &local_socket_list && !result; s = s->next) { if(s->id == id) result = s; } adb_mutex_unlock(&socket_list_lock); return result;}void install_local_socket(asocket *s){ adb_mutex_lock(&socket_list_lock); s->id = local_socket_next_id++; s->next = &local_socket_list; s->prev = local_socket_list.prev; s->prev->next = s; s->next->prev = s; adb_mutex_unlock(&socket_list_lock);}void remove_socket(asocket *s){ // socket_list_lock should already be held if (s->prev && s->next) { s->prev->next = s->next; s->next->prev = s->prev; s->next = 0; s->prev = 0; s->id = 0; }}void close_all_sockets(atransport *t){ asocket *s; /* this is a little gross, but since s->close() *will* modify ** the list out from under you, your options are limited. */ adb_mutex_lock(&socket_list_lock);restart: for(s = local_socket_list.next; s != &local_socket_list; s = s->next){ if(s->transport == t || (s->peer && s->peer->transport == t)) { local_socket_close_locked(s); goto restart; } } adb_mutex_unlock(&socket_list_lock);}static int local_socket_enqueue(asocket *s, apacket *p){ D("LS(%d): enqueue %d\n", s->id, p->len); p->ptr = p->data; /* if there is already data queue'd, we will receive ** events when it's time to write. just add this to ** the tail */ if(s->pkt_first) { goto enqueue; } /* write as much as we can, until we ** would block or there is an error/eof */ while(p->len > 0) { int r = adb_write(s->fd, p->ptr, p->len); if(r > 0) { p->len -= r; p->ptr += r; continue; } if((r == 0) || (errno != EAGAIN)) { D( "LS(%d): not ready, errno=%d: %s\n", s->id, errno, strerror(errno) ); s->close(s); return 1; /* not ready (error) */ } else { break; } } if(p->len == 0) { put_apacket(p); return 0; /* ready for more data */ }enqueue: p->next = 0; if(s->pkt_first) { s->pkt_last->next = p; } else { s->pkt_first = p; } s->pkt_last = p; /* make sure we are notified when we can drain the queue */ fdevent_add(&s->fde, FDE_WRITE); return 1; /* not ready (backlog) */}static void local_socket_ready(asocket *s){ /* far side is ready for data, pay attention to readable events */ fdevent_add(&s->fde, FDE_READ);// D("LS(%d): ready()\n", s->id);}static void local_socket_close(asocket *s){ adb_mutex_lock(&socket_list_lock); local_socket_close_locked(s); adb_mutex_unlock(&socket_list_lock);}static void local_socket_close_locked(asocket *s){ apacket *p, *n; if(s->peer) { s->peer->peer = 0; // tweak to avoid deadlock if (s->peer->close == local_socket_close) local_socket_close_locked(s->peer); else s->peer->close(s->peer); } /* IMPORTANT: the remove closes the fd ** that belongs to this socket */ fdevent_remove(&s->fde); /* dispose of any unwritten data */ for(p = s->pkt_first; p; p = n) { D("LS(%d): discarding %d bytes\n", s->id, p->len); n = p->next; put_apacket(p); } D("LS(%d): closed\n", s->id); remove_socket(s); free(s);}static void local_socket_event_func(int fd, unsigned ev, void *_s){ asocket *s = _s; if(ev & FDE_READ){ apacket *p = get_apacket(); unsigned char *x = p->data; size_t avail = MAX_PAYLOAD; int r; int is_eof = 0; while(avail > 0) { r = adb_read(fd, x, avail); if(r > 0) { avail -= r; x += r; continue; } if(r < 0) { if(errno == EAGAIN) break; if(errno == EINTR) continue; } /* r = 0 or unhandled error */ is_eof = 1; break; } if((avail == MAX_PAYLOAD) || (s->peer == 0)) { put_apacket(p); } else { p->len = MAX_PAYLOAD - avail; r = s->peer->enqueue(s->peer, p); if(r < 0) { /* error return means they closed us as a side-effect ** and we must retutn immediately */ return; } if(r > 0) { /* if the remote cannot accept further events, ** we disable notification of READs. They'll ** be enabled again when we get a call to ready() */ fdevent_del(&s->fde, FDE_READ); } } if(is_eof) { s->close(s); } return; } if(ev & FDE_WRITE){ apacket *p; while((p = s->pkt_first) != 0) { while(p->len > 0) { int r = adb_write(fd, p->ptr, p->len); if(r > 0) { p->ptr += r; p->len -= r; continue; } if(r < 0) { if(errno == EAGAIN) return; if(errno == EINTR) continue; } s->close(s); return; } if(p->len == 0) { s->pkt_first = p->next; if(s->pkt_first == 0) s->pkt_last = 0; put_apacket(p); } } /* no more packets queued, so we can ignore ** writable events again and tell our peer ** to resume writing */ fdevent_del(&s->fde, FDE_WRITE); s->peer->ready(s->peer); return; } if(ev & FDE_ERROR){ /* this should be caught be the next read or write ** catching it here means we may skip the last few ** bytes of readable data. */// s->close(s); return; }}asocket *create_local_socket(int fd){ asocket *s = calloc(1, sizeof(asocket)); if(s == 0) fatal("cannot allocate socket"); install_local_socket(s); s->fd = fd; s->enqueue = local_socket_enqueue; s->ready = local_socket_ready; s->close = local_socket_close; fdevent_install(&s->fde, fd, local_socket_event_func, s);/* fdevent_add(&s->fde, FDE_ERROR); */ //fprintf(stderr, "Created local socket in create_local_socket \n"); D("LS(%d): created (fd=%d)\n", s->id, s->fd); return s;}asocket *create_local_service_socket(const char *name){ asocket *s; int fd;#if !ADB_HOST if (!strcmp(name,"jdwp")) { return create_jdwp_service_socket(); } if (!strcmp(name,"track-jdwp")) { return create_jdwp_tracker_service_socket(); }#endif fd = service_to_fd(name); if(fd < 0) return 0; s = create_local_socket(fd); D("LS(%d): bound to '%s'\n", s->id, name); return s;}#if ADB_HOSTstatic asocket *create_host_service_socket(const char *name, const char* serial){ asocket *s; s = host_service_to_socket(name, serial); if (s != NULL) { D("LS(%d) bound to '%s'\n", s->id, name); return s; } return s;}#endif /* ADB_HOST *//* a Remote socket is used to send/receive data to/from a given transport object** it needs to be closed when the transport is forcibly destroyed by the user
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -